365 lines
13 KiB
C
365 lines
13 KiB
C
|
|
/* 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%
|
|||
|
|
Header:The length is 1 byte, and the value is fixed at 0x54,
|
|||
|
|
indicating the beginning of the data packet;
|
|||
|
|
VerLen:The 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
|
|||
|
|
Speed:The 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
|
|||
|
|
Data:Indicates 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;
|
|||
|
|
Timestamp:The length is 2 bytes, the unit is milliseconds, and the maximum is 30000.
|
|||
|
|
When it reaches 30000, it will be counted again
|
|||
|
|
CRC check:The 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));
|
|||
|
|
}
|
|||
|
|
|