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.

CCS/TM4C1294NCPDT: 32 bit Timer in TIVA129

Part Number: TM4C1294NCPDT

Tool/software: Code Composer Studio

Dear all 

I am working on a project that requires pulses very long, so far everything was working perfect with my old friend TM4C123, but now I need to move on my code to the 129 because I need its Ethernet capabilities. I used the Wide Timers on 123 and I am aware that TM4C129 does not have, but I read is possible to configure them as 32 bit so I could achieve a very low frequency. Does anyone have experience on this matter or could give a look to my code in case I am missing something. 

Thanks in advance 

void timer1 (){ //SH
    uint32_t ulPeriod, dutyCycle1;

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2);
    GPIOPinConfigure(GPIO_PA5_T2CCP1); 
    GPIOPinTypeTimer(GPIO_PORTA_BASE, GPIO_PIN_5);

    
    ulPeriod = g_ui32SysClock/0.5;
    dutyCycle1 = (unsigned long)(ulPeriod-1)*0.33;

    TimerConfigure(TIMER2_BASE, TIMER_CFG_SPLIT_PAIR|TIMER_CFG_B_PWM); 
    TimerControlLevel(TIMER2_BASE, TIMER_B, 1); 

    TimerLoadSet(TIMER2_BASE, TIMER_B, ulPeriod-1); 
    TimerMatchSet(TIMER2_BASE, TIMER_B, dutyCycle1); 
    TimerEnable(TIMER2_BASE, TIMER_B);

}

and my system clock 

g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
SYSCTL_CFG_VCO_480), 120000000);

  • A few things:

    Israel Rebolledo said:

        TimerConfigure(TIMER2_BASE, TIMER_CFG_SPLIT_PAIR|TIMER_CFG_B_PWM); 
    

    I think that TIMER_CFG_SPLIT_PAIR is not what you want, as that configures only the 16-bit TimerB of the timer peripheral. You need to configure it for 32-bit mode, which concatenates both 16-bit half-timers to form one 32-bit timer.

    Israel Rebolledo said:
        ulPeriod = g_ui32SysClock/0.5;
        dutyCycle1 = (unsigned long)(ulPeriod-1)*0.33;
    

    Your mileage may vary, but on multiple CPU/MCU platforms and with multiple compilers, I've encountered problems when converting a number from float type directly to unsigned int type. I'm not 100% sure but I think the compiler's point of view is that I am asking for the bit pattern of the floating point number, when what I really want is to truncate the decimal part of the number and convert the remaining whole part to an unsigned integer. For this reason, I convert floating point values to a signed int type first, and then typecast that to an unsigned int type. Before the conversion, I check that the value will fit into the intermediate and final int types without overflow.

    Also, you did not specify what is your "very low frequency," but perhaps it is possible to achieve by using a sufficient prescaler, and//or to drive the clock from a slower source. 

  • Dear @twelve12pm TimerConfigure is my main suspect (I am working on that), about the float type conversion is a very good point, I must say I did not find problems on that with the Tiva 123, so I discarded as a problem but I will keep it in mind.

    The very low freq is about 0.5 Hz (I was amazed how easy I achieved it with the wide timer), I tried with the prescaler with no success. Thanks for you reply, I will reconfigure the timer and report it.
  • Israel Rebolledo said:
    Dear @twelve12pm TimerConfigure is my main suspect (I am working on that), about the float type conversion is a very good point, I must say I did not find problems on that with the Tiva 123, so I discarded as a problem but I will keep it in mind.

    The very low freq is about 0.5 Hz (I was amazed how easy I achieved it with the wide timer), I tried with the prescaler with no success. Thanks for you reply, I will reconfigure the timer and report it.

    Does your 0.5 Hz frequency need to be very accurate? If it is not so time-critical, you can set up the systick timer (which is part of the TM4C12x's embedded Arm Cortex M4F CPU) to give, say, a 1000 Hz interrupt. I always set up such an interrupt. In the interrupt handler, I increment a global volatile uint32_t variable called Global.Ticks. This variable can be used for low-resolution timing in the range of from milliseconds to about 49 days (7 weeks), after which it rolls over back to 0. To use it, main context code can save the value of Global.Ticks in a variable, and later subtract that from the latest tick timer value to calculate the elapsed time. If a certain amount of time has elapsed, the new Global.Ticks value is saved to the variable and some action is performed. It is surprising how many things that are measured in milliseconds, seconds, minutes, hours, or days, this method can handle with relatively good accuracy -- dependent on how often your main loop executes, and provided that your main loop does not get "stuck" in some blocking code that will prevent servicing of the timed events.

    Meanwhile, to generate your 0.5 Hz waveform, I would set up the output pin to GPIO mode, and in the SysTick interrupt handler, I would count to 500, then reset the counter and toggle the output -- this is assuming of course that your waveform does not need to be extremely accurate, as there will be some jitter due to the software nature of it.

  • I wrote some pseudocode to illustrate what I described in the previous post:

    #define SYSTEM_CLOCK_FREQ_HZ           120000000
    #define SYSTICKS_FREQ_HZ               1000
    
    
    struct {             
    	uint32_t SysClockFreqHz;
    	uint32_t Ticks;
    	// Any other global data you want to put here
    } Global;
    
    
    // Make sure your C startup file assigns this function to the correct
    // interrupt vector!!
    void IsrLowResTimerHandler(void)
    {
    	static uint32_t Counter = 0;
    	
    	Global.Ticks++;
    
    	// Generate a 0.5 Hz square wave here
    	Counter++;
    	if (Counter >= 1000) {
    		Counter = 0;
    		... Toggle the GPIO pin here ...
    	}
    }
    
    
    uint32_t TickGet(void) 
    { 
    	return Global.Ticks; 
    }
    
    
    void Init(void)
    {
    	// ...
    	MAP_FPULazyStackingEnable();
    
    	// The following two lines are for TM4C129, with external 25 MHz clock,
    	// to achieve 120 MHz system clock
    	SysCtlMOSCConfigSet(SYSCTL_MOSC_HIGHFREQ);
    	Global.SysClockFreqHz = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), SYSTEM_CLOCK_FREQ_HZ);
    	
    	MAP_SysTickPeriodSet(Global.SysClockFreqHz / SYSTICKS_FREQ_HZ);
    	MAP_SysTickEnable();
    	MAP_SysTickIntEnable();
    	
    	// ...
    }
    
    
    void Run(void)
    {
    	static bool FirstTime = true;
    	static uint32_t LocalTicks = 0;
    	
    	if (FirstTime) {
    		FirstTime = false;
    		LocalTicks = TickGet();
    	}
    	
    	if (TickGet() - LocalTicks >= ONE_HOUR_IN_TICKS) {
    		LocalTicks = TickGet();
    		
    		... do some action once per hour here ...
    	}
    }
    
    
    int main(void)
    {
    	Init();
    	while (1) {
    		Run();
    	}
    }
    

    Hope this is helpful