Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Valued Contributor III
841 Views

push_button irq handler question

Hi, 

I use NEEK CycloneIII (CP3C25). App is quite simple it turns on the led corresponding the push button pressed (see code below). 

I copied irq handler procedure from standard binary_counter.c example and it doesn't work unless I put some delay at the end of handler. When I comment delay in the handler and debug my app it works fine, but when I run app in hardware it doesn't work. Any ideas why the app doesn't run propelry? 

 

# include <stdio.h># include "system.h"# include "alt_types.h"# include "sys/alt_irq.h"# include "altera_avalon_pio_regs.h" //#include <unistd.h> /* A variable to hold the value of the button pio edge capture register. */ volatile int edge_capture; /* button IRQ function */ static void handle_button_interrupts(void* context, alt_u32 id) { /* Cast context to edge_capture's type. It is important that this be * declared volatile to avoid unwanted compiler optimization. */ int delay; volatile int* edge_capture_ptr = (volatile int*) context; /* Store the value in the Button's edge capture register in *context. */ *edge_capture_ptr = IORD_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE); /* Reset the Button's edge capture register. */ IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE, 0); //now optional delay is commented /*delay=0x0; while (delay<100000) { delay++; } */ } /* Initialize the button_pio. */ static void init_button_pio() { /* Recast the edge_capture pointer to match the alt_irq_register() function * prototype. */ void* edge_capture_ptr = (void*) &edge_capture; /* Enable all 4 button interrupts. */ IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUTTON_PIO_BASE, 0xf); /* Reset the edge capture register. */ IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE, 0x0); /* Register the interrupt handler. */ alt_irq_register( BUTTON_PIO_IRQ, edge_capture_ptr, handle_button_interrupts ); } static void handle_button_press(alt_u8 type) { /* Button press actions while counting. */ if (type == 'r') { IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, ~edge_capture); } } int main() { IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, 0xf); while (1) { if(edge_capture!=0) { handle_button_press('r'); } } return 0; }
0 Kudos
8 Replies
Highlighted
Valued Contributor III
6 Views

Some remarks: 

 

I can't see the init_button_pio() call in main. Anyway I think you have it, otherwise the code won't work in neither case, delay or not. 

 

Try to directly assign edge_capture in interrupts handler, instead of using the context pointer. 

 

Did you enable edge capture register for your PIO in SOPC builder? 

If not, probably the interrupt would continuously retrigger when button is pressed and this could explain the behaviour you are observing.
0 Kudos
Highlighted
Valued Contributor III
6 Views

Hi, 

 

Just a question, why do you not call the function init_button_pio in your main ? 

Because, like this, I would say it should do nothing since you do not initialize the interrupt. 

 

Jérôme 

0 Kudos
Highlighted
Valued Contributor III
6 Views

Also, the main program seems to copy the 'edge capture' value to the leds whenever the value is non-zero. This may not be what you had in mind! 

Once set, nothing probably zeros it either. 

Outputting a counter to the leds might be more informative.
0 Kudos
Highlighted
Valued Contributor III
6 Views

I haven't looked at your code closely but this sounds an awful lot like a simple button bounce issue. A common way to account for button bounce is to simply add a delay after first detecting the button press.

0 Kudos
Highlighted
Valued Contributor III
6 Views

Hi, 

Thanks to everybody for advises. I tried to put IOWR_ALTERA_AVALON_PIO_DATA(...) in the handler, but it didn't help either. 

One thing I noticed that in a debug mode when i press button once there is a number of interrups occur. Can it be because of the button bounce?
0 Kudos
Highlighted
Valued Contributor III
6 Views

This code works fine even with such delay in the handler. Without this delay I noticed only quick flash on the corresponding led.  

Unfortunately, I still don't understand the core of the problem:( 

 

/* * "Hello World" example. * * This example prints 'Hello from Nios II' to the STDOUT stream. It runs on * the Nios II 'standard', 'full_featured', 'fast', and 'low_cost' example * designs. It runs with or without the MicroC/OS-II RTOS and requires a STDOUT * device in your system's hardware. * The memory footprint of this hosted application is ~69 kbytes by default * using the standard reference design. * * For a reduced footprint version of this template, and an explanation of how * to reduce the memory footprint for a given application, see the * "small_hello_world" template. * */ # include <stdio.h># include "system.h"# include "alt_types.h"# include "sys/alt_irq.h"# include "altera_avalon_pio_regs.h" //#include <unistd.h> /* A variable to hold the value of the button pio edge capture register. */ volatile int edge_capture; /* button IRQ function */ static void handle_button_interrupts(void* context, alt_u32 id) { int delay; IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, ~IORD_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE)); IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE, 0); delay=0x1; while (delay<1) { delay++; } } /* Initialize the button_pio. */ static void init_button_pio() { /* Recast the edge_capture pointer to match the alt_irq_register() function * prototype. */ void* edge_capture_ptr = (void*) &edge_capture; /* Enable all 4 button interrupts. */ IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUTTON_PIO_BASE, 0xf); /* Reset the edge capture register. */ IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE, 0x0); /* Register the interrupt handler. */ alt_irq_register( BUTTON_PIO_IRQ, edge_capture_ptr, handle_button_interrupts ); } int main() { printf("Hello from Nios II!\n"); init_button_pio(); IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, 0xf); while (1); return 0; }
0 Kudos
Highlighted
Valued Contributor III
6 Views

Try just displaying a binary count on the LEDs, this should increment once per button push. The usleep call should take care of debounce. 

# include "unistd.h" //provides usleep function 

 

unsigned int gCount //global counter 

 

static void handle_button_interrupts(void* context, alt_u32 id) 

gCount++; 

 

IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, (gCount & 0x0F)); 

 

usleep(1000); //wait for 1 ms before clearing the button 

 

IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE, 0); 

 

in init_button_pio() add the line "gCount = 0;" 

 

This should show a binary count on the LEDs that increments each time the interrupt occurs.
0 Kudos
Highlighted
Valued Contributor III
6 Views

Tried to display increment. That's what i got. 

1. If I put usleep before IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE, 0); it is incremented twice per button push. 

2. If I put usleep after clearing function it is incremented once per button push. 

 

So i conclude the delay after clearing edge_capture reg is necessary.
0 Kudos