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.

Timer Capture on Tiva C Launchpad

Other Parts Discussed in Thread: TM4C123GH6PM

I want to capture time of negative edges on clock signal, and look at the period for multiple clock cycles. At moment I have a 68kHz clock with even mark space generated via PWM on PB0, this works fine, However I want to measure the period of say twenty clock cycles, in order to generate a synchronous sub clock. Using timer0A as capture, but can't get it to work. Project started off as a variant of the timer example, coupled with the LED drive at 1Hz via timer1, which works if I comment out the timer0 code. If I don't the code compiles and runs, but  appears to constantly run into the timer0 interrupt. I did not set a value for the timer0A overflow as I left it to default 0xFFFF, which should be adequate given the clock speed. Can someone advise what I am doing wrong or missing. I am new to the Tiva C series, but much more familiar with the MSP430 timers, with which I have coded some complex quite functionality.

Code:

// include file references

#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
//#include "inc/hw_types.h"
//#include "driverlib/debug.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/sysctl.h"
#include "driverlib/timer.h"

// constant defines

#define RED_LED   GPIO_PIN_1
#define BLUE_LED  GPIO_PIN_2
#define GREEN_LED GPIO_PIN_3

// variable defines

 unsigned char toggleRED_LED = 0x00;                                        // value for RED LED toggle
 unsigned char toggleBLUE_LED = 0x04;                                        // value for BLUE LED toggle

 unsigned long timer1APeriod = 0;                                                // value for timer 1A period
 unsigned short timer2APeriod = 0;
 unsigned short timer2AHalfPeriod = 0;

 unsigned short currentClockCapture = 0;                                // value at negative edge
 unsigned short lastClockCapture = 0;                                        // value at last negative edge

//*****************************************************************************
//
// The interrupt handler for the first timer interrupt.
//
//*****************************************************************************
void Timer0IntHandler(void)
{
    ROM_TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT);            // clear the timer interrupt
    currentClockCapture = ROM_TimerValueGet(TIMER0_BASE, TIMER_A);
    lastClockCapture = currentClockCapture;
}

//*****************************************************************************
//
// The interrupt handler for the second timer interrupt.
//
//*****************************************************************************
void Timer1IntHandler(void)
{
    ROM_TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT);        // clear the timer interrupt
    toggleBLUE_LED ^= 0x04;
    ROM_GPIOPinWrite(GPIO_PORTF_BASE, BLUE_LED, toggleBLUE_LED);
    toggleRED_LED ^= 0x02;
    ROM_GPIOPinWrite(GPIO_PORTF_BASE, RED_LED, toggleRED_LED);
}

//*****************************************************************************
//
// This example application demonstrates the use of the timers to generate
// periodic interrupts and drive LEDs
//
//*****************************************************************************
int main(void)
{
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);// sys clock to run at 80 Mhz from PLL with 16MHz crystal

    timer1APeriod = SysCtlClockGet() - 1;                                    // 1 Hz - SysCtlClockGet() divided by x, gives count for x Hz period
    timer2APeriod = (SysCtlClockGet()/68000) - 1;                    // 68 kHz
    timer2AHalfPeriod = (SysCtlClockGet()/136000) - 1;        // 68/2 kHz

    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);            // enable GPIO port B
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);          // enable GPIO port F

    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);            // enable timer peripheral
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);            // enable timer peripheral
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2);            // enable timer peripheral

    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, RED_LED|BLUE_LED|GREEN_LED);// enable the GPIO pins as output for the tri colour LED
    ROM_GPIOPinConfigure(GPIO_PB0_T2CCP0 | GPIO_PB6_T0CCP0);// configure for peripherals
    ROM_GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_6);// enable the GPIO pins for timer

    ROM_TimerConfigure(TIMER0_BASE, (TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_TIME));// timer0A configured 16 bit time capture
    ROM_TimerControlEvent(TIMER0_BASE, TIMER_A, TIMER_EVENT_NEG_EDGE);
    ROM_IntEnable(INT_TIMER0A);                                                        // interrupt enabled for the timer0A
    ROM_TimerIntEnable(TIMER0_BASE, TIMER_CAPA_EVENT);        // interrupt setup for the timer0 capture events

    ROM_TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC);    // timer1A configured 32 bit periodic
    ROM_TimerLoadSet(TIMER1_BASE, TIMER_A, timer1APeriod);
    ROM_IntEnable(INT_TIMER1A);                                                        // interrupt enabled for the timer0A
    ROM_TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);    // interrupt setup for the timer0A timeouts

    ROM_TimerConfigure(TIMER2_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM);// timer2A configured 16 bit PWM
    ROM_TimerLoadSet(TIMER2_BASE, TIMER_A, timer2APeriod);
    ROM_TimerMatchSet(TIMER2_BASE, TIMER_A, timer2AHalfPeriod);

    ROM_IntMasterEnable();                                                                // enable processor interrupts

    ROM_TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT);
    ROM_TimerEnable(TIMER0_BASE, TIMER_A);                                // enable the timer0A
    ROM_TimerEnable(TIMER1_BASE, TIMER_A);                                // enable the timer1A
    ROM_TimerEnable(TIMER2_BASE, TIMER_A);                                // enable the timer2A

    while(1);                                                                                            // loop forever while the timers run
}

OK comments everywhere, just helps me resolve code issues when switching from one project to another, micro to another, and long periods in between sorting hardware out


dBell

  • Hello David,

    The 68KHz PWM pulse basically means a ned edge will come every 14us. Hence whenever you stop the core with the debugger, the chances are that you would be in the timer-0 interrupt loop

    A simple check would be remove the input PWM signal and then check if it remains in the Interrupt Handler or not.

    From initialization perspective it looks pretty clean, except that the IntEnable should be always be done after TimerIntEnable is done which should be done after TimerIntClear. This removes any stray interrupt from a previous run.

    TimerIntClear

    TimerIntEnable

    IntEnable

    Regards

    Amit

  • Amit

    Moving the Master Interrupt enable to just before the while(1), seems to have stopped the interrupt firing all the time when the 68kHz clock is removed from PB6. More work to do in debug to confirm the timer values are reported OK when the clock is re connected. In the datasheet tm4c123gh6pm.pdf section 11.3.2.4 Input Edge-Time Mode, we are told the capture values reside in GPTMTnR register, can you advise which ROM_ call I need to access this and pass it to a user register, such as currentClockCapture in the code. At moment I use currentClockCapture = ROM_TimerValueGet(TIMER0_BASE, TIMER_A); and this I presume returns the TAR value, not the captured timer value.

    dBell

  • Hello David,

    You are correct. The ROM_TimerValueGet is the correct API to use,

    Regards

    Amit

  • Amit Ashara said:

    From initialization perspective it looks pretty clean, except that the IntEnable should be always be done after TimerIntEnable is done which should be done after TimerIntClear. This removes any stray interrupt from a previous run.

    TimerIntClear

    TimerIntEnable

    IntEnable

    Amit's writing is perfectly clear above - yet he made the time/effort to really "drive the point home" with the sequential (program like) listing - as well.

    Bravo - that care, attention to detail saves countless users lost time/effort - and goes far to enable clients to reach production sooner - rather than later - thus boosting Sales...

  • Amit

    Thanks for the order info regards the interrupt settings and enables. I have now updated the code and still have problems. I hope you can help. The files are still the same as the original timer example except that I have updated to Compiler V5.1.5 and put the original setup_ccs.c back and removed the tm4c.... linker and tm4c...setup_ccs.c files from the project. The two interrupts are named as in the timer example. The problem I have is that when I remove the comments from the code below, the timer2 output does not work properly, so the capture won't work either. At this stage all I need to do is get the capture working properly. I have had it working once, however stopping and starting the code then stopped the timer2 PWM output. I have spent some time trying to get this to work, so perhaps someone else can see a mistake or something missing / wrong. Once fixed we will move on to using the capture count to create two synchronous sub clocks on two other timer channels.

    revised code:

    //*****************************************************************************
    //
    // This application produces 68kHz clock using timer2A in PWM mode and
    // captures its time period using timer0A capture. The GREEN_LED of the
    // tricolour LED illuminates if clock period samples properly, this allows
    // any error glitches to be detected by monitoring PF3 with a logic analyser
    //
    // RED and BLUE LEDs are toggled at 1s interval by timer1A in periodic mode
    //
    //*****************************************************************************

    // include file references

    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    //#include "inc/hw_types.h"
    //#include "driverlib/debug.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/timer.h"

    // constant defines

    #define RED_LED           GPIO_PIN_1
    #define BLUE_LED          GPIO_PIN_2
    #define GREEN_LED         GPIO_PIN_3
    #define CLOCK_OUT            GPIO_PIN_0
    #define CLOCK_SAMPLE     GPIO_PIN_6

    #define PWM                        GPIO_PB0_T2CCP0
    #define CAPTURE                GPIO_PB6_T0CCP0

    // variable defines

     uint32_t timer1APeriod = 0;                                                // value for timer 1A period
     uint16_t timer2APeriod = 0;
     uint16_t timer2AHalfPeriod = 0;

     uint16_t currentClockCapture = 0;                                // value at negative edge
     uint16_t lastClockCapture = 0;                                        // value at last negative edge
     uint16_t masterClockPeriod = 0;                                    // master clock period sampled
     uint8_t error = 0;

     uint32_t RED_LEDtoggle = 0x00000000;                            // value for RED toggle
     uint32_t BLUE_LEDtoggle = 0x00000004;                            // value for BLUE toggle
     uint32_t GREEN_LEDtoggle = 0x00000000;

    //*****************************************************************************
    //
    // interrupt handler for the first timer interrupt
    // capture negative edge of 68kHz clock and report period in multiples of 12ns
    //
    //*****************************************************************************
    void Timer0IntHandler(void)
    {
        TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT);                    // clear the timer interrupt
        currentClockCapture = TimerValueGet(TIMER0_BASE, TIMER_A);
        masterClockPeriod    = lastClockCapture - currentClockCapture;
        lastClockCapture = currentClockCapture;
    }

    //*****************************************************************************
    //
    // interrupt handler for the second timer interrupt
    // toggles RED_LED and BLUE_LED drive at 1s intervals
    //
    //*****************************************************************************
    void Timer1IntHandler(void)
    {
        TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT);                // clear the timer interrupt

        RED_LEDtoggle ^= 0x00000002;
        GPIOPinWrite(GPIO_PORTF_BASE, RED_LED|GREEN_LED, RED_LEDtoggle);

        BLUE_LEDtoggle ^= 0x00000004;
        GPIOPinWrite(GPIO_PORTF_BASE, BLUE_LED|GREEN_LED, BLUE_LEDtoggle);
    }

    //*****************************************************************************
    //
    // application demonstrates the use of the timers to generate
    // periodic interrupts and drive LEDs
    // port PB0 is used as output for a 68kHz clock signal generated by timer2A
    //
    //*****************************************************************************
    int main(void)
    {
        SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);// system clock to run at 80 MHz from PLL with 16MHz xtal

        timer1APeriod = SysCtlClockGet() - 1;                                    // 1 Hz - SysCtlClockGet() divided by x, gives count for x Hz period
        timer2APeriod = (SysCtlClockGet()/68000) - 1;                    // 68 kHz
        timer2AHalfPeriod = (SysCtlClockGet()/136000) - 1;        // 68/2 kHz

        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);                    // enable the GPIO port
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);                    // enable the GPIO port
        SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);                    // enable the timer peripherals
        SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);                    // enable the timer peripherals
        SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2);                    // enable the timer peripherals

        GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, RED_LED|BLUE_LED|GREEN_LED);// configure the GPIO pins

        GPIOPinConfigure(PWM);                                                        // configure for peripherals
    //    GPIOPinConfigure(PWM | CAPTURE);                                            // configure for peripherals
        GPIOPinTypeTimer(GPIO_PORTB_BASE, CLOCK_OUT);            // enable the GPIO pins for timer
    //    GPIOPinTypeTimer(GPIO_PORTB_BASE, (CLOCK_OUT | CLOCK_SAMPLE));// enable the GPIO pins for timer

        IntMasterEnable();                                                                        // enable processor interrupts
        //  IntPrioritySet(INT_TIMER0A, 0x00);
        //  IntPrioritySet(INT_TIMER1A, 0x40);

    //    TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_TIME);// timer0A configured 32 bit time capture
    //    TimerControlEvent(TIMER0_BASE, TIMER_A, TIMER_EVENT_NEG_EDGE);
    //    TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT);
    //    IntEnable(INT_TIMER0A);                                                                // interrupt enabled for the timer0A

        TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC);            // timer1A configured 32 bit periodic
        TimerLoadSet(TIMER1_BASE, TIMER_A, timer1APeriod);
        TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);            // interrupt setup for the timer1A timeouts
        IntEnable(INT_TIMER1A);                                                                // interrupt enabled for the timer1A

        TimerConfigure(TIMER2_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM);// timer2A configured 16 bit PWM with output on PB0
        TimerLoadSet(TIMER2_BASE, TIMER_A, timer2APeriod);
        TimerMatchSet(TIMER2_BASE, TIMER_A, timer2AHalfPeriod);

    //    TimerEnable(TIMER0_BASE, TIMER_A);                                        // enable the timer0A
        TimerEnable(TIMER2_BASE, TIMER_A);                                        // enable the timer2A
        TimerEnable(TIMER1_BASE, TIMER_A);                                        // enable the timer1A

        while(1)                                                                                            // loop forever while the timers run
        {
            if  (masterClockPeriod == 0x0498)                                        // GREEN_LED goes off if not this value
            {
                GPIOPinWrite(GPIO_PORTF_BASE, GREEN_LED, 0x00000008);
                error = 0;
            }
            else
            {
                GPIOPinWrite(GPIO_PORTF_BASE, GREEN_LED, 0x00000000);
                error = 1;
            }
        }
    }


    The watch window has the following visible:

    timer1APeriod    unsigned int    79999999    0x20000100    
    timer2APeriod    unsigned short    0x0497 (Hex)    0x20000104    
    timer2AHalfPeriod    unsigned short    0x024B (Hex)    0x20000106    
    RED_LEDtoggle    unsigned int    0    0x20000110    
    BLUE_LEDtoggle    unsigned int    4    0x20000114    
    currentClockCapture    unsigned short    0x0000 (Hex)    0x20000108    
    lastClockCapture    unsigned short    0x0000 (Hex)    0x2000010A    
    error    unsigned char    1 (Decimal)    0x2000010E    
    masterClockPeriod    unsigned short    0x0000 (Hex)    0x2000010C    

  • Hello David.

    The configuration is of Timer-1 and Timer-2 but the Interrupt handler is for Timer-0 and Timer-1, shouldn't it be for Timer-1 and Timer-2?

    Also please attach the code for the startup.c

    Regards

    Amit

  • Hi,

    In function GPIOPinConfigure(), param ui32PinConfig is the pin configuration value, specified as only one of the GPIO_P??_??? values. Only one peripheral function at a time can be associated with a GPIO pin, and each peripheral function should only be associated with a single GPIO pin at a time

    So your line:
        ROM_GPIOPinConfigure(GPIO_PB0_T2CCP0 | GPIO_PB6_T0CCP0);// configure for peripherals
    is not correct (GPIO_P??_??? values are big constants, not similar to bit-packing constants). 
       And this disappeared in your second code snippet!
    Your code line:
     if  (masterClockPeriod == 0x0498)
    is hardly believed to work correctly - since the period can be by chance of this value (allow at least +/- 1 count as noise/jitter/temperature effects), and even if it happens once, the next period (14us) will have another value and a LED should be on for at least 50 ms to be perceived by the eye (not all persons are able to see rapid blinking…). But if you use the same pin for driving something else, that will be OK.
    Petrei
  • Petrei


    Thanks for advising about the GPIO_PB0_T2CCP0 not being a bit packing constant, I think that may have given me the unpredictable debug performance.

    For now the 68kHz clock is generated by PWM so will be synchronous to the system clock, due to this the masterClockPeriod test actually works 100% of the time, I fully understand that with jitter or noise or temperature effects a clock source can change. In fact the clock source we are measuring will be external when the project is finished, so we will need to take the asyncronous nature including frequency drift into account, when creating additional sub clocks. We have done all this before successfully with an MSP430.

    Regards blinking LED, when this code works it does not blink, however it is only used as an indicator of the capture value being correct. The true test is using a logic analyzer or oscilloscope on the LED drive pin PF3, and I can report that PF3 is high all the time and there are no glitches.

    Separating the two GPIOPinConfigure lines seems to have made the code work, however when I exit the debug, reset the processor on the LaunchPad, I now find that I can't get the Timer1 interrupt to work, that was toggling the LED READ and BLUE. Even when I reflash the LaunchPad and run in debug again. Odd. In the past it was the PWM output that went AWOL after the first debug session.

    dBell

  • Hi David,

    Good to know your capture code works. About the Timer1 problem: wouldn't be better to use the SysTick timer for 1 second instead Timer1? Also you commented out the interrupt priority settings - maybe you set a higher prio for timer1?

    Petrei

  • HI David

    your code will be general debugging is fine .But while i  download into Tiva c launchpad over after  they d'not show any output.if any file required to enable in startup.c file.if its required plz send what file we enable details.

  • Hello CSReddy,

    The startup.c is required for the interrupt, sp and pc vectors. The file that David had needs to be added to the CCS project. What is the exact issue that you face when downloading to the flash? Does it go into a bus fault, etc. Also do mention which device you are using e.g. TM4C123 or TM4C129?

    Regards

    Amit