Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
14 years ago

endless loop in stock interrupt handler

Hi people,

a bit of information about my system first:

- terasIC DE2-115 evaluation board with Cyclone IVE FPGA

- Nios II/s CPU

- also part of CPU block: SDRAM Controller, PIO, SysID, 2x Interval Timer, UART

- QuartusII 12.0 sp1 community edition

- no RTOS, just the altera BSP

please let me know if you need more information which could be useful

here is my problem:

my program only executes the first few lines of my main function and loses itself in the interrupt handler afterwards.

detailed description:

The program starts running and a few timer interrupts occur and are handled successfully (Timer IRQ is 2, which corresponds to the value of 4 in the pending interrupt register), i.e. "alt_irq_handler" in alt_irq_handler.c is called and returns. After a few more handled interrupts, the alt_interrupt_handler routine is called again, but the pending interrupt register has the value 0 (which does not correspond to any IRQ?) and keeps looping in that interrupt routine forever -> program never returns to main again and is stuck

A quick and dirty fix for this problem is to check for "pending register == 0" in the interrupt routine. This fix let's me execute my program, but actually I want to know where these interrupts come from and how to stop them... additionally my fix requires modification of BSP files, which is not what I want to do.

looking forward to your comments!

Martin

7 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    the best way is to look for the interrupt control registers and set values to disable all interrupts so you can be sure only your main program is running.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    thank you jacklsw86 for your hint!

    in general I have to use interrupts in my code, but here are my observations first:

    - when I disable all interrupts (via the PIE bit in the ctl0 register), my program executes

    - when I mask IRQ 2 via the ctl3 register, my program executes

    - when I check for pending==0 in the interrupt handler, my program executes

    IRQ2 is assigned to one of my timers. The timer creates interrupts via IRQ2 and as such, the pending register has to hold the value 4. This happens a few times and the interrupt handler finishes its execution as expected.

    But after a while (< 1s), the interrupt handler is called again and pending register holds the value 0 (this only happens, if IRQ2 is unmasked).

    How can a value of 0 be possible for the pending register? Why does disabling the timer IRQ solve my problem (as it executes fine a few times with pending set to 4)?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    What's the timer period?

    If you have a fast irq rate and a long interrupt handler, the irq could retrigger just after the previous isr has completed.

    Do you mind posting your code?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I have two timers:

    - the timer with IRQ2 has a 1ms period (the only interrupt I see came from this timer)

    - the timer with IRQ3 also has a 1ms period (surprisingly enough, I never saw this timer trigger an interrupt?)

    (edit):

    the IRQ2-timer is also set as the sys_clk_timer in the altera BSP editor

    the interrupt handler I use in the moment, is the stock interrupt handler provided by the altera BSP:

    - alt_irq_handler() in alt_irq_handler.c

    here a shortened snippet from alt_irq_handler:

      active = alt_irq_pending ();
      do {
        i = 0;
        mask = 1;
        do {
          if (active & mask) { 
            alt_irq.handler(alt_irq.context); 
            break;
          }
          mask <<= 1;
          i++;
        } while (1);
        active = alt_irq_pending ();
      } while (active);
      ALT_OS_INT_EXIT();
    
    the called handler for this particular IRQ is alt_avalon_timer_sc_irq (void* base) in alt_avalon_timer_sc.c

    shortened snippet of the code:

      IOWR_ALTERA_AVALON_TIMER_STATUS (base, 0);
      IORD_ALTERA_AVALON_TIMER_CONTROL (base);
      ALT_LOG_SYS_CLK_HEARTBEAT();
      cpu_sr = alt_irq_disable_all();
      alt_tick ();
      alt_irq_enable_all(cpu_sr);
    

    for the time being, my main() function does nothing else than controlling the blinking of an LED
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    It seems like this problem is related to the FreeRTOS operating system I am using.

    This is my code:

    /* Standard includes. */
    # include <stddef.h>
    # include <stdio.h>
    # include <string.h>
    /* Scheduler includes. */
    # include "FreeRTOS.h"
    # include "task.h"
    # include "queue.h"
    /* NiosII includes. */
    # include "system.h"
    # include "altera_avalon_pio_regs.h"
    int main()
    {
    	unsigned int i = 200;
    	unsigned int j = 0;
        unsigned char led=0x01;
        portBASE_TYPE res;
        printf("hello world!\n");
        led =0xff;
       	IOWR(LED_PIO_BASE,0,led);
      	i=50000; while(i--);
        res = xTaskCreate(
                    call_back1,
                    ( signed char * ) "Task1",
                    configMINIMAL_STACK_SIZE,
                    NULL,
                    1,
                    NULL
        );
        if ( res != pdPASS )
             printf("erro,fail to create task:%d\n", res);
        else
              printf("success to create task\n");
        xTaskCreate(
                    call_back2,
                    ( signed char * ) "Task2",
                    configMINIMAL_STACK_SIZE,
                    NULL,
                    2,
                    NULL
        );
    	led =0xaa;
    	IOWR(LED_PIO_BASE,0,led);
        printf("start schedule\n");
        vTaskStartScheduler();
        while(1);
    }
    void call_back1(void* param)
    {
        for(;;)
        {
        IOWR(LED_PIO_BASE,0,0x0f);
        printf("run task1\n");
        vTaskDelay(2000);
        }
    }
    void call_back2(void* param)
    {
    	for(;;)
        {
        IOWR(LED_PIO_BASE,0,0xf0);
        printf("run task2\n");
        vTaskDelay(1000);
        }
    }
    
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I am using altera software v12.0 sp1 and had an issue compiling the freeRTOS port for altera v12.0 first.

    Had to enable ALT_LEGACY_INTERRUPT_API_PRESENT to make it compilable.

    As my problem seems to be interrupt related, I rethaught my step and ported the Nios2-port of FreeRTOS to the new ALT_ENHANCED_INTERRUPT_API_PRESENT by changing the way it registers its interrupts (just had to swap one line of code)

    But I still have exactly the same problem (endless loop in isr). Honestly I have no more ideas how to solve this, it's driving me crazy

    Any hints which could push me into the right direction?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I don't know freeRTOS, but you must be very careful in using interrupt control functions with an underlying OS.

    Infact, an OS relies on a high priority irq to schedule application tasks; application usually doesn't work with irq at the raw level, but the OS emulates the required hw behaviour through sort virtual IRQs and the scheduling process.

    For example, if you use sys timer irq or any other device required by OS, you may corrupt the OS itself and your system would stop working.

    What I mean is that under an OS, using raw IRQs is possible but is not recommended unless you have a comprehensive knowledge of your OS's ineer workings and you are aware of what you are doing.