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.

RTOS/LAUNCHXL-CC1350: GPTImer driver for CC26XX/CC13XX

Part Number: LAUNCHXL-CC1350
Other Parts Discussed in Thread: CC1350

Tool/software: TI-RTOS

Hello everybody !

I am using a CC1350 Launch pad, working with the TI-RTOS 2.20.01.08 in Code Composer Studio.

I need to use general purpose timers in my project. But, the driver didn't work as I wanted.

I use the module driver GPTimerCC26XX.h in this installation path: C:\ti\tirtos_cc13xx_cc26xx_2_20_01_08\products\tidrivers_cc13xx_cc26xx_2_20_01_10\packages\ti\drivers\timer.

 Here is my code. Please I need your help to get starting with GP timers. If there is any example to propose or any other module driver which works better :

#include <ti/drivers/timer/GPTimerCC26XX.h>
#include <ti/drivers/power/PowerCC26XX.h>
#include <ti/sysbios/BIOS.h>
#include <xdc/runtime/Types.h>

#define CC2650_GPTIMERPARTSCOUNT                8
#define CC2650_GPTIMERCOUNT                     4

const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC2650_GPTIMERPARTSCOUNT] = {
  {.baseAddr = GPT0_BASE, .intNum = GPT_INT_TIMEOUT,
                .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A},
  {.baseAddr = GPT0_BASE, .intNum = GPT_INT_TIMEOUT,
                .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B},
  {.baseAddr = GPT1_BASE, .intNum = GPT_INT_TIMEOUT,
                .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A},
  {.baseAddr = GPT1_BASE, .intNum = GPT_INT_TIMEOUT,
                .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B},
  {.baseAddr = GPT2_BASE, .intNum = GPT_INT_TIMEOUT,
                .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A},
  {.baseAddr = GPT2_BASE, .intNum = GPT_INT_TIMEOUT,
                .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B},
  {.baseAddr = GPT3_BASE, .intNum = GPT_INT_TIMEOUT,
                .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A},
  {.baseAddr = GPT3_BASE, .intNum = GPT_INT_TIMEOUT,
                .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B}
};

GPTimerCC26XX_Object gptimerCC26XXObjects[CC2650_GPTIMERCOUNT];

const GPTimerCC26XX_Config GPTimerCC26XX_config[CC2650_GPTIMERPARTSCOUNT] = {
  { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[0], GPT_A},
  { &gptimerCC26XXObjects[0], &gptimerCC26xxHWAttrs[1], GPT_B},
  { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[2], GPT_A},
  { &gptimerCC26XXObjects[1], &gptimerCC26xxHWAttrs[3], GPT_B},
  { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[4], GPT_A},
  { &gptimerCC26XXObjects[2], &gptimerCC26xxHWAttrs[5], GPT_B},
  { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[6], GPT_A},
  { &gptimerCC26XXObjects[3], &gptimerCC26xxHWAttrs[7], GPT_B}
};

GPTimerCC26XX_Handle timerHandle1;

void InitTimer()
{
  GPTimerCC26XX_Params GPT_Params;
  GPTimerCC26XX_Params_init(&GPT_Params);
  GPT_Params.width = GPT_CONFIG_16BIT;
  GPT_Params.mode = GPT_MODE_PERIODIC_UP;
  GPT_Params.debugStallMode = GPTimerCC26XX_DEBUG_STALL_OFF;

  timerHandle1 = GPTimerCC26XX_open(0, &GPT_Params);

  Types_FreqHz  freq;
  BIOS_getCpuFreq(&freq);
  GPTimerCC26XX_Value loadVal = freq.lo / 1000 - 1; //47999
  GPTimerCC26XX_setLoadValue(timerHandle1, loadVal);
  GPTimerCC26XX_registerInterrupt(timerHandle1, timerCallback, GPT_INT_TIMEOUT);
  GPTimerCC26XX_start(timerHandle1);
}

void DeInitTimer()
{
  GPTimerCC26XX_stop(timerHandle1);
  GPTimerCC26XX_unregisterInterrupt(timerHandle1);
  GPTimerCC26XX_close(timerHandle1);
}

void timerCallback(GPTimerCC26XX_Handle handle,
                   GPTimerCC26XX_IntMask interruptMask) {

}

  • Nidhal,

    Have you checked if timerHandle1 is equal to NULL after open()? This can indicate failure to open the timer properly.

    Are you calling InitTimer() from a task context?

    Derrick
  • A question on the side: What is the reason you use TI-RTOS 2.20.01.08 and not dev.ti.com/.../ ?
  • Thank you Derrick for your answer,

    I removed the function GPTimerCC26XX_registerInterrupt() from my code and the timer is working now and counting (I checked timer registers). The problem that it's working with a wrong prescaler (it counts very fast like 10000 in 2s). Could you help me, please, to fix that ? An other question please, how can I set correctly an interruption to this timer and make a callback related to time elapsed (periodic mode) ?

    I am calling InitTimer() from a task initialization function (runned only in the initialization of the task).

    Regards,

  • Please help me. I debugged the code step by step and I found that it's always bugging in the function GPTimerCC26XX_registerInterrupt() in the GPTimerCC26XX.c file.
    Please could you confirm to me that the value .intNum = GPT_INT_TIMEOUT is correct in the definition of the constant gptimerCC26xxHWAttrs in my code ? Because the code is not able to construct the Hwi (hardware interruption). There is neither documentation nor examples about that !
    Best Regards,
  • Any full documentation or a working example would be appreciated !
  • Nidhal,

    Try using INT_GPT0A instead.

    Derrick

  • Nidhal,

    I was not specific enough in my last response. Your hwAttrs structures have the wrong .intNum specified. use the following instead.

    const GPTimerCC26XX_HWAttrs gptimerCC26xxHWAttrs[CC1350_LAUNCHXL_GPTIMERPARTSCOUNT] = {
        { .baseAddr = GPT0_BASE, .intNum = INT_GPT0A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0A, },
        { .baseAddr = GPT0_BASE, .intNum = INT_GPT0B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT0, .pinMux = GPT_PIN_0B, },
        { .baseAddr = GPT1_BASE, .intNum = INT_GPT1A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1A, },
        { .baseAddr = GPT1_BASE, .intNum = INT_GPT1B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT1, .pinMux = GPT_PIN_1B, },
        { .baseAddr = GPT2_BASE, .intNum = INT_GPT2A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2A, },
        { .baseAddr = GPT2_BASE, .intNum = INT_GPT2B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT2, .pinMux = GPT_PIN_2B, },
        { .baseAddr = GPT3_BASE, .intNum = INT_GPT3A, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3A, },
        { .baseAddr = GPT3_BASE, .intNum = INT_GPT3B, .intPriority = (~0), .powerMngrId = PowerCC26XX_PERIPH_GPT3, .pinMux = GPT_PIN_3B, },
    };

    Derrick

  • Thank you Derrick,
    This resolve my first problem. But, I still have just one question. How can I set the prescaler correctly in the periodic mode. So, I can configure my timer as I want (from 500ms to 11 s in my project). Because, I read in the technical reference manual p1193 section 13.3.2.1 table 13-2 that the maximum prescale set the period at 691.2 ms.

    Kind regards,

  • Nidhal,

    Generically, you can use this code to get pre-scalar and load register values:

    uint32_t period_us = 100;
    uint32_t period_counts;
    
    uint32_t bestDiff = ~0, bestPsr = 0, bestIload = 0;
    uint32_t diff, intervalLoad, prescaler;
    
    Types_FreqHz  clockFreq;
    BIOS_getCpuFreq(&clockFreq);
    
    period_counts = period_us * (clockFreq.lo / 1000000);
    
    /* If this period will not fit in 16 bits, we may need to calculate a prescalar */
    if (period_counts > 0xFFFF) {
    
        /* 24-bit resolution for the half timer */
        if (period_counts >= (1 << 24)) {
            /* Period too large for half timer and is invalid */
        }
    
        /* Calculator prescalar */
        /* Loop over the 8-bit prescaler */
        for (prescaler = 1; prescaler < 256; prescaler++) {
    
            /* Calculate timer interval load */
            intervalLoad = period_counts / (prescaler + 1);
    
            /* Will this fit in 16-bits? */
            if (intervalLoad > (uint16_t) ~0) {
                continue;
            }
    
            /* How close is the intervalLoad to what we actually want? */
            diff = period_counts - intervalLoad * (prescaler + 1);
    
            /* If it is closer than what we previously found */
            if (diff <= bestDiff) {
    
                /* If its a perfect match, just use this */
                if (diff == 0) {
                    period_counts = intervalLoad;
                    bestPsr = prescaler;
    
                    break;
                }
    
                /* Snapshot in case we don't find something better */
                bestDiff = diff;
                bestPsr = prescaler;
                bestIload = intervalLoad;
            }
        }
    }

    You should also consider that two 16-bit general purpose timers may be concatenated to form a 32-bit timer.

    Derrick

  • Thanks Derrick I resolved my problem with the 32 bits timer without a prescaler. The time saved in the TAILR (32 bits register) allow me to reach until 89.478 s as a period which is more than enough ((2^32 - 1) / 48000000) for an MCU working with 48 MHz clock. I will test your last posted code with 16 bits timer when I have time and I will come to you soon. I will post also a project with a timer module ready to use by the end of this week.