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.

LAUNCHXL-CC1310: GPTimer PinMux no output signal

Part Number: LAUNCHXL-CC1310
Other Parts Discussed in Thread: CC1310, SYSBIOS

Hello,

I have read several posts to the PinMuxing and also followed the API Reference examples, but i'm not able to measure anything on the output pin (DIO12) as mapped of my LAUNCHPAD with my oszilloscope.

Could you have a short look at my code to review and point me to some mistake?

In the CC1310_LAUNCHXL.c and .h header files I didn't changed anything.

#include <stdint.h>
/* XDC module Headers */
#include <xdc/std.h>
#include <xdc/runtime/System.h>


/* RTOS header files */
#include <ti/sysbios/BIOS.h>

/* Example/Board Header files */
#include <ti/drivers/Board.h>
#include <ti/drivers/PIN.h>
#include <ti/drivers/power/PowerCC26XX.h>
#include <ti/drivers/timer/GPTimerCC26XX.h>
#include <ti/drivers/pin/PINCC26XX.h>

#include <xdc/runtime/Types.h>

#include "Board.h"

#include <ti/devices/cc13x0/driverlib/osc.h>
Power_setDependency(XOSC_HF);



PIN_Handle PinHandle;
PIN_State ledPinState;
GPTimerCC26XX_Handle hTimer;

PIN_Config PinTable[] = {
    Board_DIO12 | PIN_INPUT_DIS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
    PIN_TERMINATE
};

/*
 *  ======== main ========
 */
int main(void)
{
    int32_t PinMuxRes = 0;
    /* Construct BIOS objects */

    /* Call driver init functions */
    Board_init();

    if (OSCClockSourceGet(OSC_SRC_CLK_HF)!= OSC_RCOSC_HF){
        OSCClockSourceSet(OSC_SRC_CLK_HF,OSC_RCOSC_HF);
    }

    PinHandle = PIN_open(&ledPinState, PinTable);
    if(!PinHandle) {
        /* Error initializing board LED pins */
        while(1);
    }

    GPTimerCC26XX_Params timer_params;
    GPTimerCC26XX_Params_init(&timer_params);

    timer_params.width          = GPT_CONFIG_32BIT;
    timer_params.mode           = GPT_MODE_PWM;
    timer_params.debugStallMode = GPTimerCC26XX_DEBUG_STALL_OFF;
    hTimer = GPTimerCC26XX_open(Board_GPTIMER0A, &timer_params);
    if(hTimer == NULL) {
        while(1);
    }
    Types_FreqHz  freq;
    BIOS_getCpuFreq(&freq);

    //GPTimerCC26XX_Value loadVal = freq.lo / 1000 - 1; //47999
    GPTimerCC26XX_Value loadVal = 0x00FFF;
    GPTimerCC26XX_setLoadValue(hTimer, loadVal);
    GPTimerCC26XX_setMatchValue(hTimer, 0x00000);
    GPTimerCC26XX_PinMux pinMux = GPTimerCC26XX_getPinMux(hTimer);
    PinMuxRes = PINCC26XX_setMux(PinHandle, Board_DIO12,pinMux);


    GPTimerCC26XX_start(hTimer);

    BIOS_start();    /* Does not return */
    return(0);
}

  • Hello,

    Which example is this based on and what exactly are you trying to achieve?

  • Hi Erik,

    this was based on the GPTimer example from the Ti Drivers folder and others mixed together. I have reviewed the code from the PWM example and figured out that the switching of the PIN requires a load and match value, that the PIN gets toggled...

    Currently I would like to implement a single wire driver for my DHT11 sensor. I get the timer triggered and receive some values, but for some reason that looks not correct. After reading the technical reference manual, I have seen that the timer in the edge time mode starts counting on 0x0000 or 0xFFFF depending o the direction and never stops counting. When it reaches the min or max vlaue it wraps around.

    Is there a way to implement to stop the timer on capture (ISR) and reset the counting value to 0x000.

    So for example a pos/neg edge ccurs -> ISR called -> read timer value -> reset timer to 0x0000 -> post semaphore in task to process timer value?

    The DHT11 sensor is sending the data as followed:

    The MCU starts a request to the senso by pulling the the line to ground (logical low) for at least 18ms and release, after that the data is send as followed:

    26-28µs logical HIGH means data = 0

    70µs logical HIGH means data = 1

    each bit transmission is initialted with a 50µs logical low level.

    So I have to meet that timings

    At the moment I'm diving in the driverlib, but i'm not sure if such a low level programming is neccessary, could you give me some advice how determine the timings in the MCU?

    Do I have to use the driverlib to realize that or is it also possible to use the GPTimer "High Level" approach for this?

    Here my code for the moment:

    /*
     *  ======== main_tirtos.c ========
     */
    #include <stdint.h>
    /* XDC module Headers */
    #include <xdc/std.h>
    #include <xdc/runtime/System.h>
    #include <xdc/runtime/Error.h>
    
    
    /* RTOS header files */
    #include <ti/sysbios/BIOS.h>
    #include <ti/sysbios/knl/Task.h>
    #include <ti/sysbios/knl/Semaphore.h>
    
    #include <ti/display/Display.h>
    
    /* Example/Board Header files */
    #include <ti/drivers/Board.h>
    #include <ti/drivers/PIN.h>
    #include <ti/drivers/power/PowerCC26XX.h>
    #include <ti/drivers/timer/GPTimerCC26XX.h>
    #include <ti/drivers/pin/PINCC26XX.h>
    
    #include <xdc/runtime/Types.h>
    
    #include "Board.h"
    
    #include <ti/devices/cc13x0/driverlib/osc.h>
    Power_setDependency(XOSC_HF);
    
    
    
    PIN_Handle PinHandle;
    PIN_State ledPinState;
    GPTimerCC26XX_Handle countTimerh;
    GPTimerCC26XX_Handle edgeTimerh;
    GPTimerCC26XX_Params countTimer_params;
    GPTimerCC26XX_Params edgeTimer_params;
    
    Semaphore_Struct semStruct;
    Semaphore_Handle semHandle;
    Semaphore_Params semParams;
    
    Task_Struct taskStruct;
    Task_Params taskParams;
    
    static Display_Handle display;
    uint32_t timerValue;
    
    #define TASKSTACKSIZE 512
    
    Task_Struct task1Struct, task2Struct;
    Char task1Stack[TASKSTACKSIZE], task2Stack[TASKSTACKSIZE];
    
    
    PIN_Config OutputPinTable[] = {
        Board_DIO12 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL | PIN_DRVSTR_MAX,
        PIN_TERMINATE
    };
    
    PIN_Config InputPinTable[] = {
        Board_DIO12 | PIN_INPUT_EN | PIN_HYSTERESIS,
        PIN_TERMINATE
    };
    
    void countTimerCallback(GPTimerCC26XX_Handle handle, GPTimerCC26XX_IntMask interruptMask){
        PIN_setOutputValue(PinHandle, Board_DIO12, 1);
        PIN_setConfig(PinHandle, PINCC26XX_BM_INPUT_EN, &InputPinTable);
        GPTimerCC26XX_PinMux pinMux = GPTimerCC26XX_getPinMux(edgeTimerh);
        PINCC26XX_setMux(PinHandle, Board_DIO12,pinMux);
        GPTimerCC26XX_start(edgeTimerh);
        return;
    }
    
    void edgeTimerCallback(GPTimerCC26XX_Handle handle, GPTimerCC26XX_IntMask interruptMask){
        timerValue = GPTimerCC26XX_getFreeRunValue(edgeTimerh);
        Semaphore_post(semHandle);
    
    }
    
    void task1Fxn(UArg arg0, UArg arg1){
        static uint32_t timerValues[100];
        static uint8_t i=0;
        while(1){
            Semaphore_pend(semHandle,BIOS_WAIT_FOREVER);
            timerValues[i] = timerValue;
            i++;
            if(i>=100) i=0;
            Display_printf(display, 0, 0, "Timer value: %d\n", timerValue);
        }
    
    }
    
    /*
     *  ======== main ========
     */
    int main(void)
    {
        Error_Block eb;
    
    
        /* Construct BIOS objects */
    
        /* Call driver init functions */
        Board_init();
    
        Task_Params_init(&taskParams);
        taskParams.stackSize = TASKSTACKSIZE;
        taskParams.stack = &task1Stack;
        taskParams.priority = 1;
        Task_construct(&task1Struct, (Task_FuncPtr)task1Fxn, &taskParams, NULL);
    
        /* Construct a Semaphore object to be use as a resource lock, inital count 1 */
        Semaphore_Params_init(&semParams);
        semHandle = Semaphore_create(0, &semParams, &eb);
    
        if (OSCClockSourceGet(OSC_SRC_CLK_HF)!= OSC_RCOSC_HF){
            OSCClockSourceSet(OSC_SRC_CLK_HF,OSC_RCOSC_HF);
        }
    
        PinHandle = PIN_open(&ledPinState, OutputPinTable);
        if(!PinHandle) {
            /* Error initializing board LED pins */
            while(1);
        }
    
        display = Display_open(Display_Type_UART, NULL);
        if (display == NULL) {
            /* Failed to open display driver */
            while (1);
        }
    
        GPTimerCC26XX_Params_init(&countTimer_params);
        GPTimerCC26XX_Params_init(&edgeTimer_params);
    
        countTimer_params.width          = GPT_CONFIG_16BIT;
        countTimer_params.mode           = GPT_MODE_ONESHOT;
        countTimer_params.debugStallMode = GPTimerCC26XX_DEBUG_STALL_OFF;
    
        edgeTimer_params.width          = GPT_CONFIG_16BIT;
        edgeTimer_params.mode           = GPT_MODE_EDGE_TIME;
        edgeTimer_params.debugStallMode = GPTimerCC26XX_DEBUG_STALL_OFF;
    
    
        countTimerh = GPTimerCC26XX_open(Board_GPTIMER0A, &countTimer_params);
        edgeTimerh  = GPTimerCC26XX_open(Board_GPTIMER0B, &edgeTimer_params);
    
        if((countTimerh == NULL) || (edgeTimerh == NULL )) {
            while(1);
        }
    
        Types_FreqHz  freq;
        BIOS_getCpuFreq(&freq);
    
        //set loadVal to 30 ms
        GPTimerCC26XX_Value loadVal = 0x15F900;
        GPTimerCC26XX_setLoadValue(countTimerh, loadVal);
    
        //GPTimerCC26XX_setLoadValue(edgeTimerh, 0x0000);
        GPTimerCC26XX_setCaptureEdge(edgeTimerh, GPTimerCC26XX_BOTH_EDGES);
    
        GPTimerCC26XX_registerInterrupt(countTimerh, countTimerCallback, GPT_INT_TIMEOUT);
        GPTimerCC26XX_registerInterrupt(edgeTimerh, edgeTimerCallback, GPT_INT_CAPTURE);
        PIN_setOutputValue(PinHandle, Board_DIO12, 0);
        //Display_printf(display, 0, 0, "Setup complete\n");
        GPTimerCC26XX_start(countTimerh);
    
        BIOS_start();    /* Does not return */
    
    
        return(0);
    }
    

  • Hello ,

    Very interesting.

    1) For starters you should configure and open the drivers in a TI-RTOS task after the call to BIOS_start() to allow the kernel to run and the power drivers to control clocks and power dependencies. You can reference the TI-RTOS driver examples for this layout.

    PS:

    The GPTimer clock is dependent on the MCU system clock. If very high-accuracy outputs are needed, the application should request using the external HF crystal:

    #include <ti/sysbios/family/arm/cc26xx/Power.h>
    #include <ti/sysbios/family/arm/cc26xx/PowerCC2650.h>
    Power_setDependency(XOSC_HF);

    Please reference the driver documentation:
    2) Input edge-time mode seems to be worth investigating. But as you stated After an event has been captured, the timer does not stop counting and is not cleared until it reaches the timeout value. I am not sure if the latency requirements can be met and what the best solution to investigate first. When using the GPtimer the device cannot enter standby and the timing requirements prohibit the device to enter standby. So a polling solution might be a simpler approach.
    3) Perhaps the TDC in the sensor controller could be used. I will ask for some advice on feasibility on this approach and get back to you.
  • Hi ,

    thanks for your hints :)

    I got it working by using the Driverlib and resetting the timer counter value in the TBV register.

    void edgeTimerCallback(GPTimerCC26XX_Handle handle, GPTimerCC26XX_IntMask interruptMask){
        static uint8_t i=0;
        timerValues[i] = HWREG(GPT0_BASE + GPT_O_TBR);
        HWREG(GPT0_BASE + GPT_O_TBV) = 0x00000000;
        i++;
        if(i>=41){
            Semaphore_post(semHandle);
            i=0;
        }
    }

    This gives me sligtly accurate timing, there is some offset between the TIMERVALUE * 1/48*10^6 (48MHz) and the measured timing on my oscilloscope, but it's acceptable for my solution.

    I think this offset (~5µS) comes from the interruption of the RTOS task, because it consumes some clock cycles or what do you think?

    Do you know what is the closest timing that can be reached with the CC1310 and the timer in "high resolution" configuration?

    For reduction of power consumption, the next thing what I would like to go on, is to integrate this in the Sensor Controller Studio...

  • Hello ,

    Very cool.

    Regarding the latency, Yes there is some latency involved from the TI-RTOS HWI dispatcher. If you registered with GPTimerCC26XX_registerInterrupt the interrupt will run in HWI interrupt context which generally is the fastest except for zero latency interrupts that cannot make a scheduler call (e.g. Semaphore_post):

    https://e2e.ti.com/support/microcontrollers/other/f/908/p/598396/2200988#2200988

    You can refer to section B.1 Timing Benchmarks in the TI-RTOS Kernel (SYS/BIOS) User's Guide:

    http://dev.ti.com/tirex/explore/node?node=AFxFnk6SnDBDb76vo0gB8A__eCfARaV__LATEST

    5 us seems reasonable based on the benchmark values found in the SDK path:

    C:\ti\simplelink_cc13x0_sdk_4_10_00_10\kernel\tirtos\packages\ti\sysbios\benchmarks\doc-files