• 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
*/

🌱 Back to Garden