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++
12597 Discussions

uclinux PIO device driver interrupt handler not execute

Altera_Forum
Honored Contributor II
2,326 Views

Hi, 

 

Thanks in advance for any help I can get. I have a NIOS2 w/MMU running uClinux v3.7. It's a DE2-115 development kit with Cyclone IV FPGA. I use the PIO megafunction to monitor input rising edge from the SMA pin and generate interrupt IRQ. I developed an uClinux device driver in the misc folder. All seem correct and compile, but the handler function doesn't seem like it was executed when I generate a pulse signal to the SMA.  

 

Here is my device driver code: 

 

in the probe function call 

- res_mem = platform_get_resource(pdev, IORESURCE_MEM, 0) 

- request_mem_region(res_mem->start, resource_size(res_mem), "GPIO_NAME") 

- of_iomap(pdev->dev.of_node, 0); 

- irq = irq_ofparse_and_map(pdev->dev.of_node, 0) 

- request_irq(irq, pps_gpio_irq_handler, 1, "GPIO_NAME", NULL); 

 

in the interrupt handler call 

static irqreturn_t pps_gpio_irq_handler(int irq, void *dev_id) 

printk(KERN_ALERT "Trigger"); 

return IRQ_HANDLED; 

 

If I execute command "cat /proc/interrupt", the driver was successful requested. 

 

2: 0 NIOS2-INTC GPIO_NAME 

 

As you can see, the interrupt count didn't get incremented and "Trigger" was never print out after I apply a pulse signal to the SMA port. Is there a function call I am missing? or anything that I miss?
0 Kudos
14 Replies
Altera_Forum
Honored Contributor II
805 Views

Hi, 

 

 

--- Quote Start ---  

All seem correct and compile, but the handler function doesn't seem like it was executed when I generate a pulse signal to the SMA.  

 

--- Quote End ---  

 

 

At first, please check whether the interrupt signal (irq No.2 in this case?) is asserted or not. This check is easily done by using your Signal Tap II. 

 

Kazu
0 Kudos
Altera_Forum
Honored Contributor II
805 Views

 

--- Quote Start ---  

Hi, 

 

 

 

At first, please check whether the interrupt signal (irq No.2 in this case?) is asserted or not. This check is easily done by using your Signal Tap II. 

 

Kazu 

--- Quote End ---  

 

 

Hi Kazu, 

 

You are right about the irq signal isn't asserted. I took a screen shot of the signaltap II (attached) and find out the chip select and input clock isn't either. I use the PIO IP in the QSYS and configure it as follow. 

clk -> 50Mhz PLL 

s1 -> clock crossing bridge ->NIOS2 CPU data master bus 

reset -> clock and jtag reset lines 

external_connection -> ext_pins 

 

The PIO configuration are 

Width: 1 

Input 

Edge Capture regiser -> Synchronously capture (check) Edge Type: Rising 

Interrupt: Generate IRQ (check) IRQ Type: Edge 

 

Any help is greatly appreciated. 

 

Thanks, 

 

Yeung
0 Kudos
Altera_Forum
Honored Contributor II
805 Views

Hi, 

 

 

--- Quote Start ---  

 

You are right about the irq signal isn't asserted. I took a screen shot of the signaltap II (attached) and find out the chip select and input clock isn't either.  

 

--- Quote End ---  

 

 

Did you set the 'interruptmask register' of your PIO core ? And how many frequencies did you use for capturing of Signal Tap II ? 

 

Kazu
0 Kudos
Altera_Forum
Honored Contributor II
805 Views

Hi, 

 

Thank you very much. I think this may causing the problem, but please correct me if I am mistaken, isn't interrupt mask register select enabled when the "Generate IRQ" is check in the QSYS? 

 

Yeung
0 Kudos
Altera_Forum
Honored Contributor II
805 Views

Hi, 

 

 

--- Quote Start ---  

 

isn't interrupt mask register select enabled when the "Generate IRQ" is check in the QSYS? 

 

--- Quote End ---  

 

 

In general, you must prepare functions to set and reset the bits of interrupt mask register in your driver, because let the kernel make it enable or disable. And you can also observe the status of interrupt mask register bits by your Signal Tap II. 

 

Kazu
0 Kudos
Altera_Forum
Honored Contributor II
805 Views

I tried to do couple things in my uClinux device driver to enable the interrupt. 

1) Enabling the PIO Core interrupt: 

Because my PIO base address is 0x00000060 on the a clock_crossing_bridge w/ base address of 0x08200000, my driver define base address is 0x082000060 (<-Is this correct?) 

# define ALTERA_PIO_BASE_ADDRESS 0x08200060 

# define ALTERA_OFFSET_DATA 0x00 

# define ALTERA_OFFSET_DIRECTION 0x01 

# define ALTERA_OFFSET_IRQ_MASK 0x02 

# define ALTERA_OFFSET_EDGE_CAPTURE 0x03 

... 

in probe function I have 

volatile int *base_addr = (int *) ALTERA_PIO_BASE_ADDRESS; 

... 

*(base_addr + ALTERA_OFFSET_IRQ_MASK) = 0x01; //One input PIO from the SMA pin in the DE2-115, rising edge interrupt generator 

 

2) __builtin_wrctl(3, 3); //irq2, write into ienable register (3) 

__builtin_wrctl(0, 1); //write 1 into status register (0) to enable PIE 

 

I got Kernel panic - not syncing: Oops 

Unable to handle kernel paging request at virtual address 08200000 

ea = c70e418c, ra = c70e4178, cause =15 

 

Did I write into or enable the wrong interrupt? my irq_mask is definite not turn on showing in the signaltapII. Any help is greatly appreciated. 

 

Yeung
0 Kudos
Altera_Forum
Honored Contributor II
805 Views

Hi, 

 

 

--- Quote Start ---  

 

1) Enabling the PIO Core interrupt: 

Because my PIO base address is 0x00000060 on the a clock_crossing_bridge w/ base address of 0x08200000, my driver define base address is 0x082000060 (<-Is this correct?)# define ALTERA_PIO_BASE_ADDRESS 0x08200060# define ALTERA_OFFSET_DATA 0x00# define ALTERA_OFFSET_DIRECTION 0x01# define ALTERA_OFFSET_IRQ_MASK 0x02# define ALTERA_OFFSET_EDGE_CAPTURE 0x03 

... 

in probe function I have 

volatile int *base_addr = (int *) ALTERA_PIO_BASE_ADDRESS; 

... 

*(base_addr + ALTERA_OFFSET_IRQ_MASK) = 0x01; //One input PIO from the SMA pin in the DE2-115, rising edge interrupt generator 

 

2) __builtin_wrctl(3, 3); //irq2, write into ienable register (3) 

__builtin_wrctl(0, 1); //write 1 into status register (0) to enable PIE 

 

I got Kernel panic - not syncing: Oops 

Unable to handle kernel paging request at virtual address 08200000 

ea = c70e418c, ra = c70e4178, cause =15 

 

 

--- Quote End ---  

 

 

At first, please don't forget the existence of MMU. All cpu's memory accesses are filtered by it. So you must convert the virtual address 0x08200000 to I/O memory space one. According to the formal way, you should use the function 'ioremap' like 

 

volatile int *base_addr = ioremap(ALTERA_PIO_BASE_ADDRESS, 16);  

 

but for the convenience test, please try next code 

volatile int *base_addr = (int *) (ALTERA_PIO_BASE_ADDRESS | 0xe0000000);  

 

And because cpu's control registers are controlled by the kernel core, you don't need to tamper those like 

 

__builtin_wrctl(3, 3); //irq2, write into ienable register (3) __builtin_wrctl(0, 1); //write 1 into status register (0) to enable PIE  

 

There is also a formal way to set or reset these bits, so you should not touch control registers directly except the case you are sure what you do. 

 

Kazu
0 Kudos
Altera_Forum
Honored Contributor II
805 Views

Hi Kazu, 

 

You are right. I have left out the virtual memory to be part of the base address. After I included the MMU, the interrupt handler function trigger when there is a rising edge. You have mentioned there is a formal way to set and reset the ienable and status register without implementing directly into the control registers. Which function call are you referring to? 

I apologize for another dope question regarding clearing the interrupt flag. Do I have to clear the "edge_capture" register in the interrupt handler function? 

*(ALTERA_BASE_ADDRESS + 0x03) = 0x00 

 

Thanks again, 

 

Yeung
0 Kudos
Altera_Forum
Honored Contributor II
805 Views

Hi, 

 

 

--- Quote Start ---  

 

You have mentioned there is a formal way to set and reset the ienable and status register without implementing directly into the control registers. Which function call are you referring to? 

 

--- Quote End ---  

 

 

Please refer the file 'linux-*.*/include/linux/irqflags.h'. For example, 'local_irq_disable()' reset the PIE bit.  

 

 

--- Quote Start ---  

 

Do I have to clear the "edge_capture" register in the interrupt handler function? 

*(ALTERA_BASE_ADDRESS + 0x03) = 0x00 

 

--- Quote End ---  

 

 

Please refer the data sheet of Altera's PIO core. How can you de-assert the interrupt signal for NiosII cpu ? In general, NiosII uses level triggered interruption. 

 

Kazu
0 Kudos
Altera_Forum
Honored Contributor II
805 Views

Got it! Thanks for your help.  

 

Do you know a good way to get time(second/usecond)? I tried to use the do_gettimeofday function call in the interrupt handler but with random timestamp return. Sometime it jump back time as well. If you may know, can you kindly point me to a right direction? 

 

Yeung
0 Kudos
Altera_Forum
Honored Contributor II
805 Views

Hi, 

 

 

--- Quote Start ---  

 

Do you know a good way to get time(second/usecond)? I tried to use the do_gettimeofday function call in the interrupt handler but with random timestamp return. Sometime it jump back time as well. If you may know, can you kindly point me to a right direction? 

 

--- Quote End ---  

 

 

What 'jump back time' means? 

 

/** * do_gettimeofday - Returns the time of day in a timeval * @tv: pointer to the timeval to be set * * NOTE: Users should be converted to using getnstimeofday() */ void do_gettimeofday(struct timeval *tv) { struct timespec now; getnstimeofday(&now); tv->tv_sec = now.tv_sec; tv->tv_usec = now.tv_nsec/1000; }  

 

'tv_sec' will not increase monotonously ? How does the command 'date' response in your shell ? 

 

Kazu
0 Kudos
Altera_Forum
Honored Contributor II
805 Views

Hi Kazu, 

 

The jump back time I have experience with do_gettimeofday is captured in attached jpg. I apologize the terminology I use may cause confusion. The timestamp showing unreliable outcome. The major concern I have here is the GPIO receive pulse signal supposedly every 100ms so the interrupt handler get trigger on each pulse's rising edge and grab the current timestamp. Nonetheless, as the picture have show, it receive interrupt in 4, 11, 20, or even 40 msec, but not 100msec in between. The input signal come from a signal generator and verified with a scope to ensure each pulse is 100msec in between. I am trying to narrow down the cause of this problem by trying various setting to request_irq and using jiffies to see any different. The results are the same. Is it because I am not suppose to call timestamp in an interrupt handler? or was it because the system can't handle the fast pace pulse trigger? Any help is greatly appreciated.  

 

Following is my interrupt handler: 

static irqreturn_t gpio_irq_handler(int irq, void *dev_id) 

int ipending = __builtin_rdctl(4); 

 

if((ipending & 0x03) > 0) 

*(base_addr + 3) = 0;//Clear the Edge Capture 

do_gettimeofday(&tv); 

time_to_tm(tv.tv_sec, 0, &broken); 

printk ("%02d:%02d:%02d:%03ld\n",broken.tm_hour, broken.tm_min, broken.tm_sec, (tv.tv_usec/1000)); 

///////////////////////////////////////////////////////////////////////////////  

return IRQ_HANDLED; 

 

Yeung
0 Kudos
Altera_Forum
Honored Contributor II
805 Views

Hi, 

 

 

--- Quote Start ---  

 

Following is my interrupt handler: 

static irqreturn_t gpio_irq_handler(int irq, void *dev_id) 

int ipending = __builtin_rdctl(4); 

 

if((ipending & 0x03) > 0) 

*(base_addr + 3) = 0;//Clear the Edge Capture 

do_gettimeofday(&tv); 

time_to_tm(tv.tv_sec, 0, &broken); 

printk ("%02d:%02d:%02d:%03ld\n",broken.tm_hour, broken.tm_min, broken.tm_sec, (tv.tv_usec/1000)); 

///////////////////////////////////////////////////////////////////////////////  

return IRQ_HANDLED; 

 

--- Quote End ---  

 

 

Did you take account of the execution time of 'printk' ? Please consider what will happen if it will take over 100msec. And you don't need to check 'ipending', because the kernel checks it and calls this handler. But it's better for you to check whether the edge is really captured or not. 

 

Kazu
0 Kudos
Altera_Forum
Honored Contributor II
805 Views

Hi Kazu, 

 

I have experience missing receive bytes using UART RS232 port on uClinux running NIOS2 /f. I implemented a loopback application to send 128 bytes hex data from ttyA0 (RS232 port) and receive on ttyA5 (RS232 port). This is a DE2-115 development kit. The IRQ for both port is 1 and 2. I have a JTAG for nios2-terminal, but it's irq is 3. I have disabled the flow control (ctsrts, xon/xoff,etc), but each loopback test I do, I always missing 10 to 11 bytes. However, if I send less than 10 bytes of data, I have higher chance of success getting the same bytes across. I have heard I need a FIFO MEGAIP for the design but there no current uClinux driver support it. If you know of this problem and have a solution to it, please kindly let me know what I am missing? 

 

Thanks, 

 

Yeung
0 Kudos
Reply