How to use interrupt in the bare-metal mode on Cyclone V?

I try to run the simple code for GPIO’s interrupt on a SoCkit board (Cyclone V).
When I configure interrupt as level-sensitive, it seems to work properly, and the ISR is called many times when i press a buttton on the board. But when i configure the interrupt as edge sensitive, it doesn’t work properly. The ISR is called when i press the button first time, and then called again and again, as if interrupt in level mode. I tried all possible combinations of level/edge modes and polarity modes, but it doesn’t work.

My example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <inttypes.h>
#include “alt_interrupt.h”
#include “alt_timers.h”
#include “alt_generalpurpose_io.h”

        volatile bool blink = false;

        /******************************************************************************/
        /*!
         * ISR Callback
         *
         * \param       icciar
         * \param       context ISR context.
         * \return      none
         */
        static void gpio_isr_callback() {

        	long mask = alt_gpio_port_int_status_get(ALT_GPIO_PORTC);
        	// Clear interrupt source don't care about the return value
        	long status = alt_gpio_port_int_status_clear(ALT_GPIO_PORTC, 0x00200000);
        	mask = alt_gpio_port_int_status_get(ALT_GPIO_PORTC);
        	alt_gpio_port_data_write(ALT_GPIO_PORTB, 0x0F000000, blink << 24);
        	blink = !blink;
        }

        /******************************************************************************/
        /*!
         * Main entry point
         *
         */
        int main(void) {
        	alt_gpio_init();
        	alt_gpio_port_datadir_set(ALT_GPIO_PORTB, 0x0F000000, 0x0F000000);
                // System init
                alt_gpt_all_tmr_init();
                // Setup Interrupt
        	alt_int_global_init();
                // Initialize CPU interrupts
                alt_int_cpu_init();
                // Set interrupt distributor target
                int cpu_target = 0x1; //CPU0 will handle the interrupts
                alt_int_dist_target_set(ALT_INT_INTERRUPT_GPIO2, cpu_target);
                // Set interrupt trigger type
                alt_int_dist_trigger_set(ALT_INT_INTERRUPT_GPIO2, ALT_INT_TRIGGER_EDGE);
                // Enable interrupt at the distributor level
                alt_int_dist_enable(ALT_INT_INTERRUPT_GPIO2);
                // Enable CPU interrupts
                alt_int_cpu_enable();
                // Enable global interrupts
                alt_int_global_enable();
                
                alt_gpio_port_datadir_set(ALT_GPIO_PORTC, 0x01e00000, 0x00000000);
        	alt_gpio_port_debounce_set(ALT_GPIO_PORTC, 0x01e00000, 0x00200000);
        	alt_gpio_port_int_type_set(ALT_GPIO_PORTC, 0x01e00000, 0x002000000);
        	alt_gpio_port_int_pol_set(ALT_GPIO_PORTC, 0x01e00000, 0x00200000);

        	// Register gpio ISR
        	alt_int_isr_register(ALT_INT_INTERRUPT_GPIO2, gpio_isr_callback, NULL);
        	alt_gpio_port_int_enable(ALT_GPIO_PORTC, 0x00200000);

        	while(1);
        	return 0; //unreachable
        }

Thanks in advance.

1 Like

Hi. There is an error: undefined reference to “alt_int_global_init” when I compile the interrupt program. Can u help me solve the problem? Thanks a lot!

You need to include “alt_interrupt.h” in your project.

I included “alt_interrupt.h” already. I don’t know why the error occurred. Thanks.

Do u know how to use the interrupt in a C++ project? Maybe the error occurred because of the compiler. Thanks.

No, it is not because of the compiler.
I’ve solved my problem, error occured because of error in the function “alt_gpio_port_int_status_clear”.
If you are interested, you can download full source from my github repository: https://github.com/arktur04/cyclone-v-baremetal

Hii arktur04

I’ve also implemented the code for initialize interrupts like as you on a DE0 Nano SoC Kit and I have exactly the same problems.
Did you find a solution in the meantime? I would be very happy about some tipps!

Kind rigards.

Yes, I’ve found a solution.
In the file alt_generalpurpose_io.c there is an error in the function alt_gpio_port_int_status_clear.

In the original version:

ALT_STATUS_CODE alt_gpio_port_int_status_clear(ALT_GPIO_PORT_t gpio_pid,
uint32_t clrmask)
{
volatile uint32_t *addr;

if (clrmask & ~ALT_GPIO_BITMASK)      { return ALT_E_ERROR; }
if (gpio_pid == ALT_GPIO_PORTA)      { addr = ALT_GPIO0_INTSTAT_ADDR; }
else if (gpio_pid == ALT_GPIO_PORTB) { addr = ALT_GPIO1_INTSTAT_ADDR; }
else if (gpio_pid == ALT_GPIO_PORTC) { addr = ALT_GPIO2_INTSTAT_ADDR; }
else { return ALT_E_BAD_ARG; }         /* argument error */

alt_write_word(addr, clrmask);
return ALT_E_SUCCESS;

}

Correct version:

uint32_t alt_gpio_port_int_status_get(ALT_GPIO_PORT_t gpio_pid)
{
volatile uint32_t *addr;

if (gpio_pid == ALT_GPIO_PORTA)      { addr = ALT_GPIO0_INTSTAT_ADDR; }
else if (gpio_pid == ALT_GPIO_PORTB) { addr = ALT_GPIO1_INTSTAT_ADDR; }
else if (gpio_pid == ALT_GPIO_PORTC) { addr = ALT_GPIO2_INTSTAT_ADDR; }
else { return 0; }         /* error */

return alt_read_word(addr);

}