Programmable Devices
CPLDs, FPGAs, SoC FPGAs, Configuration, and Transceivers
21602 Discussions

Cyclone V - Interrupt Handling

Altera_Forum
Honored Contributor II
9,146 Views

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
0 Kudos
14 Replies
Altera_Forum
Honored Contributor II
6,527 Views

Yes you can as long as you use a later version of the tools. I forget when they were introduced but 12.1 SP1 or later should have the feature. The HPS has 64 bits of interrupt lines that originate in the FPGA fabric that are sent to the HPS. These interrupt lines connect to the generic interupt controller (GIC) in the MPU subsystem. The MPU subsystem chapter in the device handbook contains the mapping of the FPGA interrupt lines to GIC interrupt numbers, off the top of my head FPGA interrupt [0] connects to GIC interrupt [72]: http://www.altera.com/literature/hb/cyclone-v/cv_54006.pdf 

 

When you connect the PIO to the HPS, use the lightweight HPS-to-FPGA bridge for the memory mapped accesses to the PIO. That lightweight bridge is for accessing CSRs like the PIO. Also the FPGA-to-HPS interrupts are 64-bit but Qsys only supports 32-bit interrupts. As a result the HPS exposes two interrupt receivers, one for the lower 32 bits and the other for the upper 32 bits. 

 

Alteratively you can also configure unused HPS I/O as GPIO and use them instead of the FPGA fabric. Each HPS GPIO is capable of generating interrupts as well.
0 Kudos
Altera_Forum
Honored Contributor II
6,527 Views

I am using 13.0sp1 and when I enable the 64 fpga2hps interrupt lines, I can't figure out how to make a connection to these interrupt lines. There is no interface created in Qsys and the generated soc_system.v file does not bring these interrupts out to a port. It does create two internal wires: 

 

wire [31:0] hps_f2h_irq0_irq; // irq_mapper:sender_irq -> hps:f2h_irq_p0 

wire [31:0] hps_f2h_irq1_irq; // irq_mapper_001:sender_irq -> hps:f2h_irq_p1 

 

and these wires do connect to the hps instantiation, but I don't see how to make an external connection to any of these lines. Compiling the design with these turned on does generate an extra warning: 

 

Warning (11713): The configuration of the Hard Processor Subsystem (HPS) within this design has changed. 

The Preloader software that initializes the HPS requires an update. 

Using hps_isw_handoff/soc_system_hps/, run the Preloader Support Package Generator to update your Preloader software 

 

This warning seems to indicate that the preloader is responsible for setting up these connections, but I'm not sure how to make the connection on the fpga side? Is there another component that needs to be instantiated in qsys? Is there another setting that needs to be done in the hps parameter settings? Is this another feature that is not available with the current tools but will be available in a future release (13.1)?
0 Kudos
Altera_Forum
Honored Contributor II
6,527 Views

Interrupt wiring is a little different in Qsys. Over on the right side of your system you should see another patch panel where you can type numbers into them. The numbers normally represents interrupt priority but in the case of the HPS they represent which interrupt bit you are connecting a perheriphals interrupt to out of the group of 32. The interrupt priority is determined by how the generic interrupt controller settings inside the HPS and not the numbers you choose in Qsys, the numbers are just determining connectivity.

0 Kudos
Altera_Forum
Honored Contributor II
6,527 Views

Yes, of course. I see the interrupt connection you're talking about in Qsys. Thanks.

0 Kudos
Altera_Forum
Honored Contributor II
6,527 Views

Hello, 

 

I'm currently trying to make use of the FPGA -> HPS interrupt lines as well and I'm running into issues. In summary, I have interrupts coming in from the FPGA on FPGA_IRQ0 and FPGA_IRQ1 (GIC interrupts 72 and 73) and an IRQ handler registered for these same lines. However, I never see the interrupts appear in Linux. See the below cat /proc/interrupts (my module is "fpgaint"): 

 

CPU0 CPU1 

29: 15752236 15740759 GIC twd 

72: 0 0 GIC fpgaint0 

73: 0 0 GIC fpgaint1 

147: 47023 0 GIC eth0 

160: 1 0 GIC dwc_otg, dwc_otg_hcd:usb1 

171: 2052 0 GIC dw-mci 

 

By peeking around the ARM GIC registers, I verified that the triggering is set properly according to the nodes I placed in the device tree (edge triggered) and that the interrupts are in fact enabled. So at this point I'm confident that the Linux setup and the ARM GIC setup are correct. I've read the GIC interrupt status register as well and never see my interrupt lines go high. I'm currently working with our hardware engineer to verify the interrupt lines are going high from the FPGA side using SignalTap. 

 

 

I noticed in the above discussion that after enabling these interrupt lines in the FPGA build, the preloader needed to be regenerated. I looked through the handoff files and I don't see anything that corresponds to these interrupt lines.  

 

Overall, I have the below questions: 

 

 

  1. What exactly needs to be done at the initialization stage by the preloader to enable these interrupt paths? 

  2. Which variables get modified in the handoff files when these interrupt lines are enabled (so I can trace to ensure my preloader is handling this)? 

  3. Is there anything else that comes to mind that might be going wrong here? Do some bridges need to be released from reset? 

  4. I don't know anything about FPGA code but is there any special way that these interrupts have to be generated? Or is simply pulsing that line sufficient for edge triggered configuration? 

 

 

I appreciate any guidance either of you could give. 

 

Thanks, 

 

-Chris
0 Kudos
Altera_Forum
Honored Contributor II
6,527 Views

I can't speak for the software side but for the hardware there is no need to release the bridges for IRQs from the FPGA to propogate through to the GIC in the HPS. The IRQs from the FPGA are considered asynchronous so they undergo clock domain crossing followed by edge detection so you might need a wider IRQ pulse from the FPGA side. What clock frequency do you use the MPU and the FPGA logic generating the interrupt, and how many clock cycles does the FPGA logic assert the IRQ for?

0 Kudos
Altera_Forum
Honored Contributor II
6,527 Views

" Over on the right side of your system you should see another patch panel where you can type numbers into them." 

I am sorry but I am not immediately seeing a place where I can type numbers on the right side.  

Has this changed in 13.1, or can somebody maybe post a screenshot ? 

Or should something be enabled first before you get this option ?
0 Kudos
Altera_Forum
Honored Contributor II
6,527 Views

You might need to scroll the system panel to the right to see it. It'll be a column to the right of the HPS and all the other components in your system. You might also have interrupts filtered from the UI so if you click the filter button you can expose the interrupts (I normally just click the "all" filter so that I can see everything). 

 

Last but not lease make sure the interrupt interface for the HPS is enabled in the HPS component, otherwise those interrupt lines will not be exposed in Qsys.
0 Kudos
Altera_Forum
Honored Contributor II
6,527 Views

I am not at the setup right now so this is from memory, but we can see a column named IRQ(s), it is just now obvious what we can do with it.  

There are some short horizontal lines/diamonds(?) in it at some locations , but there not immediately an obvious way to make a connection between them and the HPS component.  

Based on your comment we started looking for some kind of input field for numbers, but we can't see that either. 

Probably we are just overlooking something very obvious (sorry ;p), I will try to add a screenshot tomorrow. 

 

>Last but not lease make sure the interrupt interface for the HPS is enabled in the HPS component, otherwise those interrupt lines will not be exposed in Qsys.  

By that you mean 'Enable FPGA-to-HPS Interrupts' as eg mentioned in http://www.altera.com/literature/hb/cyclone-v/cv_54027.pdf p 27-6, right ? 

(this is enabled)
0 Kudos
Altera_Forum
Honored Contributor II
6,527 Views

The interrupt column represents connectivity. The HPS exposes two 32-bit interrupt receivers (input) and you connect the interrupt sender (output) from the peripherals to either of the HPS interrupt receivers. Once connected you can type a number between 0 and 31 in the interrupt connection to specify the interrupt mapping. irq receiver 0 interrupts between 0-31 map the HPS GIC interrupts 72-103 and irq receiver 1 interrupts between 0-31 map to HPS GIC interrupts 104-135. 

 

You might be wondering why there are two interrupt recievers, it's a limitation of Qsys that an interrupt reciever can only be up to 32-bits wide. So because the HPS exposes 64 interrupts it was split into two interrupt reciever interfaces. 

 

My recommendation would be to look at an existing design like the golden hardware reference design so that you can see how the interrupts are connected in it. Just make note of which interrupt numbers you choose in Qsys since that determines which GIC interrupt number will be used. You can find the GIC numbers in table 6-2 in this chapter: http://www.altera.com/literature/hb/cyclone-v/cv_54006.pdf
0 Kudos
Altera_Forum
Honored Contributor II
6,527 Views

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.
0 Kudos
Altera_Forum
Honored Contributor II
6,527 Views

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.
0 Kudos
Altera_Forum
Honored Contributor II
6,527 Views

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!
0 Kudos
Altera_Forum
Honored Contributor II
6,527 Views

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.
0 Kudos
Reply