Task appears to get suspended, while it should be unblocked

thoru wrote on Tuesday, August 25, 2015:

Hi,

I’m using an LPC824 part from NXP (ARM cortex-M0+).
I’ve a project with a single task, that’s blocked on a task notification. It has a timeout, which loops back to the beginning:

static void vDSBCommunicationTask (void *pvParameters) {
    for(;;) {
    	uint32_t events;

    	if (xTaskNotifyWait(pdFALSE,UINT32_MAX,&events,pdMS_TO_TICKS(WWDT_DSB_FEED_TIMEOUT_MS))!=pdTRUE) {
			Board_LED_Toggle();
    		continue;
    	}
        
        //Do some real work.......
    }

Normally this toggles the LED fine.
The interrupt notifies the task at various occasions, but one of these seems to suspend the task:

static int16_t dsb_allow_command(enum dsb_commands command) { //Called in interrupt context
	switch (command) {
	case dsb_command_enumerate:
xTaskNotifyFromISR(dsbCommunicationTask,dsb_communication_event_request_address,eSetBits,NULL);
		return -1;
     //more case's.....
	}
}

After this xTaskNotifyFromISR() is called, the LED stops blinking and the task is never unblocked.
When I stop the debugger, the vApplicationIdleHook() function is running fine, so the scheduler seems to be running.
If I request a context switch from within the dsb_allow_command() function, the task does get unblocked, but I don’t understand why it doesn’t work without that context switch request. I would expect that at the next systick event, the scheduler would notice that the task can be unblocked.

Why does the task stop working?

Thanks in advance.

Kind regards,

Remco Poelstra

rtel wrote on Tuesday, August 25, 2015:

On the Cortex-M port a tick interrupt will not force a context switch unless:

  1. The tick interrupt causes a higher priority task to leave the blocked state (time out), or
  2. configUSE_TIME_SLICING is not 0 and there is another task of the same priority as the currently executing task.

This is a good point - and needs documenting better. Older ports would context switch on each tick, but the behaviour was changed as an optimisation.

Regards.

thoru wrote on Wednesday, August 26, 2015:

Hi,

Thanks for your response.
I don’t think I fully understand your answer, as I seem unable to explain why the xTaskNotifyWait() will (regularly) timeout before the (I2C) interrupt has occured, and will no longer timeout after the (I2C) interrupt has occured.
The task has a priority of tskIDLE_PRIORITY + 1UL, so your point 1) tells me that after the (I2C) interrupt has occured (and the notification is posted) the tick interrupt should notice that the task (with a higher priority than the idle task) has become unblocked. At least it should keep noticing that it times out every now and then, just as it did before the (I2C) interrupt occurs.

Regards,

Remco Poelstra

rtel wrote on Wednesday, August 26, 2015:

Point (1) says a context switch will occur if the tick interrupt causes a task to unblock. In your case it was not the tick interrupt that caused a task to unblock.

If I request a context switch from within the dsb_allow_command() function, the task does get unblocked

So why not do that? You are setting the xHigherPriorityTaskWoken parameter to NULL - but it is intended that parameter is used to determine if a context switch is required or not.

Regards.

thoru wrote on Wednesday, August 26, 2015:

Ah, now I see the difference.

Yes, I will use that solution. I was wondering whether it was the right solution or just masked the real problem.

Thanks for your help.

Regards,

Remco Poelstra