Recently I had to work with the interrupt features of Zynq and encountered some challenges.
Thankfully I managed to solve them so I decided to share the information in case other people encounter the same issue.
I know there are a lot of tutorials out there that explain how the interrupts work and how to set them up,
however, most of them describe how to connect interrupt coming from Xilinx IP or from PS peripheral.
Unfortunately there are some things that are not that obvious when having an interrupt from a custom IP.
For this example the setup is very simple – the PS and a counter, which sends one 10ns pulse each second.
Packaging the IP
No matter what the IP is doing the most important thing when packaging is to declare the output pin as an interrupt.
This happens by right-clicking on the pin and interring it as interrupt.
Once this is done, the signal can be connected to the PS. If this step is skipped then the interrupt will not show in the xparameters.h,
which means that the user cannot include it in the IRQ functionality in the software part. Therefore the IP has to be re-packaged.
Connecting to the GIC
I’m not going to describe how the interrupts work in detail, however, if you are interested, you can check out the following tutorial.
In an essence when configuring the GIC there is a lot of Xilinx defined code that can be reused, no matter where the IRQ comes from or what is it supposed to do.
In fact the most important piece of code is the XScuGic_Connect function.
This is used to connect the interrupt source to the GIC and the IRQ handler (i.e. the function that should be executed once the interrupt is received).
The first parameter is pointer to the GIC instance, the second is the ID of the IRQ source, the third is the handler and the fourth is a callback reference.
The problem I encountered here is the last parameter of the function. If you look through the above mentioned tutorial you will see that the argument is an instance of the peripheral (&my_Timer).
The problem is that such an instance does not exist if you have a custom IP. It took me a while to found out what to do. It turns out the answer is quite simple - put it to 0.
And it works!!!
I have included a screenshot of the code, but if you want to try it yourself, then you can fetch it from my Github.
Thanks for the attention and have fun!