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.

CCS/CC1352P: Sensor Controller task block hangs BLE/OTA application when triggered by M4 POSIX thread

Part Number: CC1352P
Other Parts Discussed in Thread: BLE-STACK

Tool/software: Code Composer Studio

SDK: simplelink_cc13x2_26x2_sdk_4_10_00_78

IDE: CCS

SCS: 2.6.0.132

HW: CC1352P

RTOS: TI-RTOS w/ POSIX

Starting Point to Application: simple_peripheral_oad_offchip


 

Issue Overview


Our device consists of a simple sensor application that performs periodic sensor measurements that immediately get sent out via BLE to a gateway. Due to our device requirements, the sensor controller MCU is being used to reduce power usage. We currently are seeing strange behaviors that aren't specifically referenced in TI's SC documentation, so we would like to get word from the e2e community to see if anyone else has any information or experience on the matter.

 

Without posting a bunch of unrelated code, here is a stripped down version of the problem..


Example #1

// 'scPressureThread' -- SC thread
void* scPressureThread(void *arg0)
{
    // Initialize the Sensor Controller...
    scifOsalInit();
    scifOsalRegisterCtrlReadyCallback(scCtrlReadyCallback);
    scifOsalRegisterTaskAlertCallback(scTaskAlertCallback);
    scifInit(&scifDriverSetup);

    int status = sem_init(&SensorControllerSem, 0, 0);

    for (;;)
    {
        sem_wait(&SensorControllerSem);

        gpio_write(VSEN, 0); // Turn on voltage rail powering the sensors

        /*
         * Run the "PressureAndAccelerometer" Execution Code only via TI's recommendation
         */
        if (scifWaitOnNbl(20000) != SCIF_SUCCESS)
        {
            //... Handle timeout or usage error ...
        }
        else if (scifSwTriggerExecutionCodeNbl(
                1 << SCIF_PRESSURE_AND_ACCELEROMETER_TASK_ID) != SCIF_SUCCESS)
        {
            //... Handle usage error ...
        }

        usleep(100000); // liberal 100ms delay to ensure SC task block finishes execution 

        gpio_write(VSEN, 0); // Turn off voltage rail powering the sensors
    }
}


Observations/Notes on Code Block #1


In the main application, a posix thread is initialized with the SC drivers as shown above. The actual contents of the SC task block are unimportant in this observation. The only thing that I'd like to mention is that
the GPIO pin that is being used to toggle the voltage rail is not being shared between the SC and main application CPU.

When the thread's semaphore gets posted, the power rail to the sensor gets enabled and the SC execution code gets triggered to run. Where things get dodgey is the following usleep() operation under the POSIX
API. The goal was to use POSIX's usleep function to put the main application to sleep for a liberal amount of time (more than enough time for the SC execution code to complete) before waking up and disabling the
power rail since TI's documentation states that the scifSwTriggerExecutionCodeNbl() returns immediately. In reality, this configuration crashes the application. The BLE stops advertising and the sensor controller
thread seems to only partially execute a single time before never executing again.


Example #2

/* Callback for Pressure and Tilt timer */
void pressure_tilt_cb(Timer_Handle handle, int_fast16_t status) {
    gpio_write(VSEN, 0);
}

// 'scPressureThread' -- SC thread
void* scPressureThread(void *arg0)
{

    // Initialize the Sensor Controller...
    scifOsalInit();
    scifOsalRegisterCtrlReadyCallback(scCtrlReadyCallback);
    scifOsalRegisterTaskAlertCallback(scTaskAlertCallback);
    scifInit(&scifDriverSetup);

    /* Timer setup */
    Timer_init();
    Timer_Handle    pt_tim_handle;
    Timer_Params    params;
    Timer_Params_init(&params);
    params.periodUnits = Timer_PERIOD_US;
    params.period = 100000;
    params.timerMode  = Timer_ONESHOT_CALLBACK;
    params.timerCallback = pressure_tilt_cb;
    pt_tim_handle = Timer_open(CONFIG_TIMER_PRESSURE_TILT, &params);

    int status = sem_init(&SensorControllerSem, 0, 0);

    for (;;)
    {
        sem_wait(&SensorControllerSem);

        gpio_write(VSEN, 1);

        /*
         * Run the "PressureAndAccelerometer" Execution Code via TI's recommendation
         * If either checks result in an unsuccessful call, the thread does not run and the issue is tracked
         */
Timer_start(pt_tim_handle);
if (scifWaitOnNbl(20000) != SCIF_SUCCESS) { //... Handle timeout or usage error ... } else if (scifSwTriggerExecutionCodeNbl( 1 << SCIF_PRESSURE_AND_ACCELEROMETER_TASK_ID) != SCIF_SUCCESS) { //... Handle usage error ... } } }

Observations/Notes on Code Block #2


For this implementation, the usleep(10000) was replaced by a similar approach to controlling the VSEN rail via a timer callback. In this implementation, the SC execution
block executes properly, the BLE advertising remains, and the application does not appear to hang.


Questions for the TI e2e Community

  1. Why does implementation #2 work while #1 does not?

  2. What is the mechanism at play when the Sensor controller execution finishes?

  3. If the nbl() function does in fact return immediately, why would the usleep() delay method crash the system?

  4. Has anyone ran into POSIX/SC limitations before?

 

 

 

  • Hi Josh,

    Have you enabled POSIX support in the TI-RTOS .cfg file? If unsure, could you post the .cfg file here for me to look at? 

    As for the sensor controller execution, this has nothing to do with usleep, task sleeps or any such equivalents. I suspect your issue is on the ARM side and not really on the Sensor Controller side. That said, I would recommend using the "scifExecuteTasksOnceNbl(uint32_t bvTaskIds)" API to execute the task as it runs all code blocks (init, execution, termination) and not only the execution block, it is basically an API that makes sure to make a full complete execution of the task.

  • Hi Josh,

    1) The BLE examples are written with a main application thead where events (both from the BLE stack and from the application) are handled. When you use usleep() in your application you are preventing these events fro being processed. This goes against the philosophy of the BLE-Stack application. 

    I would actually recommend that you replace the semaphore with an event processed in the same application main thread.

    2) The sensor controller is a separate processor. It can execute in parallel with the M4.

    3) See 1).

    4) I haven't heard about it.

  • M-W,

    Yes, POSIX is enabled in the .cfg file.

    I will try, however, the scifExecuteTasksOnceNbl() approach. In the Sensor Controller code, there is nothing in the initialization or the termination blocks, but it might be worth a try.

    Thanks for the suggestion and I will let you know if it works out.

    -Josh

  • Marie H,

    I did not post it in the original post, but the scPressureThread() is a separate thread from the main application BLE thread. Both threads are initialized in main before BIOS_start() is executed. Under this scenario, I don't see how putting the scPressureThread() to sleep would effect the main application BLE thread. In fact, there are many other threads in our project that have the same make-up (POSIX semaphores, usleep/sleep, etc.) that don't result in a hang or unexpected BLE functionality. This is solely a result of  scPressureThread()..

    I feel if I were to replace the semaphore with an event that gets serviced by the BLE main application thread, then and only then would a usleep() prevent the BLE thread from servicing events.

    Am I confused on this?

    Thanks for the quick response btw,

    -Josh

  • Hi Josh,

    If you would look at the POSIX sleep, it should be a Task_sleep() wrap and there is really no reason for this crash your application:

    /*
     *  ======== usleep ========
     */
    int usleep(useconds_t usec)
    {
        UInt32 timeout;
    
        /* usec must be less than 1000000 */
        if (usec >= 1000000) {
            errno = EINVAL;
            return (-1);
        }
    
        /*  Implementations may place limitations on the granularity of timer
         *  values. For each interval timer, if the requested timer value requires
         *  a finer granularity than the implementation supports, the actual timer
         *  value shall be rounded up to the next supported value.
         */
        /* Clock_tickPeriod is the Clock period in microseconds */
        timeout = (UInt32)((usec + Clock_tickPeriod - 1) / Clock_tickPeriod);
    
        /* must add one tick to ensure a full duration of timeout ticks */
        Task_sleep(timeout + 1);
    
        return (0);
    }

    Could you provide a "Runtime Object Viewer" dump of the "Task" and "Hwi" modules (check these modules for errors)? Or the entire project in private so that I could run it myself.