problem with SPM

Go To Last Post
4 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

this is my first post so please forgive me for my mistakes (if any). I was looking at a tutorial on how to use the SPM, I hardly found two tutorials on this. one was more complicated so I went with this. here the author uses a ATmega 16 but I use atmega328p. The problem is the function 

boot_page_fill(address, data)

uses a byte address right ?. but the author says that he is trying with the address 0x0100 (ie 256), he is not mentioning whether its byte address or word address. but in this diagram

 

the author uses word address right ? because the ending addres 0x1FFF is word address. In the program he just directly uses the address 256.

#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 little-endian word//
            uint16_t w = *buf++;
            w += (*buf++) << 8;
       //convert the bytes to little-endian word//
 
            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
 
}

my question is dont we need to convert to byte address ? or the author is wrong somewhere ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The m328 page size is 128 Bytes 64 words if I'm not mistaken. If you're pointing to FLASH in Assembler, you will multiply your pointer (Z reg) times 2.  I am not fluent in C/C++ but a lot of stuff gets done behind your back in C, so not sure about pointing to Flash. I think there's a library for that. There's an example in the old data sheet for the M328P, it works but is missing a lot of supporting code to coax it into working... and it's in assembler. I think You're going to want to increment your ZL pointer by (PAGESIZE in bytes). Which I beleive is what this is for

boot_page_fill(address, data)

I just don't know how C handles the Z pointer.  The Invisible Page Buffer gets filled 2 bytes (1 word) at a time through R1, R0. and is repeated till the page buffer is filled and then the code is written to flash to wherever Z is pointing. Bootloaders are kind of an advanced subject. The guys on the forum are way smarter than me and fluent in C so be patient and good luck!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks again

Plexd wrote:

The m328 page size is 128 Bytes 64 words if I'm not mistaken. If you're pointing to FLASH in Assembler, you will multiply your pointer (Z reg) times 2.  I am not fluent in C/C++ but a lot of stuff gets done behind your back in C, so not sure about pointing to Flash. I think there's a library for that. There's an example in the old data sheet for the M328P, it works but is missing a lot of supporting code to coax it into working... and it's in assembler. I think You're going to want to increment your ZL pointer by (PAGESIZE in bytes). Which I beleive is what this is for

boot_page_fill(address, data)

I just don't know how C handles the Z pointer.  The Invisible Page Buffer gets filled 2 bytes (1 word) at a time through R1, R0. and is repeated till the page buffer is filled and then the code is written to flash to wherever Z is pointing. Bootloaders are kind of an advanced subject. The guys on the forum are way smarter than me and fluent in C so be patient and good luck!

Thanks for the help rookie. I'm https aka ms remoteconnect about to start a new thread and instead did the search. 

Last Edited: Wed. Oct 14, 2020 - 02:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As this is avr-gcc I'd just take a look at API UsageExample on:

 

https://www.nongnu.org/avr-libc/...

 

That boot_program_page() example code is all you really need at the heart of a bootloader. The "page" parameter it takes is just a little confusing in that you might read the parameter name "page" to be "page 5" or "page 7" or something but the parameter is actually a "page address" so with 128 byte SPM pages (say) it would be "128 * 5" or "128 * 7" in this example.