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.

TM4C1294NCPDT: TIVA TM4C Timer switch between 16 bit Periodic and PWM modes

Part Number: TM4C1294NCPDT
Other Parts Discussed in Thread: EK-TM4C1294XL

Hi,

I am using EK-TM4C1294XL EVM.  I need to switch between 16 bit Periodic and PWM modes of Timer3 (same pin). Timer PWM mode with system clock source does not work correctly if I use the timer earlier in 16-bit periodic mode with alternating clock source.

In the code below I have configured the timer in 16-bit periodic mode with an alternating clock source. I disable the timer. And then configured it in 16-bit PWM mode with system clock source:  

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

void Timer3AIntHandler(void) {
    MAP_TimerIntClear(TIMER3_BASE, TIMER_TIMA_TIMEOUT);
}

void clock_init(void) {
    // System Clock 120 MHz
    MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120E6);

    // Alternating Clock RTCOSC 32768 Hz
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_HIBERNATE);
    while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_HIBERNATE)) {
    }
    MAP_HibernateEnableExpClk(0);// Enable the Hibernation module for operation.
    while (!(HWREG(HIB_RIS) & HIB_RIS_WC))
        ;                                          // Wait for 32.768kHz clock to stabilize.
    MAP_HibernateClockConfig(HIBERNATE_OUT_SYSCLK);// 32.768 kHz Osc, Output Hibernate Clk
    MAP_HibernateRTCEnable();
    MAP_HibernateRTCSet(0);// Load initial RTC value.
    MAP_SysCtlAltClkConfig(SYSCTL_ALTCLK_RTCOSC);
}

void timer_init(void) {
    // T3CCP0: TIMERA :PA.6
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER3);
    while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER3)) {}
    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOA)) {}
    MAP_GPIOPinConfigure(GPIO_PA6_T3CCP0);
    MAP_GPIOPinTypeTimer(GPIO_PORTA_BASE, GPIO_PIN_6);
}

void set_timer_periodic_mode(void) {
    // MAP_TimerClockSourceSet(TIMER3_BASE, TIMER_CLOCK_SYSTEM);
    MAP_TimerClockSourceSet(TIMER3_BASE, TIMER_CLOCK_PIOSC);// alternating clock
    MAP_TimerConfigure(TIMER3_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC_UP);
    // uint32_t cycles = 120E3;// System clock: 1 ms timeout
    uint32_t cycles = 32;// Alternating clock: 1 ms timeout
    MAP_TimerPrescaleSet(TIMER3_BASE, TIMER_A, cycles / 65536);
    MAP_TimerLoadSet(TIMER3_BASE, TIMER_A, cycles);
    TimerIntRegister(TIMER3_BASE, TIMER_A, Timer3AIntHandler);
    MAP_TimerIntEnable(TIMER3_BASE, TIMER_TIMA_TIMEOUT);
    MAP_IntEnable(INT_TIMER3A);
    MAP_IntPrioritySet(INT_TIMER3A, 0xA0);
    MAP_TimerEnable(TIMER3_BASE, TIMER_A);
}

void disable_timer(void) {
    MAP_IntDisable(INT_TIMER3A);
    MAP_TimerIntDisable(TIMER3_BASE, TIMER_TIMA_TIMEOUT);
    TimerIntUnregister(TIMER3_BASE, TIMER_A);
    MAP_TimerDisable(TIMER3_BASE, TIMER_A);
}

void set_timer_pwm_mode(void) {
    MAP_TimerClockSourceSet(TIMER3_BASE, TIMER_CLOCK_SYSTEM);
    MAP_TimerConfigure(TIMER3_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM);
    uint32_t cycles    = 120E6 / 100;// PWM frequency: 100 Hz
    uint16_t load      = cycles % 65536;
    uint8_t  prescalor = cycles / 65536;
    uint32_t period    = load + prescalor * 65536;
    uint32_t duty      = period / 2;// Dutycyle:  50%
    MAP_TimerPrescaleSet(TIMER3_BASE, TIMER_A, prescalor);
    MAP_TimerLoadSet(TIMER3_BASE, TIMER_A, load);
    MAP_TimerPrescaleMatchSet(TIMER3_BASE, TIMER_A, duty / 65536);
    MAP_TimerMatchSet(TIMER3_BASE, TIMER_A, duty % 65536);
    MAP_TimerEnable(TIMER3_BASE, TIMER_A);
}

int main(void) {
    clock_init();

    MAP_IntMasterEnable();

    timer_init();

    // Timer3 as 16 bit periodic timer with timeout interrupt
    set_timer_periodic_mode();

    // Disable timer
    disable_timer();

    // Timer3 in PWM mode
    set_timer_pwm_mode();

    while (1) {
    }
}

The switch problem arises only if I use an alternating clock source in 16-bit periodic mode. Could anyone please guide me on whether I am switching between timer modes correctly?

Thank you,

Hassan

  • Hello Hassan,

    You aren't entirely disabling the Timer 3 peripheral that way so I'd suggest that you try to use

    MAP_SysCtlPeripheralDisable(SYSCTL_PERIPH_TIMER3);

    as part of your disable sequence and then for set_timer_pwm_mode add the line

    MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER3);

    as the first line executed.

    See if that resolves your issue.

    Best Regards,

    Ralph Jacobi

  •  Hello Ralph,

    Thank you for your response. I have added Timer3 peripheral disable and enable but still, the issue remains.

     

    #include <stdbool.h>
    #include <stdint.h>
    #include <time.h>
    
    #include "driverlib/gpio.h"
    #include "driverlib/hibernate.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/timer.h"
    #include "inc/hw_hibernate.h"
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    
    void Timer3AIntHandler(void) {
        MAP_TimerIntClear(TIMER3_BASE, TIMER_TIMA_TIMEOUT);
    }
    
    void clock_init(void) {
        // System Clock 120 MHz
        MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120E6);
    
        // Alternating Clock RTCOSC 32768 Hz
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_HIBERNATE);
        while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_HIBERNATE)) {
        }
        MAP_HibernateEnableExpClk(0);// Enable the Hibernation module for operation.
        while (!(HWREG(HIB_RIS) & HIB_RIS_WC))
            ;                                          // Wait for 32.768kHz clock to stabilize.
        MAP_HibernateClockConfig(HIBERNATE_OUT_SYSCLK);// 32.768 kHz Osc, Output Hibernate Clk
        MAP_HibernateRTCEnable();
        MAP_HibernateRTCSet(0);// Load initial RTC value.
        MAP_SysCtlAltClkConfig(SYSCTL_ALTCLK_RTCOSC);
    }
    
    void timer_init(void) {
        // T3CCP0: TIMERA :PA.6
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER3);
        while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER3)) {}
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
        while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOA)) {}
        MAP_GPIOPinConfigure(GPIO_PA6_T3CCP0);
        MAP_GPIOPinTypeTimer(GPIO_PORTA_BASE, GPIO_PIN_6);
    }
    
    void set_timer_periodic_mode(void) {
        // MAP_TimerClockSourceSet(TIMER3_BASE, TIMER_CLOCK_SYSTEM);
        MAP_TimerClockSourceSet(TIMER3_BASE, TIMER_CLOCK_PIOSC);// alternating clock
        MAP_TimerConfigure(TIMER3_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC_UP);
        // uint32_t cycles = 120E3;// System clock: 1 ms timeout
        uint32_t cycles = 32;// Alternating clock: 1 ms timeout
        MAP_TimerPrescaleSet(TIMER3_BASE, TIMER_A, cycles / 65536);
        MAP_TimerLoadSet(TIMER3_BASE, TIMER_A, cycles);
        TimerIntRegister(TIMER3_BASE, TIMER_A, Timer3AIntHandler);
        MAP_TimerIntEnable(TIMER3_BASE, TIMER_TIMA_TIMEOUT);
        MAP_IntEnable(INT_TIMER3A);
        MAP_IntPrioritySet(INT_TIMER3A, 0xA0);
        MAP_TimerEnable(TIMER3_BASE, TIMER_A);
    }
    
    void disable_timer(void) {
        MAP_IntDisable(INT_TIMER3A);
        MAP_TimerIntDisable(TIMER3_BASE, TIMER_TIMA_TIMEOUT);
        TimerIntUnregister(TIMER3_BASE, TIMER_A);
        MAP_TimerDisable(TIMER3_BASE, TIMER_A);
    }
    
    void set_timer_pwm_mode(void) {
        MAP_TimerClockSourceSet(TIMER3_BASE, TIMER_CLOCK_SYSTEM);
        MAP_TimerConfigure(TIMER3_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM);
        uint32_t cycles    = 120E6 / 100;// PWM frequency: 100 Hz
        uint16_t load      = cycles % 65536;
        uint8_t  prescalor = cycles / 65536;
        uint32_t period    = load + prescalor * 65536;
        uint32_t duty      = period / 2;// Dutycyle:  50%
        MAP_TimerPrescaleSet(TIMER3_BASE, TIMER_A, prescalor);
        MAP_TimerLoadSet(TIMER3_BASE, TIMER_A, load);
        MAP_TimerPrescaleMatchSet(TIMER3_BASE, TIMER_A, duty / 65536);
        MAP_TimerMatchSet(TIMER3_BASE, TIMER_A, duty % 65536);
        MAP_TimerEnable(TIMER3_BASE, TIMER_A);
    }
    
    int main(void) {
        clock_init();
    
        MAP_IntMasterEnable();
    
        timer_init();
    
        // Timer3 as 16 bit periodic timer with timeout interrupt
        set_timer_periodic_mode();
    
        // Disable timer
        disable_timer();
    
        MAP_SysCtlPeripheralDisable(SYSCTL_PERIPH_TIMER3);
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER3);
        while (!MAP_SysCtlPeripheralReady(SYSCTL_PERIPH_TIMER3)) {}
    
        // Timer3 in PWM mode
        set_timer_pwm_mode();
    
        while (1) {
        }
    }
    

    Regards,

    Hassan  

  • Hello Hassan,

    Sorry for the delay in reply here but I had taken your code to re-create the issue and was trying to work through how to get this configured in a way that resolves the issue.

    The only resolution I've been able to achieve is by using PIOSC as the Alternate Clock Source instead of SYSCTL_ALTCLK_RTCOSC.

    I did some deeper digging into Alternate Clock Sources for the General Purpose Timers on TM4C129x devices, and I uncovered that in the past there was an issue identified with using clock sources other than System Clock with General Purpose Timers. From what I can tell, the investigation results were that the PIOSC and System Clock are valid clock sources, but using the other Alternate Clock Sources can result in unexpected behavior and should be avoided. This should have been published as an errata item, but it has not been. However in TivaWare this is reflected by the verbiage used for the TimerClockSourceSet API which states the following:

    //! This function sets the clock source for both timer A and timer B for the
    //! given timer module.  The possible clock sources are the system clock
    //! (\b TIMER_CLOCK_SYSTEM) or the precision internal oscillator
    //! (\b TIMER_CLOCK_PIOSC).

    Unfortunately all of this predates my time with the team and the experts who worked through that investigation don't support this part anymore, so I need to do further digging into why the errata was not published after discovery of the issue.

    Errata publishing aside, as far as your system goes, you will need to resort to using the PIOSC as the alternate clock for the General Purpose Timer to get things working as you need.

    Best Regards,

    Ralph Jacobi

  • Hi Ralph,

    Thank you for the help. Okay, then I will use the System clock in 32-bit mode to cover our requirement. Actually, PIOSC as an alternating clock source is not very accurate.

    Kind Regards,

    Hassan