You are on page 1of 11

How To Use SPM To load Application from EEPROM

Summary:

In any microcontroller the Boot-Loader is the first code which executes before the application code does.
The major function of the Boot-Loader is to load the application code into the flash memory of the
microcontroller and execute it. In AVR microcontroller the Self Programming Mode (SPM) helps the
Boot-Loader to load a particular application from where the application binary is stored.The Boot-Loader
may receive the code binary from other memory chips, SD-cards or through the serial port of the
microcontroller in case of serial programming.
It is then with the help of the SPM that the microcontroller write the binary code into the application flash
section. In this particular project the operation of a Boot-Loader code using the SPM is demonstrated by
re-writing flash memory with the code binary which has already been flashed into the built-in EEPROM of
the ATMEGA16. The hardware used in this project includes ATMEGA16 as microcontroller, USBASP as
the programmer and the software used are AVR STUDIO 4 as IDE and AVR-BURNO-MAT as the burner
software.

Description:

The BLS section is normally used for storing the Boot-loader code for the microcontroller. The Boot-
Loader code can be used for initializing the peripherals in the microcontroller, initialize the devices
connected to the microcontroller, select the application to load and execute from a storage medium, load
the selected application to the application section, jump to the application section and execute the
application. The code running in the BLS section can execute Self Programing Mode (SPM) instructions
which are blocked for the code running in the Application section. Using SPM instructions the code from
the BLS can rewrite the code in the application section or the code in the BLS itself.
The task of writing the BLS code with SPM has been made simple by the APIs available in the header file
<avr/boot.h>. The following are the important APIs available in the header file which helps in the SPM.

FUNCTION DESCRIPTION PARAMETER

boot_page_erase (address) Erase the flash page that is referred by A byte address in flash
address
boot_page_fill (address, Fill the Boot-Loader temporary page The address is a byte
data) buffer for flash address with data word address. The data is a
word

boot_page_write (address) Write the Boot-Loader temporary page Byte address in flash
buffer to flash page that contains
address

Using the above APIs one can write a code for SPM in an AVR microcontroller provided that the code
should follow certain steps in the order.
Step: 1 Erase the flash page which is about to write into
Step: 2 Store the binaries in a temporary buffer before write into a flash page
Step: 3 Program the filled temporary buffer into the already erased flash page
The above three steps are explained with details in a previous project on AVR SPM. In this particular
project the data that is required to fill the temporary page buffer as discussed in the step: 2 is taken from
the built-in EEPROM of the AVR microcontroller where a simple code has already been flashed into.The
internal EEPROM of the AVR microcontroller has 512 bytes capacity. It can be easily read and write with
the help of APIs available in the header file <avr/eeprom.h>. The following are the important APIs
available in the header file which helps in accessing the EEPROM memory.

FUNCTION DESCRIPTION

void eeprom_is_ready (void) Returns 1 if EEPROM is ready for


a new read/write operation, 0 if
not

void eeprom_read_block (void *dst, const void *src, size_t n Returns a block of n bytes from
) EEPROM address src to SRAM
dst

uint8_t eeprom_read_byte (const uint8_t *p) Returns one byte from EEPROM
address referred by the pointer p

uint32_t eeprom_read_dword (const uint32_t *p) Read one 32-bit double from
EEPROM address referred by the
pointer p

float eeprom_read_float (const float *p) Returns one float value from
EEPROM referred by the pointer
p
uint16_t eeprom_read_word (const uint16_t *p) Read one 16-bit word from
EEPROM address referred by the
pointer p

void eeprom_update_block (const void *src, void *dst, size_t n) Update a block of n bytes to
EEPROM address dst from src

void eeprom_update_byte (uint8_t *p, uint8_t value) Update a byte value to EEPROM
address referred by the pointer p

void eeprom_update_dword (uint32_t *p,uint32_t value) Update a 32-bit double word


value to EEPROM address
referred by the pointer p

void eeprom_update_float (float *p, float value) Update a float value to EEPROM
address referred by the pointer p

void eeprom_update_word (uint16_t *p, uint16_t value) Update a word value to EEPROM
address referred by the pointer p

void eeprom_write_block (const void *src, void *dst, Write a block of n bytes to
size_t n) EEPROM address dst from src.

void eeprom_write_byte (uint8_t *p, uint8_t value) Write a byte value to EEPROM
address referred by the pointer p

void eeprom_write_dword (uint32_t *p, uint32_t value) Write a 32-bit double word value
to EEPROM address referred by
the pointer p

void eeprom_write_float (float *p, float value) Write a float value to EEPROM
referred by the pointer p

void eeprom_write_word (uint16_t *p, uint16_t value) Write a word value to EEPROM
referred by the pointer p

The data for filling the temporary buffer as discussed in the step: 2 is read from the built-in EEPROM
memory of the AVR microcontroller using the library function;
uint8_t eeprom_read_byte (const uint8_t *p)
The above function can return the data byte which is stored in the EEPROM address referred by the
pointer argument. The code is written in such a way that the pointer first points to the 0th location of the
EEPROM and then increases the address as it reads each byte for storing in the temporary buffer. Thus
the steps with which binary of a code are read from the EEPROM memory and flashing the same into the
flash memory is represented pictorially in the following;
Step: 1 Erase the flash page which is about to write into
The first step is to erase the flash page which is about to be written with the new values. The API which
helps in executing this step is;
Boot_page_erase (address)
This API can erase an entire page in the flash which the parameter addresses. In the code the address of
the page erased is 256. The following image shows the status of the temporary page buffer and the flash
memory at the step 1. The temporary page buffer is a buffer in which an entire page can be stored before
it is flashed into a page in the flash memory.
Step: 2 Store the values in a temporary buffer before write into a flash page
This is the second step in which one should store the required binary in a temporary buffer, before writing
to any of the flash memory page. The API that can be used for this purpose is;
boot_page_fill (address, data)
This API fills the Boot-Loader temporary page buffer byte by byte before flashing the data in the
temporary page buffer into a page as such. The parameter data represents each byte in the buffer and
the parameter address represents the page address + offset of the buffer location where the data byte
need to be stored.The parameter data in the API boot_page_fill (address, data) is actually read from the
first location of EEPROM memory with the help of an API which is available in the header file
<avr/eeprom.h>.
uint8_t eeprom_read_byte (const uint8_t *p)

FUNCTION DESCRIPTION PARAMETER

uint8_t The function returns one data byte which The pointer refers to the
eeprom_read_byte (const is stored in the EEPROM address EEPROM address from which
uint8_t *p) referred by the pointer p the data byte need to be read

Step: 3 Program the filled temporary buffer into the already erased flash page
This is the final step in which the filled temporary buffer is flashed using an API into already erased page
of the flash memory. The API which helps in this step is;
boot_page_write (address)
The code in this project which is written for the BLS can copy 300bytes from the EEPROM memory into
the temporary buffer starting from the address 0x00. These bytes are then flashed into the flash memory
page starting from the address 0x0000. After doing this the code from the BLS will make a jump to the
address 0x0000 so that the re-written binary can be executed next. With this boot loader code, whatever
program flashed into the EEPROM will get rewritten at the Application flash section of the AVR and get
executed. A simple LED blinking test application can be written into the EEPROM memory starting to test
the working.bFlash the code for the BLS first and then the LED application code to the EEPROM memory
using the steps explained in the previous project on LED blinking from BLS of AVR. When the led blinks,
it means that the code has been loaded from one section of the EEPROM memory to the flash memory
and is executing. With that the code in the BLS can load any application which is programmed into the
EEPROM on reset and hence it acts like a Boot-Load

Circuit:
Code 1:

#define F_CPU 8000000

#include <avr/io.h>

#include <util/delay.h>

#include <avr/boot.h>

#include <inttypes.h>

#include <avr/interrupt.h>

#include <avr/pgmspace.h>

#include <stdio.h>

#include <avr/eeprom.h>

int main ( void )

uint16_t i;
uint8_t A [ 300 ];
uint8_t sreg;
uint32_t page = 0;
unsigned char *buf = A;
uint16_t w;
volatile int j = 2;

DDRD |= 0x80;

for ( i = 0; i < 3; i ++ )
{
PORTD &= 0x7F;
_delay_ms ( 500 );
PORTD |= 0x80;
_delay_ms ( 500 );
}

for ( i = 0; i < 300; i ++ )


A [ i ] = eeprom_read_byte ((const uint8_t *) i);

while(1)
{

//==============================================================================//
if(j)
{
// Disable interrupts.
sreg = SREG;
cli();
eeprom_busy_wait ();
boot_page_erase (page);
boot_spm_busy_wait (); // Wait until the memory is erased.

for (i=0; i<SPM_PAGESIZE; i+=2)


{
// Set up little-endian word.
w = *buf++;
w += (*buf++) << 8;

boot_page_fill (page + i, w);


}
boot_page_write (page); // Store buffer in flash page.
boot_spm_busy_wait(); // Wait until the memory is written.
boot_rww_enable ();
SREG = sreg;
}
else
{
asm ( "jmp 0x0000" );
}

j--;
page = page + 128;
//==============================================================================//
}

Code 2:

#define F_CPU 8000000

#include <avr/io.h>

#include <util/delay.h>
int main ( void )

DDRD |= 0x80;

while(1)
{
PORTD &= 0x7F;
_delay_ms ( 2000 );
PORTD |= 0x80;
_delay_ms ( 2000 );
}

You might also like