Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
12 years ago

Cyclone V - Interrupt Handling

Hello,

i would like to know, how I can use interrupts in conjunction with a Cyclone V. (Comparative Avalon)

Do you probably have an example for me? I would like to trigger an interrupt using a button.

Thanks!

Greetings

14 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I realized I updated the Rocketboards mailing list but not this forum post with my solution to the problem (thanks for calling me out Bram!).

    I wrote the software side of things, however, I didn’t write the FPGA code that triggers the IRQ lines.

    It was my desire to be able to receive FPGA -> HPS interrupts in user space, so I wrote a simple module that accomplishes that. The module creates “fpgaint” devices under /dev for each “fpgaint” node present in the device tree that has interrupt information. A user space program can then open these devices and poll/read them to get interrupt triggers. I attached a patch that adds the module I created to the 3.9 Linux tree as well as 3 example nodes to the device tree to create the IRQ devices for FPGA_HPS IRQs 0, 1 and 2. Note that this module is very simple and has a pretty extreme limitation in that only 1 user space program can receive these interrupts from a fpgaint device node at a time. If someone wanted to expand the module so that more programs can wait on the fpgaint device node and have them all wake up at each interrupt, that would be excellent. ;) Also note that this patch has a bunch of debugging printks that you should probably remove if you want to actually use this stuff.

    I also attached a little test program that shows how to capture these interrupts in user space.

    In order to verify this stuff, I had our FPGA guy tie the FPGA_IRQ2 line to a simple register that I can write high or low to toggle the interrupt line. Then after insmoding the fpgaint module (with a device tree node for that interrupt line present), I ran the fpgaint_test.c program on the device created for that interrupt line (/dev/fpgaint2 according to my device tree node setup). I then performed the FPGA register writes to toggle the line and saw my test program receiving the interrupts in user space.

    The FPGA guy said this with respect to how we tested the interrupt interface: I routed the GPIO output register (from the HPS) to the IRQ lines. You were able to write to bits on that register and create an interrupt.

    Hopefully this is helpful to the folks on the forum.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Have there been any updates to your FPGAINT driver? It seems as though whenever I get a valid interrupt, the fgpaint_irq_handler gets repeatedly called and locks up my system. (I end up in an infinite loop with the "FPGA interrupt module: fpgaint_irq_handler called" output message on the console.) I am not a driver guru by any means but is your driver an edge or level triggered ISR? Also, it appears that the fpgaint_irq_handler process calls wake_up_interruptable(); Can you offer any assistance in understanding the connection between that call and my "user space" ISR?

    Thanx in advance.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi there, for those of you who are having trouble getting interrupts from the FPGA through to Linux, here are some pointers:

    1. Qn: I've written a custom Linux driver to catch interrupts on the FPGA IRQ line with GIC offset of 72. I see no interrupts happening. What is going on??

    Ans: If you are using a PIO core in Qsys to generate an interrupt, you need to manually enable the interrupts! Otherwise, the PIO core will never ever generate any interrupts (http://www.altera.co.uk/literature/ug/ug_embedded_ip.pdf pg.12-3) The Interrupt bit mask register (fancy name for the register to enable interrupts) is on offset 0x8 w.r.t PIO register base address.

    2. Qn: The IRQ handler gets repeatedly called! This locks up the system as you cannot do a normal CTRL+C to the terminal since it is loaded as a Linux Kernel Device driver.

    Ans: By default, interrupts on the ARM are level based (logic high) and not edge triggered. When an interrupt is generated by a PIO core, you need to reset the interrupts on the PIO core manually or else the interrupt line will stay high forever (you can confirm this via SignalTap). Since the IRQ line from the FPGA is always high unless you reset it, the ARM gets interrupted repeatedly!

    The IRQ reset register is located on offset 0xc. Writing any value to this register would reset the interrupts on the PIO core and the IRQ signal would return back to logic low.

    3. You can write to the IRQ bit mask register and IRQ reset register of the PIO core via SystemConsole. A more elegant method is to have your custom kernel driver write to the PIO registers directly (see http://zhehaomao.com/blog/fpga/2013/12/29/sockit-4.html)!

    4. Qn: How do you make a custom Linux Kernel Driver??

    Ans:

    -Check out these great tutorials to get you started: http://www.tldp.org/ldp/lkmpg/2.6/html/lkmpg.html ,http://zhehaomao.com/blog/fpga/2014/05/24/sockit-10.html

    -You can only build your custom Linux Kernel Driver on a Linux machine

    -Set up your terminal environment variables to point to the correct cross compiler: export PATH=.../altera-linux/linaro/gcc-linaro-arm-linux-gnueabihf-4.7-2012.11-20121123_linux/bin:$PATH

    -Locate the Linux kernel source code that you used to build your Linux kernel. If you are using a Yocto build flow, the path looks like: .../yocto/build/tmp/work/socfpga_cyclone5-poky-linux-gnueabi/linux-altera-dist-1.0-r1/linux-socfpga

    -The above step is crucial as Linux really really does not like it if you use a different kernel version to build your driver. For example, if you are using a 3.12 linux source code to build your kernel driver and try to load that kernel module on a 3.9 Linux version, it will throw errors that are extremely confusing to debug.

    -Use insmod <your kernel driver.ko> to load your custom Linux driver to your Linux kernel

    -Likewise, use rmmod <your kernel driver.ko> to unload your custom Linux driver

    -I have a simple example project where a custom written Linux driver registers interrupts from the FPGA user buttons. PM me for the Quartus Project, custom linux driver code and Makefile if you would like a simple example to get you started quickly.

    5. One last tip, Linux kernel driver development is very different from that of a userspace linux program. It can get very frustrating at times! Hell, it took me 2 full days just to set up my environment to build a simple hello_world kernel driver!! But persevere through and don't be discouraged!
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    On "2. Qn:": GIC may be programmed to Edge mode and you may not hold IRQ line from the FPGA in 1 longer than 1 tact.

    And clearing of GIC pendig bits not clear IRQ line from the FPGA !

    In Level mode interrupt handler MUST send a command to FPGA with clearing IRQ demand: GIC don't know about your hardware process.