Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++

Interrupt problem

Altera_Forum
Honored Contributor II
1,151 Views

Hi 

 

We are developing our own board. We use interrupts and DMA to transfer data between FPGA and linux kernel in Nios. 

 

We get an interrupt when data is available in the FPGA FIFO. Then we start transferring data from the FIFO into a kernel ring buffer using DMA. DMA controller sends an interrupt when data is transferred, and we check the DMA status register to see if everything is OK. Data interrupt and DMA interrupt uses different IRQ number. We use PIO and edge-trigged interrupts for data. 

 

The problem is: 

Sometimes we receive extra interrupts on both interrupt lines. We know this because DMA controller will only send interrupts when the DONE bit is set in the status register, and we receive interrupts also when the DMA status register is 0x00. 

 

The same goes for the data interrupt. Here we receive interrupts when we are in the middle of processing the last interrupt, e.g. in the middle of a DMA transfer. We know this because when we get our own generated "data ready"-interrupt, the fifo is cleared and a header word is placed on top of the fifo.  

 

Is there any software or hardware errors that may cause this behavior? 

 

We previously used IRQ 0 for timer, but we have now changed this and we are not using IRQ 0 anymore. That did not fix our problem. 

 

Here is a list of interrupts currently used in the kernel: 

1: 7672339 L timer 

2: 18311178 dmac-0 

6: 51344 eth0 

7: 18676714 dataready 

9: 19914 NIOS serial 

10: 0 NIOS serial 

 

We use kernel 2.6.17, Intel StrataFlash P30 and a SMC91111 ethernet controller. 

 

Regards, 

Hein Gustavsen
0 Kudos
4 Replies
Altera_Forum
Honored Contributor II
311 Views

In general, you should use level trigger interrupt, which should be more reliable for Linux. 

Since the source of interrupts are inside the fpga, there is no need to use PIO for edge trigger. 

You should generate level trigger interrupt, and drive it directly to CPU. 

Then clear the interrupt request in your service routine.
0 Kudos
Altera_Forum
Honored Contributor II
311 Views

 

--- Quote Start ---  

originally posted by hippo@Oct 25 2006, 03:13 PM 

in general, you should use level trigger interrupt, which should be more reliable for linux. 

since the source of interrupts are inside the fpga, there is no need to use pio for edge trigger. 

you should generate level trigger interrupt, and drive it directly to cpu. 

then clear the interrupt request in your service routine. 

<div align='right'><{post_snapback}> (index.php?act=findpost&pid=18903) 

--- quote end ---  

 

--- Quote End ---  

 

 

Thank you for your reply. 

 

We will start using level trigged interrupts, but this does not affect the DMA controller interrupts. I have created a module to test DMA transfer only, and I still get extra interrupts with status 0x00. See source code below. The invalid interrupt is trigged in addition to the correct interrupt. 

 

How is this possible? Can this be a hardware related error? 

 

#include <linux/interrupt.h># include <linux/i2o.h># include <asm/dma.h># include <asm/nios.h> MODULE_LICENSE("GPL"); # define DEVICE_NAME "dmatest"# define FIFO_ADDRESS na_DSP_data_fifo_avalonS# define FIFO_COUNT 256 void *buffer; dma_addr_t dma_handle; struct device dev; static void start_dma(void *dev_id) {        /* Set DMA destination address */        nios2_set_dma_waddr(0, dma_handle);        /* Set DMA count */        set_dma_count(0, FIFO_COUNT);        // Start DMA transfer        enable_dma(0); } static DECLARE_WORK(start_dma_work, start_dma, (void*)&dev); static int dmatest_handle_dma(void *dev_id, int stat) {        if (stat & 0x01)                schedule_work(&start_dma_work);        else                printk(KERN_ERR "Invalid DMA status 0x%.2X\n",stat);        return IRQ_HANDLED; } static int __init dmatest_init(void) {        // allocate memory for DMA transfer        buffer = dma_alloc_coherent(&dev, FIFO_COUNT, &dma_handle, GFP_KERNEL);        if (!request_dma(0, DEVICE_NAME)) {                nios2_set_dma_handler(0, dmatest_handle_dma, &dev);                nios2_set_dma_data_width(0, 0x04);                nios2_set_dma_rcon(0, 1);                nios2_set_dma_wcon(0, 0);                nios2_set_dma_raddr(0, FIFO_ADDRESS);        }        else {                printk(KERN_ERR DEVICE_NAME ": request_dma failed\n");                return -1;        }        printk(KERN_ERR "Start DMA test transfer (0x%.8X,0x%.8X)\n",(unsigned)buffer,dma_handle);        start_dma(&dev);        return 0; } static void __exit dmatest_exit(void) {        disable_dma(0);        free_dma(0);        dma_free_coherent(&dev, FIFO_COUNT, buffer, dma_handle); } module_init(dmatest_init); module_exit(dmatest_exit); 

 

Hein
0 Kudos
Altera_Forum
Honored Contributor II
311 Views

 

--- Quote Start ---  

originally posted by heing+oct 26 2006, 12:07 pm--><div class='quotetop'>quote (heing @ oct 26 2006, 12:07 pm)</div> 

--- quote start ---  

<!--quotebegin-hippo@Oct 25 2006, 03:13 PM 

in general, you should use level trigger interrupt, which should be more reliable for linux. 

since the source of interrupts are inside the fpga, there is no need to use pio for edge trigger. 

you should generate level trigger interrupt, and drive it directly to cpu. 

then clear the interrupt request in your service routine. 

<div align='right'><{post_snapback}> (index.php?act=findpost&pid=18903) 

--- quote end ---  

 

--- Quote End ---  

 

 

Thank you for your reply. 

 

We will start using level trigged interrupts, but this does not affect the DMA controller interrupts. I have created a module to test DMA transfer only, and I still get extra interrupts with status 0x00. See source code below. The invalid interrupt is trigged in addition to the correct interrupt. 

 

How is this possible? Can this be a hardware related error? 

[/b] 

--- Quote End ---  

 

 

Here is some more information regarding the problem. 

 

I have taken a screen shot from our oscilloscope: 

image from oscilloscope (http://www.gustavsen.cc/images/interrupts.png

 

Channel 1 is a pulse trigged from my interrupt handler. The short pulses are OK, but the long pulse indicates that the interrupt handler is called even if the interrupt signal is low, which should not be possible. 

 

Channel 2 is the interrupt signal. The signal is set high by the FPGA when data is written to a FIFO and cleared by my interrupt handler. The long pulse here indicates that the interrupt is handled much later than usual. The previous and next interrupts are OK. 

 

This situation happens at with even intervals. The interval depends on the interrupt rate. Sometimes it is every 4 seconds, and sometimes it is every 17s. 

 

My question is why the interrupt handler is called later sometimes, and is it possible for the kernel to trig interrupt handlers without an external interrupt? 

 

As I mentioned in my earlier post, we have this problem with DMA too, but AFAIK we cannot probe DMA interrupt with the scope since it is internal in NIOS. 

 

Do you have any tips for further troubleshooting? 

 

Regards 

Hein Gustavsen
0 Kudos
Altera_Forum
Honored Contributor II
311 Views

heing, 

sorry, I have never used the altera&#39;s DMA core nor the DMA driver. 

I always use custom DMA. So I can&#39;t help you on this. 

Maybe you can check the Microtronix&#39;s DMA driver in more details. 

And cross check with the DMA driver of other arch. 

Try register irq yourself, and bypass the DMA driver. 

 

Hippo
0 Kudos
Reply