We ran into a peculiar problem last week. We are using FreeRTOS v10.0 on a Zynq 7020 SoC (Cortex A9 processor) with the ARM GCC toolchain. Essentially, we had one task running doing some simple floating point computations and a DMA triggered interrupt, which invoked a deferred interrupt handler task blocking on a queue from the interrupt.
When running in isolation, the task and the interrupt behaved as expected. However, when they are running together, sometimes the float variables get random values. On some digging, we found this thread (the float operation got corruption on zynq - FreeRTOS) that seems to report the same issue. Following the suggestions provided in the thread, we made the following changes :
configUSETASKFPU_SUPPORT is set to 2
The function vApplicationIRQHandler() is renamed to vApplicationFPUSafeIRQHandler() in the portZynq7000.c file which is part of the BSP auto-generated by Xilinx SDK.
These changes seem to have fixed the issue. However, I would like some insight as to what has actually happened.
The GCC Cortex A9 port that comes with the FreeRTOS distribution does not have the portZynq7000.c file. Is this file needed or just the three files - port.c, portASM.s and portmacro.h sufficient ?
I am not able to locate the vApplicationIRQHandler() function in the files in GCC/ARM_CA9. Where do I find it?
Would appreciate some insight as to what’s really happening. Thanks for the help.
-yogesh
Hello @jyogesh, as you probably know, the FPU has many registers. By default, these registers are not stored on the stack during a task-switch.
The FPU registers are also used in some implementations of memcpy() and memset(). I have also seen that FPU registers were used in stead of the stack when using an ellipsis function.
Thanks. The portZynq7000.c file comes when the BSP is generated by Xilinx SDK using the FreeRTOS. Just to be clear, I am using the FreeRTOS port provided by Xilinx SDK BSP instead of manually adding FreeRTOS source files and compiling as a part of the application, as mentioned here (FreeRTOS BSP for Xilinx Software Development Kit (SDK)).
I didn’t see any calls made to this function, but I suspect that is because the call be being made in the assembly file portASM.S. Interestingly, the port.c has the following section :
/*
* If the application provides an implementation of vApplicationIRQHandler(),
* then it will get called directly without saving the FPU registers on
* interrupt entry, and this weak implementation of
* vApplicationFPUSafeIRQHandler() is just provided to remove linkage errors -
* it should never actually get called so its implementation contains a
* call to configASSERT() that will always fail.
*
* If the application provides its own implementation of
* vApplicationFPUSafeIRQHandler() then the implementation of
* vApplicationIRQHandler() provided in portASM.S will save the FPU registers
* before calling it.
*
* Therefore, if the application writer wants FPU registers to be saved on
* interrupt entry their IRQ handler must be called
* vApplicationFPUSafeIRQHandler(), and if the application writer does not want
* FPU registers to be saved on interrupt entry their IRQ handler must be
* called vApplicationIRQHandler().
*/
void vApplicationFPUSafeIRQHandler( uint32_t ulICCIAR ) __attribute__((weak) );
while the portZynq7000.c defines the following function : void vApplicationIRQHandler( uint32_t ulICCIAR ){
so back to the issue: How to generate the map files will depend on the tool set and IDE you are using. Very likely it is gcc based, so you will need to add appropriate command line parameters to the compiler or linker. Some IDEs already allow to do that with a check box. Are you using command line based tools (if yes you may want to share your make file)?
I generated the map file using the -Wl,-M=d:/test.map option. I am hitting the forum limitation on directly pasting it here. Which sections would be relevant for this discussion?
Another question I had was about the relationship between the XScuGic Interrupt handler function that is done in baremetal code using : Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, &my_Gic); where my_GIC is the GIC instance and the vApplicationIRQHandler() / vApplicationFPUSafeIRQHandler()
functions.
@rtel thanks, but getting the error Body is limited to 88000 characters; you entered 293740 while attempting to directly copy the map file contents here. I get an error about invalid extension when uploading a map file. I’ve attached the map file in the rar map_file.zip (22.5 KB)
.
Hey @ozanagma,
I was hoping to get some more information about the problem you’re facing and what you’ve tried to fix it?
I’m going to make the assumption that you’re attempting to use the GCC Cortex A9 port and seeing your floating point registers have their values over-written when using an IRQ.
If this is the case it is likely caused by not installing a function called vApplicationFPUSafeIRQHandler(), like this one,
which causes vApplicationIRQHandler() to be called first, which saves the floating point registers as described here
If you’re running a different demo or using a different port please provide that information so I can assist you better!
Our current FPU configurtion is configUSE_TASK_FPU_SUPPORT =1, before all tasks we call vPortTaskUsesFPU(), we do not overwrite any standart library memory functions( like memcpy and memset), and we changed vApplicationIRQHandler() to vApplicationFPUSafeIRQHandler(). As of now, we don’t have any floating point problem. Thank you for asking.