Blinkenlight Shield Compatibility

The Blinkenlight Shield is 100% hard- and software compatible to all known versions of Arduino. However some readers notices that some of the sketches on my pages do not work with their Arduinos. The dirty little secret is that even original Arduinos are not 100% compatible to each other. They may differ in their pin layout and/or their inner workings. Thus my example sketches are not 100% software compatible to all versions of Arduino. They can be adapted to other Arduino variants but since I do not own all of them I have no way of testing everything. Instead I will describe the differences and hopefully enable everyone to fix it on their own.

There are some issues to consider.

  1. Port Mapping
  2. Digital Pin Mapping
  3. Timers
  4. Clock Stability

Port Mapping

All Arduino variants (but the Due) use some AVR microcontrollers. These controllers organize the IO with so called ports. Up to 8 (digital) IO pins are controlled by a port. The ports are usually enumerated with letters A, B, C and so on. Accordingly the ports are called port A, port B, port C and so on. Each port is controlled by several registers. These are the data direction register (usually abreviated DDR), the port input register (abreviated PIN) and the port output register (PORT). For example port A is controlled by the registers DDRA, PINA and PORTA.

Controlling the attached IO pins is subject to some relatively easy bit manipulation but the Arduino inventors decided to add some hardware abstraction most notably the the digitalRead and digitalWrite functions.

Here come two old rules of computing:

  • You can always hide complexity by adding a layer of abstraction.
  • You can always improve performance by removing a layer of abstraction.

Due to the intended target group of Arduino the designers valued simplicity over performance. However for some of my experiments I need the maximum possible performance and thus implement direct port manipulations. Unfortunately different variants of Arduino have different chips and thus different physical port to pin mappings. As a consequence all experiments that rely on some specific port to pin mapping will only work with boards that have an Atmega 88, Atmega 168, Atmega 328 or another chip with compatible port to pin mapping.

The bottom line is: as soon as my sketches contain some assigned to a PORT variable you need an “real” Arduino. That is one with a compatible port/pin mapping.

Examples for such sketches are all removing flicker sketches like the heartbeat sketch. In order to fix this you have to possible routes. You may either download the datasheets for the Atmega 328 as well as your Arduino from Atmel. Another option is to search for the pin/port mappings in the Arduino source files. The relevant files are the pins_arduino.h files which are found below arduino/hardware/arduino/variants. Either way you can find out the proper pin/port mappings and the adapt the sketches accordingly to your controller.

Digital Pin Mapping

If performance does not matter that much direct port manipulation is somewhat anoying. Thus the digitalRead and digitalWrite functions provide very convenient abstractions to address the pins. What most Arduino users are not aware of is the fact that all IO pins are digital pins. That is the pins labelled A0-A5 are digital pins as well. Conveniently they are mapped as pins 14-19. This makes a lot of sense as the other pins are 0-13. However for the some Arduino variants the pin mappings for the pins above 13 are different. I can only specualte why this is the case. Interestingly the proper pin numbers can be read from the constants A0-A5. Also for all boards it seems to hold that A0+1 = A1, A1+1 = A2, …, A4+1 = A5. Thus the sketches that require access to all 20 Pins of the Blinkenlight Shield can be modified to work with other than the “original” Arduino.

The crucial piece is to recompute the proper pin values with a small helper function like below.

uint8_t led_to_pin(const uint8_t led) {
    return led<14? led: led-14 + A0;
}
[/code]

For example the sketch below does not work with all Arduino variants.


//
//	www.blinkenlight.net
//
//	Copyright 2011 Udo Klein
//
//	This program is free software: you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	This program is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with this program. If not, see http://www.gnu.org/licenses/

// This sketch will set all outputs to high.

void setup() {
	for (uint8_t pin=0; pin<20; ++pin) {
		pinMode(pin, OUTPUT);
		digitalWrite(pin, HIGH);
	}
}

void loop() { }

Adding the mapper function like below will make it work for every version of Arduino.

//
//	www.blinkenlight.net
//
//	Copyright 2013 Udo Klein
//
//	This program is free software: you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	This program is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with this program. If not, see http://www.gnu.org/licenses/

// This sketch will set all outputs to high.

uint8_t led_to_pin(const uint8_t led) {
    return led<14? led: led-14 + A0;
}

void setup() {
	for (uint8_t led=0; led<20; ++led) {
		pinMode(led_to_pin(led), OUTPUT);
		digitalWrite(led_to_pin(led), HIGH);
	}
}

void loop() { }

Timers

Some of my experiments require tight control on hardware timers. Although the operation of timers is very similar between different Atmel processors it is not exactly the same. Typically the differences are in the naming of the timer registers and the assignment of the different flags. In theory I could look them all up (or look up how existing libraries call them). Since I do not own all these variants I do have no way to test such code. If you want to port the timer code to a different CPU you can either look up the datasheets or peek how existing timer libraries handle the different registers.

Clock Stability

Most of my DCF77 experiments require a stable local clock. Unfortunately the Arduino team decided to “improve” newer Arduinos (like the Uno). The “improvements” mainly decrease manufacturing cost. One of them is the replacement of the 16 MHz crystal by a resonator. Crystal stability is almost always better than 50 ppm, even poorly designed crystal oscillators can reach this pretty easily. Resonator stability on the other hand is usually worse than 1000 ppm and sometimes even as bad as 5000 ppm (that is 0.5%). In general crystals are ~100 times more stable than resonators. As a consequence you need an Arduino with a crystal clock.

If you can solder you can retrofit the “improved” Arduinos with a crystal or a crystal oscillator. If you can not solder you need to get hold of a crystal based design (e.g. Arduino Due). Of course the Blinkenlighty was designed with a crystal and without to much consideration of the manufacturing costs. Since it also has integrated Blinkenlights and comes with a (German) manual you may consider this as another option. As a bonus with each Blinkenlighty you also help to fund my blog 🙂

2 Responses to Blinkenlight Shield Compatibility

  1. Ramade says:

    Hello
    I got recently one of your blinkenlight board.
    I am since a bit puzzled about the suitable arduino board to buy ;
    For I am not an arduino expert ; can you be more explicit for the
    ‘good choice’ or at least a ‘good’ solution;
    -ie a seller web adress in france or germany for instance .
    thanks for the help
    greatings
    mik

    • Hi Mik,

      I suggest to search for an “older” compatible board. E.g. like the SainSmart Duemilanove clone. This can be found at *bay for ~15 Euro including shipping. This would most probably deliver the most bang for the buck. If you are not interested in any of the timing relevant experiments an Uno or compatible will do.

      Greatings,
      Udo

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s