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 of TM4C1294

Hi everyone,

I met some difficult in Timer configuration of EK-TM4C1294. I want to set a timer interrupt with 1ms.

I read many documentaries on the internet, however, I could not understand fully about PresscaleSet.

I have not oscilloscope to check so please help me with this.

Here is my stupid code:

SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_320), 40000000);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
	GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE,led1|led2);


	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
	TimerDisable(TIMER0_BASE,TIMER_A);
	TimerConfigure(TIMER0_BASE,TIMER_CFG_SPLIT_PAIR|TIMER_CFG_PERIODIC_UP);
	TimerPrescaleSet(TIMER0_BASE,TIMER_A,8-1);
        int period = 5000;
	TimerLoadSet(TIMER0_BASE,TIMER_A,period-1);
	IntEnable(INT_TIMER0A);
	TimerIntEnable(TIMER0_BASE,TIMER_TIMA_TIMEOUT);

	IntMasterEnable();
	TimerEnable(TIMER0_BASE,TIMER_A);

Please give me the equation to change 'period' to 'real time' with presscale and without presscale.

Regard,

Phu

 

  • Phu,

    The attached file contains an example of how to set up timer 2A. The timer is initialized in io_init(). The timer interrupt service routine is AnimTimerIntHandler(). The timer is started by calling io_set_timer(). The period of timer interrupt can be dynamically changed by calling io_set_timer().

    //*****************************************************************************
    //
    // io.c - I/O routines for the enet_io example application.
    //
    // Copyright (c) 2013-2014 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    // 
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    // 
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    // 
    // This is part of revision 2.1.0.12573 of the EK-TM4C1294XL Firmware Package.
    //
    //*****************************************************************************
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_pwm.h"
    #include "inc/hw_types.h"
    #include "inc/hw_adc.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pwm.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/timer.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/rom.h"
    #include "driverlib/adc.h"
    #include "utils/ustdlib.h"
    #include "io.h"
    #include "board.h"
    #include "buttons.h"
    
    #define APP_TICKS_PER_SEC                   100
    #define APP_INPUT_BUF_SIZE                  1024
    #define NUM_STATS                           12
    
    //*****************************************************************************
    //
    // Hardware connection for the user LED.
    //
    //*****************************************************************************
    #define LED_PORT_BASE GPIO_PORTN_BASE
    #define LED_PIN GPIO_PIN_0
    
    //*****************************************************************************
    //
    // Hardware connection for the animation LED.
    //
    //*****************************************************************************
    #define LED_ANIM_PORT_BASE GPIO_PORTN_BASE
    #define LED_ANIM_PIN GPIO_PIN_1
    
    //*****************************************************************************
    //
    // The system clock speed.
    //
    //*****************************************************************************
    extern uint32_t g_ui32SysClock;
    
    //*****************************************************************************
    //
    // The current speed of the on-screen animation expressed as a percentage.
    //
    //*****************************************************************************
    volatile unsigned long g_ulAnimSpeed = 10;
    volatile unsigned long g_timer2count = 0;
    volatile unsigned long g_ui32SW1Presses = 0;
    volatile unsigned long g_ui32SW2Presses = 0;
    volatile unsigned long g_ui32InternalTempF = 0;
    volatile unsigned long g_ui32InternalTempC = 0;
    volatile unsigned long g_ui32TimerIntCount = 0;
    volatile unsigned long g_ui32SecondsOnTime = 0;
    volatile unsigned long g_LED_Status = 0;
    volatile unsigned long g_LED_Toggle_Status = 0;
    volatile unsigned long g_Temperature_U = 0;
    
    void UpdateButtons(void);
    void UpdateInternalTemp(void);
    void ConfigureADC0(void);
    void ConfigureTimer0(void);
    
    //*****************************************************************************
    //
    // Set the timer used to pace the animation.  We scale the timer timeout such
    // that a speed of 100% causes the timer to tick once every 20 mS (50Hz).
    //
    //*****************************************************************************
    void
    io_set_timer(unsigned long ulSpeedPercent)
    {
        unsigned long ulTimeout;
    
        //
        // Turn the timer off while we are mucking with it.
        //
        ROM_TimerDisable(TIMER2_BASE, TIMER_A);
    
        //
        // If the speed is non-zero, we reset the timeout.  If it is zero, we
        // just leave the timer disabled.
        //
        if(ulSpeedPercent)
        {
            //
            // Set Timeout
            //
            ulTimeout = g_ui32SysClock / 50;
            ulTimeout = (ulTimeout * 100 ) / ulSpeedPercent;
    
            ROM_TimerLoadSet(TIMER2_BASE, TIMER_A, ulTimeout);
            ROM_TimerEnable(TIMER2_BASE, TIMER_A);
        }
    }
    
    //*****************************************************************************
    //
    // Initialize the IO used in this demo
    //
    //*****************************************************************************
    void
    io_init(void)
    {
        //
        // Enable the peripherals used by this example.
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2);
    
        //
        // Configure the timer used to pace the animation.
        //
        ROM_TimerConfigure(TIMER2_BASE, TIMER_CFG_PERIODIC);
    
        //
        // Setup the interrupts for the timer timeouts.
        //
        ROM_IntEnable(INT_TIMER2A);
        ROM_TimerIntEnable(TIMER2_BASE, TIMER_TIMA_TIMEOUT);
    
        //
       	    // Configure necessary peripherals.
       	    //
       	    ConfigureTimer0();
       	    ConfigureADC0();
    
       	    //
       	    // Take an initial reading of the internal temperature
       	    //
       	    UpdateInternalTemp();
    
       	    //
       	    // Initialize the buttons
       	    //
       	    ButtonsInit();
    
        //
        // Set the timer for the current animation speed.  This enables the
        // timer as a side effect.
        //
    //    io_set_timer(g_ulAnimSpeed);
    }
    
    
    
    //*****************************************************************************
    //
    // Set the speed of the animation shown on the display.  In this version, the
    // speed is described as a decimal number encoded as an ASCII string.
    //
    //*****************************************************************************
    unsigned int string2decimal(char *pcBuf)
    {
        unsigned long ulSpeed;
    
        //
        // Parse the passed parameter as a decimal number.
        //
        ulSpeed = 0;
        while((*pcBuf >= '0') && (*pcBuf <= '9'))
        {
            ulSpeed *= 10;
            ulSpeed += (*pcBuf - '0');
            pcBuf++;
        }
    
        return (ulSpeed);
    }
    
    //*****************************************************************************
    //
    // Set the speed of the animation shown on the display.
    //
    //*****************************************************************************
    void
    io_set_animation_speed(unsigned long ulSpeed)
    {
        //
        // If the number is valid, set the new speed.
        //
        if(ulSpeed <= 100)
        {
            g_ulAnimSpeed = ulSpeed;
            io_set_timer(g_ulAnimSpeed);
        }
    }
    
    //*****************************************************************************
    //
    // Get the current animation speed as an ASCII string.
    //
    //*****************************************************************************
    unsigned int
    decimal2string(char* pcBuf, int number)
    {
        unsigned int iBufLen, i, digit;
        char temp[3],temp1;
        iBufLen = 3;
        if((number/100)== 0)
        {
        	iBufLen = 2;
        	if((number/10)==0)
        	{
        		iBufLen = 1;
        	}
        }
    
         pcBuf +=iBufLen;
         for(i=0;i<iBufLen;i++)
         {
            digit = number %10;
            number = number /10;
            pcBuf--;
    
            switch(digit)
            {
                     case 0: *pcBuf = '0'; break;
                     case 1: *pcBuf = '1'; break;
                     case 2: *pcBuf = '2'; break;
                     case 3: *pcBuf = '3'; break;
                     case 4: *pcBuf = '4'; break;
                     case 5: *pcBuf = '5'; break;
                     case 6: *pcBuf = '6'; break;
                     case 7: *pcBuf = '7'; break;
                     case 8: *pcBuf = '8'; break;
                     case 9: *pcBuf = '9'; break;
    
     		}
         }
         return(iBufLen);
    }
    
    //*****************************************************************************
    //
    // Get the current animation speed as a number.
    //
    //*****************************************************************************
    unsigned long
    io_get_animation_speed(void)
    {
        return(g_ulAnimSpeed);
    }
    
    /*****************************************************************************
    //
    // The interrupt handler for the timer used to pace the animation.
    //
    //*****************************************************************************/
    void
    AnimTimerIntHandler(void)
    {
        //
        // Clear the timer interrupt.
        //
        TimerIntClear(TIMER2_BASE, TIMER_TIMA_TIMEOUT);
    
        //
        // toggle LED
        //
        g_timer2count++;
        if(g_timer2count & 1)
        {
        	turnLedOn(LED1);
        }
        else
        {
        	turnLedOff(LED1);
        }
    }
    
    //*****************************************************************************
    //
    // Interrupt handler for Timer0A.
    //
    // This function will be called periodically on the expiration of Timer0A It
    // performs periodic tasks, such as looking for input on the physical buttons,
    // and reporting usage statistics to the cloud.
    //
    //*****************************************************************************
    void
    Timer0IntHandler(void)
    {
        //
        // Clear the timer interrupt.
        //
        TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
    
        //
        // Keep track of the number of times this interrupt handler has been
        // called.
        //
        g_ui32TimerIntCount++;
    
        //
        // Poll the GPIOs for the buttons to check for press events. Update global
        // variables as necessary.
        //
        UpdateButtons();
    
        //
        // Once per second, perform the following operations.
        //
        if(!(g_ui32TimerIntCount % APP_TICKS_PER_SEC))
        {
            //
            // Keep track of the total seconds of on-time
            //
            g_ui32SecondsOnTime++;
    
            //
            // Take a reading from the internal temperature sensor.
            //
            UpdateInternalTemp();
    
         }
    
        //
        // Make sure the running tally of the number of interrupts doesn't
        // overflow.
        //
        if(g_ui32TimerIntCount == (20 * APP_TICKS_PER_SEC))
        {
            //
            // Reset the interrupt count to zero.
            //
            g_ui32TimerIntCount = 0;
    
        }
    
    }
    
    void
    Temp_Button_Update_IntHandler(void)
    {
        //
        // Clear the timer interrupt.
        //
        TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
    
        //
        // Keep track of the number of times this interrupt handler has been
        // called.
        //
        g_ui32TimerIntCount++;
    
        //
        // Poll the GPIOs for the buttons to check for press events. Update global
        // variables as necessary.
        //
        UpdateButtons();
    
        //
        // Once per second, perform the following operations.
        //
        if(!(g_ui32TimerIntCount % APP_TICKS_PER_SEC))
        {
            //
            // Keep track of the total seconds of on-time
            //
            g_ui32SecondsOnTime++;
    
            //
            // Take a reading from the internal temperature sensor.
            //
            UpdateInternalTemp();
    
         }
    
        //
        // Make sure the running tally of the number of interrupts doesn't
        // overflow.
        //
        if(g_ui32TimerIntCount == (20 * APP_TICKS_PER_SEC))
        {
            //
            // Reset the interrupt count to zero.
            //
            g_ui32TimerIntCount = 0;
    
        }
    
    }
    
    
    //*****************************************************************************
    //
    // Configures Timer 0 as a general purpose, periodic timer for handling button
    // presses.
    //
    //*****************************************************************************
    void
    ConfigureTimer0(void)
    {
        //
        // Enable the peripherals used by this example.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    
        //
        // Configure the two 32-bit periodic timers.
        //
        TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
        TimerLoadSet(TIMER0_BASE, TIMER_A, g_ui32SysClock / APP_TICKS_PER_SEC);
    
        //
        // Lower the priority of this interrupt
        //
        IntPriorityGroupingSet(4);
        IntPrioritySet(INT_TIMER0A, 0xE0);
    
        //
        // Setup the interrupts for the timer timeouts.
        //
        IntEnable(INT_TIMER0A);
        ROM_TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
        ROM_TimerEnable(TIMER0_BASE, TIMER_A);
    }
    
    //*****************************************************************************
    //
    // Enables and configures ADC0 to read the internal temperature sensor into
    // sample sequencer 3.
    //
    //*****************************************************************************
    void
    ConfigureADC0(void)
    {
        //
        // Enable clock to ADC0.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
    
        //
        // Configure ADC0 Sample Sequencer 3 for processor trigger operation.
        //
        ADCSequenceConfigure(ADC0_BASE, 3, ADC_TRIGGER_PROCESSOR, 0);
    
        //
        // Increase the hold time of this sample sequencer to account for the
        // temperature sensor erratum (ADC#09).
        //
        HWREG(ADC0_BASE + ADC_O_SSTSH3) = 0x4;
    
        //
        // Configure ADC0 sequencer 3 for a single sample of the temperature
        // sensor.
        //
        ADCSequenceStepConfigure(ADC0_BASE, 3, 0, ADC_CTL_TS | ADC_CTL_IE |
                                     ADC_CTL_END);
    
        //
        // Enable the sequencer.
        //
        ADCSequenceEnable(ADC0_BASE, 3);
    
        //
        // Clear the interrupt bit for sequencer 3 to make sure it is not set
        // before the first sample is taken.
        //
        ADCIntClear(ADC0_BASE, 3);
    }
    
    //*****************************************************************************
    //
    // Polls the buttons, and updates global state accordingly.
    //
    //*****************************************************************************
    void
    UpdateButtons(void)
    {
        uint8_t ui8Buttons, ui8ButtonsChanged;
    
        //
        // Check the current debounced state of the buttons.
        //
        ui8Buttons = ButtonsPoll(&ui8ButtonsChanged,0);
    
        //
        // If either button has been pressed, record that status to the
        // corresponding global variable.
        //
        if(BUTTON_PRESSED(USR_SW1, ui8Buttons, ui8ButtonsChanged))
        {
            g_ui32SW1Presses++;
        }
        else if(BUTTON_PRESSED(USR_SW2, ui8Buttons, ui8ButtonsChanged))
        {
            g_ui32SW2Presses++;
        }
    }
    
    //*****************************************************************************
    //
    // Takes a reading from the internal temperature sensor, and updates the
    // corresponding global statistics.
    //
    //*****************************************************************************
    void
    UpdateInternalTemp(void)
    {
        uint32_t pui32ADC0Value[1], ui32TempValueC, ui32TempValueF;
    
        //
        // Take a temperature reading with the ADC.
        //
        ADCProcessorTrigger(ADC0_BASE, 3);
    
        //
        // Wait for the ADC to finish taking the sample
        //
        while(!ADCIntStatus(ADC0_BASE, 3, false))
        {
        }
    
        //
        // Clear the interrupt
        //
        ADCIntClear(ADC0_BASE, 3);
    
        //
        // Read the analog voltage measurement.
        //
        ADCSequenceDataGet(ADC0_BASE, 3, pui32ADC0Value);
    
        //
        // Convert the measurement to degrees Celcius and Fahrenheit, and save to
        // the global state variables.
        //
        ui32TempValueC = ((1475 * 4096) - (2250 * pui32ADC0Value[0])) / 40960;
        g_ui32InternalTempC = ui32TempValueC;
        ui32TempValueF = ((ui32TempValueC * 9) + 160) / 5;
        g_ui32InternalTempF = ui32TempValueF;
    }
    
    
    
    

    Thanks and regards,

    Zhaohong

  • Hi Mr Phu,

    The period in the timer in seconds can be calculated as follow.
    1 / system frequency = time in seconds betwen timer values.
    So the time in seconds that the timer takes to count from 0 to the load value (or backwards if in countdown mode) is:
    1/system frequency * load value.
    Alternatively you can use systemfreq/desiredfreq. The desired freq is simply the inverse of the desired period (usefull for setting PWM frequencies)

    With pre scaler it depends on the mode.
    In most modes it works as a extender. It holds the most significant bits. In case of a 16bit timer you have a 8bit prescaler. If you need a load value bigger than 16bits then you set the 8 most significant bits of that number on the prescaler load value.
    Now I dont quite know on the top of my head the other modes in which the prescaler behaves diferently.
  • Hi, 

    Sorry for reply late.

    Thanks so much Zhaohong and Luis Afonso.

    I understand like that: with system clock = 40MHz, without prescale, the load value should be 40000 for timer 1ms.

    With timer 16bits, loadvalue must be smaller 2^16 - 1.

    Having prescale, with calculate like that: real time = (1/SystemClock) * (loadvalue * prescale).

    Is that right?

    Phu.

  • Hello Phu,

    There is a table titled "16-bit timer with prescaler configurations" in the data sheet. That will help understand how the timer variation occurs. But you are right except that it would be (prescale+1) in the equation.

    Regards
    Amit