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.

CC1352R: TI15.4 Stack - new task priority problem

Part Number: CC1352R

Hey all,

I'm developing an application using TI15.4 stack with CC1352R, based of collector example (SDK6.20).

I've added a new task for a demanding real time application, which maybe occupies around 50-60% of the collector processing time and is very time sensitive. It's a proprietary, constantly repetitive wired communications protocol, which this new task is controlling. 

The problem I'm having is regarding this new task's timing, most of the times it works fine, but sometimes the processing comes too late for my application. I've tried different priority levels, I've tried with the same level as the app task, and higher level than the app and mac task, but the delay still happens sometimes. I've disabled all time consuming functionalities like CUI, UART, SPI, DISPLAY, etc from the demo. I suspect the issue might related to a Hwi or Swi happening on the radio/mac side. I understand the radio/wireless protocol is very time sensitive, but so is this wired communication. So I have to find a good way to allow both task when needed, without causing delays on each other.

Any help finding and/or solving the issue? This new task I've created can't have any delays, anything higher than 50us is already problematic.

Thanks.

  • Hi,

    Do you have a baseline that this wired communication task works ok all the time in standalone? That is, when everything else is removed, including the TI 15.4 Stack.

    I have notified the Sub1-GHz team for further insights and comments.

    Thanks,
    Toby

  • Hi Toby,

    Thanks for the quick reply.

    Yes, If I never start the main app and mac, this new task runs flawlessly. 

    Thanks

    JD

  • Hi JD, 

    The HWIs are of the highest priority and stack timing is critical to maintain stack level deadlines. 

    A couple of scenarios I can think about when the timing of the stack is critical and are probably performed at the highest priority are CSMA/LBT and transmission of beacons/ broadcast messages. 

    How are you measuring the delays in your application? The duration between the point from which you schedule a command or trigger an event till the action you expect to happen. What exactly are you expecting to happen at hard deadlines? 

    Regards,

    Sid

  • Hi Sid,

    So at the moment I have the following setup.

    1 - One Launchpad serving as a wave form generator to emulate my wired protocol, I did this so you could test it on your side. The code for this launchpad is the less relevant part of this thread but still important if you want to replicate it. It is based of the timerled demo from the SDK. This is the code:

    #include <stddef.h>
    #include <ti/drivers/GPIO.h>
    #include <ti/drivers/Timer.h>
    #include "ti_drivers_config.h"
    
    static Timer_Handle timer0;
    static Timer_Params params;
    
    static Timer_Handle timer1;
    static Timer_Params params1;
    
    void timerCallback(Timer_Handle myHandle, int_fast16_t status);
    void timerCallback1(Timer_Handle myHandle, int_fast16_t status);
    
    void *mainThread(void *arg0)
    {
        GPIO_init();
        Timer_init();
    
        GPIO_setConfig(CONFIG_GPIO_LED_0, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
        GPIO_setConfig(CONFIG_GPIO_LED_1, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    
        GPIO_write(CONFIG_GPIO_LED_0, CONFIG_GPIO_LED_OFF);
    
        Timer_Params_init(&params); //off time
        params.period        = 938;
        params.periodUnits   = Timer_PERIOD_US;
        params.timerMode     = Timer_ONESHOT_CALLBACK;
        params.timerCallback = timerCallback;
    
        Timer_Params_init(&params1);// on time
        params1.period        = 265;
        params1.periodUnits   = Timer_PERIOD_US;
        params1.timerMode     = Timer_ONESHOT_CALLBACK;
        params1.timerCallback = timerCallback1;
    
        timer0 = Timer_open(CONFIG_TIMER_0, &params);
        timer1 = Timer_open(CONFIG_TIMER_1, &params1);
    
       if (timer0 == NULL || timer1 == NULL)
        {
            GPIO_write(CONFIG_GPIO_LED_1, 1);
            while (1) {}
        }
    
        if (Timer_start(timer0) == Timer_STATUS_ERROR)
        {
            while (1) {}
        }
    
        while(1) {}
    
        return (NULL);
    }
    
    void timerCallback(Timer_Handle myHandle, int_fast16_t status)
    {
        GPIO_toggle(CONFIG_GPIO_LED_0);
        Timer_stop(timer0);
        Timer_start(timer1);
    }
    
    void timerCallback1(Timer_Handle myHandle, int_fast16_t status)
    {
        GPIO_toggle(CONFIG_GPIO_LED_0);
        Timer_stop(timer1);
        Timer_start(timer0);
    }

    This signal emulates sort of a clock wave with around 22% duty cycle, which then opens a window of opportunity for the other device to send data, in this case the collector. Although I'm not sending any data in this demo, cause I'm having the timing issues even before that could happen.

    2 - One launchpad running the collector demo from the SDK, in FH mode, broadcasts and tracking disabled, to which I added a new task in main, same task params as the app task, except for priority which I chose 5, to exclude for delays created by the app and mac tasks. The new task function in main.c follows the same architecture as the collector app task:

    Void newTaskFxn(UArg a0, UArg a1)
    {
        newtask_init();
        while (1)
        {
            newtask_process();
        }
    }
     

    Then I created a newtask.c file and respective header. In the c file this is what I have:

    #include <ti/sysbios/knl/Semaphore.h>
    #include <ti/sysbios/BIOS.h>
    #include <stdint.h>
    #include <stddef.h>
    #include <stdio.h>
    #include <ti/drivers/GPIO.h>
    #include "ti_drivers_config.h"
    
    Semaphore_Struct sleeperSem;
    Semaphore_Handle sleeperSemHandle;
    uint32_t timestamp,currentTime, elapsedTime;
    
    void dataCallback(uint_least8_t index)
    {
        GPIO_toggle(CONFIG_GPIO_3);
        timestamp = Clock_getTicks();
        Semaphore_post(sleeperSemHandle);
        GPIO_toggle(CONFIG_GPIO_3);
    }
    
    void newtask_init(void)
    {
        GPIO_init();
        GPIO_setConfig(CONFIG_GPIO_3, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
        GPIO_setConfig(CONFIG_GPIO_4, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
        GPIO_setConfig(CONFIG_GPIO_16, GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    
        GPIO_setConfig(CONFIG_GPIO_DATA_IN, GPIO_CFG_IN_PD | GPIO_CFG_IN_INT_RISING );
        GPIO_setCallback(CONFIG_GPIO_DATA_IN, dataCallback);
        GPIO_enableInt(CONFIG_GPIO_DATA_IN);
    
        Semaphore_Params semParam;
        Semaphore_Params_init(&semParam);
        semParam.mode = Semaphore_Mode_BINARY;
        Semaphore_construct(&sleeperSem, 0, &semParam);
        sleeperSemHandle = Semaphore_handle(&sleeperSem);
    }
    
    void newtask_process(void)
    {
        Semaphore_pend(sleeperSemHandle, BIOS_WAIT_FOREVER);
        GPIO_toggle(CONFIG_GPIO_4);
        GPIO_toggle(CONFIG_GPIO_4);
        currentTime = Clock_getTicks();
        elapsedTime = (currentTime >= timestamp) ? (currentTime - timestamp) : (UINT32_MAX - timestamp + currentTime + 1);
        if ((elapsedTime) >= 100 / Clock_tickPeriod)
        {
            GPIO_toggle(CONFIG_GPIO_16);
            GPIO_toggle(CONFIG_GPIO_16);
        }
    }

    New task process pends on a semaphore, which is posted via a GPIO callback created by a rising edge interrupt on GPIO_DATA_IN which is physically connected via a wire to the LED_0 of the signal generator launchpad. 

    For debug purposes I added GPIO3 which I toggle 2 times at beginning and ending of the GPIO data callback function, also GPIO4 which is toggled 2 times after the semaphore pend in newtask_process, and GPIO16 which is toggled 2 times also after the semaphore pend but only if more than 100us have passed since the callback activated, this is done by manually collecting timestamps via clock_getTicks() at the start of the callback, and after the semaphore pend, and calculating the elapsed time. So this is how I easily identify delays that have occurred.  

    Still for debug signals, and based of what you mentioned, I also added these to appTaskFxn in main.c in order to correlate delays with TX and RX:

    IOCPortConfigureSet(CONFIG_GPIO_24, IOC_PORT_RFC_GPO3, IOC_IOMODE_NORMAL); //TX
    IOCPortConfigureSet(CONFIG_GPIO_22, IOC_PORT_RFC_GPO0, IOC_IOMODE_NORMAL); //LNA

    3 - I have 3 other launchpads running the sensor demos also in FH mode. But even without sensors, you can still see delays happening, although the sensors aggravate the situation.

    4 - I have a logic analyzer checking all this signals.

    If I zoom in on one pulse of the red signal, the GPIO16 which indicates delays, I can see that it almost always related to a transition of the LNA signal:

    The last screenshot, also shows some slight delays in between the yellow toggles (callback duration), but these are relatively small, therefore not a big issue. But the delay between the callback and the code running after the pend, is too much for our requirements. I've also tried adding code I want to run inside the callback instead of after the pend, to give more urgency to the processing on my side, but the callback also waits for whatever is happening in/before the LNA transitions.

    I'm not entirely sure what's causing the delay but it is certainly related with radio. But my most important question is how do I avoid this if possible? Because this kind of delays will make the collector respond to the DATA IN signal too late for the wire protocol, and the communication will fail. But I also understand that the radio cannot wait on anything else, otherwise the radio will fail. 

    Any possibilities here? 

    I've tried using the sensor controller to deal with this wired protocol, but unfortunately I ran out of memory... I'm trying as much as possible to avoid adding another CPU to the mix.

    Thanks 

    JD

  • Hi JD, 

    Thanks for the detailed response and logic analyzer trace. Since you mention the LNA signal transition causing the most delay, please can you check if you reduce the frequency hopping scope to just one channel, you get this same delays or not.

    Regards,

    Sid

  • Hey Sid,

    Ok, I changed the number of channels to only 1.

    I left it running for over 50s with 2 sensors communicating. Then I turned off the sensors for another 50s and the LNA transitions disappear.

    Latencies when LNA  transitions (485us):

    Latencies when there are no LNA transitions (122us): 

    Regarding the latency issues, they clearly reduce when the sensors disappear, but they still exist, although much smaller in duration. But I must consider the existence of sensor nodes in the network, so the higher latencies still exist.

    Thanks,

    JD

  • Hi JD,

    It seems like the probable cause of transitions are the message exchanges between the sensor and the collector.

    And it looks like frequency synth command is executed anyway even in the single channel setting. In a frequency hopping mode, since these transitions are unavoidable due to the requirement of hopping, it seems like this latency will exist unfortunately. 

    Have you considered the other modes for this application if it is acceptable? 

    Regards,
    Sid