Writing a program for the ATSAMC21E18A, using Microchip Studio, FreeRTOS 10.
One of my tasks, which is very similar to another, which is not misbehaving, is throwing an error that I cannot explain.
The task is continuously cycling, checking a queue for a command to execute. It receives the command and is working its way through, and gets to one
case FPGA_HandlerState_t::operating : //FPGA is working
if (GlobalFlags.FPGA_Handler_RxQueue_Handle != NULL) { //safety
if (xQueueReceive(GlobalFlags.FPGA_Handler_RxQueue_Handle, (void *)(&IncomingMessage), portMAX_DELAY) == pdPASS) { //returns errQUEUE_EMPTY if timeout and nothing on queue
//command interpreter
switch (IncomingMessage.Command) {
case FPGA_Interface_Commands::reset :
task_this_p->FH_resetFPGA(task_this_p);
break;
case FPGA_Interface_Commands::getmode :
task_this_p->FH_getmode(task_this_p); <======
break;
Ok, no problem. For some reason, whenever it gets to this call the RTOS does a context switch, The next thing that I know it ends up at the āDummy_Handlerā routine in startup_samc21.c ā\brief Default interrupt handler for unused IRQs.ā. Looking at the call stack it gets there, every time, from vTaskSwitchContext in tasks.c, from line 2667 at the call to taskCHECK_FOR_STACK_OVERFLOW. However itās not going there from the stack-overflow handler in main.c, which is implemented, and Iāve ended up there before, so I know it works. The stack dump looks ok, the Queues look ok. No clue as to what the thing is complaining about? How do I find what is triggering this?
further data. I traced the failure down to this point:
BaseType_t FPGA_Handler_task::send8Data_to_user(uint8_t *data_p, uint8_t count)
{
BaseType_t retval = pdPASS;
char dataString[16];
//get semaphore
xSemaphoreTake(GlobalFlags.UserInterface_TxQueue_Semaphore_Handle, 100);
for (int i = 0; i < count; i++) {
sprintf(dataString, "%#.2x ", data_p[i]);
char *cp = dataString;
for (size_t i = 0; i < strlen(dataString); i++) { //do not include terminal NULL, do not trigger addition of CRLF and CURSOR
retval = xQueueSendToBack(GlobalFlags.UserInterface_TxQueue_Handle, (const void *)(cp+i), pdMS_TO_TICKS(100));
if (retval != pdPASS) {
//release semaphore
xSemaphoreGive(GlobalFlags.UserInterface_TxQueue_Semaphore_Handle);
return retval;
}
} //end for
} //end for
FPGA_Handler_task is sending a response back to the UserInterface queue for transmission through the USART. The queue has 64 elements, this message is only 5 characters long, so Iām not overflowing the queue. If fails on the last character.
The weird thing is that it fails in different places depending on where I have the breakpoints. Sometimes it fails at the final return, sometimes at the xSemaphoreGive statement.
Did you check if it is an unhandled interrupt ? I think NVIC ISPR register contains the currently pending IRQs.
If there was no matching IRQ itās probably a stack overflow or another memory corruption. Stack overflow checking even at level 2 canāt catch ALL overflows.
Usually itās possible to display the peripheral registers and also those of the NVIC (interrupt controller) in the debugger. Atmel Studio (?) supports that as far as I remember.
Also if you have some memory left to waste, try to increase the stack.
With such weird crashes a stack or (sprintf) buffer overflow is my 1st guess.
BTW Iām always using snprintf or something similar to avoid string buffer overflows.
If ISPR is 0x0 I think there is no interrupt pending and ending up in the unhandled interrupt dummy_handler is the result of something else.
Do you catch the fatal exceptions like HardFaults etc. by dedicated handlers ?
Iād propose to add exception handlers for the few processor exceptions, too.
For development ending up in a forever loop like the standard FreeRTOS asserts/failed hooks. Thatās often useful to narrow down weird crashes. Unfortunately those processor exception handlers like normal interrupt handlers have no call stack to backtrace ā¦
Itās ending up in the HardFault handler. Any suggestions on how to figure out whatās causing it?
The assembly code given in the link doesnāt work on an M0 core.
The fault handler assembly code doesnāt compile for an M0 core. Iāll try single-stepping through the code, the problem is that itās running multiple tasks so Iām having a hard time figuring out where the fault is.
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?