Timer interrupt problem
2004-01-23 by bobbruce000
I am using a LPC2106, and I need to monitor 16 pins for
level changes. Since there aren't that many external
interrupt pins, I decided to use a timer interrupt and
sample the pins every few microseconds. Since this is
the most frequent interrupt, I made it the "fast
interrupt".
But whenever I enable the timer interrupt, the interrupt
completes one time and then everything freezes up. I am
pretty sure I am resetting the timer interrupt correctly.
This is the routine (R10 is already set to 0xE0004000):
fiq: mov r9,#0xff // Set bottom eight bits
str r9,[r10] // Reset Timer interrupts
subs pc,r14,#4 // Return from interrupt
If I disable additional interrupts in the handler, then
the interrupt returns okay, but (obviously) doesn't repeat.
I know it is running because I added an instruction to
turn on an LED:
fiq: mov r9,#0xff // Set bottom eight bits
str r9,[r10] // Reset Timer interrupts
str r9,[r12] // Light up LED
msr spsr_c,#0xdf // disable interrupts on return
subs pc,r14,#4 // Return from interrupt
But here is something even weirder: If I add some nops, and
make the routine a little longer, then it freezes up, even with
interrupts disabled:
fiq: nop
nop
nop
nop
mov r9,#0xff // Set bottom eight bits
str r9,[r10] // Reset Timer interrupts
str r9,[r12] // Light up LED
msr spsr_c,#0xdf // disable interrupts on return
subs pc,r14,#4 // Return from interrupt
If there are three or fewer nops, the interrupt returns (once),
but with four or more, it does not.
Please let me know if you have any idea what I am doing wrong.
I have been fiddling with this for the last two days with no
progress.
-bob
ps: Here is the C code that intializes the timer and VIC,
followed by the ASM startup code and FIQ handler.
void
timer0_init(void) {
TIMER0_PR = 0x000000ff; // Prescaler
TIMER0_MR0 = 0x00000100; // Match register
TIMER0_MCR = 0x00000003; // Reset and interrupt on match
TIMER0_TCR = 0x3; // Enable and reset counter
TIMER0_TCR = 0x1; // Start counter
TIMER0_IR = 0xff; // Clear any pending interrupts
return;
}
static void
vic_init(void) { // Page 61
VICIntSelect = 0x00000010; // The set bit is for FIQ -- Timer 0
VICIntEnable = 0x00000010; // Timer 0 interrupt is enabled
return;
}
-------------------------------------------------------------
_start:
b reset // 0 Reset
b undef_isr // 1 Undefined Instruction
b swi_isr // 2 Software Interrupt
b prefetch_isr // 3 Prefetch abort
b data_abort_isr // 4 Data abort
b reserved // 5 Replace with checksum
b irq // 6 IRQ
fiq: // 7 Fast interrupt handler
mov r9,#0xff // Set bottom eight bits
str r9,[r10] // Reset Timer interrupts
str r9,[r12] // Light up LED
msr spsr_c,#0xdf // disable intrpts: fails if removed
subs pc,r14,#4 // Return from interrupt
.L_StackTop: .word 0x4000ffe0 // RAM top minus 32 b for IAP
.L_T0IR: .word 0xE0004000 // Timer 0 IR port address
.L_VVA: .word 0xfffff030 // VIC Vect Addr port address
.L_IOCLR: .word 0xE002800C // IOCLR address
reset:
ldr r0,.L_StackTop // r0 = top of stack
msr cpsr,#0xd1 // switch to FIQ mode
sub sp,r0,#0x00 // Set FIQ stack pointer
ldr r10,.L_T0IR // R10 = timer0_ir address
ldr r11,.L_VVA // R11 = VICVectAddr address
ldr r12,.L_IOCLR // R12 = IOCLR address
// Set up stack pointers for each mode, etc.
mov sp,r0 // Stack for FIQ
msr cpsr,#0xd2 // Switch to IRQ mode
sub sp,r0,#32 // sp_IRQ = sp_FIQ minus 32
msr cpsr,#0xd7 // Switch to Abort mode
sub sp,r0,#64 // Set Abort stack pointer
msr cpsr,#0xdb // Switch to Undef mode
sub sp,r0,#96 // Set Undef stack pointer
msr cpsr,#0xd3 // Switch to Supervisor mode
sub sp,r0,#128 // Set Supervisor stack pointer
msr cpsr,#0xdf // Switch to System mode
sub sp,r0,#160 // Set System (main) stack pointer
b main // Jump to main() C routine