Files
TweinStein/RTOS_Labs_common/LD19.c
2026-06-12 02:55:04 -07:00

365 lines
13 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 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));
}