Forum Discussion

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

Intterupt processing time

Hello!

I'd like to know how many clock ticks interrupt handler takes from the interrupt point to interrupt handler function?

I created project, which includes following components: PIO(output) and Interval Timer. I set interval timer period 50 usec and 100 usec. I wrote interrupt timer handler:

char uval=0;

static void handle_timer_interrupt(void* context,alt_u32 id)

{

uval = ~uval;

IOWR_ALTERA_AVALON_PIO_DATA( PIO_1_BASE , uval);

IOWR_ALTERA_AVALON_TIMER_STATUS (TIMER_0_BASE, 0);

return;

}

Then the simulation showed that the time between time interrupt (timestamp) and changed value at PIO_1 is about 5.4 usec.

Is it notmal? How can I reduce this time?

Thank you.

3 Replies

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

    Kira,

    It's hard to comment on your interrupt latency time, as all sorts of things will affect the time taken, clock frequency, version of processor, what memory your code is running from, the priority of the interrupt etc.

    Your time sounds quite long we have measured latency at between 81-83 cycles on a 1S10 full design which uses Nios II/f processor.

    Chapter 6 of the Nios II Software Developer's Guide has some documentation on Exceptions and tips on how to reduce interrupt latency

    Some things you could do to speed up your IRQ latency include:

    Use the highest priority interrupt available

    Place your interrupt handler into an on chip memory
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi,

    I did some test with "Nios II/fast core" and got those results:

    Between user space to enter the beginning of Irq sections code: 10 cycles.

    Then to came bame to user mode: 5 cycles.

    If you use HAL altera for interruption, you got 265 to enter the beginning of handler, and 100 to exit to user code.

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

    I think the HAL interrupt entry sequence is pretty good. I had a look at it and couldn't do much better than the compiler has[1]. If you want to write interrupt handlers in C you need to save all the registers which the C compiler will corrupt as otherwise your system won't work.

    I assume you are measuring the time for interrupt 0 since that's fastest. By my calculations the current version should take about 59 cycles (I may be off by a few) to get to the start of the user routine for interrupt 0 (assuming cache hits each time).

    So if you are measuring much more (you don't say how you are measuring) then the slowdown is probably due to memory latencies, for icache fills and for saving registers onto the stack. This is why its so important to put your exception handler and stack into fast onchip memories.

    Once you've done that it may be possible to rewrite the interrupt handler in assembler to get even lower latencies for one interrupt. Here is my suggestion for a faster handler for interrupt 0. I think it will take 10 cycles to get to the point where you start saving registers. If you do this then you'll also have to change the C handler to handle interrupt 0 differently.

    But if you're worrying this much about interrupt latencies then you also need to worry about the time for which interrupts are disabled, either by foreground code or because another interrupt is being handled.

            .globl save_r2
            // Define in a C file somewhere as: unsigned int save_r2;
    alt_irq_entry:
            rdctl   et, estatus
            andi    et, et, 1
            beq     et, zero, software_exception
            rdctl   et, ipending
            andi    et, et, 1
            beq    et, zero, notirq0
            // 10 cycles to get here
            stw    r2, %gprel(save_r2)(gp)
            // Save as many other registers as you need.  Your assembler code
            // is allowed to use the registers you save here and et.  If you're
            // really careful you could use bt and ba as well but then you won't
            // be able to debug this code.
            // Your assembler code goes here
            // Restore other saved registers
            ldw    r2, %gprel(save_r2)(gp)
            eret
    notirq0:
            rdctl   et, ipending
            beq     et, zero, software_exception

    [1] I did manage to save about 5 clocks so this will be better in a future release.