| |||||
Technical Support Support Resources
Product Information | ARM: SPORADIC INTERRUPT PROBLEMSInformation in this article applies to:
SYMPTOMThe interrupt code on my ARM system seems to fail sporadically. Similar code was working fine for years on an 8051 target. Below is the specific code portion extracted into a test program written with the Keil CARM Compiler for the Keil MCB2100 Evaluation Board:
#include <LPC21xx.h>
unsigned long volatile counter;
/* Timer 0 Interrupt Function */
void tc0 (void) __irq {
IOCLR1 = 0xFFFFFFFF;
counter = 0;
T0IR = 1; // Clear interrupt flag
VICVectAddr = 0; // Acknowledge Interrupt
}
/* Setup the Timer Counter 0 Interrupt */
void init_timer (void) {
T0MR0 = 149999; // 10mSec = 150000-1 counts
T0MCR = 3; // Interrupt and Reset on MR0
T0TCR = 1; // Timer0 Enable
VICVectAddr0 = (unsigned long)tc0; // set interrupt vector in 0
VICVectCntl0 = 0x20 | 4; // use it for Timer 0 Interrupt
VICIntEnable = 0x00000010; // Enable Timer0 Interrupt
}
void main (void) {
int v;
IODIR1 = 0x00FF0000;
IOCLR1 = 0x00FF0000;
init_timer();
while(1) {
v = (counter << 8) & 0xFF0000; // the true I/O pins
counter++;
IOSET1 = v; // turn on LED
IOCLR1 = ~v; // turn off LED
}
}
CAUSEIn contrast to 8051 or C166, the C statement counter++ does not translate into a single CPU instruction. Therefore, this C statement is not atomic and interrupts may happen in the middle of the increment. As a result, the statement counter = 0; in your interrupt code may not really reset the counter value. RESOLUTIONDisable the timer interrupt before you update the counter variable in your main application. This is shown in the program sequence below:
/* Default Interrupt Function: may be called when timer ISR is disabled */
void DefISR (void) __irq {
;
}
/* Timer 0 Interrupt Function: called when timer ISR is enabled */
void tc0 (void) __irq {
IOCLR1 = 0xFFFFFFFF;
counter = 0;
T0IR = 1; // Clear interrupt flag
VICVectAddr = 0; // Acknowledge Interrupt
}
/* Setup the Timer Counter 0 Interrupt */
void init_timer (void) {
T0MR0 = 149999; // 10mSec = 150000-1 counts
T0MCR = 3; // Interrupt and Reset on MR0
T0TCR = 1; // Timer0 Enable
VICVectAddr0 = (unsigned long)tc0; // set interrupt vector in 0
VICVectCntl0 = 0x20 | 4; // use it for Timer 0 Interrupt
VICIntEnable = 0x00000010; // Enable Timer0 Interrupt
}
void main (void) {
int v;
IODIR1 = 0x00FF0000;
IOCLR1 = 0x00FF0000;
init_timer();
VICDefVectAddr = (unsigned long) DefISR; // ISR for un-assigned VIC interrupts
while(1) {
VICIntEnClr |= 0x00000010; // Disable Timer0 Interrupt
// put some instructions to ensure that the interrupt is blocked (pipeline effects)!
v = (counter << 8) & 0xFF0000; // the true I/O pins
counter++;
VICIntEnable |= 0x00000010; // Enable Timer0 Interrupt
IOSET1 = v; // turn on LED
IOCLR1 = ~v; // turn off LED
}
}
The VIC (Vectored Interrupt Controller) of the ARM device may still accept interrupts even when they are disabled. Therefore you must implement a default interrupt service routine as shown above. MORE INFORMATION
SEE ALSO
FORUM THREADSThe following Discussion Forum threads may provide information related to this topic.
Last Reviewed: Thursday, July 27, 2006 | ||||
| |||||