Hi,
the code below is an ISR callback.
If in that callback or any other ones I uncomment the SYS_DEBUG_MESSAGE() lines it fails the freeRTOS assert.
I assume it is because that function (microchip built-in Harmony library) uses freeRTOS functionality…? Can anybody confirm that is the case?
That function is a non-blocking function which uses freeRTOS functionality and I thought it would just pass the string to a buffer (to be processes later) then return immediately. But perhaps there are other reasons for it to call vAssertCalled()?
Most importantly, is there a way around it? i.e. are there ways which are freeRTOS safe to send a debug message to a 232 port inside an ISR?
I am using Microchip’s PIC32MZ with XC32 compiler and Harmony framework.
void CBK_CHANGE_NOTIF_ProductSense(GPIO_PIN pin, uintptr_t context)
{
BaseType_t xHigherPriorityTaskWoken;
UBaseType_t uxSavedInterruptStatus;
xHigherPriorityTaskWoken = pdFALSE;
uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
switch(task_sensorsData.xBtn_ProdSenseSwitchState)
{
case BTN_STATE_AT_REST:
{
//check CN was because button was pressed
if (PROD_SENSE_Get() == PIN_STATE_PROD_SENSE_TRIGGERED)
{
//configure timer for debouncing
xTimerChangePeriodFromISR(task_sensorsData.xTimer_Handle_ProdSenseSwitch,
pdMS_TO_TICKS(TMR_RELOAD_PRODUCT_SENSE_PRESS_DEBOUNCE_MS),
0);
xTimerResetFromISR(task_sensorsData.xTimer_Handle_ProdSenseSwitch, 0);
xTimerStartFromISR(task_sensorsData.xTimer_Handle_ProdSenseSwitch, 0);
//disable CHANGE NOTIF interrupt for Product Sense Switch
PROD_SENSE_InterruptDisable();
//change state to BTN_STATE_DEBOUNCING
task_sensorsData.xBtn_ProdSenseSwitchState = BTN_STATE_PRESS_DEBOUNCING;
// SYS_DEBUG_MESSAGE(SYS_ERROR_DEBUG, "Changing to STATE_PRESS\r\n");
}
break;
}
case BTN_STATE_PRESSED:
{
//check CN was because button was pressed
if (PROD_SENSE_Get() == PIN_STATE_PROD_SENSE_RELEASED)
{
//configure timer for debouncing
xTimerChangePeriodFromISR(task_sensorsData.xTimer_Handle_ProdSenseSwitch,
pdMS_TO_TICKS(TMR_RELOAD_PRODUCT_SENSE_RELEASE_DEBOUNCE_MS),
0);
xTimerResetFromISR(task_sensorsData.xTimer_Handle_ProdSenseSwitch, 0);
xTimerStartFromISR(task_sensorsData.xTimer_Handle_ProdSenseSwitch, 0);
//disable CHANGE NOTIF interrupt for Product Sense Switch
PROD_SENSE_InterruptDisable();
//change state to BTN_STATE_DEBOUNCING
task_sensorsData.xBtn_ProdSenseSwitchState = BTN_STATE_RELEASE_DEBOUNCING;
// SYS_DEBUG_MESSAGE(SYS_ERROR_DEBUG, "Changing to RELEASE\r\n");
}
break;
}
case BTN_STATE_PRESS_DEBOUNCING:
case BTN_STATE_RELEASE_DEBOUNCING:
default:
{
// SYS_DEBUG_MESSAGE(SYS_ERROR_ERROR, "DEBUG ERROR - Unused state\r\n");
}
}
taskEXIT_CRITICAL_FROM_ISR(uxSavedInterruptStatus);
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
Since this is ISR code, why do you claim the critical section? As you should know by now, the only scenario where you would want to do that is when there are potential access conflicts with higher priority ISRs. I don’t know if this addresses your problem (as Richard pointed out, more info is needed), but as always in concurrent programming, too much synchronization is as dangerous as too little of it.
@rtel It calls the vAssertCalled() which is defined in the freertos_hooks.c
@RAc I claim the critical section because there is a higher priority interrupt used for synching with an external signal (printhead nozzle control/timing) and might affect a couple of variables used in this ISR the variable including task_sensorsData.xBtn_ProdSenseSwitchState. (There is more code in that ISR but I cut it out to keep it short for the post.)
With regard to that am I still using it incorrectly?
@rtel wants to know the call stack resp. the source location wherevAssertCalled is invoked which should be investigated 1st by yourself to identify the problem the assert checks.
in the xQueueSemaphoreTake() function (see further below freeRTOS code).
I noticed that the line above it has a taskENTER_CRITICAL()
Is that the reason? Perhaps taskENTER_CRITICAL() cannot be nested (I guess in a way might make sense as the first ExitCritical would void the other outer ones)?
If so I guess I cannot use that USART non-blocking function inside an ISR? Or are there ways around it?
BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait )
{
BaseType_t xEntryTimeSet = pdFALSE;
TimeOut_t xTimeOut;
Queue_t * const pxQueue = xQueue;
#if( configUSE_MUTEXES == 1 )
BaseType_t xInheritanceOccurred = pdFALSE;
#endif
/* Check the queue pointer is not NULL. */
configASSERT( ( pxQueue ) );
/* Check this really is a semaphore, in which case the item size will be
0. */
configASSERT( pxQueue->uxItemSize == 0 );
/* Cannot block if the scheduler is suspended. */
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
{
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
}
#endif
/*lint -save -e904 This function relaxes the coding standard somewhat to allow return
statements within the function itself. This is done in the interest
of execution time efficiency. */
for( ;; )
{
taskENTER_CRITICAL();
{
/* Semaphores are queues with an item size of 0, and where the
number of messages in the queue is the semaphore's count value. */
const UBaseType_t uxSemaphoreCount = pxQueue->uxMessagesWaiting;
/* Is there data in the queue now? To be running the calling task
must be the highest priority task wanting to access the queue. */
if( uxSemaphoreCount > ( UBaseType_t ) 0 )
{
traceQUEUE_RECEIVE( pxQueue );
/* Semaphores are queues with a data size of zero and where the
messages waiting is the semaphore's count. Reduce the count. */
pxQueue->uxMessagesWaiting = uxSemaphoreCount - ( UBaseType_t ) 1;
#if ( configUSE_MUTEXES == 1 )
{
if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
{
/* Record the information required to implement
priority inheritance should it become necessary. */
pxQueue->u.xSemaphore.xMutexHolder = pvTaskIncrementMutexHeldCount();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configUSE_MUTEXES */
/* Check to see if other tasks are blocked waiting to give the
semaphore, and if so, unblock the highest priority such task. */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
queueYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
taskEXIT_CRITICAL();
return pdPASS;
}
else
{
if( xTicksToWait == ( TickType_t ) 0 )
{
/* For inheritance to have occurred there must have been an
initial timeout, and an adjusted timeout cannot become 0, as
if it were 0 the function would have exited. */
#if( configUSE_MUTEXES == 1 )
{
configASSERT( xInheritanceOccurred == pdFALSE );
}
#endif /* configUSE_MUTEXES */
/* The semaphore count was 0 and no block time is specified
(or the block time has expired) so exit now. */
taskEXIT_CRITICAL();
traceQUEUE_RECEIVE_FAILED( pxQueue );
return errQUEUE_EMPTY;
}
else if( xEntryTimeSet == pdFALSE )
{
/* The semaphore count was 0 and a block time was specified
so configure the timeout structure ready to block. */
vTaskInternalSetTimeOutState( &xTimeOut );
xEntryTimeSet = pdTRUE;
}
else
{
/* Entry time was already set. */
mtCOVERAGE_TEST_MARKER();
}
}
}
taskEXIT_CRITICAL();
Thank you Richard,
is that for the reason I mentioned (that routine itself uses taskENTER_CRITICAL() and taskENTER_CRITICAL() cannot be nested) or some other reason?
Well, it starts with using xSemaphoreTake instead of xSemaphoreTakeFromISR.
The code violates the API restrictions for ISRs as Richard correctly mentioned and as documented and checked by an assert.
I was referring to the CBK_CHANGE_NOTIF_ProductSense() callback fn code you posted earlier. As Hartmut and Richard pointed out, the code you posted afterwards is not ISR compatible.
The Harmony function calls routines that ultimate use functions that aren’t designed for use inside an ISR, in particular, the xQueueSemaphoreTake function.
ISR need to be careful as to what resources they use, which can sometimes be easy to forget.