FreeRTOS queue usage from ISR

Hello,

I have been developing FreeRTOS based application on Zynq 7000 hardware platform.
My application software is divided into one interrupt service routine (ISR) and one FreeRTOS task. I have attempted to send bytes from the task into the ISR via FreeRTOS queue. Unfortunately I have encountered a problem in case I have called the xQueueReceiveFromISR function in the ISR.

The problem is in assertion failing in port.c module at lines 683 and 550. I have read the comment in function vPortValidateInterruptPriority in port.c module. Based on that I have firstly inspected value of configMAX_API_CALL_INTERRUPT_PRIORITY constant in the FreeRTOSConfig.h module and I have found that it is set to 18. According to the comment I have lowered priority of my interrupt request from 0 (i.e. highest priority) to 19. Despite this modification the above mentioned assertion still fails.

I have also read this article and it seems to me that the priority settings should work. Does anybody have any idea why the assertion still fails?

One big question is to confirm that your controller has at least 5 priority bits, so that 18 is a valid priority value.

Hello richard-damon, thank you for your reaction. I have just went through the Zynq Technical Reference Manual and there exist four 8 bits fields for interrupt priorities. Only the upper 5 bits of each 8 bit field are writable and lower bits are always 0. This results in 32 priority levels between 0 and 248. This is in accordance with the comments to the XScuGic_SetPriorityTriggerType function.

Make sure your FreeRTOSConfig.h also says 5 bits then. The other thing you may have to do is step through that assert (in assembler mode maybe) to see what is triggering it. Set a breakpoint in the ISR that is flagging just before the call to the xQueueReceiveFromISR function call, and see what exactly is not working.

I have attempted to step through the xQueueReceiveFromISR function call in debugger. The problem is in function vPortValidateInterruptPriority. There is following code at line 683:
configASSERT( portICCRPR_RUNNING_PRIORITY_REGISTER >= ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) );

I have expanded the macro and it seems to me that content of the register 0xF8F00114 (ICCRPR) is compared with value 18 (configMAX_API_CALL_INTERRUPT_PRIORITY) shifted by 3 bits to the left i.e. 144. I have also attempted to find out what value is in the ICCRPR register. I have found that there is 0x00000010 i.e. 16. So I is obvious that the assertion fails. Question is where does the value in ICCRPR register come from (priority of my ISR has been set to 19)?

Nevertheless I have done an experiment and I have changed the value of configMAX_API_CALL_INTERRUPT_PRIORITY to value 1 so that the above mentioned test will pass. During compilation process the compiler alerted me that configMAX_API_CALL_INTERRUPT_PRIORITY must be greater than ( configUNIQUE_INTERRUPT_PRIORITIES/2 ) which in my case means greater than 32/2=16.

The ICCRPR register is the current interrupt priority which should have been setup in your starting configuration of the interrupt. I would check that the register in the interrupt controller is being setup right, and is the right interrupt register (if you get your IRQ numbers messed up you can get all sorts of issues).

I am not that familiar with the Zynq port, so I don’t know where or why there would be a test for the configMAX_API_CALL_INTERRUPT_PRIORITY to be > 16 would be.

Did you see the “Essential information on interrupt priorities” section on this page? https://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html#interrupt-handling

Yes, as I wrote in my first post. Nevertheless I have probably found where the problem was. The priority of the interrupt service routine has to be shifted to the left by so many bits which is prescribed by the symbolic constant portPRIORITY_SHIFT defined in portmacro.h module. As soon as I had done that the data exchange between task and interrupt service routine started to work.

That is one of the tricky parts with ARM interrupts. The Hardware itself wants the bits shifted up, but most (but not all) API functions want them shifted down, and mixing up which is wanted where tends to cause problems.

richard-damon, thank you for your help.