SMILEY’S WORKSHOP ☺
is less portable. It’s a tradeoff well worth the
sacrifice, though, if we are using the AVR with the
free WinAVR toolset.
PSTR attribute for in line strings
We use PROGMEM to store constant strings
and arrays in Flash. We can also use the PSTR
attribute to create strings in the parameter list of a
function in a line of code. For instance:
■ FIGURE 2. Intel hex format for pgmtest.hex data.
sendStringP(PSTR(“This is a test for sending a
string.\r”));
We’ll see how this works in our pgmtest.c
demonstration program [available in Workshop25.zip at
www.nutsvolts.com].
Reading sections of Flash program memory
The final demonstration is for reading sections of
program memory. Avrlibc has a bunch of functions for
accessing program memory, depending on the data type
to be accessed, and whether the data is in the lower 64K
or in higher memory. We will only look at the function for
reading bytes from the lower memory: pgm_read_byte().
We use this function in another function that sends Flash
strings out the serial port:
void sendStringP(const char *FlashString)
{
int i = 0;
// The ‘for’ logic terminates if the byte
// is ‘\0’ or if i = 80.
// ‘\0’ is ‘null’ and terminates
// C strings
// The 80 prevents too much overrun if we
// get a bad pointer
// and it limits the string size
for( i = 0 ; pgm_read_byte(&Flash
String[i]) && i < 80; i++)
{
sendByte(pgm_read_byte
(&FlashString[i]));
}
}
Now, please relax when reading this ... yes, there will
be pointers. The first is the pointer FlashString which is set
to point to a constant character; in our case, the first
element of a string array. We then use it as an array with
the subscript ‘i’ being incremented to indicate the specific
character in the FlashString array; we add the ‘&’ ‘address
of’ operator to get the specific address of the specific
character at that position in the array. See ... that wasn’t so
hard, was it?
But then we do something a bit doofy in the ‘for’
loop that runs the loop until one of two things happen as
shown below:
pgm_read_byte(&FlashString[i]) && i < 80;
We want the loop to exit if one of two conditions
occur. The loop will run as long as &FlashString[i] is
true — meaning it is not equal to 0 and ‘i’ is less than
80. We do this because we terminate a string with
0x00 (the null character), so we want to end our loop if
we see that character. We will also end the loop if ‘i’
gets up to 80, thus limiting our string size to 80
characters. This assures that the for loop will exit if we
accidentally send it a pointer to an array that isn’t
terminated by 0x00.
Let’s Look At The Flash Memory
When we compile our pgmtest.c program (we’ll do
that later), the compiler generates several files. The
pgmtest.hex file is the file we upload to our development
board using the bootloader resident on the AVR. The
pgmtest.hex file (in the source code default directory)
contains the binary code for program in the form of an
Intel hex file (shown in Figure 1). [Note that I’ve marked
several lines in color because we will look at these later].
You can use Programmer’s Notepad [a great tool you can
find in your WinAVR directory] to open the hex file.
Figure 2 shows how our data is formatted. Each line
in the file begins with ‘:’ then ‘ 10’ to indicate that 0x10
( 16 decimal) bytes of code are in the line. This is followed
by two hex bytes that give the address that the code
■ FIGURE 3. pgmtest.lss showing stored strings.
August 2010 69