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.

Stellaris Launchpad Timer Synchronization

Hello, I'm developing an application with the stellaris launchpad board (LM4F120H5QR uC).
I've successfully used a timer to generate a PWM signal on a TxCCPx pin.
I wanted to generate an interrupt on the reset of the timer, but as far as I checked the datasheet in PWM mode the interrupt it's generated only on compare. (Am I correct on this?)
I ended up using another timer to synchronize to the PWM and use it to generate an interrupt. I can't find any example on how to synchronize timers with stellarisware.

my code basically does the following:

    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1); 
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
GPIOPinConfigure(GPIO_PB4_T1CCP0);
    GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_4);     

    TimerSynchronize(TIMER0_BASE, TIMER_1A_SYNC | TIMER_0B_SYNC);
    
    TimerConfigure(TIMER1_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM);
    TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PERIODIC);
    TimerControlLevel(TIMER1_BASE,TIMER_A,true);
    TimerLoadSet(TIMER1_BASE, TIMER_A, PERIOD_1);
    TimerLoadSet(TIMER0_BASE, TIMER_B, PERIOD_1);
    TimerMatchSet(TIMER1_BASE, TIMER_A, DUTY_CYCLE);
    IntMasterEnable();
    TimerIntEnable(TIMER0_BASE, TIMER_TIMB_TIMEOUT);
    IntEnable(INT_TIMER0B);
TimerEnable(TIMER1_BASE, TIMER_A);
 TimerEnable(TIMER0_BASE, TIMER_B);


I think I'm missing something but I can't understand if I need to use other functions of the API to set it up correctly.
As it is it just freezes, it doesn't execute the interrupt code and PWM doesn't start either.
I've tried to start the timers without synchronization, both the timers start and the ISR Routine it's running properly, but a
bit out on timing because they are started one after the other.

  • Mauro Scomparin said:
    I wanted to generate an interrupt on the reset of the timer, but as far as I checked the datasheet in PWM mode the interrupt it's generated only on compare. (Am I correct on this?)

    The only event that you can observe is TIMER_CAP?_EVENT as you can see in my experiment (I wrote that sometime ago):

    #define PART_LM4F120H5QR true
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_gpio.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/timer.h"


    volatile unsigned long counter = 0;
    volatile unsigned long ulPeriod;

    void timer1_interrupt (void);

    int main (void) {
        SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);

        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);

        SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);

        // Select/Mux the right function for Pin 2 on PORTF - select CCP on Timer 1, Timer A.
        // See LM4F120H5QR datasheet, Table 21-5. (for IO = PF2)
        GPIOPinConfigure(GPIO_PF2_T1CCP0);

        GPIOPinTypeTimer(GPIO_PORTF_BASE, GPIO_PIN_2);

        // This call is optional and will work without it. Though by default it is used 2MA strength.
        // See datasheet, Table 21-2. (Pin 31 /aka Pin 2, PORTF/) - "16/32-Bit Timer 1 Capture/Compare/PWM 1."
        // See also "Table 11-1." - "16/32-Bit Timer 1 Timer A T1CCP0", i.e. Timer B is not available for Pin 2.
        GPIOPadConfigSet(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_STRENGTH_8MA_SC,
                GPIO_PIN_TYPE_STD);

        // For Pin 2 on PORTF the only possible PWM timer is 16bit Timer 1, Timer A. For this pin is not possible
        // to use full 32 bit timer.
        TimerConfigure(TIMER1_BASE, TIMER_CFG_SPLIT_PAIR  | TIMER_CFG_A_PWM);

        // Freeze the timer counting if we are debugging (the counting is enabled automatically with the cpu).
        TimerControlStall(TIMER1_BASE, TIMER_A, true);

        ulPeriod = SysCtlClockGet() / 1000;
        TimerLoadSet(TIMER1_BASE, TIMER_A, ulPeriod-1);  // 40000 is the maximum
        TimerMatchSet(TIMER1_BASE,TIMER_A, ulPeriod-100);

        TimerIntRegister(TIMER1_BASE, TIMER_A, timer1_interrupt);
        TimerIntEnable(TIMER1_BASE, TIMER_CAPA_EVENT);    // TIMER_CAPA_EVENT is the only one available in PWM mode.

        TimerEnable(TIMER1_BASE, TIMER_A);


        while(1) {

        }
    }

    void timer1_interrupt (void) {
        TimerIntClear(TIMER1_BASE, TIMER_CAPA_EVENT);    // Clear TIMER_CAPA_EVENT immediately.
        counter++;
        if (counter > 3) {
            counter = 0;
            ulPeriod += 150;
            if (ulPeriod > 40000) {
                ulPeriod = 20000;
            }
            TimerMatchSet(TIMER1_BASE,TIMER_A, ulPeriod);
        }
    }

  • So, what I understood from the datasheet was correct, nice to know.

    Thank you a lot for the code, I used the startup.c file to assign the interrupt code to the NVIC. But I'll try out the TimerIntRegister() function!

     Any idea about the synchronization of interrupts?

  • If I understand correctly, you want something like code below. I just modified my previous example, so here I present just a diff of my changes. You can use patch to apply this diff directly to my original code.

    diff -b -u old_main.c new_main.c
    --- old_main.c    2012-11-01 23:02:54.667156000 +0200
    +++ new_main.c    2012-11-01 23:21:43.941855000 +0200
    @@ -8,11 +8,14 @@
     #include "driverlib/gpio.h"
     #include "driverlib/pin_map.h"
     #include "driverlib/timer.h"
    +#include <limits.h>
     
     
     volatile unsigned long counter = 0;
     volatile unsigned long ulPeriod;
    +volatile unsigned long is_reset = 0;
     
    +void timer1_onreset_interrupt (void);
     void timer1_interrupt (void);
     
     int main (void) {
    @@ -36,23 +39,34 @@
     
         // For Pin 2 on PORTF the only possible PWM timer is 16bit Timer 1, Timer A. For this pin is not possible
         // to use full 32 bit timer.
    -    TimerConfigure(TIMER1_BASE, TIMER_CFG_SPLIT_PAIR  | TIMER_CFG_A_PWM);
    +    TimerConfigure(TIMER1_BASE, TIMER_CFG_SPLIT_PAIR  | TIMER_CFG_A_PWM | TIMER_CFG_B_PERIODIC);
     
         // Freeze the timer counting if we are debugging (the counting is enabled automatically with the cpu).
    -    TimerControlStall(TIMER1_BASE, TIMER_A, true);
    +    TimerControlStall(TIMER1_BASE, TIMER_A | TIMER_B, true);
    +
    +    TimerSynchronize(TIMER1_BASE, TIMER_1A_SYNC | TIMER_1B_SYNC);
     
         ulPeriod = SysCtlClockGet() / 1000;
    -    TimerLoadSet(TIMER1_BASE, TIMER_A, ulPeriod-1);  // 40000 is the maximum
    -    TimerMatchSet(TIMER1_BASE,TIMER_A, ulPeriod-100);
    +    TimerLoadSet(TIMER1_BASE, TIMER_A | TIMER_B, ulPeriod-1);  // 40000 is the maximum
    +    TimerMatchSet(TIMER1_BASE,TIMER_A | TIMER_B, ulPeriod-100);
     
         TimerIntRegister(TIMER1_BASE, TIMER_A, timer1_interrupt);
    -    TimerIntEnable(TIMER1_BASE, TIMER_CAPA_EVENT);    // TIMER_CAPA_EVENT is the only one available in PWM mode.
    +    TimerIntRegister(TIMER1_BASE, TIMER_B, timer1_onreset_interrupt);
    +    TimerIntEnable(TIMER1_BASE, TIMER_CAPA_EVENT | TIMER_TIMB_TIMEOUT);    // TIMER_CAPA_EVENT is the only one available in PWM mode.
     
    -    TimerEnable(TIMER1_BASE, TIMER_A);
    +    TimerEnable(TIMER1_BASE, TIMER_A | TIMER_B);
     
     
         while(1) {
     
    +
    +    }
    +}
    +
    +void timer1_onreset_interrupt (void) {
    +    TimerIntClear(TIMER1_BASE, TIMER_TIMB_TIMEOUT);
    +    if (LONG_MAX > is_reset) {
    +        is_reset++;
         }
     }
     
    @@ -65,6 +79,6 @@
             if (ulPeriod > 40000) {
                 ulPeriod = 20000;
             }
    -        TimerMatchSet(TIMER1_BASE,TIMER_A, ulPeriod);
    +        TimerMatchSet(TIMER1_BASE,TIMER_A | TIMER_B, ulPeriod);
         }
     }

  • Yes, that was definitely what I was looking for!

    I just wanted to know when the PWM timer timed out and generate an interrupt, so I figured out that 2 timers synchronized and with the same frequency was the solution.

    The I've used pieces of your code to make my program work.

    I've just changed some point due to the fact I didn't need to generate an interrupt on capture of TIMER1A, I just wanted it to run freely, so I just skipped the TimerInitRegister() and TimerIntEnable() calls for that one and it worked ok.

    I've learned a lot of things thanks to your code, TimerInitEnable() enables the general input by itself, nice to know, also the call to TimerControlStall() was a nice thing when you're debugging interrupt driven code.

    I didn't understand what the original problem was, a wild guess would be how I started them.

    It's a bit strange to use 2 timers to get an IRQ on timeout of a timer used as PWM, but that's how the hardware has been designed, and it's not a big deal in my application to run 2 different timers just for that purpose.

    Now I'm experimenting on how to start 2 subtimers in different timers. (how to call the TimerEnable()).

    Thank you very much!

  • Mauro Scomparin said:

    I wanted to generate an interrupt on the reset of the timer, but as far as I checked the datasheet in PWM mode the interrupt it's generated only on compare. (Am I correct on this?)

    Actually, you can choose if the interrupt is generated for rising edge, falling edge or both with TimerControlEvent(). By default, it seems to be on rising edge, which corresponds in your case to the compare event since you are using TimerControlLevel to invert the signal.