Category Archives: Electronics

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 : howto master to master I2C

I’ve been working since many weeks (months) on designing a home automation “box” project, and could hardly find a way to get my Arduinos (actually bare ATMega328 + Arduino’s Optiboot bootloader) communicating together without having the (physical) master poll all the other µCs continuously.

After lots of googling, I finally got an answer thanks to the official Arduino Forum : I should use multi-master I2C to allow all my Arduino’s to talk to each other (and that doing, interrupting receivers as it would be the case with slaves).

IC logo

Doing this is in fact pretty simple : you only to use the Arduino’s official Wire (I2C) library as following.

Master #1

#include <Wire.h>

#define I2C_ADDRESS_OTHER 0x2
#define I2C_ADDRESS_ME 0x1

void setup() {
 Serial.begin(9600);
 Wire.begin(I2C_ADDRESS_ME);
 Wire.onReceive(receiveI2C);
}

void loop() {
 delay(5000);
 Wire.beginTransmission(I2C_ADDRESS_LCD);
 Wire.write("hello world from 0x1 to 0x2");
 Wire.endTransmission();
}

void receiveI2C(int howMany) {
 while (Wire.available() > 0) {
  char c = Wire.read();
  Serial.print(c);
 }
 Serial.println();
}

Master #2

#include <Wire.h>

#define I2C_ADDRESS_OTHER 0x1
#define I2C_ADDRESS_ME 0x2

void setup() {
 Serial.begin(9600);
 Wire.begin(I2C_ADDRESS_ME);
 Wire.onReceive(receiveI2C);
}

void loop() {
 delay(5000);
 Wire.beginTransmission(I2C_ADDRESS_LCD);
 Wire.write("hello world from 0x2 to 0x1");
 Wire.endTransmission();
}

void receiveI2C(int howMany) {
 while (Wire.available() > 0) {
  char c = Wire.read();
  Serial.print(c);
 }
 Serial.println();
}

That’s all, now connect Arduino Uno’s I2C pins (A4 [SDA] and A5 [SCL]) between each board, not forgetting the pull-up (1.2kΩ is fine) resistors for both SDA & SCL.

You should then see “hello world” messages sent through serial on both of your Arduino masters.

Graph your sensors data with RRDtool

RRDtool logoAs I am, you may be using your Arduino to gather data from sensors. These could be analog sensors : temperature, humidity, light,  infrared receiver, or digital sensors : door switch (hall effect), mecanic switch, etc.

I chose to store all these data to a MySQL database (over a network connection) so I can process these later as I with. Of course, depending on how often you’re polling your sensors, you may quickly have hundred thousands or even millions entries in your database.

After giving a try to Amcharts, a Javascript graphing library, I eventually decided to use RRDtool to graph my data. That choice allows me to exclusively focus on graph generation, without worrying how data is fetched, if data is time based or not, etc.

In this article, I’ll be specifically covering temperature databases / graphing, as these are the most common (and useful) data collected.

Creating the Round Robin Database

In your favorite terminal, type the following (in your working directory, i.e. your home directory) :

rrdtool create temperatures.rrd \
--step 300 \
-b 123456789 \
DS:temp1:GAUGE:600:0:50 \
DS:temp2:GAUGE:600:0:50 \
RRA:MAX:0.5:1:288

Let’s explain the above command line :

  • rrdtool create temperatures.rrd : create database in file temperatures.rrd
  • –step 300 : we are expecting a 300 seconds (5 minutes) maximum interval between each value
  • -b 123456789 : (optional) it is useful if you plan to insert older values (with a timestamp in the past) ; otherwise, rrdtool will only accept values post the database creation date (replace 123456789 with the oldest timestamp of your data)
  • DS:temp1:GAUGE:600:0:50 :
    • add a data source called temp1 which has values between 0 and 50 (large enough for inside temp in degrees Celsius) ;
    • GAUGE means this is absolute data that shouldn’t be modified in any way by rrdtool, which is the best option for temperatures ;
    • 900 is heartbeat timeout value in seconds : if no data is added within this interval, zero value will be inserted (that will show up as blank on your graphs)
  • DS:temp2:GAUGE:600:0:50 : same thing as temp1 data source, you may add as many as needed
  • RRA:MAX:0.5:1:288 : Round Robin Archive, we define how much data we will store and for how long ;
    • MAX means that only one value (the maximal) should be taken if several are available ;
    • 0.5 should be kept as is (internal resolution) ;
    • 1 specifies that only one step is necessary to store final value, no average is made ;
    • 288 is the number of steps that we will store in our database, in our case, 288 * 300 = 86400 seconds = 1 day ; you may by example set this value to 2016 (7 days)

You should now have a file called temperatures.rrd in your current directory.

Adding data to the rrd database (rrdtool update)

This step is the easiest one. In your terminal, type :

rrdtool update temperatures.rrd N:22:23

A few explainations of this command line :

  • temperatures.rrd : database we’re adding data to
  • N:22:23 :
    • N : use current time as timestamp ; you may here specify the unix timestamp you want (as long as it’s post creation or start date of your rrd database)
    • 22 : value for the first data source (temp1)
    • 23 : value for the seocnd data source (temp2)

Note that you may also use the -t modifier to specify the data sources you’re supplying data for. For more details, you can refer to the official documentation of rrdupdate.

To keep your rrd database up to date, the best option is to set up a cron task that will update it every 5 minutes with the last data available.

Let’s make it to the next step : graphing the data !

Generating your graph

This part is where all the magic happens.

rrdtool graph temp_graph.png \
-w 785 -h 120 -a PNG \
--slope-mode \
--start -604800 --end now \
--vertical-label "temperature (°C)" \
DEF:temp1=temperatures.rrd:temp1:MAX \
DEF:temp2=temperatures.rrd:temp2:MAX \
LINE1:temp1#ff0000:"temp 1" \
LINE1:temp2#0000ff:"temp 2"

Explainations of the above command line :

  • rrdtool graph temp_graph.png : generate the graph in a file called temp_graph.png in the current directory
  • -w 785 -h 120 -a PNG : width 785, height 120, PNG format
  • –slode-mode : smooth line
  • –start -604800 –end now : graph begins 7 days ago (604800 seconds) and ends now
  • –vertical-label “temperature (°C)” : vertical axis label
  • DEF:temp1=temperatures.rrd:temp1:MAX : we are using temp1 data source from temperatures.rrd
  • DEF:temp2=temperatures.rrd:temp2:MAX : same as temp1
  • LINE1:temp1#ff0000:”temp 1″ : draw temp1 as a red line with “temp 1” label
  • LINE1:temp2#0000ff:”temp 2″ : draw temp2 as a blue line with “temp 2” label

If you’re working on a remote server, copy your newly created graph to some directory in your webserver path and reach it via it’s URL. Tada !

Here are my 4 temp sensors values graphed :

Temperatures RRDtool graph

Temperatures RRDtool graph

Thanks to this tutorial of Calomel.org for helping me understand RRDtool better and of course, do not hesitate to have a look at the official RRDtool documentation.

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.

Raspberry PI + Xbee: UART / Serial howto

Happy owner of a Raspberry PI for almost a year now, I couldn’t resist to take advantage of if advanced features, and especially it’s GPIO, to communicate with my other electronics parts including my Xbee-enabled wireless sensors.

Although RPI’s onboard UART usage seemed quite simple at first, it finally took me some time to figure out exactly how to read my first bytes received trough UART via Xbee on my RPI, that’s why I’m writing this short snippet.

On the original Debian available for the Raspberry PI, the UART allow you to have a serial console so you can connect to it, without needing network nor SSH.

It takes a few steps to change this default behavior so we can connect our Xbee (Series 1) to our RPI.

First of all, you will need to edit the /boot/cmdline.txt file :

sudo cp /boot/cmdline.txt /boot/cmdline.txt.bak # Backup file
sudo vi /boot/cmdline.txt

Remove all references to ttyAMA0 (console and kgdboc) so your file looks something like that :

dwc_otg.lpm_enable=0 rpitestmode=1 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait

Now edit /etc/inittab :

sudo cp /etc/inittab /etc/inittab.bak # Backup file
sudo vi /etc/inittab

Comment out the following line :

2:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100

Now reboot your Raspberry PI.

Let’s now connect our Xbee to the RPI’s GPIO. Here is a quick schema explaining how :

Raspberry PI Xbee

Raspberry PI and Xbee Series 1

Note that on this schema, I only connected a wire from Xbee’s DOUT to RPI’s RXD as will only use it to receive data. However, you might also connect your Xbee’s DIN to RPI’s TX according to this RPI GPIO pinout.

Your Raspberry PI should now receive it’s first bytes via the Xbee ; you can test this using Minicom (sudo aptitude install minicom, if not already installed) :

sudo minicom -b 9600 -o -D /dev/ttyAMA0

(You could also use minicom without sudoing by adding your current user [I guess pi] to dialout group)

Special thanks to Clayton Smith’s blog post which greatly helped me figure out what was wrong with my RPI’s UART.