Hello everybody,
I am currently experiencing a weird bug.
I have a queue (one of a bunch of queues) of pointers that i use to transfer data between tasks. When first sending data to the queue, the task receiving data is not yet running, therefore no task is blocking on reading from that queue. The first transmission to the queue works fine, after that the receiving tasks runs, reads from the queue, processes the data and attempts to read from the queue again. As the queue is empty now, it blocks. When the sending task is executed again, it attempts to send data to the queue again. This time it results in a catch by the HardFault handler. I was able to pinpoint the error with the debugger, it occurs when trying to execute the listREMOVE_ITEM( &( pxUnblockedTCB->xEventListItem ) );
line in the xTaskRemoveFromEventList
of tasks.c
.
BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList )
{
TCB_t * pxUnblockedTCB;
BaseType_t xReturn;
/* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be
* called from a critical section within an ISR. */
/* The event list is sorted in priority order, so the first in the list can
* be removed as it is known to be the highest priority. Remove the TCB from
* the delayed list, and add it to the ready list.
*
* If an event is for a queue that is locked then this function will never
* get called - the lock count on the queue will get modified instead. This
* means exclusive access to the event list is guaranteed here.
*
* This function assumes that a check has already been made to ensure that
* pxEventList is not empty. */
pxUnblockedTCB = listGET_OWNER_OF_HEAD_ENTRY( pxEventList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
configASSERT( pxUnblockedTCB );
listREMOVE_ITEM( &( pxUnblockedTCB->xEventListItem ) );
if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
{
listREMOVE_ITEM( &( pxUnblockedTCB->xStateListItem ) );
prvAddTaskToReadyList( pxUnblockedTCB );
#if ( configUSE_TICKLESS_IDLE != 0 )
{
/* If a task is blocked on a kernel object then xNextTaskUnblockTime
* might be set to the blocked task's time out time. If the task is
* unblocked for a reason other than a timeout xNextTaskUnblockTime is
* normally left unchanged, because it is automatically reset to a new
* value when the tick count equals xNextTaskUnblockTime. However if
* tickless idling is used it might be more important to enter sleep mode
* at the earliest possible time - so reset xNextTaskUnblockTime here to
* ensure it is updated at the earliest possible time. */
prvResetNextTaskUnblockTime();
}
#endif
}
else
{
/* The delayed and ready lists cannot be accessed, so hold this task
* pending until the scheduler is resumed. */
listINSERT_END( &( xPendingReadyList ), &( pxUnblockedTCB->xEventListItem ) );
}
if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority )
{
/* Return true if the task removed from the event list has a higher
* priority than the calling task. This allows the calling task to know if
* it should force a context switch now. */
xReturn = pdTRUE;
/* Mark that a yield is pending in case the user is not using the
* "xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */
xYieldPending = pdTRUE;
}
else
{
xReturn = pdFALSE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
I am using a STM32F4 ARM Cortex M4 MCU.
Researching the cause of the HardFault Exeption leads to a PRECISERR flag in the CFSR register. The location of the executed code before the error is listed in the BFAR register, but my debugger is not happy reading the asm at that point. I may give it another try tomorrow.
I checked the usual interrupt priority configuration of the Arm Cortex port, everything is fine there. Config assert is also used correctly.
What could be the cause of the problem?
Thank you everybody!