Developed By:
Akshay Daga
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.
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.
Fig. 2: Block Diagram of SPM function with BLS in AVR
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 address
|
A byte address in flash
|
boot_page_fill (address, data)
|
Fill the Boot-Loader temporary page buffer for flash address with data word
|
The address is a byte address. The data is a word
|
boot_page_write (address)
|
Write the Boot-Loader temporary page buffer to flash page that contains address
|
Byte address in flash
|
Fig. 3: Important APIs for AVR's SPM Function
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
{C· Step: 2 Store the binaries in a temporary buffer before write into a flash page
{C}· 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, size_t n)
|
Write a block of n bytes to 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
|
Fig. 4: APIs to access EEPROM memory
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.
Fig. 5: Block Diagram of PageErase in SPM Function
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 eeprom_read_byte (const uint8_t *p)
|
The function returns one data byte which is stored in the EEPROM address referred by the pointer p
|
The pointer refers to the EEPROM address from which the data byte need to be read
|
Fig. 6: Block Diagram Loading Temporary Buffer for AVR's SPM
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)
Fig. 7: Block Diagram of Page Write in flash Memory
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.
Fig. 8: LED Blinking using SPM Function of AVR Circuit on breadboard
Circuit:
Code:
#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 );
}
}
Không có nhận xét nào:
Đăng nhận xét