This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Interrupting the interrupt

Hello,
i have a problem.
There are allways difficulties in programms with IRQ und FIQ. So i wrote this code to investigate where the problem is.

I use two Timer, Timer0 and Timer1 to generate interrupts.

Timer0 generates a periodic normal IRQ every 2000 cycles.

Inside the IRQ routine there is a for(i=80;i;i--) loop with port toggling. So i can watch on my 2-channel storage oszilloscope when this toggling is interrupted by the fast interrupt.

Timer1 generates a periodic fast interrupt FIQ every 1000 cycles.

I interprete the microcontroller datasheet that FIQ has the higher pririty and can interrupt IRQ. Am i right???

Unfortunaltely i can not post a oszilloscope screenshot in this forum.

So i try to describe the result:
On channel 1 there is a train of 40 pulses. Duration is about 33us. You can see, after pulse 31 there a little gap. This is the moment FIQ is started and returns to IRQ. Then the left 9 pulses are there. Than there is a low level for about 17us. This looks all the way i expected things to take place.

On channel 2 there is a port toggling every 25us.
Sometimes the port toggling is replaced by a single needle pulse.

Whats going on there. Unfortunaltely i have no idea where the problem occurs. I expanded FIQ-stack-size from 4 to 80. (startup.s)

//*************************************************************************
#include <ADuC7026.h>
//*************************************************************************
void Port_init(void);
void PLL_init(void);
void Timer_init(void);
void interrupt_init(void);
//*************************************************************************
int main (void)
{
        Port_init();
        PLL_init();
        Timer_init();
        interrupt_init();
        while(1)
        {
                GP4DAT ^= 0x00040000; // P4.2 toggling => program is in main loop
        }
}
//*************************************************************************
void IRQ_Handler()__irq __ram // Timer 0 => Interrupt
{
        unsigned int i;
        T0CLRI = 0;
        for(i=80;i;i--) GP4DAT ^= 0x00010000; // P4.0 shows's Interrupt
}
//*************************************************************************
void FIQ_Handler()__fiq __ram // Timer 1 => Fast Interrupt
{
        T1CLRI = 0;
        GP4DAT ^= 0x00020000; // P4.1 show's Fast Interrupt
}
//*************************************************************************
void interrupt_init(void)
{
        IRQEN = RTOS_TIMER_BIT;         // Timer 0 => Interrupt
    FIQEN = GP_TIMER_BIT;               // Timer 1 => Fast Interrupt
}
//*************************************************************************
void Timer_init(void)
{
        T0LD  = 2000 - 1;       // Timer 0 => periodic Interrupt 2000 cycles
    T1LD  = 1000 - 1;   // Timer 1 => periodic Fast Interrupt 1000 cycles
        T0CON = 0xC0;           // Enabled,Periodic,CLK/1
    T1CON = 0xC0;               // Enabled,Periodic,Binary and CLK/1
}
//*************************************************************************
void PLL_init(void)
{
    PLLKEY1 = 0xAA;
    PLLCON = 0x01;              // clear Bit5 OSEL => External 32.768kHz crystal
    PLLKEY2 = 0x55;
        while(~IRQSIG & PLL_LOCK_BIT){} // waiting for PLL lock
}
//*************************************************************************
void Port_init(void)
{
        GP4DAT |= 0x01000000; // P4.0 is output
        GP4DAT |= 0x02000000; // P4.1 is output
        GP4DAT |= 0x04000000; // P4.2 is output
}
//*************************************************************************

Parents
  • you need to enter supervisor mode using a SWI instruction (see SWI handling guide at your toolchain examples).
    then, you need to disable FIQ and IRQ when you access your stuff from the main loop, like this (FIQ only):

    int __swi(0) disable_fiq(void) ;
    int __SWI_0 ()
    {
            // disable FIQ. Note: bits 6 and 7 of the lowest byte of CPSR specify the status
            // of IRQ and FIQ respectively. But the external interrupt sources are disabled if
            // these bit are set to 1, not 0 - which means enabled.
            // FIQ can only be disabled from previlidged mode.
    
            // the intrinsic '__disable_fiq' shall be translated into the following instructions:
            // MRS       R0,CPSR
            // ORR       R0,R0,#0x00000040
            // MSR       CPSR_c,R0
    
            // whether it is available or not depends on the compiler.
            // the real view compiter V3.1.0.919 supports this feature.
            return __disable_fiq() ;
    }
    


    assuming you use the RealView compiler

    your IRQ ISR will have to do the same, but for FIQ only.
    don't forget to enable IRQ/FIQ after you're done.

Reply
  • you need to enter supervisor mode using a SWI instruction (see SWI handling guide at your toolchain examples).
    then, you need to disable FIQ and IRQ when you access your stuff from the main loop, like this (FIQ only):

    int __swi(0) disable_fiq(void) ;
    int __SWI_0 ()
    {
            // disable FIQ. Note: bits 6 and 7 of the lowest byte of CPSR specify the status
            // of IRQ and FIQ respectively. But the external interrupt sources are disabled if
            // these bit are set to 1, not 0 - which means enabled.
            // FIQ can only be disabled from previlidged mode.
    
            // the intrinsic '__disable_fiq' shall be translated into the following instructions:
            // MRS       R0,CPSR
            // ORR       R0,R0,#0x00000040
            // MSR       CPSR_c,R0
    
            // whether it is available or not depends on the compiler.
            // the real view compiter V3.1.0.919 supports this feature.
            return __disable_fiq() ;
    }
    


    assuming you use the RealView compiler

    your IRQ ISR will have to do the same, but for FIQ only.
    don't forget to enable IRQ/FIQ after you're done.

Children
  • Hi,
    there's another solution for Port-Toggling, so it is not necessary to have an atomic toggle instruction.

    (GP4DAT & 0x00010000) ? GP4CLR = 0x00010000 : GP4SET = 0x00010000;
    


    Depends on your ARM7-derivate, mine is ADuC7026

    There are some Cortex-3-derivate which have an atomic Port/Bit-Toggling instruction.

  • Sorry Georg but HOW is that atomic ?

  • The set register can only affect the bits that you set a one in.

    The clear register can only affect the bits that you set a one in.

    In short, one "setreg = bitmasp" assign can not affect other bits. If the FIQ handles one bit, IRQ another and main a third, it is impossible for the three locations to affect the wrong bit.

    When you instead read the pin register and make a change, all three locations will read and write the state for all pins in the port, which is the reason why lower-priority code may create glitches by overwriting a toggle made by the IRQ and/or the FIQ.

  • Hi Per,

    Your explanation is clear but Georg's code is not (as written) an atomic operation. It could still be interrupted, resulting in glitches (or worse).

    In the very specific case you highlight, where each access is dealing with a unique bit (or bits), you may be safe, but as a general solution, it is not applicable.

  • Correct. The Set/Cler registers are not a way to get atomic operation.

    It is a way to be able to isolate arbitrary sets of bits on a port, and have different tasks/ISR own different bits and work on them without having their changes overwritten by another task/ISR.

    In your case, you don't need any atomic updates - you just need to make sure that one task/ISR doesn't overwrite bits owned by another task/ISR. You will get task isolation without the additional burden of creating critical sections, i.e. with a minimum of overhead.

    If you look at Georg Bunter text a bit more closely, you'll notice that he says "so it is not necessary to have an atomic toggle instruction." There is no claim that you will get an atomic access - just that this is a good workaround to remove your need of atomic access.

  • Fair enough - I misinterpreted his text as claiming that his code was a viable alternative to an atomic toggle instruction !

    In the specific case under discussion, this is a more efficient solution. However, "specific cases" often have a nasty habit of subsequently being used where they're not appropriate :-)

    David.