Trouble Returning from ISR, at91sam7s256

I’m using an at91sam7s256 combined with the yagarto/eclipse gnu toolchain, with

an ISR setup based on the PIT. The vector table in the startup code is as follows:

    LDR     pc, ResetAddr    /* Reset                 */
    LDR     pc, UndefAddr    /* Undefined instruction */
    LDR     pc, SWIAddr      /* Software interrupt    */
    LDR     pc, PAbortAddr   /* Prefetch abort        */
    LDR     pc, DAbortAddr   /* Data abort            */
    LDR     pc, ReservedAddr /* Reserved              */
    LDR     pc, [PC,#-0xF20]
    LDR     pc, [PC,#-0xF20]

After the PIT increments to the appropriate value, the ISR routine is called. Whether or not I have code in the ISR, the program then branches to the data abort handler. I understand in programs like uVision it is necessary to use the __irq keyword before the ISR. The examples I have seen with GNU don’t seem to use a keyword such as that, but I believe this is related to why I’m getting sent to the data abort handler.

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!

The reason I was getting an exception I believe was because I wasn’t setting the AIC_EOICR register. In any event… when I use LDR pc,[PC,#-0xF20] in the vector table for the IRQ address, when I come out of the ISR I noticed the ARM is still in IRQ mode and the I flag has been reset again (CPSR = 0x600000d2). Inside the ISR I can put it back into system mode as it was before (whether or not this is necessary, I’m not entirely sure), however I am unable to clear the I flag again (clearing it has no effect in the ISR).

Is it customary to manually set this flag each time one exits and ISR?

evmiller:
Is it customary to manually set this flag each time one exits and ISR?

At least in the end of my C-language IRQ handler (for AT91SAM7X256) I write zero to that register and then branch back to asm code (where I will restore CPSR and PC). Also datasheet says:

Datasheet for AT91SAM7X512/256/128:
If an interrupt condition happens (or is pending) during the interrupt treatment in progress, it is delayed until the software indicates to the AIC the end of the current service by writing the AIC_EOICR (End of Interrupt Command Register). The write of AIC_EOICR is the exit point of the interrupt handling.

Maybe I’m misunderstanding the fundamental idea of the whats going on here… I was under the impression that since I have LDR pc, [PC,#-0xF20] in the vector table, rather than a branch to a handler, that when the interrupt condition occurs the PC grabs the ISR vector from the IVR. I thought that because of this, I am not using a specific handler, and the code related to the interrupt is solely placed in the ISR. Is this not what is happening here?

You are correct, in auto-vectoring the value of AIC_IVR is read using the instruction you mentioned but if you are not using any ready made macros (for example IRQ_ENTRY, IRQ_EXIT) you still need to manually mark the EOI by writing something to AIC_EOICR. More information about auto-vectoring is available in Atmel’t document [Interrupt Management: Auto-vectoring and Prioritization.](http://www.atmel.com/dyn/resources/prod_documents/DOC1168.PDF)

tparviai:
You are correct, in auto-vectoring the value of AIC_IVR is read using the instruction you mentioned but if you are not using any ready made macros (for example IRQ_ENTRY, IRQ_EXIT) you still need to manually mark the EOI by writing something to AIC_EOICR. More information about auto-vectoring is available in Atmel’t document [Interrupt Management: Auto-vectoring and Prioritization.[/quote]

Ok, I actually tried using the IRQ_ENTRY and IRQ_EXIT macros in my ISR, and am STILL getting extremely bizarre results. I have 1 breakpoint in my main loop, and 1 breakpoint in the ISR. Running the program should advance to the main loop BP a number of times, eventually stop in the ISR BP, then continue to stop in the main loop BP (until the ISR fires again). When I run through the program in eclipse’s debug mode (rather than step through line by line), the program executes the main loop a number of times, goes into the ISR, but then keeps returning to the ISR BP over and over (seemingly not returning to the main loop BP). However, when I step through the ISR line by line, the ISR finishes, and continues on back to the main loop again. I’m not sure what the difference here is between the run button, and advancing line by line, but I would think they should be equivalent. Maybe not, but anyway…

A more alarming problem is that I am unable to declare a variable in the ISR. If I do anything other than, say, modify a register, the program throws an exception and moves to the data abort handler. I am growing increasingly tired of trying to figure out whats going wrong with the eclipse/yagarto build, and may just give up and try to move towards uVision or IAR. I very much need a solution in which my ISR works correctly, and I just can’t seem to correct what I have at the moment.](http://www.atmel.com/dyn/resources/prod_documents/DOC1168.PDF)

evmiller:
A more alarming problem is that I am unable to declare a variable in the ISR. If I do anything other than, say, modify a register, the program throws an exception and moves to the data abort handler.

Just a guess but have you initialized IRQ mode stack? If the stack points to wrong location then storing something to a variable means that you are actually writing data to some random location (maybe to address 0), that might lead to data abort.

This would be taking place in the startup code, I presume? I have a very loose grasp on the specifics here, but I believe it is initialized in the following section of code (I will also upload my startup and low level init files I have been using):

    /* Initialize stack pointers for all ARM modes */
    MSR     CPSR_c,#(IRQ_MODE | I_BIT | F_BIT)
    LDR     sp,=__irq_stack_top__                /* set the IRQ stack pointer */

    MSR     CPSR_c,#(FIQ_MODE | I_BIT | F_BIT)
    LDR     sp,=__fiq_stack_top__                /* set the FIQ stack pointer */

    MSR     CPSR_c,#(SVC_MODE | I_BIT | F_BIT)
    LDR     sp,=__svc_stack_top__                /* set the SVC stack pointer */

    MSR     CPSR_c,#(ABT_MODE | I_BIT | F_BIT)
    LDR     sp,=__abt_stack_top__                /* set the ABT stack pointer */

    MSR     CPSR_c,#(UND_MODE | I_BIT | F_BIT)
    LDR     sp,=__und_stack_top__                /* set the UND stack pointer */

    MSR     CPSR_c,#(SYS_MODE | I_BIT | F_BIT)
    LDR     sp,=__c_stack_top__                  /* set the C stack pointer */

When I step through the code, the stack top locations are all the same. I’m not sure if this matters.

I quickly checked your code and that piece of code looks ok. I assume that you have main() function where your own code is and when the code branches to main() then stacks should be fine.

evmiller:
When I step through the code, the stack top locations are all the same. I’m not sure if this matters.

I think they should not be same (devices without MMU), if in SVC/SYS mode you have put variables to stack and IRQ happens (with the same stack address) then you start to overwrite values.

Maybe best way to proceed would be to try some ready made examples for AT91SAM7S256 (for example from http://gandalf.arubi.uni-kl.de/avr_proj … _at91.html) to see that those will work with your tool chain and once you have verified that then start to compare what you have different in your own project (for example linker scripts, makefile, RAM remapping etc.).