Problem with Queue Set and xQueueOverwriteFromISR() on Cortex-M4

Hi! MCU: STM32F411VET6 100 MHz FreeRTOS 9.0.0 (same thing happens in 10.0.0) I have a problem using xQueueOverwriteFromISR() with a queue set. xQueueSelectFromSet() tells that an item is available, but when trying to read out the item, xQueueReceive() returns pdFALSE. If I instead use xQueueSendToBackFromISR(), everything (seems to) work normally. But this is not quite the functionality I want. Here is a longer description of the problem area in my system: I have a “timestamp” queue (length = 1) which I write to every ~20 ms using xQueueOverwriteFromISR() from an interrupt handler. I have a “command” queue (length = 10) which I occationally write commands to using xQueueSendToBack() from a “command” task (task priority 1). I have a “receiver” task (task priority 4) that waits on both of these queues using a queue set, and reads out data from the corresponding queue. After a while of successful operation, the queue set indicates that an item in the “timestamp” queue is available, but when calling xQueueReceive(), it returns failure. I have tried to isolate the problem in a simple standalone test application (below), but not fully succeeded. In the below test application, I also get wrong behaviour (I think), after about 6 seconds, but at a different location than in my real system. (See comment in code where it fails.) Because of the task priorities, and the wait time specified in xQueueSendToBack(), the “command” queue should not get full, but it does! And also in the test application, if I replace xQueueOverwriteFromISR() with xQueueSendToBackFromISR(), everything works normally. Anyone else have problems with Queue Sets and xQueueOverwriteFromISR() ? And yes, the system should be properly set-up with HALInit() that calls HALNVICSetPriorityGrouping(NVICPRIORITYGROUP_4). ~~~

include “ClockTick.h”

include “HWTimer.h”

include “SystemCore.h”

include “FreeRTOS.h”

include “task.h”

include “timers.h”

include “semphr.h”

QueueHandlet commandqueue; QueueHandlet timestampqueue; QueueSetHandlet queueset; TaskHandlet commandtaskhandle; TaskHandlet receivertaskhandle; void hwtimercallback(unsigned ch, void * user) // IRQ priority 6 { BaseTypet higherpritaskwoken = pdFALSE; int value = 0; // If I instead use xQueueSendToBackFromISR() here, everything works normally (void) xQueueOverwriteFromISR(timestampqueue, &value, &higherpritaskwoken); portYIELDFROMISR(higherpritask_woken); } void commandtask(void * param) // task priority 1 { BaseTypet ret; int value = 0; for (;;) { vTaskDelay(20);
  ret = xQueueSendToBack(command_queue, &value, 5);

  // **** This assert fails after a while in this test application *****
  configASSERT(ret == pdTRUE);
} } void receivertask(void * param) // task priority 4 { BaseTypet ret; int value; // Start recurring HW-timer (330 us timeout) StartRecurringHWTimer(0, ClockTicksFromus(330), hwtimer_callback, NULL); for (;;) { // Wait for command or timestamp QueueSetMemberHandlet handle = xQueueSelectFromSet(queueset, 200);
  if (handle == (QueueSetMemberHandle_t) timestamp_queue)
  {
     ret = xQueueReceive(timestamp_queue, &value, 0);

     // **** This assert fails after a while in my real system *****
     configASSERT(ret == pdTRUE);
  }
  else if (handle == (QueueSetMemberHandle_t) command_queue)
  {
     ret = xQueueReceive(command_queue, &value, 0);
     configASSERT(ret == pdTRUE);
  }
  else
  {
     configASSERT(handle == NULL);
  }
} } int main(void) { // Init system: HAL, clocks, etc. ErrorHandlerInit(); SystemCoreInit(); ClockTickInit(); HWTimerInit(); // Create queues commandqueue = xQueueCreate(10, sizeof(int)); timestampqueue = xQueueCreate(1, sizeof(int)); // Create queue sets queueset = xQueueCreateSet(10 + 1); xQueueAddToSet((QueueSetMemberHandlet)commandqueue, queueset); xQueueAddToSet((QueueSetMemberHandlet)timestampqueue, queue_set); // Create command and receiver tasks xTaskCreate(commandtask, “CMD”, 3 * configMINIMALSTACKSIZE, NULL, 1, &commandtaskhandle); xTaskCreate(receivertask, “RCV”, 3 * configMINIMALSTACKSIZE, NULL, 4, &receivertaskhandle); vTaskStartScheduler(); return 0; } /*

define configUSE_PREEMPTION 1

define configUSEPORTOPTIMISEDTASKSELECTION 1

define configUSETICKLESSIDLE 0

define configCPUCLOCKHZ ( SystemCoreClock )

define configTICKRATEHZ ( ( TickTypet ) 1000 ) /* Note! 1000 Hz is MAX, as HAL tick & FreeRTOS shares SysTickHandler() */

define configUSE16BIT_TICKS 0

define configMAX_PRIORITIES 5

define configUSETIMESLICING 1

define configIDLESHOULDYIELD 1

define configMINIMALSTACKSIZE ( ( unsigned short ) 130 )

define configMAXTASKNAME_LEN 10

define configUSETASKNOTIFICATIONS 0

define configUSE_MUTEXES 1

define configUSERECURSIVEMUTEXES 1

define configUSECOUNTINGSEMAPHORES 0

define configUSEQUEUESETS 1

define configUSEALTERNATIVEAPI 0

define configQUEUEREGISTRYSIZE 8

define configUSENEWLIBREENTRANT 1 /* Integrating with Newlib & Newlib-Nano */

define configENABLEBACKWARDCOMPATIBILITY 0

define configNUMTHREADLOCALSTORAGEPOINTERS 0

define configUSEAPPLICATIONTASK_TAG 0

define configLIBRARYMAXSYSCALLINTERRUPTPRIORITY 5

*/ ~~~

Problem with Queue Set and xQueueOverwriteFromISR() on Cortex-M4

If a queue is in a queue set, and data is written into that queue, then the address of the queue is written into the queue set. When you read from the queue set you obtain that address and then read from the queue. There is therefore an assumption of a one to one relationship between the number of items in the individual queues and the number of items in the queue set. If you were to use a queue overwrite to add something to a queue all should be good, if however you then used a queue overwrite to overwrite the item already in the queue then the queue set is going to expect to items to be in the queue, whereas in fact there would be only one – a second read of the queue would then fail (as there would have only been one item in it). Do you think this is the scenario you are observing?

Problem with Queue Set and xQueueOverwriteFromISR() on Cortex-M4

If a queue is in a queue set, and data is written into that queue, then the address of the queue is written into the queue set. When you read from the queue set you obtain that address and then read from the queue.
Yes, OK.
There is therefore an assumption of a one to one relationship between the number of items in the individual queues and the number of items in the queue set.
So that is why I should sum the lengths of all queues and pass that value to xQueueCreateSet() ?
If you were to use a queue overwrite to add something to a queue all should be good,
Because that would be the same as a successful xQueueSendToBack()… ?
if however you then used a queue overwrite to overwrite the item already in the queue then the queue set is going to expect to items to be in the queue, whereas in fact there would be only one – a second read of the queue would then fail (as there would have only been one item in it).
So in my case, where I have setup the queue set with xQueueCreateSet(10 + 1), there will in this senario be two addresses stored in the queue set, pointing to the queue which have a length of only 1 ? Isn’t this a bug in FreeRTOS ? Based on this, I have now managed to reproduce it with the simple test application, and I think what you are describing is exactly what is happening. Some of the commands take time to execute by the “receiver” task, therefore the “timestamp” queue will be overwritten several times until the “receiver” task has time to check the queue set. I tried to replace the timestamp queue with a binary semaphore. The problem then dissapeared, however, with a binary semaphore, I must then pass the actual data (a timestamp value) through a separate volatile variable, and that is not as clean design as using a queue…

Problem with Queue Set and xQueueOverwriteFromISR() on Cortex-M4

I’ve just added an assert to catch that scenario.

Problem with Queue Set and xQueueOverwriteFromISR() on Cortex-M4

So this scenario is not supposed to work?