/* RTOS_Lab2.c * Jonathan Valvano * December 227, 2025 * Remove 3.3V J101 jumper to run RTOS sensor board or motor board * A two-pin female header is required on the LaunchPad TP10(XDS_VCC) and TP9(!RSTN) */ #include #include "../inc/LaunchPad.h" #include "../RTOS_Labs_common/ADC.h" #include "../inc/Clock.h" #include "../RTOS_Labs_common/ST7735_SDC.h" #include "../RTOS_Labs_common/RTOS_UART.h" #include "../RTOS_Labs_common/Interpreter.h" #include "../RTOS_Labs_common/IRDistance.h" #include "../RTOS_Labs_common/LPF.h" #include "../RTOS_Labs_common/DFT16.h" #include "../RTOS_Labs_common/TFLuna2.h" #include "../RTOS_Labs_common/OS.h" #include // PA10 is UART0 Tx index 20 in IOMUX PINCM table // PA11 is UART0 Rx index 21 in IOMUX PINCM table // Insert jumper J21: Connects PA10 to XDS_UART // Insert jumper J22: Connects PA11 to XDS_UART // Insert jumper J14 SW1 to select PA9 // Insert jumper J15 SW2 to select PA16 // Remove jumps J16,J17,J18: disconnect light sensor // PA0 is red LED1, index 0 in IOMUX PINCM table, negative logic // PB22 is BLUE LED2, index 49 in IOMUX PINCM table // PB26 is RED LED2, index 56 in IOMUX PINCM table // PB27 is GREEN LED2, index 57 in IOMUX PINCM table // PA18 is S1 positive logic switch, conflict with TFLuna1, so S1 will not be used // PB21 is S2 negative logic switch, used for aperiodic task // IR analog distance sensors // 30 cm GP2Y0A41SK0F or 80 cm long range GP2Y0A21YK0F // PA26 Right ADC0_1 // PA24 Center ADC0_3, used in Labs 1,2,3,4 // PA22 Left ADC0_7 // PA27 Extra ADC0_0 // RTOS sensor board supported three TF-Luna sensors // Serial TxD: PA17 is UART1 Tx (MSPM0 to TFLuna1) // Serial RxD: PA18 is UART1 Rx (TFLuna1 to MSPM0), conflict with LaunchPad S1 // Serial TxD: PB17 is UART2 Tx (MSPM0 to TFLuna2), used in Labs 1,2,3,4 // Serial RxD: PB18 is UART2 Rx (TFLuna2 to MSPM0), used in Labs 1,2,3,4 // Serial TxD: PB12 is UART3 Tx (MSPM0 to TFLuna3), // Serial RxD: PB13 is UART3 Rx (TFLuna3 to MSPM0), shared with LD19 Lidar //UART3 is shared between LD19 and TFLuna3 (can have either but not both) uint32_t NumCreated; // number of foreground threads created // 10-sec finite time experiment duration Sema4_t LCDFree; // SDC and LCD sharing //---------------------User debugging----------------------- // Performance Measurements int32_t MaxJitter; // largest time jitter between interrupts in 12.5ns #define JITTERSIZE 256 uint32_t const JitterSize=JITTERSIZE; uint32_t JitterHistogram[JITTERSIZE]={0,}; void Jitter_Init(void){ for(int i=0;iSECCFG.PINCM[PA8INDEX] = (uint32_t) 0x00000081; IOMUX->SECCFG.PINCM[PA9INDEX] = (uint32_t) 0x00000081; IOMUX->SECCFG.PINCM[PA16INDEX] = (uint32_t) 0x00000081; IOMUX->SECCFG.PINCM[PB4INDEX] = (uint32_t) 0x00000081; IOMUX->SECCFG.PINCM[PB1INDEX] = (uint32_t) 0x00000081; IOMUX->SECCFG.PINCM[PB20INDEX] = (uint32_t) 0x00000081; GPIOA->DOE31_0 |= (1<<8)|(1<<9)|(1<<16); GPIOB->DOE31_0 |= (1<<4)|(1<<1)|(1<<20); } #define TogglePA8() (GPIOA->DOUTTGL31_0 = (1<<8)) #define TogglePA9() (GPIOA->DOUTTGL31_0 = (1<<9)) #define TogglePA16() (GPIOA->DOUTTGL31_0 = (1<<16)) #define TogglePB4() (GPIOB->DOUTTGL31_0 = (1<<4)) #define TogglePB1() (GPIOB->DOUTTGL31_0 = (1<<1)) #define TogglePB20() (GPIOB->DOUTTGL31_0 = (1<<20)) uint32_t Checks; // number of times virus checking has run uint32_t ChecksWork; // number of checks in 10 second //------------------Task 1-------------------------------- // Fixed bandwidth // real-time sampling ADC0 channel 3, using software start trigger // 60-Hz notch high-Q, IIR filter, assuming fs=1000 Hz // y(n) = (256x(n) -476x(n-1) + 256x(n-2) + 471y(n-1)-251y(n-2))/256 (1k sampling) #define PERIOD TIME_1MS // DAS 1kHz sampling period in system time units #define FS 1000 // DAS sampling #define RUNLENGTH (10000) // display results and quit when FilterWork==RUNLENGTH uint32_t FilterOutput,Distance; uint32_t FilterWork; //******** DAS *************** // background thread, calculates 60Hz notch filter // runs 1000 times/sec // samples PA24 Center ADC0_3, calculates Distance // inputs: none // outputs: none void DAS(void){ uint32_t input; static uint32_t LastTime; // time at previous ADC sample, 12.5 ns uint32_t thisTime; // time at current ADC sample, 12.5 ns uint32_t jitter; // time between measured and expected, 12.5 ns TogglePA8(); // toggle PA8 input = ADC0_In(); // channel 3 set when calling ADC0_Init TogglePA8(); // toggle PA8 thisTime = OS_Time(); // current time, 12.5 ns FilterOutput = Filter(input); Distance = IRDistance_Convert(FilterOutput,0); // in mm if(FilterWork < RUNLENGTH){ // finite time run FilterWork++; // calculation finished if(FilterWork>1){ // ignore timing of first interrupt uint32_t diff = OS_TimeDifference(LastTime,thisTime); if(diff>PERIOD){ jitter = (diff-PERIOD); // in 12.5 ns }else{ jitter = (PERIOD-diff); // in 12.5 ns } if(jitter > MaxJitter){ MaxJitter = jitter; // in 12.5 ns } // jitter should be 0 if(jitter >= JitterSize){ jitter = JitterSize-1; } JitterHistogram[jitter]++; } ChecksWork = Checks; LastTime = thisTime; } TogglePA8(); // toggle PA8 } //--------------end of Task 1----------------------------- //------------------Task 2-------------------------------- // I/O Bound // background thread executes with S2 button // S2 negative logic switch on PB21 // one foreground task created with each button push // foreground treads run for about 500ms and dies uint32_t DataLost; // data sent by Producer, but not received by Consumer // ***********ButtonWork************* void ButtonWork(void){ uint32_t myId = OS_Id(); ST7735_Message(1,0,"myID =",myId); OS_Sleep(500); // set this to sleep for 500msec ST7735_Message(1,1,"Distance(mm)=",Distance); ST7735_Message(1,2,"Checks =",Checks); ST7735_Message(1,3,"DataLost =",DataLost); ST7735_Message(1,4,"Jitter (cyc)=",MaxJitter); ST7735_Message(1,5,"NumCreated =",NumCreated); OS_Kill(); // done, OS does not return from a Kill } //************S2Push************* // Called when S2 Button PB21 pushed // Adds another foreground task // background threads execute once and return void S2Push(void){ TogglePA9(); // toggle PA9 TogglePA9(); // toggle PA9 if(OS_MsTime() > 20){ // debounce if(OS_AddThread(&ButtonWork,100,0)){ NumCreated++; } OS_ClearMsTime(); // at least 20ms between touches } TogglePA9(); // toggle PA9 } //--------------end of Task 2----------------------------- //------------------Task 3-------------------------------- // I/O Bound // hardware-triggered TFLuna distance sampling at 100Hz // Producer runs as part of UART2 ISR // Producer uses fifo to transmit 100 distance samples/sec to Consumer // every 64 samples, Consumer calculates FFT // every 2.5ms*64 = 160 ms (6.25 Hz), consumer sends data to Display via mailbox // Display thread updates LCD with measurement uint32_t DataLost; // data sent by Producer, but not received by Consumer uint32_t Distance2; // mm int32_t x[16],ReX[16],ImX[16]; // input and output arrays for FFT //******** Producer *************** // The Producer in this lab will be called from the UART2 ISR // The TFLuna2 samples distance at about 100 Hz // sends data to the consumer, runs periodically at 100Hz void Producer(uint32_t data){ uint32_t dist2; // mm if(FilterWork < RUNLENGTH){ // finite time run TogglePA16(); // toggle PA16 dist2 = Median5((int32_t) data); TogglePA16(); // toggle PA16 if(OS_Fifo_Put(dist2) == 0){ // send to consumer DataLost++; } TogglePA16(); // toggle PA16 } } //******** Consumer *************** // foreground thread, accepts data from producer // calculates FFT, sends DC component to Display // inputs: none // outputs: none void Display(void); void Consumer(void){ uint32_t data,DCcomponent; // 12-bit raw ADC sample, 0 to 4095 uint32_t t; // time in 2.5 ms LPF_Init7(500,7); TFLuna2_Init(&Producer); TFLuna2_Format_Standard_mm(); // format in mm TFLuna2_Frame_Rate(); // 100 samples/sec TFLuna2_SaveSettings(); // save format and rate TFLuna2_System_Reset(); // start measurements NumCreated += OS_AddThread(&Display,128,0); while(FilterWork < RUNLENGTH) { for(t = 0; t < 16; t++){ // collect 64 ADC samples data = OS_Fifo_Get(); // get from producer, mm x[t] = data; // real part is 0 to 4095, imaginary part is 0 } TogglePB4(); // toggle PB4 DFT16(x,ReX,ImX); // complex FFT of last 16 distance values TogglePB4(); // toggle PB4 DCcomponent = ReX[0]&0xFFFF; // Real part at frequency 0, imaginary part should be zero OS_MailBox_Send(DCcomponent); // called every 10ms*16 = 160ms } OS_Kill(); // done } //******** Display *************** // foreground thread, accepts data from consumer // displays calculated results on the LCD // inputs: none // outputs: none void Display(void){ uint32_t data,voltage,distance; uint32_t myId = OS_Id(); ST7735_Message(0,1,"Run length = ",(RUNLENGTH)/FS); // top half used for Display while(FilterWork < RUNLENGTH) { TogglePB1(); // toggle PB1 data = OS_MailBox_Recv(); voltage = 3000*data/4095; // calibrate your device so voltage is in mV distance = IRDistance_Convert(data,1); // you will calibrate this in Lab 6 TogglePB1(); // toggle PB1 ST7735_Message(0,2,"v(mV) =",voltage); ST7735_Message(0,3,"d(mm) =",distance); TogglePB1(); // toggle PB1 } ST7735_Message(0,4,"Num samples =",FilterWork); OS_Kill(); // done } //--------------end of Task 3----------------------------- //------------------Task 4-------------------------------- // CPU Bound // foreground thread that runs without waiting or sleeping // it executes a virus detector uint32_t Check(uint32_t start, uint32_t end){ uint32_t sum=0; uint32_t *pt; pt = (uint32_t *)start; while((uint32_t)pt < end){ sum += *pt++; } return sum; } //******** Virus Detector *************** // foreground thread, performs a checksum of all ROM // never blocks, never sleeps, never dies // inputs: none // outputs: none uint32_t Checksum; // sum of data stored in ROM uint32_t ChecksumOriginal; // sum of data stored in ROM uint32_t ChecksumErrors; void VirusDetector(void){ Checks = ChecksumErrors = 0; ChecksumOriginal = Check(0,0x20000); while(1) { TogglePB20(); // toggle PB20 Checksum = Check(0,0x20000); Checks++; if(Checksum != ChecksumOriginal){ ChecksumErrors++; } } } //--------------end of Task 4----------------------------- //------------------Task 5-------------------------------- // I/O Bound // UART0 background ISR performs serial input/output // Two software fifos are used to pass I/O data to foreground // The interpreter runs as a foreground thread // The UART0 driver should call OS_Wait(&RxDataAvailable) when foreground tries to receive // The UART0 ISR should call OS_Signal(&RxDataAvailable) when it receives data from Rx // Similarly, the transmit channel waits on a semaphore in the foreground // and the UART0 ISR signals this semaphore (TxRoomLeft) when getting data from fifo //******** Interpreter *************** // Modify your intepreter from Lab 1, adding commands to help debug // Interpreter is a foreground thread, accepts input from serial port, outputs to serial port // inputs: none // outputs: none void Interpreter(void); // just a prototype, link to your interpreter // add the following commands, leave other commands, if they make sense // 1) print performance measures // time-jitter, number of data points lost, number of calculations performed // i.e., NumCreated, MaxJitter, DataLost, FilterWork, Check // 2) print debugging parameters // i.e., Checks, ChecksumErrors // Call these from your interpreter void Lab2(void){int i; UART_OutString("\r\nLab 2 performance data"); UART_OutString("\r\nFilterWork = "); UART_OutUDec(FilterWork); UART_OutString("\r\nNumCreated = "); UART_OutUDec(NumCreated); UART_OutString("\r\nChecksWork = "); UART_OutUDec(ChecksWork); UART_OutString("\r\nDataLost = "); UART_OutUDec(DataLost); UART_OutString("\r\nMaxJitter(cyc)= "); UART_OutUDec(MaxJitter); } void Lab2_device(int device){int i; UART_OutString("\r\nLab 2 performance data"); ST7735_Message(device, 0, "FilterWork = ", FilterWork); ST7735_Message(device, 1, "NumCreated = ", NumCreated); ST7735_Message(device, 2, "ChecksWork = ", ChecksWork); ST7735_Message(device, 3, "DataLost = ", DataLost); ST7735_Message(device, 4, "MaxJitter(cyc)= ", MaxJitter); UART_OutString("\r\nFilterWork = "); UART_OutUDec(FilterWork); UART_OutString("\r\nNumCreated = "); UART_OutUDec(NumCreated); UART_OutString("\r\nChecksWork = "); UART_OutUDec(ChecksWork); UART_OutString("\r\nDataLost = "); UART_OutUDec(DataLost); UART_OutString("\r\nMaxJitter(cyc)= "); UART_OutUDec(MaxJitter); } void DFT(void){ int i; int32_t real,imag,mag; UART_OutString("\r\nLab 2/3/4 DFT data"); UART_OutString("\r\nInput, Output Real, Output Imaginary, Magnitude"); for(i=0; i<8; i++){ real = ReX[i]; imag = ImX[i]; mag = sqrt2(real*real+imag*imag); UART_OutString("\r\n"); UART_OutUDec(x[i]); UART_OutChar(' '); UART_OutSDec(real); UART_OutChar(' '); UART_OutSDec(imag); UART_OutChar(' '); UART_OutSDec(mag); } } void Jitter(void){ int i; UART_OutString("\r\nLab 2 Real-time sampling jitter (12.5ns)"); UART_OutString("\r\nTime, Frequency"); for(i=0; i