- The Self Programming Mode (SPM) is a feature which enables a microcontroller to program its own flash memory.
- The SPM is commonly used with the microcontroller Boot-Loader codes which help to program the microcontroller serially.
- Is a key factor of the Bootloader code since the major function of the Bootloader is to load an application code into the application flash section
- Only the code running on the Bootloader Section (BLS) can make use of this SPM feature
https://www.engineersgarage.com/how-to-use-spm-for-flash-to-flash-programming-part-33-46/
Exemplo Bootloader:
#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>
int main ( void ) {
uint16_t i;
uint8_t A [ 300 ];
uint8_t sreg;
uint32_t page = 256;
unsigned char *buf = A;
//-------------------------------------------------------------------------------
DDRD |= 0x80;
PORTD |= 0x7F; //led on. bootloader ok.
_delay_ms ( 2000 );
PORTD |= 0x80; //turn off led now. We hope the application will turn on the LED again
_delay_ms ( 2000 );
//--------------------------------------------------------------------------------
// storing the bytes from ith location of flash memory to ith variable of array A//
for ( i = 0; i < 300; i ++ )
A [ i ] = pgm_read_byte ( i );
// storing the bytes from ith location of flash memory to ith variable of array A//
//================================= SPM ==========================================//
sreg = SREG; // store the current interrupt status in sreg
cli(); // clear interrupts
eeprom_busy_wait (); // wait till the eeprom is free.
boot_page_erase (page); // erase the page in the flash which we are about to write into
boot_spm_busy_wait (); // Wait until the memory is erased.
//---- fill the bytes of the page into temperory page buffer before wriying into flash ----//
for (i=0; i<SPM_PAGESIZE; i+=2) {
// convert the bytes to word (little-endian) //
uint16_t w = *buf++;
w += (*buf++) << 8;
// convert the bytes to word (little-endian) //
boot_page_fill (page + i, w); // fill the temperory page buffer byte by byte
}
//---- fill the bytes of the page into temperory page buffer before wriying into flash ----//
//--------------------------------------------------------------------//
boot_page_write (page); // Store buffer in flash page.
//--------------------------------------------------------------------//
boot_spm_busy_wait(); // Wait until the memory is written.
boot_rww_enable (); // Reenable RWW-section again
SREG = sreg; // Re-enable interrupts
//================================= SPM ==========================================//
asm ( "jmp 0x0100" ); // jump to application programmed at 0x0100
}
###The code where "convert the bytes to little-endian word" annotation takes place is taking 2 bytes and converting them to WORD, because the function boot_page_fill() takes data as WORD not Byte. The same can be done by the following code:
uint16_t result = ((uint16_t)Buffer[0] << 8) | Buffer[1];
/*
- The value of Buffer[0] is shifted 8 bits to the left. That gives you 0x0800
- A bitwise OR is performed between the prior value and the value of Buffer[1]. This sets the low order 8 bits to Buffer[1], giving you 0x0806
*/