Ardjson: https://ardjson.codeplex.com    

Previous: Ardjson-Part9b: Azure Mobile Services Scripts


In the quest to reduce RAM usage with a RAM challenged Arduino device, this blog covers using permanent storage (Flash and EEPROM).

When compared to the desktop, Arduino devices are RAM poor. Whilst it is suitable to store all of a JSon Response string and then parse it with a desktop app,as  it has been discussed in previous blogs, it isn’t appropriate for small devices. First, the size of a response to an HTTP GET is unknown. Second, the required post parsing data structure size is unknown. The first issue was addressed by developing a Stream Parser that processes the JSon string as it is received character by character. The second issue is addressed by restructuring the data so it is much smaller. One way that this is achieved is by using an auto-incremented 2 byte integer for an id rather than the default 36 byte GUID string.

 

An additional approach for minimising RAM usage is to place all permanent or semi-permanent data in non-volatile storage such as Flash or EEPROM. That data can be updated as required and a sketch can read it from those locations:


There are three pools of memory in the microcontrollers used on Arduino boards.

 

Flash memory (program space), is where the Arduino sketch is stored.
SRAM (static random access memory) is where the sketch creates and manipulates variables when it runs.
EEPROM is memory space that programmers can use to store long-term information.

Flash memory and EEPROM memory are non-volatile (the information persists after the power is turned off). SRAM is volatile and will be lost when the power is cycled.

Note: Flash (PROGMEM) memory can only be populated at program burn time. You can’t change the values in the flash after the program has started running.

The amounts of memory for various microcontrollers used on Arduino boards are as follows:

  ATMega168 ATMega328P ATmega1280 ATmega2560
Flash
(1 Kbyte used
for bootloader)
16 KBytes 32 KBytes 128 KBytes 256 KBytes
SRAM 1024 bytes 2048 bytes 8 KBytes 8 KBytes
EEPROM 512 bytes 1024 bytes 4 KBytes 4 KBytes

Reference:

Arduino Playground – Memory


The Arduino UNO uses the ATMega328 and hence there is not much dynamic storage available. An sketch is stored in Flash when uploaded and run from there.

 

Once uploaded, the sketch runs whenever the device is reset or powers up. Permanent unchanging strings can also be explicitly stored in Flash. In fact any program data that is unchanging, or at least can wait for a recompilation can be made available from there. Other volatile data is created in RAM as a program runs. Global data is created in RAM when the sketch starts with initializers copied directly from flash. Local variables (local to a function) are created in RAM on the stack when the function is called.. “Under the hoop” a heap may also be used which also consumes RAM space. Semi-permanent data that is only occasionally downloaded and/or updated can be stored in EEPROM as it can be changed whilst an sketch is running Writing to EEPROM is slower than to RAM and so you don’t treat it as read/writeable in the same manner as RAM

 

 

EEPROM data can be written to (albeit slowly) whilst a sketch is running whereas Flash data can only be written when the sketch gets flashed.

 

 

So how do you program data for Flash and the EEPROM?

Flash Storage

Flash storage would be used for any data structure that isn’t subject to any change. Consider a string (as array of characters):

char senor ="Temperature1";

This would take up 13 bytes of RAM (one extra for the null termination). At run time it would be copied along with the rest of the program from Flash into RAM. This can remain in Flash and be used indirectly from there using t the PROGMEM directive. It requires the pgmspace header file:

#include <avr/pgmspace>

...

char senor  PROGMEM="Temperature1";

Getting the data back is a little cumbersome

char ch;
for (i = 0; i < 13; i++)
{
  ch = (char) pgm_read_byte_near(sensor + i);
  Serial.print(ch);
}

 

PGM functions are :

pgm_read_byte_near
pgm_read_word_near
pgm_read_dword_near
pgm_read_float_near

Al take a (near) address. There are also  _far versions of these.

Strings in Flash

Whist the example above was for a string it is applicable to al types of data structures, Strings though do have a simpler retrieval mechanism, the F() syntax. For example:

Serial.println(F("Temperature1"));

The string in this case would be stored in Flash and inplicitly used from there. No need to be explicitly copied into RAM.

 

Thus it is encouraged to similarly place all of your UI messages in Flash in this manner.

 

EEPROM Storage

Electrically Erasable Programmable Read Only Memory

An EEPROM write takes 3.3 ms to complete. The EEPROM memory has a specified life of 100,000 write/erase cycles, so you may need to be careful about how often you write to i.

 

Writing to EEPROM:

#include <EEPROM.h>

...

EEPROM.write(137,10);

This write the byte 10 at address 137 in EEPROM space.

 

Reading from EEPROM

#include <EEPROM.h>

...

int value = EEPROM.read(137);

This would read the byte at EEPROM address 137 into the variable.

There is also an extended EEPROM library EEPROMex (that needs to be downloaded) that can work with various numeric data types rather rather single bytes.

 

Summary

Non-volatile storage,Flash and EEPROM are a suitable locations for constant data and for semipermanent data (with the EEPROM). Use of these can free up RAM.

Sample sketch to test the code from above:

#include <avr/pgmspoace>
#include <EEPROM.h>

const char sensor  PROGMEM="Temperature1";
void setup()
{
  Serial.begin(9600);

  while (!Serial) {
    ; // wait for serial port to connect.
  }

  Serial.println("Starting:\r\n");
}

void loop()
{
  int i; 
  char ch; 
  Serial.println("Testing Flash PROGMEM");
  Serial.print("Expect: \"Temperature1\"\r\nGot:     ");
  for (i = 0; i < 13; i++)
  {
    ch = (char) pgm_read_byte_near(sensor + i);
    Serial.print(ch);
  }
  Serial.println();
  Serial.println();
  
  Serial.println("Testing Flash strings with F()");
  Serial.print("Expect: \"The quick brown fox jumps oer the lazy dog.\"\r\nGot:     ");
  Serial.println(F("The quick brown fox jumps oer the lazy dog."));
  Serial.println();
  Serial.println("Testing EEPROM");
  int val =10;
  int addr = 137;
  EEPROM.write(addr,val);
  delay(50); //Takes 33mS to write
  int value = EEPROM.read(addr);
  char message[30];
  sprintf(message,"Wrote %d to EEPROM address %d", val, addr);
  Serial.println(message);
  sprintf(message,"Read %d back from %d", value, addr);
  Serial.println(message);
  Serial.println("\r\nDone");
  while (1);
}

 

Output::

Starting:

Testing Flash PROGMEM
Expect: "Temperature1"
Got:     Temperature1

Testing Flash strings with F()
Expect: "The quick brown fox jumps oer the lazy dog."
Got:     The quick brown fox jumps oer the lazy dog.

Testing EEPROM
Wrote 10 to EEPROM address 137
Read 10 back from 137

Done

 


Next::