Hi @Steve! Since I work with Zynq Ultrascale+ devices and the FreeRTOS port from xilinx, I feel like I can answer correctly to your question. Here it is :
When using freertos as opposed to bare metal, you don’t have to connect the IRQ exception. Remember, connecting an interrupt handler to an IRQ number is not the same thing as connecting an exception handler to an exception source. The processor has only a few EXCEPTION sources, where it has numerous IRQ sources. For the cortex R5 found on zynq ultrascale+ (you use 7000 devices, so there are no R5 but two A something, but the idea is the same) You have 6 exception sources, namely ‘Data abort’, ‘Prefetch Abort’, ‘Undefined Abort’, ‘IRQ’, ‘Service Call’ and ‘FIQ’. There are two others : ‘break point’ and ‘Reset’, but you dont worry about those two.
The GIC is physically connected to the IRQ line of the processor, to which are connected the peripheral irq lines. With FreeRTOS on zynq, you don’t have to connect the FreeRTOS_IRQ_Exception_Handler to the IRQ Exception because it’s already done in the assembly file. BUT, you can connect custom C functions to the 3 aborts (data,prefetch and undefined) in order to print more debug info than a simple xil_printf saying an abort occured.
The functions XScuGic_LookupConfig and XScuGic_CfgInitialize are called automatically when the scheduler is started and it will configure the xInterruptController struct appropriately. Now, there is a gotcha with this. If, before starting the scheduler, you try to initialize some peripherals and use the functions XScuGic_Connect with the xInterruptController struct, then you will get asserts because this global struct will be uninitialized. So there are two options :
1 - Only touch the xInterruptController struct AFTER the scheduler is started. This can be conter-intuitive because you need your peripherals initialized. There is a workaround to this : there is a #define you can define and it will call a ‘hook’ that is called right after the scheduler is started, but BEFORE task start to switch. You can initialize stuff in there.
2 - Initialyze yourselfe the struct xInterruptController with the functions XScuGic_LookupConfig and XScuGic_CfgInitialize.
3 - The more elegant way : Use the provided initialization function defined in the portmacro.h : xPortInstallInterruptHandler. That function, when called the first time, will initialize the xInterruptController struct the same way as solution #2, but in a ‘clean way’. With this solution, you don’t have to use the xInterruptController struct declared in the portZynqUltrascale.c (in my case) file (you have to declare it ‘extern’ in your code in order to be sure to use the same struct as freertos port code)
In the same fashion, in order to enable or disable interrupts, you can use the functions vPortEnableInterrupt and vPortDisableInterrupt that will in background use the xInterruptController struct from port.c
In my opition, use the option #3. It’s not very documented. When reading exemple code from xilinx, people are tempted to mimic the standalone code and use a XScuGic xInterruptController
I hope it clarifies the situation.