This is my ISR responding to a switch press on digital pin 2 of the Arduino. I’m assuming my Makerduino is operating @ 16 MHz, so this algo takes 0.9µ seconds.
Btn: push r20 ; Preserve current contents
in r20, SREG
push r20 ; Preserve current status register
push r19 ; and only other register used by ISR
in r20, PORTD
ldi r19, (1 << PD7)
eor r20, r19
out PORTD, r20
; *** Debounce code here
pop r19
pop r20
out SREG, r20
pop r20
reti
Tests have demonstrated this routine works 12 out of 15 times and only when I’m not really definitive with my press or release is there undesired results using this switch. This leads me to think a delay of 500µ would work inside the ISR.
Alternately, set a global variable that represents the number of nano seconds to delay and attach a delay to TIMER0 that has the appropriate duration between events. This would mean, disable INT0 in ISR and re-enable it in TIMER0 when count has elapsed.
(1) Is my thinking correct that no matter what is done in hardware, software should have some kind of debouncing mechanism.
(2) A delay outside the ISR is the only viable option, as the code becomes more complex servicing more handlers, any delay could lead to undesirable problems.
(1) Is my thinking correct that no matter what is done in hardware, software should have some kind of debouncing mechanism.
It depends on the project requirements. What if the hardware normally produces a clean signal, but the application needs to know when the hardware begins to fail ... then any debouncing would prevent this detection. You might find this interesting: Debouncing, hardware and software, part 2
Are you trying to achieve the quickest response possible to the first edge of any signal that has some noise (or bounce)?
DrDiettrich:
What do you want to achieve, by using interrupts and assembly for really simple tasks, like checking a switch?
Primarily, this is a learning experience into AVR architecture and although these snippets are not particularly useful in and of themselves, they do lead to insight. Case in point, this following modification eliminates what is a problem in the previous code by simply writing to the LED the inverse of INT0.
Btn: push r20
in r20, SREG
push r20 ; Preserve stack pointer
sbis PIND, 2
rjmp LED_Off
sbi PORTD, PIND7
rjmp LED_Off + 1
LED_Off: cbi PORTD, PIND7
pop r20 ; Restore stack pointer
out SREG, r20
pop r20
reti
I prefer assembly because of its WYSIWYG nature and I did emulate this algorithm using Arduino IDE in "C" with a resultant size of 1,280 bytes. This code is 170 bytes. I don't intend this to be a flame toward "C" or "C++", but the proof is in the pudding and when confronted with limited space, a tight design is imperative.
dlloyd:
Are you trying to achieve the quickest response possible to the first edge of any signal that has some noise (or bounce)?
Ultimately, that is the goal to design ISR's to be as responsive as possible. I only started 6 days ago with my Makerduino Uno 3, but fundamentally there are a lot of similarities with IA32. Hopefully my experimentation and insight from others will pave the road to near bullet proof designs.
DrDiettrich:
An output pin can be toggled quickly by writing a 1 to its PIN register.
sbi PIND, PIND7
IMO is sufficient, but I'm not an assembly expert.
That was my thinking in the beginning, but as it turns out, any data written to a port is done through PORTx. If the PIN is set to input then writing to the port simply toggles PULL-UP or PULL-DOWN.
If a port is set to output:
pinMode (2, OUTPUT);
then
PIND = PIND | 0b00000100;
will toggle the output pin.
"Three I/O memory address locations are allocated for each port, one each for the Data Register – PORTx, Data
Direction Register – DDRx, and the Port Input Pins – PINx. The Port Input Pins I/O location is read only, while
the Data Register and the Data Direction Register are read/write. However, writing a logic one to a bit in the
PINx Register, will result in a toggle in the corresponding bit in the Data Register. In addition, the Pull-up Disable
– PUD bit in MCUCR disables the pull-up function for all pins in all ports when set."
CrossRoads:
PIND = PIND | 0b00000100;
will toggle the output pin.
Interestingly, changing this to address PIN rather than PORT created some very unpredictable results. Within a couple of button presses, the logic was inverted or sometimes didn’t respond at all.
Even the example on page 79 of the datasheet (section 14) uses IN & OUT, but the difference is, several pins are being changed at one time which would save space.