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 UART2IRQHandler() interrupt handler. It signals
the Modem
UARTEvent
Handler() task with the BTUART
DataSignal semaphore.
The symptoms of the problem are as follow:
1) A UART2 interrupt is generated, UART2
IRQHandler() signals MODEMUART
EventHandler()
of the event via the BT
UARTData
Signal semaphore and the event is successfully
handled. At this point MODEMUART
EventHandler() task has called xSemaphoreTake()
once.
2) The MODEM
UARTEvent_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 BTUART LPCUART2
define BTIRQ UART2IRQn
~~~
The relevant definitions from FreeRTOSConfig.h are as follows.
~~~
define configMAX_PRIORITIES ( 5 )
define configPRIO_BITS 4 /* 15 priority levels */
define configLIBRARYLOWESTINTERRUPT_PRIORITY 0xf
define configLIBRARYMAXSYSCALLINTERRUPTPRIORITY 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 configKERNELINTERRUPTPRIORITY ( configLIBRARYLOWESTINTERRUPTPRIORITY << (8 – configPRIOBITS) )
/* !!!! configMAX
SYSCALLINTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
define configMAXSYSCALLINTERRUPTPRIORITY ( configLIBRARYMAXSYSCALLINTERRUPTPRIORITY << (8 – configPRIOBITS) )
~~~
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 UART1IRQn 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
UARTData
Signal = xSemaphoreCreateBinary();
//
// BTMODEM
HANDLERTASK – Highest Priority – Almost
//
xTaskCreate(Modem
UARTEvent
Handler, (signed char *) “MODEM/UART”,
configMINIMALSTACK
SIZE, NULL, (tskIDLEPRIORITY + 3UL),
&task_id);
~~~
This is the relevant portion of the task:
~~~
TASK void Modem
UARTEvent
Handler(void *parm)
{
INTERTASKMSG 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)
{
BaseTypet hi
prioalert;
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);
}
~~~