This commit is contained in:
2026-06-12 02:55:04 -07:00
commit 30406f4f49
2040 changed files with 571534 additions and 0 deletions

364
RTOS_Labs_common/LD19.c Normal file
View File

@@ -0,0 +1,364 @@
/* LD19.c
* Jonathan Valvano
* Date: Nov 5, 2025
LiDAR Sensor LD19 distance sensor
The LD19 consists mainly of
a laser ranging core,
a wireless power transmission unit,
a wireless communication unit,
an angle measuring unit,
a motor drive unit and
a mechanical housing
Range 20mm to 12m
Sampling rate 10 Hz
Accuracy: 45mm
Standard deviation 10mm
Resolution: 15mm
Angular resolution: 0.8deg (540 measurements per rotation)
*/
#include <ti/devices/msp/msp.h>
#include "../RTOS_Labs_common/LD19.h"
#include "../inc/Clock.h"
#include "../inc/LaunchPad.h"
// There are four possible UART3 Rx pins that could be used
// Sensor board uses PB13 (UART3) and PB12=0 (GPIO output)
// LiDAR Sensor LD19 on RTOS sensor board
// Pin LD19 MSPM0
// 1 Tx PB13 RxD: is UART3 Rx (LD19 to MSPM0) baud=230400 bps
// 2 PWM PB12 GPIO write a 0 to run fastest (MSPM0 to LD19)
// 3 GND ground
// 4 P5V 5V
// UART3 is shared between LD19 and TFLuna3 (can have either but not both)
uint32_t LostDataLD19;
#define LD19_SIZE 64 // usable size is 63
#define LD19_MESSAGESIZE 47 // LD19 packet is 47 bytes, assuming length remains 12
// prototypes for private functions
void LD19Fifo_Init(void);
uint32_t LD19Fifo_Put(uint8_t data);
uint32_t LD19Fifo_Get(uint8_t *datapt);
int LD19Index;
uint8_t LD19LastByte;
uint32_t StartAngle,EndAngle,Speed,Distance[12],Intensity[12],Previous;
// 0 for looking for 54 2C
// 2-47 filling the TFLunaDataMessage with 47-byte message
//int LD19Mode; // 0 for FIFO and 1 for 540 array
uint8_t LD19DataMessage[64]; // 47 should be enough
//uint16_t Starts[256],Stops[256],Times[256],II=0;
// number of angles LD19NUM 540
//uint16_t Distances[540];
uint16_t *Distances;
int BadCnt=0; // index error
int BadDistance=0; // too low
uint32_t BadIntensity;
/*
Scope Measurements Continuous packets
Baud = 230400 bps
Packet Length = 47 bytes, 2.034ms long (470bits/230400bps = 2.039ms)
Packet period = 2.447ms
Packet frequency = 409 packets/sec
Packet payload = 12 measurements
Measurement frequency =12 measurements/2.447ms = 4904measurements/sec
540 measurements per rotation
4904 measurements/sec / 540 measurements/rotation = 9.08 rotations/sec
Overhead:
Interrupts every three frames, 130.4us (30bits/230400 bps)
15 interrupts take 3.55us (overhead 2.7%)
1 interrupt takes 13.4us (overhead 10%)
average overhead = (15*2.7%+10%)/16 = 3.2%
HeaderThe length is 1 byte, and the value is fixed at 0x54,
indicating the beginning of the data packet;
VerLenThe length is 1 byte, the upper three bits indicate the packet type,
which is currently fixed at 1, and the lower five bits indicate the number of
measurement points in a packet, which is currently fixed at 12, so the byte
value is fixed at 0x2C
SpeedThe length is 2 bytes (little endian), the unit is degrees per second, indicating the
speed of the lidar, e.g., 2152 degrees per second;
Start angle: The length is 2 bytes (little endian), and the unit is 0.01 degrees, indicating
the starting angle of the data packet point; e.g., 32427, or 324.27 degrees
DataIndicates measurement data, a measurement data length is 3 bytes, 12 measurements
Distance: 2 bytes (little endian) in mm, e.g., 1234 means 1234mm
Intensity: 1 byte, the typical value of the signal strength value is around 200
End angle: The length is 2 bytes (little endian), and the unit is 0.01 degrees, indicating
the end angle of the data packet point; e.g., 33470, or 334.7 degrees;
TimestampThe length is 2 bytes, the unit is milliseconds, and the maximum is 30000.
When it reaches 30000, it will be counted again
CRC checkThe length is 1 byte, obtained from the verification of all the previous data except itself.
*/
// UART3 is in power Domain PD1
// for 32MHz bus clock, UART3 clock is 32MHz
// for 40MHz bus clock, UART3 clock is MCLK 40MHz
// for 80MHz bus clock, UART3 clock is MCLK 80MHz
//------------LD19_Init------------
// Initialize the UART3 for 230400 baud rate (assuming 80 MHz clock),
// 8 bit word length, no parity bits, one stop bit, FIFOs enabled
// Input: function 0 for debug, 1 for real time
// Output: none
void LD19_Init(uint16_t *d){
// do not reset or activate PortA, already done in LaunchPad_Init
// RSTCLR to GPIOA and UART3 peripherals
// bits 31-24 unlock key 0xB1
// bit 1 is Clear reset sticky bit
// bit 0 is reset gpio port
// GPIOA->GPRCM.RSTCTL = (uint32_t)0xB1000003; // called previously
UART3->GPRCM.RSTCTL = 0xB1000003;
// Enable power to GPIOA and UART3 peripherals
// PWREN
// bits 31-24 unlock key 0x26
// bit 0 is Enable Power
// GPIOA->GPRCM.PWREN = (uint32_t)0x26000001; // called previously
UART3->GPRCM.PWREN = 0x26000001;
Clock_Delay(24); // time for uart to power up
// the following code selects PB13 to use UART3
IOMUX->SECCFG.PINCM[PB13INDEX] = 0x00040082;
//bit 18 INENA input enable
//bit 7 PC connected
//bits 5-0=2 for UART3_Rx
// configure PB12 to be GPIO output
IOMUX->SECCFG.PINCM[PB12INDEX] = 0x00000081;
//bit 7 PC connected
//bits 5-0=1 for GPIO
GPIOB->DOE31_0 |= (1<<12); // enable output
GPIOB->DOUTCLR31_0 = (1<<12); // PWM=0, fastest sampling
UART3->CLKSEL = 0x08; // bus clock
UART3->CLKDIV = 0x00; // no divide
UART3->CTL0 &= ~0x01; // disable UART3
UART3->CTL0 = 0x00020018;
// bit 17 FEN=1 enable FIFO
// bits 16-15 HSE=00 16x oversampling
// bit 14 CTSEN=0 no CTS hardware
// bit 13 RTSEN=0 no RTS hardware
// bit 12 RTS=0 not RTS
// bits 10-8 MODE=000 normal
// bits 6-4 TXE=001 enable TxD
// bit 3 RXE=1 enable TxD
// bit 2 LBE=0 no loop back
// bit 0 ENABLE 0 is disable, 1 to enable
if(Clock_Freq() == 40000000){
// 40000000/16 = 2,500,000 Hz
// Baud = 230400
// 2,500,000/230400 = 10.8506944444
// divider = 10+54/64 = 10.84375
UART3->IBRD = 10;
UART3->FBRD = 54; // baud =2,500,000/10.84375 = 230,547.55
}else if (Clock_Freq() == 32000000){
// 32000000/16 = 2,000,000
// Baud = 230400
// 2,000,000/230400 = 8.6805555
// divider = 8+43/64 = 8.671875
UART3->IBRD = 8;
UART3->FBRD = 43; // 230,630.63
}else if (Clock_Freq() == 80000000){
// 80000000/16 = 5,000,000 Hz
// Baud = 230400
// 5,000,000/230400 = 21.701388
// divider = 21+45/64 = 21.703125
UART3->IBRD = 21;
UART3->FBRD = 45; // baud =5,000,000/21.703125 = 230,381.569
}else return;
//LD19Mode = mode;
Distances = d;
LD19Index = 0; // looking for 0x54 0x2C
LD19LastByte = 0;
LD19DataMessage[0] = 0x54;
LD19DataMessage[1] = 0x2C;
LD19Fifo_Init();
LostDataLD19 = 0;
UART3->LCRH = 0x00000030;
// bits 5-4 WLEN=11 8 bits
// bit 3 STP2=0 1 stop
// bit 2 EPS=0 parity select
// bit 1 PEN=0 no parity
// bit 0 BRK=0 no break
UART3->CPU_INT.IMASK = 0x0401;
// bit 11 TXINT no
// bit 10 RXINT yes
// bit 0 Receive timeout, yes
UART3->IFLS = 0x0232;
// bits 11-8 RXTOSEL receiver timeout select 2 (0xF highest)
// bits 6-4 RXIFLSEL 3 is greater than or equal to 3/4 full (three elements)
// bits 2-0 TXIFLSEL 2 is less than or equal to half
NVIC->ICPR[0] = 1<<3; // UART3 is IRQ 3
NVIC->ISER[0] = 1<<3;
NVIC->IP[0] = (NVIC->IP[0]&(~0xFF000000))|(1<<30); // set priority (bits 31-30) IRQ 3
UART3->CTL0 |= 0x01; // enable UART3
}
// pointer to most recent array of 540 measurements
//uint16_t *LD19_GetDistances(void){
// return Distances;
//}
// copy from hardware RX FIFO to software LD19Fifo
// stop when hardware RX FIFO is empty
// data are lost if software LD19Fifo is full
void static copyHardwareToSoftwareLD19(void){
uint8_t letter;
if(Distances==0){ // raw data mode
while((UART3->STAT&0x04) == 0){// empty RX hardware FIFO
letter = UART3->RXDATA;
if((LD19Fifo_Put(letter))==0){
LostDataLD19++;
}
}
}else{
while((UART3->STAT&0x04)==0){ // empty RX hardware FIFO
letter = UART3->RXDATA;
if(LD19Index == 0){ // looking for sequence 0x54,0x2C
if((letter == 0x2C)&&(LD19LastByte == 0x54)){
LD19Index = 2; // looking for message
}
LD19LastByte = letter;
}else{
LD19DataMessage[LD19Index] = letter;
LD19Index++;
if(LD19Index == LD19_MESSAGESIZE){
// GPIOB->DOUTTGL31_0 = BLUE; // PB22
// Speed = LD19DataMessage[2]+(LD19DataMessage[3]<<8);
StartAngle = LD19DataMessage[4]+(LD19DataMessage[5]<<8);
//EndAngle = LD19DataMessage[42]+(LD19DataMessage[43]<<8);
// StartAngle goes from 0 to 35999
// index goes from 0 to 540-1 (539()
//uint32_t index = (540*StartAngle)/36000; // 0 to 539
uint32_t findex = (983*StartAngle)>>16;
if(findex>=540) {
findex = 540-1;
BadCnt++; // never happens
}
for(int i=0;i<12;i++){
uint16_t d = LD19DataMessage[6+3*i]+(LD19DataMessage[7+3*i]<<8);
if(d < 10){
BadDistance++; // happens a lot, might be low intensity
BadIntensity = LD19DataMessage[8+3*i];
if(findex==0){
d = Distances[539];
if(d > 10){
Distances[findex+i] = d;
}
}else{
d = Distances[findex+i-1];
if(d > 10){
Distances[findex+i] = Distances[findex+i-1];
}
}
}else{
Distances[findex+i] = d;
}
// if(findex > 270){
// GPIOA->DOUTSET31_0 = 1;
// GPIOB->DOUTSET31_0 = BLUE; // PB22
// }
// if(findex < 200){
// GPIOA->DOUTCLR31_0 = 1;
// GPIOB->DOUTCLR31_0 = BLUE; // PB22
// }
// Distance[i] = d;
// Intensity[i] = LD19DataMessage[8+3*i];
}
/*
Starts[II] = StartAngle;
Stops[II] = EndAngle;
Times[II] = LD19DataMessage[44]+(LD19DataMessage[45]<<8);
II = (II+1)&0xFF;
*/
LD19LastByte = 0; // get ready for next message
LD19Index = 0;
}
}
}
}
}
//------------LD19_InChar------------
// Wait for new serial port input
// Input: none
// Output: ASCII code for key typed
uint8_t LD19_InChar(void){uint32_t status;
uint8_t letter;
do{
status = LD19Fifo_Get(&letter);
}while(status==0);
return(letter);
}
void UART3_IRQHandler(void){ uint32_t status;
status = UART3->CPU_INT.IIDX; // reading clears bit in RIS
// GPIOA->DOUTTGL31_0 = 1;
GPIOB->DOUTSET31_0 = BLUE; // PB22
if(status == 0x01){ // 0x01 receive timeout
copyHardwareToSoftwareLD19();
}else if(status == 0x0B){ // 0x0B receive
copyHardwareToSoftwareLD19();
}
GPIOB->DOUTCLR31_0 = BLUE; // PB22
}
// Declare state variables for FiFo
// size, buffer, put and get indexes
int32_t static LD19PutI; // Index to put new
int32_t static LD19GetI; // Index of oldest
uint8_t static LD19Fifo[LD19_SIZE];
// *********** LD19Fifo_Init**********
// Initializes a software LD19Fifo of a
// fixed size and sets up indexes for
// put and get operations
void LD19Fifo_Init(void){
LD19PutI = LD19GetI = 0;
}
// *********** LD19Fifo_Put**********
// Adds an element to the LD19FIFO
// Input: data is character to be inserted
// Output: 1 for success, data properly saved
// 0 for failure, LD19Fifo is full
uint32_t LD19Fifo_Put(uint8_t data){
if(((LD19PutI+1)&(LD19_SIZE-1)) == LD19GetI){
return 0;
}
LD19Fifo[LD19PutI] = data;
LD19PutI = (LD19PutI+1)&(LD19_SIZE-1);
return 1;
}
// *********** LD19Fifo_Get**********
// Gets an element from the LD19FIFO
// Input: pointer to empty 8-bit variable
// Output: If the LD19FIFO is empty return 0
// If the LD19FIFO has data, remove it, and put in *datapt, return 1
uint32_t LD19Fifo_Get(uint8_t *datapt){
if(LD19GetI == LD19PutI){
return 0;
}
*datapt = LD19Fifo[LD19GetI];
LD19GetI = (LD19GetI+1)&(LD19_SIZE-1);
return 1;
}
//------------LD19_InStatus------------
// Returns how much data available for reading from LD19 FIFO
// Input: none
// Output: number of elements in receive FIFO
uint32_t LD19_InStatus(void){
return ((LD19PutI - LD19GetI)&(LD19_SIZE-1));
}