EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

Returning from ISR erases my local variables. What am I doing wrong?

Started by "evan.miller530" May 13, 2011
I'm using an at91sam7s256 combined with the yagarto/eclipse gnu toolchain, with an ISR setup based on the PIT. After the first interrupt fires, it enters the ISR, executes a few lines of code, then returns to the main loop.

The problem I seem to be having is that all local variables/pointers have been reverted back to their reset values (0xAAAA....) once I've returned from the ISR, and the ISR itself will only fire 1 time. I have made sure to read from the PIT_PIVR register in the ISR, and the PIT does keep incrementing correctly (and rolling over at the proper value). The AIC_IMR register shows the interrupt is still enabled, and for good measure I have tried re-enabling the interrupt in the AIC.

What I've noticed after returning from the ISR is that the 8 LSBs of the CPSR have changed from 01011111 to 11010010 (getting stuck in IRQ mode?) Is this normal?

I am using the following code for my IRQ handler, although I am very new to the ARM environment, and not very familiar with assembly. I understand in programs like uVision it is necessary to use the __irq keyword before the ISR, so I'm not sure if I need to add something like that or not. The examples I have seen with GNU don't seem to use a keyword such as that.

Any input would be greatly appreciated! I'm at the end of my list of things to try here, and am really unsure of whats going wrong/how to fix the problem. Thanks in advance!

IRQHandler:
/*- Manage Exception Entry */
/*- Adjust and save LR_irq in IRQ stack */
sub lr, lr, #4
stmfd sp!, {lr}

/*- Save SPSR need to be saved for nested interrupt */
mrs r14, SPSR
stmfd sp!, {r14}

/*- Save and r0 in IRQ stack */
stmfd sp!, {r0}

/*- Write in the IVR to support Protect Mode */
/*- No effect in Normal Mode */
/*- De-assert the NIRQ and clear the source in Protect Mode */
ldr r14, =AT91C_BASE_AIC
ldr r0 , [r14, #AIC_IVR]
str r14, [r14, #AIC_IVR]

/*- Enable Interrupt and Switch in Supervisor Mode */
msr CPSR_c, #SVC_MODE

/*- Save scratch/used registers and LR in User Stack */
stmfd sp!, { r1-r3, r12, r14}

/*- Branch to the routine pointed by the AIC_IVR */
mov r14, pc
bx r0
/*- Restore scratch/used registers and LR from User Stack*/
ldmia sp!, { r1-r3, r12, r14}

/*- Disable Interrupt and switch back in IRQ mode */
msr CPSR_c, #I_BIT | IRQ_MODE

/*- Mark the End of Interrupt on the AIC */
ldr r14, =AT91C_BASE_AIC
str r14, [r14, #AIC_EOICR]

/*- Restore SPSR_irq and r0 from IRQ stack */
ldmia sp!, {r0}

/*- Restore SPSR_irq and r0 from IRQ stack */
ldmia sp!, {r14}
msr SPSR_cxsf, r14

/*- Restore adjusted LR_irq from IRQ stack directly in the PC */
ldmia sp!, {pc}^

I was slightly mistaken about what I had previously written... I believe although I had the asm code in place for the IRQ handler, I was not loading it properly in the vector table. When I point the IRQ entry in the vector table (in startup code) at the IRQ handler referenced in code below, it jumps to the ISR and (as long as there are no new variables defined) jumps back to the beginning of the main loop (not where it was supposed to). It's as if the system is being restarted. If I modify a new variable defined in the ISR, it branches to the Data Abort Handler.

The way I think I am supposed to be doing this:
Alternatively, if in the vector table for the IRQ entry I use the suggested command LDR pc,[PC,#-0xF20]
I branch to the Data Abort handler whether or not I have code in the ISR. I am doing something fundamentally wrong here, in a little bit over my head, and not sure where to look next. Any suggestions would be very welcome.

--- In A..., "evan.miller530" wrote:
>
> I'm using an at91sam7s256 combined with the yagarto/eclipse gnu toolchain, with an ISR setup based on the PIT. After the first interrupt fires, it enters the ISR, executes a few lines of code, then returns to the main loop.
>
> The problem I seem to be having is that all local variables/pointers have been reverted back to their reset values (0xAAAA....) once I've returned from the ISR, and the ISR itself will only fire 1 time. I have made sure to read from the PIT_PIVR register in the ISR, and the PIT does keep incrementing correctly (and rolling over at the proper value). The AIC_IMR register shows the interrupt is still enabled, and for good measure I have tried re-enabling the interrupt in the AIC.
>
> What I've noticed after returning from the ISR is that the 8 LSBs of the CPSR have changed from 01011111 to 11010010 (getting stuck in IRQ mode?) Is this normal?
>
> I am using the following code for my IRQ handler, although I am very new to the ARM environment, and not very familiar with assembly. I understand in programs like uVision it is necessary to use the __irq keyword before the ISR, so I'm not sure if I need to add something like that or not. The examples I have seen with GNU don't seem to use a keyword such as that.
>
> Any input would be greatly appreciated! I'm at the end of my list of things to try here, and am really unsure of whats going wrong/how to fix the problem. Thanks in advance!
>
> IRQHandler:
> /*- Manage Exception Entry */
> /*- Adjust and save LR_irq in IRQ stack */
> sub lr, lr, #4
> stmfd sp!, {lr}
>
> /*- Save SPSR need to be saved for nested interrupt */
> mrs r14, SPSR
> stmfd sp!, {r14}
>
> /*- Save and r0 in IRQ stack */
> stmfd sp!, {r0}
>
> /*- Write in the IVR to support Protect Mode */
> /*- No effect in Normal Mode */
> /*- De-assert the NIRQ and clear the source in Protect Mode */
> ldr r14, =AT91C_BASE_AIC
> ldr r0 , [r14, #AIC_IVR]
> str r14, [r14, #AIC_IVR]
>
> /*- Enable Interrupt and Switch in Supervisor Mode */
> msr CPSR_c, #SVC_MODE
>
> /*- Save scratch/used registers and LR in User Stack */
> stmfd sp!, { r1-r3, r12, r14}
>
> /*- Branch to the routine pointed by the AIC_IVR */
> mov r14, pc
> bx r0
> /*- Restore scratch/used registers and LR from User Stack*/
> ldmia sp!, { r1-r3, r12, r14}
>
> /*- Disable Interrupt and switch back in IRQ mode */
> msr CPSR_c, #I_BIT | IRQ_MODE
>
> /*- Mark the End of Interrupt on the AIC */
> ldr r14, =AT91C_BASE_AIC
> str r14, [r14, #AIC_EOICR]
>
> /*- Restore SPSR_irq and r0 from IRQ stack */
> ldmia sp!, {r0}
>
> /*- Restore SPSR_irq and r0 from IRQ stack */
> ldmia sp!, {r14}
> msr SPSR_cxsf, r14
>
> /*- Restore adjusted LR_irq from IRQ stack directly in the PC */
> ldmia sp!, {pc}^
>


The 2024 Embedded Online Conference