PYNQ: PYTHON PRODUCTIVITY FOR ZYNQ

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

2 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 Peter,
I have followed your reference, but sometime it registers the interrupt and sometime its not.
I mean if i run for the first time it wored fine and if i restart the notebook then its not working anymore.