■ FIGURE 4. pgmtest.lss showing 16 bytes
stored at address 0x0100.
written. The last byte in the line is a checksum. As you can
see from Figure 1, I’ve marked three sections of the hex
file. The green is for the data for the string: “pgmtest -
Butterfly 1.06\r”. The pink is for “This is a test for sending
a string.\r”.And the blue is 16 bytes beginning at memory
location 0x0100 that we will read in the demonstration
program.
In Figures 3 and 4 we look at the pgmtest.lss file that
is also in the default directory along with pgmtest.hex.
Figure 3 shows the green data that is stored beginning at
address 0x005C, and the red data stored beginning at
address 0x0076. You can see that the .lss file also shows
the characters for the data to the right. In Figure 4 we see
the 16 bytes of code that are stored beginning at address
0x0100 and to the right we see the assembly instructions
that this code represents. Above the code we see the C
instructions. The .lss can be very useful for debugging and
■ FIGURE 5. pgmtest using Bray’s Terminal.
70
August 2010
for learning how the compiler translates our C code into
the AVR assembly language.
The pgmtest.c demonstration program will print the
two strings stored in Flash and when you send it ‘R’ it will
read out the 16 bytes of Flash beginning at address
0x0100.
Program Memory Demonstration
— pgmtest.c
The full source code for this demonstration is included
in Workshop25.zip on the NV site www.nutsvolts.com. In
this section, we will look at a few of the more relevant
items.
One source file for multiple devices
The following discussion isn’t related to memory, but
to creating the demonstration program pgmtest.c. At one
time, I found that lots of #define and #ifdef in source code
seemed to make things more confusing. It does, but it also
makes it possible to write one source code file that can be
compiled for multiple devices. This comes in handy when
you have situations like the one that requires different
register names for the USART in different AVRs (as is the
case of the Butterfly’s ATmega169 versus the BeAVR40’s
ATmega644). The compiler preprocessor looks for #if
defined structures and, based on what was previously
defined, it selects the correct code section. For instance,
in pgmtest.c you see:
#define Butterfly // ATmega169
//#define Arduino // ATmega328
//#define BeAVR40 // ATmega644
// SmileyUSART.h uses the above defines
// Note that Butterfly USART runs at 19200 Baud
// while the Arduino and BeAVR40 run at
// 57600 Baud
#include “SmileyUSART.h”
#if defined(Arduino)
const char HELLO[] PROGMEM = “pgmtest -
Arduino 1.01\r “;
#elif defined (Butterfly)
const char HELLO[] PROGMEM = “pgmtest -
Butterfly 1.04\r “;
#elif defined (BeAVR40)
const char HELLO[] PROGMEM = “pgmtest -
BeAVR40 1.00\r”;
#else
const char HELLO[] PROGMEM = “pgmtest -
UNDEFINED\r”;
#endif
There are three main things going on here. First, we
select the platform we want to compile our code for:
either the Butterfly, the Arduino, or the BeAVR40. We
remove the preprocessor comment delimiter \\ in front of
the one we want to compile the code for. Note that we
must also leave the \\ in front of the other two or we’ll get
some strange errors. The second thing to note is that the
include file SmileyUSART.h follows this define list. That is
because the SmileyUSART header file needs to know