Other Parts Discussed in Thread: EK-TM4C1294XL
Hi all,
I am trying to modify a custom board utilizing the TM4C1294NCPDT microcontroller to create trigger source/fan out. The goal of the board is to receive a trigger signal, causing multiple timers (ideally all 6) to start counting which then outputs a signal when they timeout (counter values are updated through an HTTP POST request, therefore a running Ethernet routine in the background).
Software use:
- Code Composer Studio 7.1.10
- LM Flash Programmer
Hardware use:
- EK-TM4C1294XL (debug portion as the debugger/programmer)
- Tektronix TDS 2024C Oscilloscope (felt the need to mention this)
As mentioned above, timers start counting when the user triggers (rising edge input) the board, the purpose of the timers is to create a delay before triggering their respective devices. Right now, I'm attempting to put a 10 us delay in both Timer 4 and Timer 5 using PIOSC as my peripheral clock with no success (where success means that I trigger my devices with a 10 us delay, with little error as possible). The output of my board with the most current code is as follows:
- Above image is the output of the board, where yellow is the triggering trace
- The user triggers the LED (rising edge) and Timer 5 (Purple trace) interrupt service routine will turn it off (falling edge) prior to clearing interrupt flag.
- Blue and purple trace are timer 4 and timer 5 ISR respectively.
- The trigger trace is 13.40 us wide (from trigger signal to purple ISR routine), blue trace is 600 ns past the falling edge of the trigger (turns on 4 us later than intended), and purple is 1.8 us past the falling edge of the trigger (turns on 5.2 us later than intended).
- Cursors (dashed yellow lines) in the above image is 10 us wide to show the discrepancy of the time elapsed to entering the ISR.
Timer configuration code is as follows:
void initTimer(void) { // Enable all timer module peripherals MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER4); MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER5); // Enable PIOSC MAP_SysCtlAltClkConfig(SYSCTL_ALTCLK_PIOSC); // Calibrate PIOSC to ensure best/closest to 16 MHz timer value MAP_SysCtlPIOSCCalibrate(SYSCTL_PIOSC_CAL_FACT); // Configure Timer peripheral to use PIOSC instead of default (system clock) MAP_TimerClockSourceSet(TIMER4_BASE, TIMER_CLOCK_PIOSC); MAP_TimerClockSourceSet(TIMER5_BASE, TIMER_CLOCK_PIOSC); // Configure Timers into two 16-bit timers in edge time count up mode MAP_TimerConfigure(TIMER4_BASE, TIMER_CFG_PERIODIC); MAP_TimerConfigure(TIMER5_BASE, TIMER_CFG_PERIODIC); // Enable processor interrupts to occur MAP_IntMasterEnable(); // Ensure no pending interrupts occur after enabling the timer interrupts MAP_TimerIntClear(TIMER4_BASE, INT_TIMER4A); MAP_TimerIntClear(TIMER5_BASE, INT_TIMER5A); // Enable timer interrupts to occur on timeouts MAP_IntEnable(INT_TIMER4A); MAP_IntEnable(INT_TIMER5A); MAP_TimerIntEnable(TIMER4_BASE, TIMER_TIMA_TIMEOUT); MAP_TimerIntEnable(TIMER5_BASE, TIMER_TIMA_TIMEOUT); }
Trigger Code is as follows:
void PortBIntHandler (void) { if (MAP_GPIOIntStatus(GPIO_PORTB_BASE, false) & GPIO_INT_PIN_5) { MAP_GPIOIntClear(GPIO_PORTB_BASE, GPIO_INT_PIN_5); //uint32_t timerDelayLoad = delay[0] * 120 - 300; //uint32_t timerDelayLoad2 = delay[1] * 120 - 300; uint32_t timerDelayLoad1 = delay[0] * 8; uint32_t timerDelayLoad2 = delay[1] * 8; //MAP_TimerLoadSet(TIMER4_BASE, TIMER_A, delay[0] * 120 - 288); //MAP_TimerLoadSet(TIMER5_BASE, TIMER_A, delay[1] * 120 - 308); MAP_TimerLoadSet(TIMER4_BASE, TIMER_A, timerDelayLoad1); MAP_TimerLoadSet(TIMER5_BASE, TIMER_A, timerDelayLoad2); //HWREG(TIMER4_BASE + TIMER_O_TAILR) = delay[0] * 120; //HWREG(TIMER5_BASE + TIMER_O_TAILR) = delay[0] * 120; MAP_TimerEnable(TIMER4_BASE, TIMER_A); MAP_TimerEnable(TIMER5_BASE, TIMER_A); MAP_TimerSynchronize(TIMER0_BASE, (TIMER_4A_SYNC | TIMER_5A_SYNC)); } }
Timer Handlers are as follows:
void Timer4IntHandler(void) { // Used for debugging purpose only MAP_GPIOPinWrite(GPIO_PORTP_BASE, GPIO_PIN_1, 0 << 1); // Clear interrupt flag first as MAP_TimerIntClear(TIMER4_BASE, TIMER_TIMA_TIMEOUT); if (MAP_GPIOPinRead(GPIO_PORTN_BASE, GPIO_PIN_1) != GPIO_PIN_1) { MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 1 << 1); MAP_TimerLoadSet(TIMER4_BASE, TIMER_A, 1200000); } else if (MAP_GPIOPinRead(GPIO_PORTN_BASE, GPIO_PIN_1) == GPIO_PIN_1) { MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1, 0 << 1); MAP_TimerDisable(TIMER4_BASE, TIMER_A); } } void Timer5IntHandler(void) { MAP_GPIOPinWrite(GPIO_PORTP_BASE, GPIO_PIN_0, 0); MAP_TimerIntClear(TIMER5_BASE, TIMER_TIMA_TIMEOUT); if (MAP_GPIOPinRead(GPIO_PORTN_BASE, GPIO_PIN_2) != GPIO_PIN_2) { MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_2, 1 << 2); MAP_TimerLoadSet(TIMER5_BASE, TIMER_A, 1200000); } else if (MAP_GPIOPinRead(GPIO_PORTN_BASE, GPIO_PIN_2) == GPIO_PIN_2) { MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_2, 0 << 2); MAP_TimerDisable(TIMER5_BASE, TIMER_A); } }
System Clock is configured as follows:
g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_INT | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000);
Initially, I used the system clock as the timer source clock, which did come close to the intended delay value, as opposed to the above PIOSC method. However, it was off by at least 1.2 us and 2.4 us (timer 4 and timer 5 respectively) which easily translates to 200 clock cycles on a 120 MHz clock. I thought possibly that the Ethernet code I have running (based on enet_io) was causing the delay, so I figured because the delay had a consistent error that I could subtract this amount of cycles. Unfortunately, this did not have my intended ideal result, but rather it brought the output closer to 10 us inconsistently.
You can see my other attempts to remedy the problem as I have just commented them out (like Direct register programming to reduce clock cycles).
I suppose my question would be - is a 5 us delay even attainable on the timers with an Ethernet Routine running in the background?
Regards,
Stephen B.
I can post more pictures if it helps - I am avoiding making this too lengthy.