Archive for February, 2012

Precious Memory

There are two kinds of memory(well three including EEPROM, but we won’t deal with that here) you can run out of when doing an Arduino project (or any embedded project):

  1. Flash Memory: For a lot of applications, the Arduino has a fairly big flash memory (the UNO and all atmega328 based Arduinos give you 32k flash.) The Arduino IDE will also tell you if your program size exceeds the amount of flash in the particular Arduino you have selected.
  2. Static RAM: Atmega328 in the UNO gives you 2k of RAM. This is the most precious commodity in Arduino programming, and it’s often surprising how fast you can run out. The bad thing is,  the IDE won’t warn you, and your program can go from working to behaving really weirdly by doing something as simple as adding an additional debug print statement. This post will attempt to explain this, and give you a few tips for understanding your RAM use.

Where Did it All Go?
When you run out of SRAM, your program can just stop working, for reasons ranging from one data structure overwriting another (so your program does something based on the wrong value) to overflowing into the stack. When that happens, generally, your program dies a horrible death, because returning from subroutines can cause the processor to jump to random places in memory. If you make an innocuous change to your code (like adding another debug statement) and your program suddenly behaves very differently, chances are you have run out of SRAM.

It’s obvious if you declare large variable arrays like:

int valueArray[1024];

would instantly overflow memory because int’s occupy 2 bytes in atmega land. You also need to leave room for stack, and any other variables your libraries, and the Arduino software itself uses.

What’s Harvard got to do with it?
Not so obvious is the fact that:

Serial.println("Hello");
const char constantString[] = {"Hello"};

both  occupy 6 bytes in both flash memory and in SRAM (c-strings are terminated with a Null, or 0×00 byte).  The reason is AVR 8 bit microcontrollers use a Harvard architecture addressing scheme. This means that when an instruction addresses memory, there are two versions, one that addresses program memory (flash), and another to address RAM. Most routines like Serial.println use regular RAM, as they don’t know if you’ll be passing in constant info or stuff that you’ve constructed. As a result, even static strings (with a const declaration) are copied from flash to SRAM at system startup. It’s possible to write routines to only use flash (using the PROGMEM attribute) and it’s definitely useful, but that’s covered elsewhere.

I ran into this porting the avrdude stk500 routines to Arduino, blindly converting the printfs into Serial.print statements. In order to get enough RAM I ended up using numeric codes for errors (I’ll probably eventually get around to PROGMEM-ing them).

So, how do you tell if you are nearly running out, or have already? The IDE won’t tell you, so you have to dig in a little.

The build process for arduino produces an “ELF” file or Executable and Linkable File. This is used to create the actual HEX file for programming, but still has memory segment information embedded in it.

First find your build directory. On Windows 7 this is \users\<youruser>\AppData\Temp\build<a bunch of numbers>.tmp

Now, assuming you have the avrdude files somewhere in your path, use the command:

avr-size -C --mcu=atmega328p <yourelf-file.elf>

For example, the current version of Bootdrive gives me:

avr-size -C --mcu=atmega328p BootDrive.cpp.elf
 AVR Memory Usage
 ----------------
 Device: atmega328p
Program: 19272 bytes (58.8% Full)
 (.text + .data + .bootloader)
Data: 1340 bytes (65.4% Full)
 (.data + .bss + .noinit)

It’s probably best not to go beyond 95% full for your Data (that’s the SRAM part) to save room for your stack, and even less if you pass big variables on the stack or have deep call chains.

24

02 2012

BootDrive for Arduino

Announcing the formal release of BootDrive for Arduino. If you’ve been reading the blog, you know that I’ve been working with Justin Shaw of Wyolum labs to enable their I2SD (Arduino clone with a micro-sd card) to bootload a program onto another Arduino. After battling several issues, mostly related to porting avrdude code to the Arduino (assumptions about infinite memory, etc!) it’s working well enough people can fool around with it.

Right now the code looks for a single file (“program.hex”) and waits 5 sec and then blasts it into the target arduino. Details about setting up to try this yourself follow the video.

Here’s a demo of it in action:

If you’d like to try this with a couple of Arduinos, you’ll also need an SD card (or micro-sd) interface such as the Adafruit Micro-SD breakout. This board is great because it has onboard 3.3v conversion so it’s safe to use with 5V (stock) Arduinos. Download the code from github: https://github.com/osbock/Baldwisdom/tree/master/BootDrive
or a zipped version here

Hook up your Arduinos like this:

I

The basic setup is:

Arduino Control:
Master Digital Pin6  –> Target reset
GND                                –> GND
MASTER Digital Pin1 –>Target Digital Pin2
MASTER Digital Pin2 –>Target Digital Pin3

SD Card Interface:
 Master Digital Pin 10 –> SD-breakout CS
Master Digital Pin 11  –>  SD breakout DI
Master Digital Pin 12  –> SD breakout DO
Master Digital Pin 13  –> SD breakout CLK
Master GND                    –> SD breakout GND
Master 5V                       –> SD breakout 5V

Optional debugging serial interface (This lets you see error messages and the like)
Master GND    –> FTDI cable Pin 1 (GND)
Master Digital Pin 4 –> FTDI cable Pin 5 (diagram is wrong, but you can change it in the code if you need to)

Here are the defines you can change to swap the pins around:

#define BOOT_BAUD 115200 // This is the Arduino UNO’s bootloader baud rate. Other boards are different!
#define DEBUG_BAUD 19200 // for software serial debugging
#define txPin 4
#define rxPin 5 // not really used…
#define rstPin 6

Also if you want to put your SD card on a different line (or are using a shield that uses a different chip select) change this:

const int chipSelect = 10;

Action!

Right now, 5 seconds after initialization, the program blasts a file called “program.hex”. You can add your own user interface to select amongst multiple programs.
Just call:

void programArduino(char *filename)

with the filename, e.g.”

programArduino("program2.hex");

You can build new hex files by grabbing them from the Arduino build directory. Make sure you have the IDE set up for your target board and press the “compile/verify” button.

From http://arduino.cc/en/Hacking/BuildProcess:

The .hex file is the final output of the compilation which is then uploaded to the board. During a “Verify” the .hex file is written to /tmp (on Mac and Linux) or \Documents and Settings\<USER>\Local Settings\Temp (on Windows). During upload, it’s written to the applet sub-directory of the sketch directory (which you can open with the “Show Sketch Folder” item in the Sketch menu)

Note on Windows7, the base directory is \users\<USER> \appdata\local\Temp\build<some bunch of numbers>.tmp\<sketchname>.cpp.hex

Note that if you want to load an Arduino other than UNO, you’ll need to change the baud rate. You can find that in “hardware/arduino/boards.txt” in the arduino directory. This won’t work on MEGA based Arduinos as they use the stk500v2 protocol (thanks westfw!)

16

02 2012