I'm currently messing around with some ARM Assembler on the lpc2378, I've wrote a loop to control a furnace's temperature, however; I believe I need to implement some kind of interrupt handling to complete my project.

When the application runs, it enters a loop, which waits for Button_1 input, the loop then carries on and goes through various stages but it cannot reach wait for Button_2 input for the application to function.

So a couple of questions here, how exactly does the interrupt handler work? and how could I implement it into my application.

2 Answers
2

If you dont have it already you need to get the ARM ARM (ARM Architectural Reference Manual). there used to be only one but there are so many cores now they had to split it up for the different architectures. http://infocenter.arm.com along the left side ARM Architecture, then Reference Manuals, then ARMv5, yes I know you have an ARMv4 (ARM7TDMI). The ARMv5 manual is what used to be, THE manual.

It will cover the exception vectors and such.

You probably already know that on boot, the instruction at address 0x00000000 is executed.
For interrupts the instruction at address 0x00000018 is called.

From the ARM ARM you should also see that the registers are banked, in particular r13 the stack pointer, there is a separate stack pointer when in interrupt mode. So on boot, when you are setting up your normal stack you also want to setup some space for the interrupt stack.

at some point you need to enable the interrupt in the cpsr. you might wait on this until you have enabled whatever interrupt in whatever peripheral (in the chip, outside the core).

;@ SVC MODE, IRQ ENABLED, FIQ DIS
mov r0,#0x53
msr cpsr_c, r0

You will need to read the manual for the lpc part to understand how to enable the interrupt, as well as how to clear the interrupt when it happens.

The first thing you need to do in the interrupt handler (the code you branch to at address 0x18) is preserve the shared (not banked) registers on the stack so that you dont mess them up. If you dont when you return to the code that was interrupted the registers will have changed and that code may not work. Since your project appears to be in ASM it is possible for you to use some registers in the application and reserve some regsiters only for the isr and not have to setup the stack. If you are going to use bl anywhere in the handler you need to save lr on the stack.

At some point your handler needs to clear the interrupt in the peripheral so it doesnt fire again until the next interrupt, gotta read the lpc manual for that. Yes when I say lpc I mean NXP formerly Philips...

The last thing is if you have pushed lr, pop it, and pop other registers if you had pushed them, then use this exact instruction and the arm will return and switch modes back to the mode that was interrupted (switching to the use of those banked registers).

subs pc,lr,#4

Note you might also need, and it is generally a good idea with ARM, to get the TRM (Techincal Reference Manual) for the specific core, in your case the ARM7TDMI-S. On the infocenter page, left side go to ARM7 Processors, not ARMv7 under architecture but lower where it has ARM11, ARM9, ARM7.

Buttons can be messy with interrupts as they bounce and cause many edges on the I/O pin. Looking at your other post I dont see where you would need an interrupt. You should in general avoid interrupts unless otherwise necessary. they are messy in general. There are designs that you cant avoid using one, certainly. And there are event driven designs where all of your code is an interrupt handler and there is nothing in the application but startup code and an infinite loop (or some sort of sleep).

You can use interrupts to debounce, for example, if you setup a timer interrupt and sample the I/O pins for the buttons in the interrupt, you avoid a fair amount of the bouncing, but you also risk the chance of missing a button press. Just because the button I/O pin is asserted two interrupts in a row that is not two presses, you change a state variable somewhere, and when the button is released you change the state variable. edge changes on that state variable are of interest to the application. when the button goes from unpressed to pressed, do something, if it goes from pressed to unpressed, dont do anything, wait for it to change from unpressed to pressed as an example.

You can also use the same timer interrupt to start or sample the adc.

Since you have not solved your other problem which is also mentioned here, I wouldnt go near interrupts. Figure that problem out first, then decide if there is a feature you need that requires an interrupt. Like even/regular sampling of the adc.

that should be more than enough to get you started. If you do try interrupts DO NOT try them as part of this application, create a completely separate application, for example an led blinker. change the state of the led in the interrupt handler, and/or change a global variable or register in the handler and have the forground watch for that and change the led as a result. Always divide your problems/learning exercises into individual pieces, solve those then glue them together add one piece, test, add one piece, test.

There are more reliable ways of dealing with switch bounce. For example, on a switch interrupt set a timestamp from a free running timer, if a subsequent interrupt occurs within say 10ms of the first, ignore it. Or on a switch interrupt, disable the interrupt, start a timer for say 10ms, then on timer expiry interrupt re-enable the switch interrupt.
–
CliffordMay 19 '12 at 16:23

sure, many ways to do it, just pointing out that there is such a thing (switch bounce) so the poster could go look it up..
–
dwelchMay 19 '12 at 19:41

Dwelch would you please explain this point of yours,So on boot, when you are setting up your normal stack you also want to setup some space for the interrupt stack. Also code for reset setting up interrupt stack?
–
Amit Singh TomarNov 13 '13 at 6:41

where STOP is a target that performs a safe furnace shut-down (i.e. does not leave it running indefinitely).

Note that your loop includes a wait for button1 - surely that should be beforeLoopStart? Otherwise the control loop will wait on a button press on each iteration without performing any control actions - possibly a dangerous situation if the last action was a heaterOn!

Beyond that, note that prior to ARM-Cortex cores (LPX2378 is an ARM7TDMI-S core), the ARM core only defines two interrupt sources IRQ and FIQ, most parts have a separate interrupt controller external to the ARM core itself, and this interrupt controller is vendor specific. Therefore to determine how GPIO interrupts for example are handled on your part, you will need to refer to the device's reference manual rather than ARM documentation.

ARM Cortex-M based devices are rapidly replacing ARM7 devices, and you might be better off with such a device. In particular interrupt handling is far more straightforward, flexible and efficient. See this article for how Cortex-M improves on ARM7.