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-CC1312R1: Not able to set/clear GPIO inside watchdog timer callback function

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

Hello,

When I try to set/clear GPIO22 in my main task, it work perfectly, but when I'm trying to set/clear GPIO22 in watchdog timer callback noting happen, the GPIO state is not modified.

Using below GPIO:

#define Board_GPIO_TEST1        GPIOCC26XX_DIO_22

GPIO configuration: GPIO_PinConfig gpioPinConfigs[] = {

/* GPIO_TEST1 */
GPIOCC26XX_DIO_22 | GPIO_CFG_OUT_STD | GPIO_CFG_OUT_STR_MED | GPIO_CFG_OUT_LOW,

Set/clear function I use:

PIN_setOutputValue(PIN_Handle handle, PIN_Id pinId, uint32_t val);

  • - What is GPIOCC26XX_DIO_22 defined as?

    - Have you disable syscfg to use the pin driver? 

    - Would you be able to provide a minimum example showing your issue? 

  • 1. I'm using syscfg and the definition of DIO22 is as follow: GPIOCC26XX_DIO_22 | GPIO_CFG_OUT_STD | GPIO_CFG_OUT_STR_MED | GPIO_CFG_OUT_LOW.

    2. No, syscfg is enable. should I disable it ? why it should be disable?

  • The reason I asked about syscfg is that it looks like you are using the PIN driver which is not supported directly by syscfg meaning that you have to include the required files manually. You can use the PIN driver is you prefer this to the GPIO driver.

    - Would you be able to provide a minimum example showing your issue? 

  • Here is an example that show my issue:

    /* Driver configuration */
    #include "ti_drivers_config.h"

    #define THREADSTACKSIZE 1024

    #define TIMEOUT_MS 1000
    #define SLEEP_US 500000

    typedef void (*watchdogCallback_t)( void );
    watchdogCallback_t g_cb;
    PIN_Handle g_pinHandle[32];
    PIN_State g_pinState[32];
    uint32_t pin_enable_disable_array;


    typedef enum
    {
    WATCHDOG_DISABLE_RESET, //!< disable reset - debug mode
    WATCHDOG_ENABLE_RESET //!< enable reset - regular mode
    }watchdogReset_t;

    Watchdog_Params wp;
    Watchdog_Handle g_watchdogHandler;
    void watchdogTimerCallback(void);


    struct
    {
    Event_Struct strct;
    Event_Handle handle;
    }event;

    void *mainThread(void *arg0);


    /*
    * ======== board_openPin ========
    */
    void board_openPin( PIN_Id pinId, PIN_Config config )
    {

    PIN_Config pinConfig[2];
    pinConfig[0] = PIN_ID( pinId ) | config;
    pinConfig[1] = PIN_TERMINATE;
    g_pinHandle[pinId] = PIN_open( &g_pinState[pinId], pinConfig );
    }


    /*
    * ======== board_setPin ========
    */
    void board_setPin( PIN_Id pinId )
    {
    PIN_Status ps = PIN_setOutputValue( g_pinHandle[pinId], pinId, 1 );
    }


    /*
    * ======== board_clrPin ========
    */
    void board_clrPin( PIN_Id pinId )
    {
    PIN_Status ps = PIN_setOutputValue( g_pinHandle[pinId], pinId, 0 );
    }


    /*
    * ======== watchdogDriver_initModule ========
    */
    void watchdogDriver_initModule( watchdogReset_t resetEn, watchdogCallback_t cb )
    {
    g_cb = cb;

    Watchdog_init();
    Watchdog_Params_init( &wp );
    wp.callbackFxn = (Watchdog_Callback) watchdogTimerCallback;

    wp.debugStallMode = Watchdog_DEBUG_STALL_ON;
    wp.resetMode = Watchdog_RESET_OFF;

    g_watchdogHandler = Watchdog_open(CONFIG_WATCHDOG_0, &wp);
    Watchdog_setReload(g_watchdogHandler, 1500000);
    }


    /*
    * ======== watchdogTimerCallback ========
    */
    void watchdogTimerCallback(void)
    {
    // Set port 22
    board_setPin(GPIOCC26XX_DIO_22);

    // Dummy delay
    for (uint16_t i=0; i<10; i++);

    //post Event to mainTread
    Event_post( event.handle, 0x01 );

    // Dummy delay
    for (uint16_t i=0; i<10; i++);

    Watchdog_clear( g_watchdogHandler );

    // Set port 22
    board_clrPin(GPIOCC26XX_DIO_22);
    }

    /*
    * ======== mainThread_init ========
    */
    extern void maiThread_init(void)
    {
    pthread_t thread;
    pthread_attr_t attrs;
    struct sched_param priParam;
    int retc;

    /* Initialize the attributes structure with default values */
    pthread_attr_init(&attrs);

    /* Set priority, detach state, and stack size attributes */
    priParam.sched_priority = 1;
    retc = pthread_attr_setschedparam(&attrs, &priParam);
    retc |= pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);
    retc |= pthread_attr_setstacksize(&attrs, THREADSTACKSIZE);
    if (retc != 0) {
    /* failed to set attributes */
    while (1) {}
    }

    retc = pthread_create(&thread, &attrs, mainThread, NULL);
    if (retc != 0) {
    /* pthread_create() failed */
    while (1) {}
    }

    Event_construct(&event.strct,NULL);
    event.handle = Event_handle(&event.strct);
    }

    /*
    * ======== mainThread ========
    */
    void *mainThread(void *arg0)
    {
    Watchdog_init();

    board_openPin(GPIOCC26XX_DIO_22, PIN_GPIO_OUTPUT_EN | PIN_PUSHPULL | PIN_GPIO_LOW);
    board_openPin(GPIOCC26XX_DIO_24, PIN_GPIO_OUTPUT_EN | PIN_PUSHPULL | PIN_GPIO_LOW);

    /* Open a Watchdog driver instance */
    watchdogDriver_initModule(WATCHDOG_DISABLE_RESET, watchdogTimerCallback);

    while (1)
    {
    uint32_t events = Event_pend(event.handle, Event_Id_NONE, 0xFFFFFFFF, BIOS_WAIT_FOREVER);

    board_setPin(GPIOCC26XX_DIO_24);
    board_clrPin(GPIOCC26XX_DIO_24);
    }
    }

  • Short description for above example:

    watchdogTimerCallback() is called every 1 seconds, as defined by watchdog timer.  watchdogTimerCallback() is toggling GPIO_22 and post an event for the mainThread().

    When the mainThread() receive the event is will toggle port GPIO_24 and will wait for the next event.

     

    Expected result:

    GPIO_22 will toggle every 1seconde, and immediately afterward GPIO_24 will be toggle.

     

    Actual result:

    GPIO_22 is NOT toggle.

    GPIO_24 is toggle every 1 second.

     

  • I tried to switch the content of watchdog.c with the code posted (using TI-RTOS) but I get a lot of compilation errors. In which context should I use this example/ how should I set it up to manage to compile it without errors?

  • SetPort_in_WDTcallback.zip

    Hi, 

    attached zip that include the entire project.

    Please try it and update 

  • BTW, the project is for IAR.

  • Thank you. I got it up and running (out of the box) in CCS but when I did a small change in the code it stopped working (CCS looses contact with the Launchpad indicating that the watchdog is not cleared for some reason). I will try to install IAR and see if I get it up and running there. 

  • Still have some issues with running the code (when I try to import in IAR I get an error message related to SDK 3.30 but it looks like all files points to 4.40)

    Which SDK version is used and which IAR version did you use? 

    - Does it works if you try to use the GPIO driver? (the PIN and GPIO driver should behave equal in this two cases)

    - Does it make a difference if you switch DIO22 and DIO24? 

    I have run the following with success before:

    /*
     *  ======== uartecho.c ========
     */
    #include <stdint.h>
    #include <stddef.h>
    
    /* Driver Header files */
    
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/UART.h>
    #include <ti/drivers/Watchdog.h>
    #include <xdc/runtime/System.h>
    /* Driver configuration */
    #include "ti_drivers_config.h"
    
    
    
    /*
     *  ======== watchdogCallback ========
     */
    void watchdogCallback(uintptr_t watchdogHandle)
    {
        /*
         * If the Watchdog Non-Maskable Interrupt (NMI) is called,
         * loop until the device resets. Some devices will invoke
         * this callback upon watchdog expiration while others will
         * reset. See the device specific watchdog driver documentation
         * for your device.
         */
        GPIO_write(CONFIG_GPIO_LED_1, CONFIG_GPIO_LED_ON);
        while (1) {}
    }
    
    /*
     *  ======== mainThread ========
     */
    void *mainThread(void *arg0)
    {
        char        input;
        const char  echoPrompt[] = "Start:\r\n";
        const char  watchdogPromt[] = "Watchdog event\r\n";
        UART_Handle uart;
        UART_Params uartParams;
        Watchdog_Handle watchdogHandle;
        Watchdog_Params params;
    
        /* Call driver init functions */
        GPIO_init();
        UART_init();
        Watchdog_init();
    
    
        /* Configure the LED pin */
        GPIO_setConfig(CONFIG_GPIO_LED_0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    
        /* Create a UART with data processing off. */
        UART_Params_init(&uartParams);
        uartParams.writeDataMode = UART_DATA_BINARY;
        uartParams.readDataMode = UART_DATA_BINARY;
        uartParams.readReturnMode = UART_RETURN_FULL;
        uartParams.baudRate = 115200;
    
        uart = UART_open(CONFIG_UART_0, &uartParams);
    
        if (uart == NULL) {
            /* UART_open() failed */
            while (1);
        }
    
        /* Open a Watchdog driver instance */
        Watchdog_Params_init(&params);
        params.callbackFxn = (Watchdog_Callback) watchdogCallback;
        params.debugStallMode = Watchdog_DEBUG_STALL_OFF;
        params.resetMode = Watchdog_RESET_ON;
    
        //watchdogHandle = Watchdog_open(CONFIG_WATCHDOG_0, &params);
        if (watchdogHandle == NULL) {
            /* Error opening Watchdog */
            while (1) {}
        }
    
        /* Turn on user LED to indicate successful initialization */
        GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_ON);
    
        UART_write(uart, echoPrompt, sizeof(echoPrompt));
    
        /* Loop forever echoing */
        while (1) {
            //UART_read(uart, &input, 1);
            //UART_write(uart, &input, 1);
        }
    }
    

    meaning that it's possible to set a GPIO in the callback. From https://dev.ti.com/tirex/explore/node?node=AP24VgJ7gbuZWQrdF16tIg__pTTHBmu__LATEST:

    "The Watchdog interrupt is configured as a non-maskable interrupt (NMI) and the user-defined callback function is called in the context of NMI. Because the Watchdog interrupt is non-maskable, it is not safe to call any BIOS APIs from the Watchdog callback function." 

  • Answers for your questions:

    1. IAR 8.50.1, SDK 4.40.04.04.
    2. GPIO lib was not tested because my old project use PIN, therefore I don't think this test is relevant for now. But if you insist I will do it, just let me know.
    3. If I switch DIO22 with DIO24, the problem is switch from DIO22 to DIO24.

     

    Additional important information that I found during my investigation:

    1. When I commented the "Event_pend()" in the mainThread(), DIO22 and DIO24 are working as expected.
    2. When I replace the "Event_pend(…BIOS_WAIT_FOREVER)" with "Event_pend(…BIOS_NO_WAIT)" DIO22 and DIO24 are working as expected.
    3. Therefore I suspect issue is related to TI-RTOS configuration. But I could not find it.

     

    It is very important that you will be able the simulate my problem using my example code, therefore I will add a detail instruction for importing the example:

     

    1. Import watchdog IAR TI-RTOS example  ": C:\ti\simplelink_cc13x2_26x2_sdk_4_40_04_04\examples\rtos\CC1312R1_LAUNCHXL\drivers\watchdog\tirtos\iar\watchdog_CC1312R1_LAUNCHXL_tirtos_iar.template.eww"
    2. Create a new workspace as required when loading the example.
    3. Make sure the example compile and working using the LAUCHXL-CC1312R1.
    4. Replace the following files with my modified files (files attached):
      1. main_tirtos.c
      2. watchdog.c
      3. watchdog.syscfg
    5. Replace the TI-RTOS cfg file with the attached file:
      1. Modem_CC1312R1.cfg
    6. Compile and test.
    7. Please let me know if it works for you now.

     

    Thanks

    Yigal

    TI_setPort_Example.zip

  • I'll see if I manage to get it up and running. Is this how you plan to use the watchdog in your  final project?

  • Let me give you some background on our task,

    We are currently using CC1310 + SDK tirtos_cc13xx_cc26xx_setupwin32_2_20_00_06, our goal is to upgrade our existing working project to CC1312 using SDK 4.40.04.04.

    In general our current watchdog implementation works as implemented in the example, the watdogcallback function post event to each task for requesting alive signal.

  • The Event_pend will cause the chip to go to sleep. 

    When the chip wakes up, the power driver typically disable interrupts to run the start-up sequence. The start-up also involve turning on power domains etc.

    As I have posted before: "The Watchdog interrupt is configured as a non-maskable interrupt (NMI) and the user-defined callback function is called in the context of NMI. Because the Watchdog interrupt is non-maskable, it is not safe to call any BIOS APIs from the Watchdog callback function." Since the watchdog interrupt is NMI you risk that this interrupt is fired before the power driver has managed to power on the chip. In this case the power domain for the pad segment turned on. This can be seen by the fact that it's not possible to read the GPIO register in the watchdog callback.

    What you can do is to try to change the interrupt priority to ensure that the power driver runs first and the callback has to wait. 

  • Could you please specify how exactly I can change the power Driver and watchdog NMI interrupt priorities?

  • Another question:

    In our project based on Cc1310, the watchdog interrupt is defined as standard interrupt (meaning not NMI), could youplease instruct me how to set the watchdog interrupt to be non NMI.

  • I checked the watchdog driver in CC1310 SDK ver 4.40 and this also has defined WatchdogIntTypeSet(WATCHDOG_INT_TYPE_NMI);

    You can try: WatchdogCC26XX.c line 260 ish, change WATCHDOG_INT_TYPE_NMI to WATCHDOG_INT_TYPE_INT and that will break the callback, so also change INT_NMI_FAULT on line 168 to INT_WDT_IRQ

    I haven't tested this.

    What I'm curious about is: Does the code you sent work on CC1310 or have you done other changes? 

  • I modified file : C:\ti\simplelink_cc13x2_26x2_sdk_4_40_04_04\source\ti\drivers\watchdog\WatchdogCC26XX.c with the changes as you suggested, but looks like they are not included in completion (event after clear and rebuild of the TIRTOS project).

    Do you know the reason?

    The code I send is a simple example I wrote just to demonstrate the problem, but the algorithm is the same as in CC1310 project.

  • Default a precompiled library is used for the drivers. If you want to do modifications to the driver you have to copy the .c file you want to modify into the project ensuring that the changes is taken into account. 

    I don't think the driver has changed, nor the watchdog module from CC1312 to CC1312R. Meaning that it could be useful to also look into implementation differences.   

  • After importing WatchdogCC26XX.c to my project and modifying as you specified earlier, the watchDog timer callback is not called, looks like something is break with those changes.

    Could you please help with debugging this?

  • I added  IntEnable(INT_WDT_IRQ);, and now the GPIOs are toggle as expected.

    There is another issue still related to watchDog, I will open a new question for it.

    Thanks a lot!