/* aPeriodicIntmain.c * Jonathan Valvano * December 19, 2025 * Derived from timx_timer_mode_periodic_sleep_LP_MSPM0G3507_nortos_ticlang * gpio_toggle_output_LP_MSPM0G3507_nortos_ticlang * */ #include #include "../inc/LaunchPad.h" #include "../inc/Clock.h" #define NUMTASKS 3 #define RUNLENGTH 1000 // 7 sec #define PERIOD (80*7000) // 1+2+4ms uint32_t Count0,Count1,Count2; //---------------------User debugging----------------------- int32_t MaxJitter[NUMTASKS]; // largest time jitter between interrupts in 10 usec #define JITTERSIZE 32 uint32_t const JitterSize=JITTERSIZE; uint32_t JitterHistogram[NUMTASKS][JITTERSIZE]={0,}; // Unused sensor board pins, made outputs for debugging // Jumper J14 select PA9 // Jumper J15 select PA16 void Logic_Init(void){ IOMUX->SECCFG.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); } uint32_t TheTime(void){ return ~(TIMG12->COUNTERREGS.CTR); }; void Task0(void){ GPIOA->DOUTTGL31_0 = (1<<8); // PA8 uint32_t thisTime,jitter; static uint32_t LastTime; // time at previous execution, 12.5 ns thisTime = TheTime(); // current time, 12.5 ns Count0++; if(Count0>2){ // ignore timing of first couple interrupt uint32_t diff = thisTime-LastTime; // down count if(diff>PERIOD){ // should be 1ms (12.5ns units) jitter = (diff-PERIOD); // in 12.5ns }else{ jitter = (PERIOD-diff); // in 12.5ns } if(jitter > MaxJitter[0]){ MaxJitter[0] = jitter; // in 12.5ns } // jitter should be 0 if(jitter >= JitterSize){ jitter = JitterSize-1; } JitterHistogram[0][jitter]++; } LastTime = thisTime; } void Task1(void){ GPIOA->DOUTTGL31_0 = (1<<9); // PA9 uint32_t thisTime,jitter; static uint32_t LastTime; // time at previous execution, 12.5 ns thisTime = TheTime(); // current time, 12.5 ns Count1++; if(Count1>2){ // ignore timing of first couple interrupt uint32_t diff = thisTime-LastTime; // down count if(diff>PERIOD){ // should be 1ms (12.5ns units) jitter = (diff-PERIOD); // in 12.5ns }else{ jitter = (PERIOD-diff); // in 12.5ns } if(jitter > MaxJitter[1]){ MaxJitter[1] = jitter; // in 12.5ns } // jitter should be 0 if(jitter >= JitterSize){ jitter = JitterSize-1; } JitterHistogram[1][jitter]++; } LastTime = thisTime; } void Task2(void){ GPIOA->DOUTTGL31_0 = (1<<16); // PA16 uint32_t thisTime,jitter; static uint32_t LastTime; // time at previous execution, 12.5 ns thisTime = TheTime(); // current time, 12.5 ns Count2++; if(Count2>2){ // ignore timing of first couple interrupt uint32_t diff = thisTime-LastTime; // down count if(diff>PERIOD){ // should be 1ms (12.5ns units) jitter = (diff-PERIOD); // in 12.5ns }else{ jitter = (PERIOD-diff); // in 12.5ns } if(jitter > MaxJitter[0]){ MaxJitter[2] = jitter; // in 12.5ns } // jitter should be 0 if(jitter >= JitterSize){ jitter = JitterSize-1; } JitterHistogram[2][jitter]++; } LastTime = thisTime; } void TogglePB4(void){ GPIOB->DOUTTGL31_0 = (1<<4);} void TogglePB1(void){ GPIOB->DOUTTGL31_0 = (1<<1);} void TogglePB20(void){GPIOB->DOUTTGL31_0 = (1<<20);} struct event{ void(*task)(void); // this task to run uint32_t timeToNext; // time for this task }; typedef const struct event event_t; uint32_t ThisTask; event_t Tasks[NUMTASKS]={ {Task0, 4000}, // Toggle PA8 then wait 4ms {Task1, 2000}, // Toggle PA9 then wait 2ms {Task2, 1000} // Toggle PA16 then wait 1ms }; void Jitter_Init(void){ for(int j=0; jGPRCM.RSTCTL = (uint32_t)0xB1000003; TIMG7->GPRCM.PWREN = (uint32_t)0x26000001; Clock_Delay(24); // time for TimerG7 to power up TIMG7->CLKSEL = 0x08; // bus clock TIMG7->CLKDIV = 0x00; // divide by 1 TIMG7->COMMONREGS.CPS = prescale-1; // divide by prescale TIMG7->COUNTERREGS.LOAD = 80000-1; // set reload register, will be reset during each ISR TIMG7->COUNTERREGS.CTRCTL = 0x02; // bits 5-4 CM =0, down // bits 3-1 REPEAT =001, continue // bit 0 EN enable (0 for disable, 1 for enable) TIMG7->CPU_INT.IMASK |= 1; // zero event mask TIMG7->COMMONREGS.CCLKCTL = 1; NVIC->ISER[0] = 1 << 20; // TIMG7 interrupt NVIC->IP[5] = (NVIC->IP[5]&(~0x000000FF))|(priority<<6); // set priority (bits 7,6) IRQ 20 TIMG7->COUNTERREGS.CTRCTL |= 0x01; } // G12 for profiling void TimerG12_Init(void){ TIMG12->GPRCM.RSTCTL = (uint32_t)0xB1000003; TIMG12->GPRCM.PWREN = (uint32_t)0x26000001; Clock_Delay(24); // time for TimerG8 to power up TIMG12->CLKSEL = 0x08; // bus clock TIMG12->CLKDIV = 0; // divide by 1 // TIMG8->COMMONREGS.CPS = prescale-1; // divide by prescale, TIMG12->COUNTERREGS.LOAD = 0xFFFFFFFF; // set reload register TIMG12->COUNTERREGS.CTRCTL = 0x02; // bits 5-4 CM =0, down // bits 3-1 REPEAT =001, continue // bit 0 EN enable (0 for disable, 1 for enable) TIMG12->COMMONREGS.CCLKCTL = 1; TIMG12->COUNTERREGS.CTRCTL |= 0x01; } int main(void){ __disable_irq(); Clock_Init80MHz(0); Count0=Count1=Count2=0; ThisTask = 0; LaunchPad_Init(); Logic_Init(); Jitter_Init(); TimerG12_Init(); // free running timer for OS_Time TimerG7_IntArm(80,2); // 80MHz/80 = 1MHz, or 1us period __enable_irq(); while(1){ TogglePB1(); } } void TIMG7_IRQHandler(void){ if((TIMG7->CPU_INT.IIDX) == 1){ // this will acknowledge (*Tasks[ThisTask].task)(); // execute user task ThisTask = (ThisTask+1)%NUMTASKS; TIMG7->COUNTERREGS.LOAD = Tasks[ThisTask].timeToNext-1; // set reload register } }