How to avoid Spurious Interrupt

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How to avoid Spurious Interrupt

1,936 Views
sanghavi
Contributor I

Hi, I am using Coldfire 5373 processor in my system.  System is using several MCU interrupts i.e. Serial, External Interrupt, timer , DMA, Ethernet. As per MCU datasheet, they suggest "first write a higher level interrupt mask to the status register, before setting the mask in the IMR or the module’s interrupt mask register. After the mask is set, return the interrupt mask in the status register to its previous value.".

Can any one suggest few sample code suggest as per MCU datasheet ? I tried  to disable interrupt as below but my system is still generating spurious interrupt & behavior isn't predictable when its happen.

 

Func1(void)

{

unsigned short interrupt_save;

 

//Disable Interrupt

interrupt_save = __GETSR();

__SETSR(interrupt_save | 0x0700);

 

Func2();

 

//Restore Interrupt

__SETSR(interrupt_save);

}

 

Thanks.

Labels (1)
Tags (1)
1 Reply

990 Views
TomE
Specialist II

There are lots of things that could be wrong here.

> but my system is still generating spurious interrupt & behavior isn't predictable when its happen.

That's the first bug. A system should be totally stable with spurious interrupts happening. All you need is an interrupt handler that does NOTHING, but simply returns. If you do that and your system is "unstable" then that simplest of all interrupt handlers is wrong somehow, or something else is happening that is making your system "unstable" and you're wrongly blaming spurious interrupts.

You have to look at the exact generated assembly code to see if the compiler, linker and the other "support stuff" is doing what you want it to do.

> Func2();

Why don't you show your actual code? I'm guessing "Func2()" is the code that "setting the mask in the IMR or the module’s interrupt mask register". You may have got that wrong. That should be in-line anyway. Or more precisely, the interrupt disable and enable should be each side of the single line of code that is messing with the IMR. That's the proper way to code it.

> __SETSR(interrupt_save);

I have no idea what that does. Where is it defined? What assembly code does it generate? There are Privileged and User versions of the machine code instructions. "MOVE.W <ea>y,SR" writes to the entire 16 bits of the Status Register, including the Priority Bits, and "MOVE.B Dy,CCR" only writes to the lower 8 bits. Depending on who wrote the "__SETSR()" function, it might be doing the wrong one.

There may be a "function" in the library you're using that "__SETSR()" is in that is specifically written to change the interrupt priority bits. If there is one, then you should be using that instead. Watch out that some versions of these function expect the interrupt levels to be "0 - 7" and not "0x0000 - 0x0700" as they shift the bits for you.

Here's the definition of an interrupt unmask (enable) macro for an MCF5235 system I work on:

#define INT_UNMASK( x )                                                 \     do {                                                                \         unsigned long old_ipl_32 = arch_local_irq_save();               \         if ( x.controller == 0 )                                        \         {                                                               \             if ( x.source < 32 )                                        \             {                                                           \                 MCF_INTC0_IMRL &= ~( 1 << x.source | MCF_INTC0_IMRL_MASKALL ); \             }                                                           \             else                                                        \             {                                                           \                 MCF_INTC0_IMRH &= ~( 1 << ( x.source - 32 ) );          \             }                                                           \         }                                                               \         else                                                            \         {                                                               \             if ( x.source < 32 )                                        \             {                                                           \                 MCF_INTC1_IMRL &= ~( 1 << x.source | MCF_INTC1_IMRL_MASKALL ); \             }                                                           \             else                                                        \             {                                                           \                 MCF_INTC1_IMRH &= ~( 1 << ( x.source - 32 ) );          \             }                                                           \         }                                                               \         arch_local_irq_restore(old_ipl_32);                             \     } while ( 0 );

The above macro is called like:

typedef struct {     uint8_t controller;     uint8_t source;     uint8_t level;     uint8_t priority; } INT_INFO; // controller, source, level, priority static const INT_INFO int_qspi = { 0, 18, 7, 6 }; static const INT_INFO int_flash = { 0, 3, 3, 0 }; static const INT_INFO int_post_conv = { 0, 2, 2, 0 };

static const INT_INFO int_fec_rxf = { 0, 27, 1, 6 }; static const INT_INFO int_fec_rxb = { 0, 28, 1, 4 }; static const INT_INFO int_fec_mii = { 0, 29, 1, 5 };

fec.c:    INT_UNMASK( int_fec_rxf ); fec.c:    INT_UNMASK( int_fec_mii ); system/adc.c:    INT_UNMASK( int_qspi ); system/dmatimer.c:      INT_UNMASK( int_timer[timer] ); system/etpu.c:    INT_UNMASK( int_etpu[chan] ); system/flash.c:    INT_UNMASK( int_flash );

The definition of the interrupt enable and disable functions I lifted directly from the Linux sources, function names and all. These definitions are for the gcc compiler, so they won't work for you. But they should give the gist of how it works.

/* From arm-linux/arch/m68k/include/asm/irqflags.h */ static inline unsigned long arch_local_save_flags(void) {         unsigned long flags;         __asm__ volatile ("movew %%sr,%0" : "=d" (flags) : : "memory");         return flags; } static inline void arch_local_irq_disable(void) {         __asm__ volatile (                 "move   %/sr,%%d0       \n\t"                 "ori.l  #0x0700,%%d0    \n\t"                 "move   %%d0,%/sr       \n"                 : /* no outputs */                 :                 : "cc", "%d0", "memory"); } static inline void arch_local_irq_enable(void) {         __asm__ volatile (                 "move   %/sr,%%d0       \n\t"                 "andi.l #0xf8ff,%%d0    \n\t"                 "move   %%d0,%/sr       \n"                 : /* no outputs */                 :                 : "cc", "%d0", "memory"); } static inline unsigned long arch_local_irq_save(void) {         unsigned long flags = arch_local_save_flags();         arch_local_irq_disable();         return flags; } static inline void arch_local_irq_restore(unsigned long flags) {         __asm__ volatile ("movew %0,%%sr" : : "d" (flags) : "memory"); }

Tom