At wits end - going to unhandled-IRQ handler from vTaskSwitchContext for no apparent reason

Thanks much. I’m new to ARM interrupt handling. Quite a bit of a step up from AVR’s.
Just out of curiousity, the FreeRTOSConfig.h has
configMAX_PRIORITIES = 5
but the M0 only uses 3 interrupt priority levels (2 bits). Is this FreeRTOS priority the same as the processor priority? Should I set this to 3?

Found it! It was an indexing problem in a loop. Thanks much, all.

Don’t get confused by FreeRTOS task priorities and hardware interrupt priorities. These are different things.
Great that you found the issue :+1:

Well, that wasn’t it. There was a loop problem, but the hard fault continues. I managed to trace it down to a call to xQueueSendToBack

BaseType_t FPGA_Handler_task::send8Data_to_user(uint8_t *data_p, uint8_t count)
{
  BaseType_t ErrorVal = pdPASS;
  char dataString[16];
  
  //get semaphore
  ErrorVal = xSemaphoreTake(GlobalFlags.UserInterface_TxQueue_Semaphore_Handle, 100);
  if (ErrorVal == pdPASS) {
  
    for (int i = 0; i < count; i++) {
      sprintf(dataString, "%#.2x ", data_p[i]);
    
      char *cp = dataString;
      for (size_t j = 0; j < strlen(dataString); j++) { //do not include terminal NULL, do not trigger addition of CRLF and CURSOR
        ErrorVal = xQueueSendToBack(GlobalFlags.UserInterface_TxQueue_Handle, (const void *)(cp+j), pdMS_TO_TICKS(100));
        if (ErrorVal != pdPASS) {
        
          //release semaphore
          xSemaphoreGive(GlobalFlags.UserInterface_TxQueue_Semaphore_Handle);
        
          return ErrorVal;
        }
      } //end for
    } //end for
  
    char lineEnd = 0;
    ErrorVal = xQueueSendToBack(GlobalFlags.UserInterface_TxQueue_Handle, (const void *)&lineEnd, pdMS_TO_TICKS(100));  <=====
  
    //release semaphore
    xSemaphoreGive(GlobalFlags.UserInterface_TxQueue_Semaphore_Handle);
  } //end if
  
  //done
  return ErrorVal;
}

If I read the registers right, somewhere in there it’s trying to execute a non-Thumb instruction.

BTW sprintf already returns the number of chars converted. I’d use it instead of calling extra, lengthy strlen to get the same number.
Edit: I wouldn’t call strlen in a loop. Better determine the const loop limit before entering a loop even though the compiler might or might not optimize/move e.g. the strlen call out of the loop.
However, the code seems ok so far and this really strange issue still occurs … :thinking:
How is the queue created ? As a queue of N char items ? And I guess the queue is never destroyed elsewhere, right ? dataString[16] should be large enough, too.
This brings me back to a possible stack overflow… can you retry using a (much) larger stack ?

1 Like

Thanks. I create the queue staticly at the start of the program

//User Interface
// outgoing - 1 character at a time
UserInterface_TxQueue_Handle = xQueueCreateStatic((UBaseType_t)USERINTERFACE_MSG_LEN,
(UBaseType_t)sizeof(uint8_t),
UserInterface_TxQueue_buffer,
&UserInterface_TxQueue_data);
if (UserInterface_TxQueue_Handle == NULL) {
Error.Info.ErrorCode = FailCodes::FC_GlobalFlags;
Error.Info.ErrorTrace = HANDLE_CREATION_ERROR;
Error.Info.ErrorData = LINE; //location
return;
}
#ifdef DEBUG
vQueueAddToRegistry(UserInterface_TxQueue_Handle, “UI_RX”);
#endif
where
QueueHandle_t UserInterface_TxQueue_Handle; ///<Outgoing to user
and
uint8_t UserInterface_TxQueue_buffer[USERINTERFACE_MSG_LEN*sizeof(uint8_t)];

Thing is, I’ve been using this for a long time. It’s the primary user interface and everything gets dumped to it. In the user-interface task there’s a loop that takes one character at a time and feeds it to the USART. Never had a problem with it.
I’ll try increasing the stack.

and
#define USERINTERFACE_MSG_LEN 64
so there’s lots of room in the queue.

I agree, the queue and the related code is most likely not the problem.

Hmm. Doubling the stack size seems to have worked! Thanks. I have the vApplicationStackOverflowHook routine in there and that wasn’t triggered. I wonder why?

we discussed this before:

Right. Oh well, live and learn. Thanks.

In my experience, the FreeRTOS stack check catches stack overflows very rarely. I am thinking of turning it off. Usually I find that either the overflow causes a hard fault or memory protection fault before the FreeRTOS dispatcher has a chance to check the stack; or FreeRTOS doesn’t detect the overflow because a buffer was allocated on the stack, but the buffer was not fully written to, so it didn’t overwrite the canary at the bottom of the stack that FreeRTOS looks for (RAc described the same thing in his response).

1 Like

FreeRTOS check the stack every time a task is switched out, how often that is depends a lot on the code.

Major overruns will tend to crash the system, that is their nature. What the check can do is detect minor overruns that just make a small piece unstable, and can often catch a problem before you have hit a full crash.

You do have to watch out about allocating large buffers that aren’t fully written to on the stack, but in my opinion, large buffers don’t belong on the stack.

Automatic buffers don’t have to be large to make the overflow check fail. If I recall correctly (don’t have access to the code right now), a few 4 byte units suffice. David’s observation about it failing repeatedly matches mine.

I thought the macros checked 4 WORDS, which will be 16 bytes for many systems, 8 for some 16 bit processors. That is getting reasonably large in my mind. The main use I see for buffers that are partially written above that are building text messages, which tends to imply the nasty sprints. If sending a message I malloc a buffer so I can pass a pointer, or if sending a message for a serial port, I send each piece out rather than wasting the space to build a unified message.

It also check the Stack Pointer itself a switch, so non-transitory overflows are always caught.

Getting into murky waters here as these tend to be questions of taste, and there’s no arguing about taste… I tend to avoid malloc() where it is not strictly needed because a) frequent uses of it foster heap fragmentation, b) the timing becomes unpredictable and c) the code must take precautions for it to fail. Since FreeRTOS makes a verbatim copy of the message anyways, the only useful application (in my opinion) for passing pointers (even to automatic memory) instead of messages is when the receiver needs to modify elements of the structure.

But again, there’s a time for everything, and in most cases, several ways to skin the cat serve the purpose.

Along those lines, I wouldn’t normally call 16 bytes a “large chunk” of memory, although I perfectly understand that on some platforms/systems with strict memory constraints, that amount can be significant.

Have a nice weekend!

Well, the other simple solution is when you declare your buffer, do it as:

char buffer30] = 0;

setting all the bytes of it, gets around the undetected stack overflow issue, and if you are going to fill the buffer with something like sprintf, the clearing time is negligible to the generation time.

The key is that as long as you initialize everything when you create it, you can’t get the stealth overflow.

Ok, that makes sense.

Just as a note, I’m avoiding malloc in this project and using static allocation for all FreeRTOS elements. Added benefit in that I can see pretty close how full RAM is when the compile is done.