paulromero wrote on Wednesday, July 27, 2016:
Dear Group:
I am having a FreeRTOS problem which I believe is due to incorrect
interrupt priority configuration.
The generic hardware is the Cortex M4 and the LPC4088 processor running on
on an Embedded Artist’s LPC4088-32 Developer’s Kit in particular. (i.e. The FreeRTOS
version is V8.0.1.)
Interrupts generated by LPC4088 UART2 are associated with NVIC interrupt
UART2_IRQn and handled by the UART2_IRQHandler() interrupt handler. It signals
the Modem_UART_Event_Handler() task with the BT_UART_Data_Signal semaphore.
The symptoms of the problem are as follow:
-
A UART2 interrupt is generated, UART2_IRQHandler() signals MODEM_UART_Event_Handler()
of the event via the BT_UART_Data_Signal semaphore and the event is successfully
handled. At this point MODEM_UART_Event_Handler() task has called xSemaphoreTake()
once. -
The MODEM_UART_Event_Handler() call xSemaphoreTake() again and crashes as follows:
In the FreeRTOS ListInsert() routine the crash occurs when the following line
of code executes:pxNewListItem->pxPrevious = pXIterator;
The sequence of FreeRTOS calls is as follows:
SemaphoreTake(); QueueGenericReceive(); TaskPlaceOnEventList(); ListInsert();
The definitions and code I consider relevant follow below.
The relevant UART definitions are as follows:
#define BT_UART LPC_UART2
#define BT_IRQ UART2_IRQn
The relevant definitions from FreeRTOSConfig.h are as follows.
#define configMAX_PRIORITIES ( 5 )
#define configPRIO_BITS 4 /* 15 priority levels */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0xf
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
/* Interrupt priorities used by the kernel port layer itself. These are generic
to all Cortex-M ports, and do not rely on any particular library functions. */
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
The priority initialization for the interrupt handler for UART2 is as follows and
the interrupt handler follows below:
unsigned int pri;
//
// Finally enable the IRQ interrupt.
// The priority of SysTickIRQn is 30, and that of TIMER1_IRQn is 29
// Set the UART1_IRQn to 28 as it is the highest priority less than
// that of TIME1_IRQn.
//
// The LPC4088 interrupt priority range is as follows:
//
// HIGH: 0 - 15
// LOW: 16 - 31
//
pri = ((1u << __NVIC_PRIO_BITS) - 2u) - 2u; // SysTickIRQn
pri -= 3;
NVIC_SetPriority(BT_IRQ, pri);
This is the relevant task and semaphore initialization:
BT_UART_Data_Signal = xSemaphoreCreateBinary();
//
// BT_MODEM_HANDLER_TASK - Highest Priority - Almost
//
xTaskCreate(Modem_UART_Event_Handler, (signed char *) "MODEM/UART",
configMINIMAL_STACK_SIZE, NULL, (tskIDLE_PRIORITY + 3UL),
&task_id);
This is the relevant portion of the task:
TASK void Modem_UART_Event_Handler(void *parm)
{
INTERTASK_MSG msg;
UINT ecause, n;
vTaskDelay(configTICK_RATE_HZ * 3);
for(;;)
{
//
// Wait until the UART #2 interrupt handler signals that data is available.
//
xSemaphoreTake(BT_UART_Data_Signal, portMAX_DELAY);
switch(MU_Event.type)
{
case MU_XE_TXFIFO_EMPTY:
if(MU_Data->mode == FRAME_MODE)
{
msg.event = IEV_BT_FIFO_EMPTY;
msg.data = NULL;
msg.length = 0;
X_SEND_MSG(LINK_HANDLER_TASK, &msg, X_HI_PRIO);
}
else
atd_tx_stored(TRUE);
break;
case MU_XE_RXDATA:
n = Chip_UART_ReadRB(BT_UART, &MU_Data->rx_ring,
(void *) MU_Data->rx_data_buf, BT_MAX_RING_BUF);
if(MU_Data->mode == FRAME_MODE)
link_handle_data(MU_Data->rx_data_buf, n);
else
atd_rx_data(MU_Data->rx_data_buf, n);
break;
case MU_XE_PHY_ERROR:
ecause = MU_Event.cause;
bt_rx_phy_error(ecause);
break;
default:
//
// BUG
//
abort();
}
}
}
Finally, this is the interrupt handler:
ROUTINE void UART2_IRQHandler(void)
{
BaseType_t hi_prio_alert;
UINT cause;
MU_Event.type = MU_XE_INVALID;
MU_Event.cause = 0;
//
// Examine te IIR register to determine the interrupt cause.
//
cause = Chip_UART_ReadIntIDReg(BT_UART);
cause &= 0xFF;
//
// Ignore a spurious interrupt.
//
if( !(cause & UART_IIR_INTSTAT_PEND) )
{
if( (cause & (UART_IIR_INTID_THRE | UART_IIR_INTID_RDA)) ||
( (cause & UART_IIR_INTID_CTI) == UART_IIR_INTID_CTI ) )
{
//
// In the case of a RBR or THR interrupt, this the following routine
// manages Ring Buffer and FIFO data transfer transactions.
//
// After the data transfer, notify the BT_MODEM_HANLDER_TASK that
// data is available for reading, or that a data transmission operation
// is complete.
//
Chip_UART_IRQRBHandler(BT_UART, &MU_Data->rx_ring, &MU_Data->tx_ring);
if( cause & UART_IIR_INTID_THRE )
MU_Event.type = MU_XE_TXFIFO_EMPTY;
else
MU_Event.type = MU_XE_RXDATA;
}
else
if( (cause & UART_IIR_INTID_RLS) == UART_IIR_INTID_RLS )
{
MU_Event.type = MU_XE_PHY_ERROR;
MU_Event.cause = Chip_UART_ReadLineStatus(BT_UART);
MU_Event.cause &= 0xFF;
}
else
{
//
// BUG: Invalid cause.
//
abort();
}
//
// Signal the BT_MODEM_HANDLER_TASK of an event.
//
xSemaphoreGiveFromISR(BT_UART_Data_Signal, &hi_prio_alert);
}
else
{
//
// Spurious interrupt
//
;
}
//
// The BT_MODEM_HANDLER_TASK has a higher priority than almost
// all other tasks which could be executing. If that is the case,
// force a context switch to the BT_MODEM_HANDLER_TASK.
//
portEND_SWITCHING_ISR(hi_prio_alert);
}