Task Crash While Waiting for Semaphore

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 UART2IRQn and handled by the UART2IRQHandler() interrupt handler. It signals the ModemUARTEventHandler() task with the BTUARTDataSignal semaphore. The symptoms of the problem are as follow: 1) A UART2 interrupt is generated, UART2IRQHandler() signals MODEMUARTEventHandler() of the event via the BTUARTDataSignal semaphore and the event is successfully handled. At this point MODEMUARTEventHandler() task has called xSemaphoreTake() once. 2) The MODEMUARTEvent_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) )

/* !!!! configMAXSYSCALLINTERRUPT_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 TIMER1IRQn 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: ~~~ BTUARTDataSignal = xSemaphoreCreateBinary(); // // BTMODEMHANDLERTASK – Highest Priority – Almost // xTaskCreate(ModemUARTEventHandler, (signed char *) “MODEM/UART”, configMINIMALSTACKSIZE, NULL, (tskIDLEPRIORITY + 3UL), &task_id); ~~~ This is the relevant portion of the task: ~~~ TASK void ModemUARTEventHandler(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 UART2IRQHandler(void) { BaseTypet hiprioalert; 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);
} ~~~

Task Crash While Waiting for Semaphore

First, tripple check the value of
__NVICPRIOBITS
, as this has been the cause of some confusion over the years with the NXP headers and documentation mismatching. For example, a quick web search finds it set to 3 in this file: http://www.keil.com/dd/docs/arm/nxp/lpc43xx/lpc43xx.h (you have it set to 4) and a comment that it has been corrected in this change history: http://cdn.rowleydownload.co.uk/arm/packages/LPC4300.htm Do you have configASSERT() defined? http://www.freertos.org/a00110.html#configASSERT That should assist in finding a priority assignment error – it might be worth updating to a newer version of FreeRTOS to as newer versions have additional assert() points for better error detection.

Task Crash While Waiting for Semaphore

There is a conflict between the number of NVIC interrupt priority bits of the LPC4088 Cortex M4 processor as defined by NXP versus CMIS3. NXP defines 5 bits and 32 priority levels split into two groups–the maskable group is appropriate for use with FreeRTOS. CMIS3 defines 4 bits and 16 priority levels by necessity. (i.e. The target environment is an LPC4088 processor on the Embedded Artist’s LPC4088-32 Developer’s Kit board.) I am fairly certain that the NXP 5 bit definition is correct. When __NVICPRIOBITS is set to 5 bits in my environment and xSemaporeGiveFromISR(), called from the interrupt handler, correctly signals the ModemUARTHandler() task with BTUARTData_Signal semaphore. In that case the priority of SysTickIRQn = 30 and can be computed as follows:
(1 << NVIC_PRIO_BITS)  - 2;
The important FreeRTOSConfig.h definitions should be as follows:
#define configPRIO_BITS   5      /* 32 priority levels */
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x1f
It isn’t clear if configLIBRARYMAXSYSCALLINTERRUPTPRIORITY should be set but it is set to 5 as in the current configuration and any clues would be appreciated. If the value is 5, the encoded value, configMAXSYSCALLINTERRUPT_PRIORITY, is 40. In LPC407x8x177x_8x.h the value is as follows:
#define __NVIC_PRIO_BITS   5    /* !< Number of Bits used for Priority Levels */
This seems reasonable since a great deal of Cortex M4 documentation indicates there are 32 rather than 15 priority levels. Chapter 5 section 3.5 of the LPC17xx edition of “Using the FreeRTOS Real Time Kernel” indicates there are 32 priority levels. Section 5.5 of the UM10562–The LPC408x/LPC407x User Manual, indicates there are 5 interrupt bits and 32 levels as well. In CMSIS/Include/core_cm3.h the value is as follows:
#define __NVIC_PRIO_BITS          4
Best Regards, Paul R.

Task Crash While Waiting for Semaphore

It isn’t so clear how configLIBRARYMAXSYSCALLINTERRUPTPRIORITY should be set but it is set to 5 in the current configuration. This is important because the priority of an interrupt that uses xSemaphoreGiveFromISR() must be numerically greater than configLIBRARYMAXSYSCALLINTERRUPTPRIORITY if I understand the documentation correctly. Is this right ?
Here is an example for 5 bits:
/* Use the system definition, if there is one */
#ifdef __NVIC_PRIO_BITS
  #define configPRIO_BITS  __NVIC_PRIO_BITS
#else
  #define configPRIO_BITS  5
#endif

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY  0x1f
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5

/* The lowest priority. */
#define configKERNEL_INTERRUPT_PRIORITY ( 
configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( 
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. Yes it must be lower than configMAXSYSCALLINTERRUPT_PRIORITY - which means a higher numerical value. See the link above.
NVIC_SetPriority(irq, (1 << (__NVIC_PRIO_BITS - 1)) + priority);
Why not just
NVIC_SetPriority(irq, configMAX_LIBRARY_INTERRUPT_PRIORITY + whatever );

Task Crash While Waiting for Semaphore

Please clarify the recommendation about NVICSetPriority(). Do you really mean to use configMAXLIBRARYINTERRUPTPRIORITY = 5 or configMAXSYSCALLINTERRUPT_PRIORITY = 40 ?

Task Crash While Waiting for Semaphore

I mean you really have to set the parameter to whatever the processor actually needs - but you will find, as others have, that different documents and source files say different things about what the processor actually needs, so you will first have to work that out (which can be done by experimentation - you can write 0xff into one of the priority registers, then read the value back, and see how many of the bits actually got set).