Developing in C for the ATmega328: Using PROGMEM
Where I discuss how to use PROGMEM (storing values in Flash memory) for storage.
Introduction
Storing message strings in AVR RAM can become prohibitively expensive, very quickly. With only 2KB of RAM, the Uno needs as much RAM available for dynamic storage, while message strings are best stored in Flash memory. Due to the AVR microcontroller’s different architecture, you can’t simply read the Flash memory as reading RAM. You also can’t simply “embed” strings in Flash, by making them a constant, there are very specific commands to do both of these tasks.
This entry will describe three different methods of printing the contents of Flash memory along with storing and retrieving values as well.
Storing in PROGMEM
The simple way to store data in PROGMEM is to use the PROGMEM macro along with the C language declaration constructs:
const char ParameterA[] PROGMEM = "Parameter A";
const char ParameterB[] PROGMEM = "Parameter B";
- const: In this case, since the data will be in Flash memory, it won’t be alterable. The C99 avr-gcc compiler will demand this.
- char: For string data, make it a char.
- ParameterA[]: Name it and make it an array so we can store a string.
- PROGMEM: Places all of it in program memory (Flash) and not RAM.
- “Parameter A” the desired text to be stored, typically, static error or informational messages.
Simple byte access
|
|
This is the most simple and common method used to access variables in PROGMEM, the pgm_read_byte().
- Line 1: pointer to the message array and a value passed to the function
- Line 6: the macro strlen_P will provide the length of the message array
- Line 8: pgm_read_byte will fetch each character from Flash
- Line 9: print the character
- Line 11: finish by printing the value passed as well
I use this same method to fetch the constants required for creating a tone via one of the ATmega PWM channels. There are three constants, each one in an array in Flash and the array is indexed by a musical note. When tone() is provided a note, it uses pgm_read_byte(array(note)) to fetch each one of the constants, then it uses the three constants to program the PWM.
Simple, non-standard string access
|
|
This method is recommended by Dean Camera and uses a non-standard version of format to make it work. In this case, we treat the array as a C string and print using the %S format. The capital S format was written to print strings stored in Flash memory. It isn’t part of standard C and will cause an warning unless you specifically use -Wno-format when you compile.
More complex, yet standard string access
|
|
This last version is from the AVR-GCC FAQ. While an explanation is provided, its a bit terse and not entirely comprehisible (to me.)
In a nutshell, the memory is setup in the same manner as the previous two examples. They (Lines 1-5) add an array which consists of the two addresses of the arrays in program memory (PROGMEM). The access to the messages is via this second array. An index (msg) is provided to select the specific array in Flash memory (Line 17) and that array is used to fill a buffer (Line 21) which is subsequently printed (Line 21).
The value of this approach is that it doesn’t require the non-standard format of the previous example. I thought it would be faster, however, all three methods take the same amount of time to print.
Comments powered by Talkyard.