Minimal simple Interrupt handling with UIO device in Pynq

Hi,
I want to test and build a simple Interrupt example for a custom board, connecting from an external signal using only UIO framework.

  1. I have connected the external pin with IRQ_F2P[0:0] interrupt line on Zynq IP

  2. I have added device tree fragment in system_user.dtsi

&amba_pl {

#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges ;

uio_0: uio_int0@0{
            compatible="generic-uio";
            status="okay";
            interrupt-controller;
            interrupt-parent=<&intc>;
            interrupts=<0x0 0x1d 0x4>;
};
  1. once the system boots up the uio device is in place as
    /dev/uio0
    and also in cat /proc/interrupt
    49: 1 0 GIC-0 63 Level uio0

Previously i have used and serviced the interrupt using c applications.
Now in my Board Pynq framework is working and tested.
What will be the minimal python code to test the interrupt using the only uio.py?

The UioController class bridges the asyncio and UIO worlds and works by waiting on the UIO file and setting asyncio events when an interrupt is received.

controller = UioController("/dev/uio0")
event = asyncio.Event()
async def interrupt_test():
   while True:
       event.clear()
       controller.add_event(event, 0) # Number is a dummy variable
       await event
       print("Interrupt Triggered")

loop = asyncio.get_event_loop()
loop.run_until_complete(interrupt_test())

This should print the message each time that the interrupt is triggered. You can create other asyncio coroutines to generate the interrupts if you want to test everything in process. If you’re using a GPIO controller to driver the interrupt line then something along the lines of:

async def drive_interrupts():
    while True:
         gpio.write(0, 0x1)
         gpio.write(0, 0x0)
         await asyncio.sleep(1)

driver_task = asyncio.ensure_future(drive_interrupts())

In a full program, you should ensure that the interrupt line is cleared before calling add_event otherwise you might end up with interrupts being duplicated.

Hope this makes some kind of sense - the underlying asyncio code can be fairly messy which is why we tried to abstract as much as possible of this away with the Interrupt class. That assumes a tree structure of AXI interrupts controllers connected to interrupt line 0 and a UIO device with the name “fabric”.

Peter

3 Likes

Hi,
Thanks for the detailed solution it worked nicely, for multiple interrupts, I followed external axi-int-controller in pl, just a side question may be its more related to python.
In pynq interrupt service routine is using asyncio but i dont now how to run it in the background? Is there any standard way? Do you have any reference implementation for monitoring interrupt in Pynq Framework in backgroun?

As long as you are careful with the multi-threading aspects you can start a new thread to run the asyncio loop - cell 2 in this this notebook shows one way to go about doing this. You can then add tasks to run in the background to the loop using asyncio.run_coroutine_threadsafe as shown in the following cell. The threadsafe is important to avoid corrupting the event loop when adding new tasks.

Peter

Hi,

I want to read my BRAM on Linux of my PYNQ board, can you give any guide on this, will uio serve this purpose? if yes, can you give any reference material or tutorial for using UIO

Hello,
It is best to use mmio for this. It allows you to read and write registers on memory-mapped buses such as AXI4.

With Pynq, you can do this by loading your bitstream, then find the attribute corresponding to your IP using. The read and write methods of your IP objects are shortcuts for the mmio api: overlay.axi_xxxx.read and overlay.axi_xxxx.write.

With any language, you can the mmio interface using mmap on /dev/mem and setting the propers offsets corresponding to your IP’s address on the memory bus.

Hello,

Thank you for your response, However, I think loading my bitstream, then using overlay.axi_xxxx.mmio.read to read will reset the values on my BRAM and give me a default value on the BRAM.

I aim to read the data stored on my BRAM immediately after an inference, I noticed after the inference, the server time out and I have to reload the bitstream before I can read using the overlay.axi_xxxx.mmio.read

Thank you for your assistance

Then set the option download=False when you load the bitstream in the Pynq API. It will keep your FPGA untouched.

Here is the relevant documentation page.

Thank you, will try and give a feedback.

One more question, my 32b BRAM has a depth of 512, can I read the various data written on each array row?

Yes, just read at the corresponding address.

You need to reset the parser after the Overlay object is created as shown in here

Mario

1 Like

Thank you Mario for taking this back to the original thread