I was playing around with this example. I had the same issues as @jancumps .
I believe that the PYNQ implementation is correct/good enough. The main problem was that the block design automation decided to change the interrupt inputs to use the “level detection”, which results in an interrupt being sent immediately after clearing it because timer1.register_map.TCSR0.T0INT = 1
is only set after the waiting is over. Therefore, during the wait operation, the interrupt will be triggered, PYNQ sees the new input and clears it, and lets wait
continue. Now, because the interrupt line from the timer is still high and “level detection” is used, another interrupt is immediately triggered. And only afterwards are we able to disable the interrupt from the timer.
I then tested if changing the level detection to “edge” will fix the observed behavior, because only one interrupt should be triggered. This did indeed fix the behavior.
In conclusion, I believe that PYNQ does work as intended. When setting the interrupt controller to do “edge detection”, it works as expected.
I am, however, curious how one would try to work with “level detection” in PYNQ. There would probably be need a way to be able to execute some code right before the clear command is sent to the interrupt controller (https://github.com/Xilinx/PYNQ/blob/master/pynq/interrupt.py#L235 ).
Please mention/describe this issue regarding the level interrupt detection type in the newly added documentation:
By default it chooses level detection:
Had to set interrupt detection to use edge detection manually:
Block diagram (as described in this example, I did use timers to generate interrupts):