Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Optimizing the reaction time of the ATMega328
/**
* ---------------------------------------------------------------------------
* Control of an LED by a push button with an Arduino Nano board
* ---------------------------------------------------------------------------
* Classical approach with the Arduino API
* ---------------------------------------------------------------------------
* PIN |
* ----+----------------------------------------------------------------------
* D2 | Push button wired up to a pull-down resistor (10 kΩ)
* ----+----------------------------------------------------------------------
* D4 | Red LED with a 220 Ω resistor in series
* ----+----------------------------------------------------------------------
*/
#include <Arduino.h>
#define BTN_PIN 2
#define LED_PIN 4
#define DEBOUNCE_DELAY_MS 1
bool led_level = LOW;
uint8_t input;
uint8_t last_input;
uint8_t output;
uint32_t last_debounce;
void setup() {
pinMode(BTN_PIN, INPUT);
pinMode(LED_PIN, OUTPUT);
}
void loop() {
uint32_t now = millis();
input = digitalRead(BTN_PIN);
if (input != last_input) last_debounce = now;
last_input = input;
if (now - last_debounce > DEBOUNCE_DELAY_MS) {
if (output != input) {
output = input;
if (output) {
digitalWrite(LED_PIN, led_level = !led_level);
}
}
}
}
/**
* ---------------------------------------------------------------------------
* Control of an LED by a push button with an Arduino Nano board
* ---------------------------------------------------------------------------
* Dramatically improved reaction time of the ATMega328
* ---------------------------------------------------------------------------
* Pinout:
* ----+------+
* PIN | PORT |
* ----+------+---------------------------------------------------------------
* D2 | PD2 | Push button wired up to a pull-down resistor (10 kΩ)
* ----+------+---------------------------------------------------------------
* D4 | PD4 | Red LED with a 220 Ω resistor in series
* ---------------------------------------------------------------------------
* Instead of using the digitalRead() and digitalWrite() functions of the
* Arduino API, we will instead use the internal registers, and the INT0
* interrupt vector (External Interrupt Request 0) of the ATMega328.
* ---------------------------------------------------------------------------
* As a result, the reaction time of the ATMega328 is 1000 times faster!
* ---------------------------------------------------------------------------
* Documentation:
*
* @see https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf
*
* I/O Ports:
*
* PORTD - The Port D Data Register
* ----+--------+-------+-----------------------------+---------
* PD2 | PORTD2 | Bit 2 | External Interrupt Source | pp.71,73
* PD4 | PORTD4 | Bit 4 | Pin Change Interrupt Source | pp.70,73
* ----+--------+-------+-----------------------------+---------
*
* Register Description:
* -------+---------------------------------------+-------+-----
* SREG | AVR Status Register | | p.11
* SREG_I | Global Interrupt Enable | Bit 7 | p.11
* EICRA | External Interrupt Control Register A | | p.54
* ISC01 | Interrupt Sense Control 0 | Bit 1 | p.54
* ISC00 | Interrupt Sense Control 0 | Bit 0 | p.54
* EIMSK | External Interrupt Mask Register | | p.55
* INT0 | External Interrupt Request 0 Enable | Bit 0 | p.55
* EIFR | External Interrupt Flag Register | | p.55
* INTF0 | External Interrupt Flag 0 | Bit 0 | p.55
* DDRD | Port D Data Direction Register | | p.73
* -------+---------------------------------------+-------+-----
*
* Interrupt Sense Control 0:
* ------+-------+------------------------------------------------------------
* ISC01 | ISC00 | Description
* ------+-------+------------------------------------------------------------
* 0 | 0 | The low level of INT0 generates an interrupt request
* 0 | 1 | Any logical change on INT0 generates an interrupt request
* 1 | 0 | The falling edge of INT0 generates an interrupt request
* 1 | 1 | The rising edge of INT0 generates an interrupt request
* ------+-------+------------------------------------------------------------
*/
#include <Arduino.h>
#define DEBOUNCE_DELAY_MS 1
ISR(INT0_vect) {
EIMSK &= ~(1 << INT0); // Override of interrupt vector INT0
PORTD ^= 1 << PD4; // PD4 bit toggle
}
void setup() {
DDRD &= ~(1 << PD2); // Setting the button reading pin
DDRD |= 1 << PD4; // Setting the LED control pin
EICRA = (1 << ISC01) | (1 << ISC00); // Setting the interrupt vector INT0 (RISING)
EIMSK = 1 << INT0; // Arming the interrupt vector INT0
SREG |= 1 << SREG_I; // Activation of interrupts
}
void loop() {
static uint32_t last = 0;
uint32_t now = millis();
// If the interrupt vector INT0 has been disarmed,
// and the debouncing time has expired...
if (!(EIMSK >> INT0) && now - last > DEBOUNCE_DELAY_MS) {
last = now; // Reset the stabilization window
// Resets the interrupt vector INT0
// as soon as the read pin is at LOW
if (!((PIND >> PD2) & 0x1)) {
EIFR = 1 << INTF0; // Cancels any previous interruption on interrupt vector INT0
EIMSK = 1 << INT0; // Rearming the interrupt vector INT0
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment