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.

Call API crash , TimerConfigure() in CC2650 + smartrf06

Other Parts Discussed in Thread: CC2650, CC2640

Hi,

I use CC2650 + smartrf 06 and IAR 7.30.4.

When I call function

TimerConfigure(GPT0_BASE,TIMER_CFG_SPLIT_PAIR|TIMER_CFG_A_PWM);

The application crash.

I can not check register value of GPT0 from IAR register view.

But I try other API , GPIODirModeSet(), AON_BatmonTempGetDegC(), that's all work fine.

When call timer API, application no more respond.

Any ideal?

Thanks,

Terry Chang

  • Hi Terry,

    The GPTimers are not enabled by default so writing or reading from the timer will trigger a bus fault.

    It is important to notice that there are two layers of drivers on the CC26XX. The lower layer (driverLib) drivers does not include any power management so using these directly will in many cases not work. This is typically handled in a OS-level driver which we haven't released yet.

    Below is some example code showing how to set up a standalone task to output PWM. The PWM output is enabled/disabled by pressing SELECT on the SmartRF06 board.

    Regards,
    Svend

    #include "Board.h"
    #include <ti/sysbios/knl/Clock.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/family/arm/cc26xx/Power.h>
    #include <ti/sysbios/family/arm/cc26xx/PowerCC2650.h>
    
    #include <ti/drivers/PIN/PINCC26XX.h>
    #include <driverLib/timer.h>
    
    #define TASK_STACK_SIZE 512
    #define TASK_PRI        1
    
    
    char        taskStack[TASK_STACK_SIZE];
    Task_Struct taskStruct;
    
    
    void taskFxn(UArg a0, UArg a1);
    
    
    int main(void) {
    
      PIN_init(BoardGpioInitTable);
    
      Task_Params params;
      Task_Params_init(&params);
      params.priority = TASK_PRI;
      params.stackSize = TASK_STACK_SIZE;
      params.stack = taskStack;
    
      Task_construct(&taskStruct, taskFxn, &params, NULL);
    
      BIOS_start();
    }
    
    #define PWM_DIV_FACTOR 48 //48MHz / 48 = 1MHz
    
    #define TIMER_LOADSET (PWM_DIV_FACTOR-1)
    #define TIMER_MATCH (PWM_DIV_FACTOR/2-1)
    
    bool timerEnabled = 0;
    
    PIN_Config pwmExamplePins[] = {
      Board_LED1       | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW   | PIN_PUSHPULL | PIN_DRVSTR_MAX,
      Board_LED2       | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW   | PIN_PUSHPULL | PIN_DRVSTR_MAX,
      Board_KEY_SELECT | PIN_INPUT_EN       | PIN_HYSTERESIS | PIN_HYSTERESIS | PIN_PULLUP | PIN_IRQ_NEGEDGE,
      PIN_TERMINATE };
    
    PIN_State  pinState;
    PIN_Handle pinHandle;
    
    
    static void timerInitialize() {
      TimerConfigure(GPT0_BASE, TIMER_CFG_SPLIT_PAIR|TIMER_CFG_A_PWM);
      TimerLoadSet(GPT0_BASE, TIMER_A, TIMER_LOADSET);
      TimerMatchSet(GPT0_BASE, TIMER_A, TIMER_MATCH);
    
      //Stall timer when halting debugger
      //TimerStallControl(GPT0_BASE, TIMER_A, true)
    
    }
    
    static void pinCallBack(PIN_Handle handle, PIN_Id pinId) {
    
      if( timerEnabled) {
        timerEnabled = 0;
    
        // Allow standby in TI RTOS and stop timer
        Power_releaseConstraint(Power_SB_DISALLOW);
        TimerDisable(GPT0_BASE, TIMER_A);
    
      }
      else {
        timerEnabled = 1;
    
        // Disallow standby in TI RTOS to allow timer to run
        Power_setConstraint(Power_SB_DISALLOW);
        TimerEnable(GPT0_BASE, TIMER_A);
      }
    
    }
    
    void taskFxn(UArg a0, UArg a1) {
    
      // Register client for pins in pwmExamplePins array
      pinHandle = PIN_open(&pinState, pwmExamplePins);
      // Route LED1 pin on SmartRF06EB to IO event port 0 (0 = Timer0A, 1 = Timer0B, 2 = Timer1A..)
      PINCC26XX_setMux(pinHandle, PIN_ID(Board_LED1), IOC_PORT_MCU_PORT_EVENT0);
    
      PIN_registerIntCb(pinHandle, pinCallBack);
    
      // Turn on PERIPH power domain and clock for GPT0
      Power_setDependency(PERIPH_GPT0);
    
      timerInitialize();
    
      // 100ms
      uint32_t sleepTicks = 100 * 1000/Clock_tickPeriod;
    
      bool ledValue = 0;
    
      while(1) {
    
        // Let task sleep, chip will go into IDLE or STANDBY mode depending on whether timer is enabled
        Task_sleep(sleepTicks);
    
        PIN_setOutputValue(pinHandle, PIN_ID(Board_LED2), ledValue);
        // Invert LED value
        ledValue = (ledValue ? 0 : 1);
    
      }
    }

  • Thanks Svend,

    I will try it.

    Terry

  • Hello

    I tried this example and it worked perfectly. But I have problem ending on high or low. Could you please advice how to do this?

    // Daniel
  • Hi Daniel,

    That is a good point which we will need to take care of in the PWM driver. I will check this with the SW team and get back to you.

    Regards,
    Svend
  • Hi Daniel,

    A quick update on this. You might need to reset the timer or re-configure it to get rid of the output when the timer is suddenly stopped.
    A better workaround might be to use PINCC26XX_setMux and connect the pin again to the GPIO module which can then be set to a known value using PIN_setOutputValue.

    Regards,
    Svend
  • I am using a CC2640 custom board and can't seem to get this code to work. I get the flashing LED from the while loop at the end but no the PWM. I don't have any buttons so that may be the problem. I set timerEnabled = 1, I thought this would work...

    /* PWM */
    char        		taskStack[TASK_STACK_SIZE];
    Task_Struct 		taskStruct;
    bool timerEnabled = 1;
    PIN_State  pinState;
    PIN_Handle pinHandle;
    
    /*
     * Application LED pin configuration table:
     *   - All LEDs board LEDs are off.
     */
    PIN_Config pwmPinTable[] = {
    LED1 		| PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,
    LED2 		| PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
    HAPTIC_PWM	| PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
    PIN_TERMINATE };

    static void timerInitialize() {
      TimerConfigure(GPT0_BASE, TIMER_CFG_SPLIT_PAIR|TIMER_CFG_A_PWM);
      TimerLoadSet(GPT0_BASE, TIMER_A, TIMER_LOADSET);
      TimerMatchSet(GPT0_BASE, TIMER_A, TIMER_MATCH);
    
      //Stall timer when halting debugger
      //TimerStallControl(GPT0_BASE, TIMER_A, true)
    
    }
    
    static void pinCallBack(PIN_Handle handle, PIN_Id pinId) {
    
      if( timerEnabled) {
        timerEnabled = 0;
    
        // Allow standby in TI RTOS and stop timer
        Power_releaseConstraint(Power_SB_DISALLOW);
        TimerDisable(GPT0_BASE, TIMER_A);
    
      }
      else {
        timerEnabled = 1;
    
        // Disallow standby in TI RTOS to allow timer to run
        Power_setConstraint(Power_SB_DISALLOW);
        TimerEnable(GPT0_BASE, TIMER_A);
      }
    }
    
    void pwmFxn(UArg a0, UArg a1) {
    
      // Register client for pins in pwmPinTable array
      pinHandle = PIN_open(&pinState, pwmPinTable);
      // Route LED1 pin to IO event port 0 (0 = Timer0A, 1 = Timer0B, 2 = Timer1A..)
      PINCC26XX_setMux(pinHandle, PIN_ID(LED2), IOC_PORT_MCU_PORT_EVENT0);
    
      PIN_registerIntCb(pinHandle, pinCallBack);
    
      // Turn on PERIPH power domain and clock for GPT0
      Power_setDependency(PERIPH_GPT0);
    
      timerInitialize();
    
      // 100ms
      uint32_t sleepTicks = 100 * 1000/Clock_tickPeriod;
    
      bool ledValue = 0;
    
      while(1) {
    
        // Let task sleep, chip will go into IDLE or STANDBY mode depending on whether timer is enabled
        Task_sleep(sleepTicks);
    
        PIN_setOutputValue(pinHandle, PIN_ID(LED1), ledValue);
        // Invert LED value
        ledValue = (ledValue ? 0 : 1);
    
      }
    }

  • It seems there is a logical error by initializing timerEnabled to 1.
    Also, yiou have not set up any pins to detect an interrupt so I assume your pin callback function will not be executed?
  • Thanks for the response. Sorry but I am very new to RTOS. Not sure what you mean by logical error but after you pointed out the callback routine I eliminated timerEnabled from the code. I now enable the timer in timerInitialize() as below. I don't see any visible dimming but LED1 does turn on here:

    PINCC26XX_setMux(pinHandle, PIN_ID(LED1), IOC_PORT_MCU_PORT_EVENT0);

    I will try it on the scope later but is there any way to tell if the timer is actually running?

    /*PWM*/
    #define PWM_DIV_FACTOR 4800000					//48MHz / 48 = 1MHz
    #define TIMER_LOADSET (PWM_DIV_FACTOR-1)
    #define TIMER_MATCH (PWM_DIV_FACTOR/2-1)
    #define TASK_STACK_SIZE 512
    #define TASK_PRI        1
    
    void pwmFxn(UArg a0, UArg a1);
    static void timerInitialize();
    void led();
    
    char        		taskStack[TASK_STACK_SIZE];
    Task_Struct 		taskStruct;
    bool timerEnabled = 1;
    PIN_State  pinState;
    PIN_Handle pinHandle;
    PIN_Handle ledPinHandle;
    
    /*=====================================================================================
     * 				PWM
     * ====================================================================================
     */
    
    static void timerInitialize() {
      TimerConfigure(GPT0_BASE, TIMER_CFG_SPLIT_PAIR|TIMER_CFG_A_PWM);
      TimerLoadSet(GPT0_BASE, TIMER_A, TIMER_LOADSET);
      TimerMatchSet(GPT0_BASE, TIMER_A, TIMER_MATCH);
    
      Power_setConstraint(Power_SB_DISALLOW);
      TimerEnable(GPT0_BASE, TIMER_A);
    
      //Stall timer when halting debugger
      //TimerStallControl(GPT0_BASE, TIMER_A, true)
    
    }
    
    void pwmFxn(UArg a0, UArg a1) {
    
      // Register client for pins in pwmPinTable array
      pinHandle = PIN_open(&pinState, pwmPinTable);
      // Route LED1 pin to IO event port 0 (0 = Timer0A, 1 = Timer0B, 2 = Timer1A..)
      PINCC26XX_setMux(pinHandle, PIN_ID(LED1), IOC_PORT_MCU_PORT_EVENT0);
    
    //  PIN_registerIntCb(pinHandle, pinCallBack);
    
      // Turn on PERIPH power domain and clock for GPT0
      Power_setDependency(PERIPH_GPT0);
    
      timerInitialize();
    
      // 100ms
      uint32_t sleepTicks = 100*1000/Clock_tickPeriod;
    
      bool ledValue = 0;
    
      while(1) {
    
        // Let task sleep, chip will go into IDLE or STANDBY mode depending on whether timer is enabled
        Task_sleep(sleepTicks);
    
        PIN_setOutputValue(pinHandle, PIN_ID(LED2), ledValue);
        // Invert LED value
        ledValue = (ledValue ? 0 : 1);
      }
    }
  • Hi Cameron,

    run into the same problem with you, however enabling the timer in timerInitialize() works for me.

  • Hello,

    I using your example for my application. I would like to generate two independent pwm outputs (actually oposed signals). Like an AC Square if you add the two signals. 

    I do not know really how to set an output running for example at 15KHz and the other at 100KHz. 

    Any help will be appreciatted.

    Using (CCS + CC2640 own board).

  • You need to configure two timers for PWM (e.g. both timer 0A and 0B). Then the load and match values for both need to be set.
    For 100kHz:
    - Load value will be 480-1, match 480/2-1 (50% duty cycle)
    For 15kHz:
    - Load value will be 3200-1, match 3200/2-1 (50% duty)

    To find the load/match values you simply take the timer frequency and divide by your output frequency. 1 is subtracted since the timer counts down to 0.

    Regards,
    Svend
  • Thanks for you response Svend,

    I made as you said but only one of the both pwm is running. It seems like some register is rewritten when I configure the second pwm output. Maybe you can see what I am missing


    pinHandle = PIN_open(&pinState, pwmExamplePins);

    Power_setDependency(PERIPH_GPT0);
    Power_setConstraint(Power_SB_DISALLOW);

    //Configure timer 0A
    PINCC26XX_setMux(pinHandle, PIN_ID(PWM1), IOC_PORT_MCU_PORT_EVENT0);
    TimerConfigure(GPT0_BASE, TIMER_CFG_SPLIT_PAIR|TIMER_CFG_A_PWM);
    TimerLoadSet(GPT0_BASE, TIMER_A, 500);
    TimerMatchSet(GPT0_BASE, TIMER_A, 200);

    //Configure timer 0B
    PINCC26XX_setMux(pinHandle, PIN_ID(PWM2), IOC_PORT_MCU_PORT_EVENT1);
    TimerConfigure(GPT0_BASE, TIMER_CFG_SPLIT_PAIR|TIMER_CFG_B_PWM);
    TimerLoadSet(GPT0_BASE, TIMER_B, 100);
    TimerMatchSet(GPT0_BASE, TIMER_B, 20);

    //Enable both timers
    TimerEnable(GPT0_BASE, TIMER_BOTH);


    Sincerely,

    Albert
  • Found it, sorry for bothering:
    TimerConfigure(GPT0_BASE, TIMER_CFG_SPLIT_PAIR|TIMER_CFG_A_PWM|TIMER_CFG_B_PWM);
    as I said I was rewritting a register.
    Thanks
  • We are unable to set the higher bits of the 32 bit Match register (TAMATCHR). The Maximum value the register reaches is 0x0000FFFF. What could be the issue?
    We are using halfwidth timer mode (split timer) , & timer A is configured for PWM mode, with 8 Bit prescaler.
  • Hello Ramya,

    A PWM driver for CC26XX can now be found here:
    e2e.ti.com/.../474000

    Regards,
    Svend
  • Is this code only meant for IAR ?

    I am getting build errors in CCS6.1.

    Please let me know, as i am interested in this.