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.

Task starvation

Other Parts Discussed in Thread: CC2650, SYSBIOS

Hi

I added a second task to the SimpleBLECentral example project. I use the smartRF06EB with a CC2650 BLE IC. My problem is that the additional task stops running as soon as the main task gets scheduled. Here the code for the additional task:

#define MAIN_CENTRAL_TASK_PRIORITY            3
#define AUXILIARY_TASK_PRIORITY               1

int main()
{
  PIN_init(BoardGpioInitTable);

#ifndef POWER_SAVING
    /* Set constraints for Standby, powerdown and idle mode */
    Power_setConstraint(Power_SB_DISALLOW);
    Power_setConstraint(Power_IDLE_PD_DISALLOW);
#endif //POWER_SAVING

    /* Initialize ICall module */
    ICall_init();
 
    /* Start tasks of external images - Priority 5 */
    ICall_createRemoteTasks();
    
    /* Kick off profile - Priority 3 */
    GAPCentralRole_createTask();
    
    /* Kick off application - Priority 1 */
    SimpleBLECentral_createMainCentralTask();
    SimpleBLECentral_createAuxiliaryTask();
    
    /* enable interrupts and start SYS/BIOS */
    BIOS_start();
    
    return 0;
}

void SimpleBLECentral_createAuxiliaryTask(void)
{
  Task_Params taskParams;

  // Configure task
  Task_Params_init(&taskParams);
  taskParams.stack = auxiliaryTaskStack;
  taskParams.stackSize = AUXILIARY_TASK_STACK_SIZE;
  taskParams.priority = AUXILIARY_TASK_PRIORITY;

  PIN_setOutputValue(ledPinHandle, Board_LED2, 1);
  PIN_setOutputValue(ledPinHandle, Board_LED2, 0);

  Task_construct(&auxiliaryTask, SimpleBLECentral_auxiliaryTaskFxn, &taskParams, NULL);

  PIN_setOutputValue(ledPinHandle, Board_LED2, 1);
  PIN_setOutputValue(ledPinHandle, Board_LED2, 0);
}

static void SimpleBLECentral_auxiliaryTaskFxn(UArg a0, UArg a1)
{
  PIN_setOutputValue(ledPinHandle, Board_LED1, 1);
  PIN_setOutputValue(ledPinHandle, Board_LED1, 0);

  for (;;)
  {
      PIN_setOutputValue(ledPinHandle, Board_LED1, 1);
      PIN_setOutputValue(ledPinHandle, Board_LED1, 0);
  }
}

As you see, the auxiliary task has lower priority compared to the main task. So the main task is allowed to stop the auxiliary task. But as soon as the main task has no more work to do, the auxiliary task should continue running. The auxiliary task does not use a semaphore and it does not register with ICall. Is this an issue?

Here some code of the main task:

static void SimpleBLECentral_mainCentralTaskFxn(UArg a0, UArg a1)
{
  // ******************************************************************
  // N0 STACK API CALLS CAN OCCUR BEFORE THIS CALL TO ICall_registerApp
  // ******************************************************************
  // Register the current thread as an ICall dispatcher application
  // so that the application can send and receive messages.
  ICall_registerApp(&selfEntityMainCentral, &semMainCentralTask);

  // Hard code the DB Address till CC2650 board gets its own IEEE address
  //uint8 bdAddress[B_ADDR_LEN] = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 };
  //HCI_EXT_SetBDADDRCmd(bdAddress);

  // Set device's Sleep Clock Accuracy
  //HCI_EXT_SetSCACmd(40);

  // Create an RTOS queue for message from profile to be sent to app.
  appMsgQueueMainCentral = Util_constructQueue(&appMsgMainCentral);

  // Initialize application
  SimpleBLECentral_init();
 
  // Application main loop
  for (;;)
  {
    // Waits for a signal to the semaphore associated with the calling thread.
    // Note that the semaphore associated with a thread is signaled when a
    // message is queued to the message receive queue of the thread or when
    // ICall_signal() function is called onto the semaphore.

    PIN_setOutputValue(ledPinHandle, Board_LED3, 1);

    ICall_Errno errno = ICall_wait(ICALL_TIMEOUT_FOREVER);

    PIN_setOutputValue(ledPinHandle, Board_LED3, 0);

    if (errno == ICALL_ERRNO_SUCCESS)
    {
      ICall_EntityID dest;
      ICall_ServiceEnum src;
      ICall_HciExtEvt *pMsg = NULL;
      
      if (ICall_fetchServiceMsg(&src, &dest, (void**)&pMsg) == ICALL_ERRNO_SUCCESS)
      {
        if ((src == ICALL_SERVICE_CLASS_BLE) && (dest == selfEntityMainCentral))
        {
          // Process inter-task message
          SimpleBLECentral_processStackMsg((ICall_Hdr *)pMsg);
        }

        if (pMsg)
        {
          ICall_freeMsg(pMsg);
        }
      }
    }

    // If RTOS queue is not empty, process app message
    while (!Queue_empty(appMsgQueueMainCentral))
    {

      ...

I connected a logic analyzer to the evaluation board to display the LED status. I see that both tasks get created correctly. The auxiliary task enters the infinite loop (LED1 going high and low many times). But if LED3 goes low (the main task passes ICall_Errno errno = ICall_wait(ICALL_TIMEOUT_FOREVER); ), then the auxiliary tasks gets never scheduled again, even if LED3 goes high again (which is the case if the main task is waiting for work again). What am I doing wrong? I think a stack size of 512 bytes is enough. Here the logic analyzer output:

D0 is connected to LED1, D1 to LED2, D2 to LED3 and D3 to led4.

Predefined symbols:

ICALL_MAX_NUM_TASKS=4

ICALL_MAX_NUM_ENTITIES=7

Both numbers are increased by one as described here: .

Is increasing these nubers really necessary, because my task is a pure RTOS task and has (as far as I know) nothing to do with ICall, right?

Remark: If i switch the task priorities, then the auxiliary task causes starvation of the main task: LED1 is going high and low in an infinite loop that is never left.

  • Your auxiliary task will only get call if the main task blocks. I'm not familiar with what ICall is doing?
    I know its not part of the SYSBIOS so my best guess as to what is happening is that the ICall_wait() is not a SYSBIOS blocking call.
    So the main tasks is still running even though its not doing any work. My best guess is ICall_wait() is more like a spin?

    Judah
  • Here is the description of ICall_wait taken from ICall.h

    /**
    * Waits for a signal to the semaphore associated with the calling thread.
    *
    * Note that the semaphore associated with a thread is signaled
    * when a message is queued to the message receive queue of the thread
    * or when ICall_signal() function is called onto the semaphore.
    *
    * @param milliseconds timeout period in milliseconds.
    * @return @ref ICALL_ERRNO_SUCCESS when the semaphore is signaled.<br>
    * @ref ICALL_ERRNO_TIMEOUT when designated timeout period
    * has passed since the call of the function without
    * the semaphore being signaled.
    */
    static ICall_Errno ICall_wait(uint_fast32_t milliseconds)
    {
    ICall_WaitArgs args;
    args.hdr.service = ICALL_SERVICE_CLASS_PRIMITIVE;
    args.hdr.func = ICALL_PRIMITIVE_FUNC_WAIT;
    args.milliseconds = milliseconds;
    return ICall_dispatcher(&args.hdr);
    }

    As the description says that the function waits for a signal to the semaphore I strongly assume that it is not a busy wait.
  • Are you using CCS with emulation to debug this?

    For TIRTOS/SYSBIOS projects, you can open up the ROV plugin. It can show you what the state of each Tasks in the system.

    Its not clear to me whether the ICall API is based on SYSBIOS semaphore object or not. If it is, seems like your Task should get executed assuming its ready. The question really is where's the program execution?

    Judah
  • I am not (yet) using the ROV plugin. The ICALL API uses semaphores different from the normal SYSBIOS semaphores:

    ICall_Semaphore

    Semaphore_Struct (regular SYSBIOS semaphore)

    Is it ok to use task that do not register with ICall and tasks that do concurrently in a project?

  • From that description, it looks to me like ICall_Semaphore is built upon a SYSBIOS Semaphore.
    So, I would expect the Task that ICall_wait() to be block on a Semaphore and the execution to go to another thread.

    If you can get ROV plugin working...I highly recommend that you use it. It details the state of the SYSBIOS objects.
    Like which Tasks is currently the running Task and which is Blocked.
  • Found the error:
    In the SimpleBLECentral example project, the function PIN_init(BoardGpioInitTable); is called in main before any tasks get created. So I assumed the PIN driver is ready to use after the initialization. Bu the function PIN_open get called in the main task function. After that call, the auxiliary thread was no more able to modify the GPIO values. When I wrote, that I have a problem with task starvation I was actually wrong. I did juist not use the PIN driver correctly. Moving the function call of PIN_open to main befor I create additional tasks solved the problem.
  • Good to hear. I will be closing this thread.