You can interrupt the Zynq ARM side with a signal coming out of the FPGA part of the chip. In this post, I test this.
The FPGA part has a few blocks that will generate interrupts. In a Jupyter notebook, I'll try to show that they are detected by the processors and OS.
In this article, I try out an approach discussed on the Pynq forum. It doesn't use VHDL or Verilog.
The interrupts are generated from 2 Xilinx Timer IP blocks.
But they could as well be generated from your own IP (E.g.: you could generate it from one of the pins of the Johnson Counter used in a previous post).
image: block design. Green blocks generate interrupts in the fabric. Red blocks are helpers to collect and format to a signal that's understood by the ARM/Linux part.
The processing system, reset and interconnect blocks are wired up as usual.
The design uses 3 masters in the interconnect. Two are used as interface with the 2 timers. The 3rd master talks to the interrupt controller.
These blocks will be addressable from Linux - in this case a Jupyter notebook.
I take these into account in this design.
In the version of Pynq that I'm using (2.6), there is a practical issue: the interrupt fires twice from FPGA before the Python code in the Jupyter notebook resets it. This makes that every other time the code returns immediately after priming the interrupt. It's acknowledged by Pynq designers (see my comment in the Pynq forum thread I linked at the start of this frame.
Two timers will generate interrupts. They are managed by an interrupt controller.
The processor system is configured to accept interrupts
Not shown, but input for the interrupt controller: processor clock is 650 MHz (fixed on my board), fabric clock 0 is set to 100 MHz (configured for this project..
Catching the interrupts in the ARM/Linux part
When the bitstream of this design is loaded in the Zynq, there should be interrupts arriving each time one of the timers fires one.
In the spirit of the Pynq ecosystem, a Jupyter notebook is used to make this visible.
The notebook will execute a loop, that will be interrupted when the trigger of timer 1 fires.
image: interrupt path through fabric
- register and configure the timer
- define an interrupt handler wait_for_timer1()
- create an event loop and have it interrupted by the handler.
This is the exact code of the Pynq forum thread I referred to above.
The exercise is successful if the last block of the notebook doesn't spin indefinitely, but completes.
You can see that if the annotation in the front of the block changes from [*] to [a number].
Vivado project (2020.2) and Jupyter notebook attached.
|Pynq - Zync - Vivado series|
|Add Pynq-Z2 board to Vivado|
|Learning Xilinx Zynq: port a Spartan 6 PWM example to Pynq|
|Learning Xilinx Zynq: use AXI with a VHDL example in Pynq|
|VHDL PWM generator with dead time: the design|
|Learning Xilinx Zynq: use AXI and MMIO with a VHDL example in Pynq|
|Learning Xilinx Zynq: port Rotary Decoder from Spartan 6 to Vivado and PYNQ|
|Learning Xilinx Zynq: FPGA based PWM generator with scroll wheel control|
|Learning Xilinx Zynq: use RAM design for Altera Cyclone on Vivado and PYNQ|
|Learning Xilinx Zynq: a Quadrature Oscillator - 2 implementations|
|Learning Xilinx Zynq: a Quadrature Oscillator - variable frequency|
|Learning Xilinx Zynq: Hardware Accelerated Software|
|Automate Repeatable Steps in Vivado|
|Learning Xilinx Zynq: Try to make my own Accelerated OpenCV Function - 1: Vitis HLS|
|Learning Xilinx Zynq: Try to make my own Accelerated OpenCV Function - 2: Vivado Block Design|
|Learning Xilinx Zynq: Logic Gates in Vivado|
|Learning Xilinx Zynq: Interrupt ARM from FPGA fabric|
|Learning Xilinx Zynq: reuse and combine components to build a multiplexer|