Monday, September 17, 2012

i.MX51/i.MX53: Interrupt occurs with no bit set in HIPND


Problem:

In my program, whenever interrupt occurs, I read HIPND0, HIPND1, HIPND2, HIPND3, registers to decide the interrupt number of the interrupt source.

But, when there are frequent interrupts, sometimes all of HIPND0, HIPND1, HIPND2, HIPND3 registers read zero(0). Because of this, I could not decide the interrupt number/source. Are they spurious interrupts? There is nothing specified about the spurious interrupts in i.MX51 Reference Manual.

In other words, none of interrupt bits are set in HIPNDx registers, inside my interrupt service routine. Or, interrupt occurs without any bit set in HIPNDx registers. Thus, reading of HIPND results in interrupt number of 0.

Solution:

What happens?

They are not spurious interrupts. There are no spurious interrupts in i.MX51. Problem is in your program. If your program reads HIPNDx registers in series as follows, there is chance that the contents of HIPND registers changed whenever a higher priority interrupt occurs.

For example, assume that interrupt occurs and HIPND2 register is set 0x80000000 and all other registers are set to zero. When you are reading HIPND1, there is chance that a higher priority interrupt occurs and HIPND0 register will become set to 0x40000000 and HIPND2 register will become set to 0. So, your reading will result that all are HIPND registers are zero.

    int intr_number;

    if (register_read(HIPND0) != 0)
        intr_number = 0;
    else  if (register_read(HIPND1) != 0)
        intr_number = 32;
    else  if (register_read(HIPND2) != 0)
        intr_number = 64;
    else  if (register_read(HIPND3) != 0)
        intr_number = 96;
//    else
//        printf("Error: All are set to zero\n");

Howto correct it?

1) Reread the HIPND registers as follows:

    int retry = 0;

    for (;;) {
        if (register_read(HIPND0) != 0)
            intr_number = 0;
        else  if (register_read(HIPND1) != 0)
            intr_number = 32;
        else  if (register_read(HIPND2) != 0)
            intr_number = 64;
        else  if (register_read(HIPND3) != 0)
            intr_number = 96;
        else if (retry++ < NUMBER_OF_PRIORITY_LEVELS)
            continue;
    }

2) Use PND registers to read the pending interrupts, if your program do not worry about interrupt priority.

3) Set all interrupts same priority.

It applies to iMX series processors i.MX515, i.MX535, etc,. Give your comments to improve this post. Have a nice day!

No comments: