Ardjson: https://ardjson.codeplex.com
Previous: Ardjson-Part9b: Azure Mobile Services Scripts
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:
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:
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 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.
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.
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.
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::