Attempting to enable the external interrupt on a ATmega328P via the following lines:
LDI R16, (1 << ISC00) | (1 << ISC01)
LDI R17, (1 << INT0)
STS EICRA, R16
STS EIMSK, R17
SEI
during my reset subroutine.
The idea is to have INT0 trigger a external interrupt upon a rising edge (i.e. from button press). The appropriate JMP
instruction has been placed withing the interrupt vector table at 0x0002
.
During debugging in Atmel Studio 6 using the simulator, not only does no interrupt run when I toggle the INT0 pin, whilst manually stepping over instructions I found that the EIMSK
register isn't being updated and that the instruction STS EIMSK, R17
seems to be doing completely nothing despite R17 being set to 0x01 just prior execution of that instruction.
Quite a noob at AVR assembly, is this an issue with my code or something in atmel studio.
check also the following points:
EIMSK
lies in the address range that is supported by OUT
. if you refer it via data store/load instructions you have to add some constant (0x20) to its addressadditional to this i think its not a good idea to let a pushbutton trigger an interrupt, because pushbuttons bounce. so you get several dozens of interrupts per button push.
you should read about debouncing techniques and consider an timer interrupt driven readout of button state with software debouncing. if you understand german you may read http://www.mikrocontroller.net/articles/Entprellung this is a very good article and an efficient and nice implementation for debouncing of multiple keys.
at http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=54896&start=0 this question is asked:
some registers are both IO and memory mapped so neither 'OUT' and 'STS' generate a compiler error but only one works. How can this be easily be determined?
two answers were given. one quite pragmatic approach:
using IN/OUT by default and only LDS/STS on compiler error alway is correct
the other suggest using some asembler macros that distinguish between both cases (did not tested them):
; usage: InReg reg, addr
.macro InReg
.if @1 < 0x40
in @0, @1
.elif ((@1 >= 0x60) && (@1 < SRAM_START))
lds @0,@1
.else
.error "InReg: Invalid I/O register address"
.endif
.endmacro
; usage: OutReg addr, reg
.macro OutReg
.if @0 < 0x40
out @0, @1
.elif ((@0 >= 0x60) && (@0 < SRAM_START))
sts @0,@1
.else
.error "OutReg: Invalid I/O register address"
.endif
.endmacro