STM32L4 USB CDC Interrupt Priority Failure (vPortRaiseBASEPRI)

I am trying to write to a queue within the USB CDC interrupt. The xQueueSendToFrontFromISR is failing intermittently with error below.

Program stopped.
0x080075f0 in vPortRaiseBASEPRI () at 
../Middlewares/Third_Party/FreeRTOS/Source/portable/GCC/ARM_CM4F/portmacro.h:195
195             __asm volatile

Below is the code I am using in the USB CDC ISR.

static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
  /* USER CODE BEGIN 6 */
  USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
  USBD_CDC_ReceivePacket(&hUsbDeviceFS);

  // Buffer must exist and not be full
  if ( (rx_queue != 0) && (uxQueueMessagesWaitingFromISR(rx_queue) < RX_QUEUE_SIZE) )
  {
      // Constructing the packet
      packet p;
      packet_reset(&p);
      packet_deserialize(&p, (unsigned char *) Buf);

      // Sending to queue
      xQueueSendToFrontFromISR(rx_queue, &p, &xHigherPriorityTaskWoken);
  }

  return (USBD_OK);
  /* USER CODE END 6 */
}

It looks like the error occurs specifically on the line:

configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); 

Like mentioned above the error is intermittent. I notice that if I remove xQueueReceive(rx_queue…) from the task which reads from the queue then the error goes away (but I need to be able to read from the queue). Note that I can successfully xQueuePeek(rx_queue…) without errors.

I have also messed around with one setting in the CubeMX in “System Core”->“NVIC”->“USB event interrupt through EXTI line 17”->“Preemption Priority” to see if I can lower the priority of the USB CDC interrupt but that did not work.

I have looked through the following pages for support but although they are useful in understanding interrupt issues, I cannot figure out what is the issue or solution.

My guesses are:

  1. The USB CDC interrupt priority is too high and somehow I need to lower that priority (tried with the CubeMX setting above but that failed)
  2. I am not managing resources appropriately and I need to add a mutex on that queue (but I thought queues don’t need semaphores?)
  3. Declare the queue memory volatile?

Appreciate your support on this.

Related issue links:
https://community.st.com/s/question/0D50X00009XkY4JSAV/usb-cdc-freertos-queue-problem

The configASSERT() statement you noted fails only for one reason, as described in the code comments immediately above it. Are you sure that’s the assertion that is failing? CubeIDE doesn’t allow you to configure the system to use sub-priority bits when you select FreeRTOS, so that configASSERT() statement should not be failing.

Also note that the interrupt priority you mentioned is specific to ultra low power wakeups. You probably mean to adjust the one found in Connectivity / USB_xxx / NVIC Settings.

It is possible you have that interrupt priority set too high, meaning numerically too low. In that case it’s the assertion before the one you mentioned that is actually failing. Watch out for the inversion between priorities and numeric values.

The settings in “Connectivity”->“USB_xxx”->“NVIC Settings”->“USB event interrupt through line 17” are not editable. However they match exactly the ones found in “System Core”->“NVIC”->“USB event interrupt through EXTI line 17”. If I edit one then the other is changed as well.

Currently the settings are:

(USB event interrupt through EXTI line 17).enabled = checked
(USB event interrupt through EXTI line 17).preemption priority = 8 (I lowered it from 5)
(USB event interrupt through EXTI line 17).sub priority = 0

I have followed the break point to the line below. That is where the code stops executing.

configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); 

Note when the xQueueReceive(rx_queue…) is removed from the task then the line above passes with the following values:

portAIRCR_REG = 4194632448 
portPRIORITY_GROUP_MASK = 1792
ulMaxPRIGROUPValue = 2779096485

When I put the xQueueReceive(rx_queue…) back in it fails with the following values:

portAIRCR_REG = 4194632448 
portPRIORITY_GROUP_MASK = 1792
ulMaxPRIGROUPValue = 2

Appreciate your time.

This looks highly suspicious. And combined with the fact that your symptom is intermittent, I think you may have some memory corruption (bad pointer, stack overflow, etc).

What MCU are you using?

Using the STM32L452RE Nucleo board.

Note all code and free rtos objects are being statically declared.

When the configASSERT is able to pass (with 2779096485) the program works as expected.

Im considering commenting out the line temporarily till this is resolved.

configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );

I think Cortex-M4 should end up with ulMaxPRIGROUPValue of 3. (Well, actually, it would be 0x300 so this code can avoid bit shifting.) And with your SCB->AIRCR value of 0xFA050300 (4194632448), you would not be asserting there at all if ulMaxPRIGROUPValue hadn’t been corrupted.

  1. How do you know that the ulMaxPRIGROUPValue should be 0x300?
  2. I notice that the ulMaxPRIGROUPValue is set in xPortStartScheduler(). In order to debug memory corruption I can get the pointer of ulMaxPRIGROUPValue and step through to see where the memory gets corrupted?
  1. According to the programming manual PM0214, pages 227-228, if the value in PRIGROUP is higher than 3, then some of the bits of an interrupt’s priority setting are used as sub-priority bits. The intention of the assertion statement is to make sure the system is configured with no sub-priority bits.

  2. Yes, you can watch in the debugger to see when that field is no longer 0x300.

You can also check for simple things like stack overflow automatically in FreeRTOS. In CubeIDE, under Middleware / FreeRTOS / Config Parameters / Hook function related definitions, you can set CHECK_FOR_STACK_OVERFLOW to Option 2. Then define vApplicationStackOverflowHook() in freertos.c (generated by CubeMX). Put a breakpoint in there.

Sweet that was it!

I added the vApplicationOverflowHook() and hit the breakpoint.

Looks like there was a stack overflow (classic :D) on the default task. It was originally set to its default of 128 bytes. After changing it to 300 bytes the breakpoint is no longer being hit and the assert no longer fails.

I can also confirm that the ulMaxPRIGROUPValue is indeed 0x300 (1100000000 binary) when running properly.

Thanks Jeff.

1 Like