in page-sized chunks that are defined in words.
The Arduino (ATmega328p) and the Butterfly (ATmega169)
both have pages of 64 words, while the BeAVR40
(ATmega644p) has 128 word pages. Later when we look at boot
section addresses, we might notice things like the ATmega644
boot section that begins at 0x7E00, and if we translate
that into decimal we might wonder why the bootsection
begins at 32256 when we are using a 65535 (64K bytes)
memory. The answer is, of course, that we are actually using
a 32K word memory and that the boot section is a word
address that corresponds to a byte address of 0xFC00 (64512).
It can sometimes be confusing whether you are talking
about words or bytes in Flash memory, so pay attention.
How Flash is written.
When we write to Flash on the ATmega644, we first
fill a SRAM temporary buffer page with 128 words and then
let the Flash circuitry write that whole page to Flash. Even
if all we wanted to do in Flash is change a single byte, we
have to find what page it is in, copy that whole page of 256
bytes (128 words) to SRAM, and then wait while the SRAM
gets written to Flash. As we’ve said before, you can write
to Flash but you can also wear it out. So, it isn’t something
we want to do a lot. We don’t use it to store frequently
changing data, but only to store occasionally changing
things like the program code itself. Most microcontrollers
only have the program written once and they run it to the
end of time. We, of course, are learning about these things,
so will write the program code many times to both learn
new stuff and to correct the inevitable mistakes we make.
Would you change code while it is running? (Hint: NO!)
A computer loads a sequence of instructions from the
program memory and performs operations based on that
code. We assume there is some logic to the design of that
sequence so that, for instance, if we add two numbers then
the result is used for some later instruction in the sequence.
But what if we could change the program sequence while
it is running? We might get lucky and change a section that
won’t be used for a while, but then we might get unlucky and
change something that is being used right now. Since that is
a risk we don’t want to take, we try to assure that the computer
won’t be running code that is in the process of being changed.
We don’t want to be reading code while writing to it.
As we introduced in Workshop 22, bootloaders write
code to program memory. A bootloader is a module of
code that writes code while it is running. You see the potential
■ FIGURE 3. ATmega644 boot size.
Boot Memory Sections
problem here? You’ve got to have a mechanism that prevents
you from writing over code you are running. The AVR has
special features that make it easier to safely use bootloaders.
One of these is to divide the program memory into two
sections: a RRW (Read While Write) and NRWW (No Read
While Write) section as shown in Figure 1. This allows us
to designate a section of memory that will not allow the
CPU to read the program memory while writing to program
memory. This assures that code running in the NRWW section
won’t overwrite itself. [We use an external ISP programmer
to write to the NRWW section which is done without the
CPU running.] As you can see in Figure 1, the NRWW
section is divided into subsections that mark boundries that
you can set for your bootloader. These boundaries are set
by fuses that tell the AVR to run code beginning at that
indicated address when coming out of reset. In our Flash
writing example [see Figure 3], we will use the smallest
section available that begins at address 0x7E00 [remember
that Flash is measured in words]. This means we have 512
words or 1,024 bytes to store in our bootloader. We will
learn how to use this to write data to Flash and next month
we will apply what we learn to developing a bootloader.
When an NRWW section is being written to, the CPU is
stopped to make sure it doesn’t try to run a page of code that
is in the midst of being changed. We can continue to execute
code in the NRWW section while parts of that section are
being written to. This allows our application to continue to run
critical code while the rest of the program is being updated.
This is an advanced topic that we won’t look at further here.
Preventing Flash Corruption.
You should never initiate a Flash write if there is a chance
that you’ll run out of power in the midst of it. This could
corrupt that page of Flash and when the power is restored,
the program may be corrupted. One way to deal with this is to
enable the internal BOD (Brown-Out Detector) to prevent
the CPU from operating below a certain voltage. We will do
this by setting the BODLEVEL fuse to “Brown-out detection
at VCC= 2.7V.” We’ll see how to set fuses in a few minutes.
Flash Read/Write Functions
Writing to Flash requires using the assembly instruction
SPM, but we are writing our code in C so we will use
some C library functions and let them handle the low level
stuff. Avrlibc is included in your WinAVR installation. You
can find the manual for it under the WinAVR directory
doc\avrlibc\avr-libc-user-manual.pdf. This library provides a
lot of useful tools and we will use some of the bootloader
support utilities available to us by including <avr/boot.h>
in our program. We use the following functions:
boot_page_erase(address); Determines the Flash
page that contains the ‘address’ and erases that page.
boot_spm_busy_wait(); Checks to see if the SPM