This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

SW-DK-TM4C123G: PWM Period Measure using rising edge capture with Timer 0A

Part Number: SW-DK-TM4C123G
Other Parts Discussed in Thread: EK-TM4C1294XL

Hi All,

    I am having a hard time getting a simple PWM period measure program to work and need some help.

    I am supplying a 320Hz PWM to port PL0 and I want to use a capture event to measure time between two rising edges.

    I am running the system at 16Mhz clock and therefore I am assuming that the timer runs off the system clock. Therefore I am hoping to measure 50000 counts/ticks between 2 rising edges.

    1 tick @ 16Mhz = 0.0000000625 sec and therefore, 50000 counts is 0.003125s = 320Hz. My input is very stable. I have checked it on a scope.

    I am putting my code below (Timer initialization code and the Interrupt Service Routine to capture period), which when run provides me alternate outputs of 34464 and 50000 instead of a consistent 50000. What am I doing wrong?

    Eventually I am planning to measure a period for waves between 2Hz and 20Hz. How can I slow down the timer clock? I tried using the TimerPrescale function from TivaWare library but that did not work.

void InitTimer(void)
{
UARTprintf("Initializing Timer0 A\n");
// Enable and configure Timer0 peripheral.
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);

while(!SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER0))
{
}

//Configure the pin that the timer reads from (PL0)
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL);
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOL))
{
}

//Configure the pin that the timer reads from (PL0)
GPIOPinConfigure(GPIO_PL0_T0CCP0);
GPIOPinTypeTimer(GPIO_PORTL_BASE, GPIO_PIN_0);

TimerDisable(TIMER0_BASE, TIMER_A); // Disable timer before configuring it
TimerConfigure(TIMER0_BASE, (TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_TIME_UP) ); // Initialize timer A to count up in edge time mode
TimerClockSourceSet(TIMER0_BASE, TIMER_CLOCK_SYSTEM); // System is set at 16MHz
// TimerPrescaleSet(TIMER0_BASE, TIMER_A, 0x20); // Unsure how this works at the moment
TimerControlEvent(TIMER0_BASE, TIMER_A, TIMER_EVENT_POS_EDGE); // Timer A records pos edge time
TimerLoadSet(TIMER0_BASE, TIMER_A, 0xFFFF); // LoadSet specifies the value upto which Timer counts

// Set the pin to use the internal pull-up. Copied from a sample project

MAP_GPIOPadConfigSet(GPIO_PORTL_BASE, GPIO_PIN_0,
GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);

// Registers a interrupt function to be called when timer A hits a rising edge event
TimerIntRegister(TIMER0_BASE, TIMER_A, Timer0CCP0IntHandler);

TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT);   // Make sure the interrupt is cleared
IntEnable(INT_TIMER0A);  // The specified interrupt is enabled in the interrupt controller.
TimerIntEnable(TIMER0_BASE, TIMER_CAPA_EVENT); // Enable the indicated timer interrupt source.

}

//When Positive edge is hit, record the values and find the difference, output to putty
void Timer0CCP0IntHandler(void)
{
TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT);
if (gFLAG == 0)
{
gEnd = TimerValueGet(TIMER0_BASE, TIMER_A);
gLength = gEnd - gStart;
UARTprintf("\ngEnd = %d\n", gEnd);
UARTprintf("\nLENGTH = %d\n", gLength);
gFLAG = 1;
}
else {
gStart = gEnd;
gEnd = TimerValueGet(TIMER0_BASE, TIMER_A);
gLength = gEnd - gStart;
UARTprintf("\ngEnd = %d ", gEnd);
UARTprintf("LENGTH = %d\n", gLength);
}
}

  • Hi,

      Please note the Timer0A is a 16-bit timer. Therefore, the Timer0A will timeout at a maximum of 244Hz assuming your System clock is 16Mhz. You didn't post your code on how you configure the System clock. If your input is slower than 244Hz then you will need to change the timebase of the Timer0 by using the TimerPrescaleSet() API or otherwise the timer counter will overflow before the next edge is detected. If you prescale by 2 then you will be able to measure input up to 244 / 2 = 122Hz input. You will prescale more if your input is slower. This information is for you if you are going to measure 2 to 20Hz in the future. 

      If you are measuring the a 320Hz signal then the 16-bit timer should do the work. There is a TivaWare example that demonstrates timer edge capture.  It can be found in C:\ti\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c1294xl\timer_edge_capture. Please note this example is for tm4c129 but you should be able to adapt to TM4C123. Another note of this example is that it uses two pins with two timers to capable of measuring very fast transition between two different edges but you can use one timer if your rise-to-rise is not fast.  

      One thing I will also suggest is that you remove the UARTprintf() in your ISR. The UARTPrintf is a blocking function. If the UARTPrintf is sending a long string to the terminal then you may miss the next rising edge interrupt. 

  • Hi Charles,

        The system clock is indeed 16Mhz.

        Your suggestion on getting the UARTprintf() out of the ISR was spot on. At first, I changed the UARTprintf to just print only the period string (minimizing the string length sent to the terminal) and that worked to get consistent results. Once I verified, I moved it out of the ISR.  So, thank you !

         The prescaler not working when using the TimerPrescaleSet() command continued to be an issue. So, I reprogrammed the initialization code using the register model and it works as expected down to measuring the duty cycle and periods for waves as low as 2hz in frequency.

         Thanks again !