Tag Archives: arduino

EEPROM advanced usage on Arduino Uno / ATMega328

Storing values in the flash memory of your microcontroller is easy and fast : simply define any variable and assign it a value, you’re done.

But hat happens if your µC is reset ? You see where this is going, right ? EEPROM (Electrically-Erasable Programmable Read-Only Memory) is a persistent memory that allows you to store up to 1024 bytes (1 kilobyte) in your microncontroller, even when it’s turned off.

Arduino offers a native EEPROM library that allows us to easily deal with the EEPROM of the ATMega328 (or whatever Atmel µC your Arduino is running).

Writing and reading values is as simple as following :

int addr = 1;
byte myValue = 42;
byte readValue = 0;

void setup() {
  Serial.begin(9600);
  EEPROM.write(addr, myValue);
}

void loop() {
  readValue = EEPROM.read(addr); // => myValue
  Serial.println(readValue);
  delay(1000);
}

That said, I guess you’re now telling yourself that storing bytes might be quite limiting, and that you’d also like to store ints, chars, or whatever.

Remember, ATMega328 (used in the Arduino Uno) is based on Atmel’s AVR architecture, which allows us to use AVR LibC EEPROM functions, of which :

  • void eeprom_write_word (uint16_t *__p, uint16_t __value)
  • void eeprom_write_float (float *__p, float __value)
  • void eeprom_write_block (const void *__src, void *__dst, size_t __n)

As you probably already know, int variables are stored on 2 bytes, and are hence 16 bits long. Also good to know, the type uint16_t is actually (and basically) … an unsigned int !

Value from analog reading storage example

Let’s say you’d like to store into your EEPROM a value read from one of your analog inputs, which will be an integer between 0 and 1023 (10-bits ADC)  :

#include <avr/interrupt.h>
#include <avr/eeprom.h>

int addr = 1;
int sensorValue = 0;
int readValue = 0;

void setup() {
 Serial.begin(9600);
 while (!eeprom_is_ready()); // Wait for EEPROM to be ready
 cli();
 eeprom_write_word((uint16_t*)addr, sensorValue); // Let's initialize our value into EEPROM
 sei();
}

void loop() {
 sensorValue = analogRead(A0); // Value between 0 and 1023

 while (!eeprom_is_ready());
 cli();
 if(eeprom_read_word((uint16_t*)addr) != sensorValue) {
  eeprom_write_word((uint16_t*)addr, sensorValue);
 }
 sei();

 while (!eeprom_is_ready());
 cli();
 readValue = eeprom_read_word((uint16_t*)addr); // => sensorValue
 sei();

 Serial.print("Sensor value = ");
 Serial.println(readValue);
 delay(1000);
}

Before you begin

  • Always check that EEPROM is ready before reading/writing to it (eeprom_is_ready function)
  • EEPROM storage can handle a limited quantity of erase / write cycles : about 100.000 according to Atmel’s specifications
  • Always prefer the “update” functions rather than the “write” ones, as “update” checks first if the stored data is different than the data, so it erases / writes the new data only if it has changed. Edit on June 19th : update functions are not implemented on Arduino ; however, you may (as updated in the example above) check first if the value has changed before writing, or even use the EEPROMex alternative EEPROM Arduino library.
  • Read / write operations on EEPROM should never be interrupted : you should always disable/clear interrupts (cli()) before any operation and re-enable/set interrupts after (sei()).

1 KB’s not enough ? External I2C EEPROM

One kilobyte of EEPROM storage may not be enough for your project : there are several external EEPROM chips available, as Microchip’s 24AA256 32 KB I2C-enabled EEPROM.

Arduino / ATMega and interrupts

As you certainly already know, Arduino boards (Uno, Mega, Due, etc.) allow us to handle interrupts.

Arduino Uno (based on Atmel’s ATMega328 microcontroller) can handle to external interrupts on it’s pins INT 0 and INT1, mapped to Arduino’s D2 and D3 (respectively pins 4 and 5 of ATMega328 in PDIP package).

External interrupts pins on an Arduino Uno

Interesting fact, ATMega328 (and therefore Arduino Uno) can handle state change interrupts on 20 of it’s pins ; however, handling these interrupts is not as simple as it is with external ones : you need to determine which pin has generated the interrupt, for which reason, etc. Good thing, an Arduino library exists to help us handling these interrupts :  arduino-pinchangeint.

Interrupts can me triggered uppon 4 modes :

  • LOW : pin is in a low state
  • RISING : pin state goes from low to high
  • FALLING : pin state goes from high to low
  • CHANGE : pin state changes

One line of code is enough to “listen” for an interrupt on Arduino ;  for example, on the pin INT0 (which is D2), we attach an interrupt, that will call the method “myInterrupt” when the pin’s state  goes from LOW to HIGH :

attachInterrupt(0, myInterrupt(), RISING);

Please notice that although the Arduino pin is “D2”, we define here pin “0” which is the interrupt pin number (0 for INT0 / D2, 1 for INT1 / D3).

We now define the method that will be called by the interrupt (this method does not take any argument and does not return anything) :

void myInterrupt() {
  // do something ...
}

A few limitations

As interrupts are based on your microcontroler’s timers, method delay() wont work and method millis() wont increment, within  the method attached to an interrupt.

Usually, it is not recommended to run time based operations in your interrupts, which will hang your µC ; for example, serial data transmission (UART), I2C, etc.

Best practices

Using interrupts is very useful to detect user actions, as a button pressed, a keypad, or even to detect a fast state change (infrared signal cut), without having to constantly poll a pin state.

Basically, a method attached to an interrupt should be the shortest and fastest possible : a good practice consists in using interrupts to set a flag in a variable (defined as “volatile”). The execution of the matching action will be done within the main loop.

For example :

volatile int change = 0;

void main() {
  attachInterrupt(0, myInterrupt(), RISING);
}

void loop() {
  if(change == 1) {
    // do something ...
    change = 0;
  }
}

void myInterrupt() {
  change = 1;
}

Useful links

Standalone Arduino (ATMega328) on a breadboard

Arduino Uno board is really amazing for prototyping, but you will soon need to build your own Arduino-like “board” based on an ATMega328 microcontroller, especially for projects where available space is limited and you can’t fit an Uno with it’s shields.

The following Fritzing schema shows how to wire an ATMega328 (with Arduino bootloader installed) on a breadboard (click on schema for full-size image) :

Standalone Arduino on a breadboard

Parts list

These are the components you’ll need :

All these components for no more than $US 7.50. We can still do better and reduce the bill by $US 1.20, flashing a bare ATMega328 ($US 4.30) and by $US 0.50 using a ceramic resonator so the two 22 pF caps are not needed, that is as low as $US 5.80 for an Arduino Uno clone !

Not mandatory but nice to have, an additional ~220 Ω resistor and a LED will be useful for testing purposes.

If you do not have one yet, you’ll also need a 5V USB to Serial converter (FTDI cable, $US 17.95 or breakout board, $US 14.95), that you can wire a shown on the schema :

  • VCC to VCC (+5V)
  • GND to GND
  • RX to TX (pin 3)
  • TX to RX (pin 2)
  • DTR to Reset via a 100 nF (0.1 µF) capacitor

ATMega328 Arduino Uno pinout

You will probably be using Arduino’s native functions to deal with I/O pins, so here is a table mapping ATMega328 pins and Arduino’s :

ATMega328 Arduino pinout(Schema from Sparkfun)

Arduino Ethernet modules and Microchip ENC28J60

Ethernet Microchip ENC28J60 module

If you’d like to connect your Arduino to a local wired network, you have several options :

This last option is offering a big advantage among others : you can use a bare microcontroller (ie. ATMega328) if you don’t need a “big” Arduino Uno for your circuit, which is my case.

As the WIZnet W5100 chip, which is also part of Ethernet shields, the Microchip ENC28J60 chip uses SPI to communicate with micocontrollers.

It can be wired to an Arduino Uno or ATMega328 as following :

Microchip ENC28J60 Arduino Uno ATMega328
CLKOUT N/C N/C
INT D2 Pin 4
WOL N/C N/C
SO D12 Pin 18
SI D11 Pin 17
SCK D13 Pin 19
CS D8 Pin 14
RESET RESET Pin 1
VCC +3.3V +3.3V
(via voltage regulator)
GROUND GND Pin 8

Unfortunately, this Ethernet module does not work at all with Arduino’s standard Ethernet library provided with the IDE. Fortunatrly, an Arduino (> 1.0 compatible) open-source library exists: EtherCard.

To install it, simply download the library’s ZIP and unzip it into your “libraries” folder of your Arduino IDE installation. Rename it to “EtherCard”.

(Re)start your Arduino IDE, you should now see EtherCard appear in File / Examples.

You can test if your module is properly working by loading the “backSoon” example on your µC / Uno.

When reaching the IP address (configured in your code) in your favorite web browser, you should see a “Back Soon” web page.