Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Created optiboot_copy #262

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion optiboot/bootloaders/optiboot/optiboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
/**********************************************************/
/* Edit History: */
/* */
/* Jan 2019 */
/* 8.1 gmattinson: Create do_spm_copy at BOOTSTART+4 to */
/* make self-updating code easier */
/* Sep 2018 */
/* 8.0 WestfW (and Majekw and MCUDude) */
/* Include do_spm routine callable from the app */
Expand Down Expand Up @@ -252,7 +255,7 @@
/**********************************************************/

#define OPTIBOOT_MAJVER 8
#define OPTIBOOT_MINVER 0
#define OPTIBOOT_MINVER 1

/*
* OPTIBOOT_CUSTOMVER should be defined (by the makefile) for custom edits
Expand Down Expand Up @@ -510,6 +513,11 @@ void pre_main(void) {
#else
" ret\n" // if do_spm isn't include, return without doing anything
#endif
#ifdef BIGBOOT
" rjmp do_spm_copy\n"
#else
" ret\n" // if do_spm_copy isn't included, return without doing anything
#endif
"1:\n"
);
}
Expand Down Expand Up @@ -1357,4 +1365,20 @@ OPT2FLASH(OPTIBOOT_CUSTOMVER);
#endif
char f_version[] = "Version=" xstr(OPTIBOOT_MAJVER) "." xstr(OPTIBOOT_MINVER);

void do_spm_copy(uint16_t dst, uint16_t src, uint8_t numPages, void(*retFunc)(void)) __attribute__((used));
void do_spm_copy(uint16_t dst, uint16_t src, uint8_t numPages, void(*retFunc)(void)) {
uint8_t i, j;

if (numPages == 0) return;

for (i = 0; i < numPages; i++) {
do_spm(dst + i * SPM_PAGESIZE, __BOOT_PAGE_ERASE, 0);
for (j = 0; j < SPM_PAGESIZE; j += 2) {
do_spm(dst + i * SPM_PAGESIZE + j, __BOOT_PAGE_FILL, pgm_read_word(src + i * SPM_PAGESIZE + j));
}
do_spm(dst + i * SPM_PAGESIZE, __BOOT_PAGE_WRITE, 0);
}
retFunc();
}

#endif
88 changes: 56 additions & 32 deletions optiboot/bootloaders/optiboot/optiboot_atmega328.hex
Original file line number Diff line number Diff line change
@@ -1,33 +1,57 @@
:107E000001C0DCC0112484B7882361F0982F9A70D8
:107E1000923041F081FF02C097EF94BF282E80E09E
:107E2000B8D0EEC085E08093810082E08093C000EE
:107E300088E18093C10086E08093C20080E1809356
:107E4000C4008EE0A6D0259A86E020E33CEF91E0C6
:107E5000309385002093840096BBB09BFECF1D9A83
:107E6000A8954091C00047FD02C0815089F7EE24DB
:107E7000E39495E0D92E21E1C22E7FD0813461F4C4
:107E80007CD0182F8CD01238E9F0113811F488E02A
:107E900001C083E06BD067C0823411F484E103C079
:107EA000853419F485E083D05EC0853539F465D01A
:107EB000C82F63D0D82FCC0FDD1F54C0863521F4D6
:107EC00084E075D080E0E6CF843609F02EC055D02E
:107ED00054D0F82E52D0B82E00E011E04ED0F80168
:107EE00081938F01FE12FACF5AD0F5E4BF1201C080
:107EF000FFCF83E0FE0187BFE89507B600FCFDCF0A
:107F0000A0E0B1E0FE018D919D910C01E7BEE895E6
:107F100011243296FA12F7CFFE01D7BEE89507B6C4
:107F200000FCFDCFC7BEE8951EC0843771F425D094
:107F300024D0F82E22D033D08E01F80185918F0104
:107F400015D0FA94F110F9CF0EC0853739F427D047
:107F50008EE10CD085E90AD08FE09CCF813511F4F9
:107F600088E017D01CD080E101D087CF9091C0006D
:107F700095FFFCCF8093C60008958091C00087FFD5
:107F8000FCCF8091C00084FD01C0A8958091C600FF
:107F90000895E0E6F0E098E1908380830895EDDFB6
:107FA000803219F088E0F5DFFFCF84E1DFCFCF9397
:107FB000C82FE3DFC150E9F7CF91F1CFFC010A01EF
:107FC00067BFE895112407B600FCFDCF667029F065
:0C7FD000452B19F481E187BFE895089566
:027FFE00000879
:0400000300007E007B
:107C000002C0E3C0F2C0112484B7882361F0982F2A
:107C10009A70923041F081FF02C097EF94BF282EF6
:107C200080E0BED0EDC182E08093C00088E1809307
:107C3000C10086E08093C20080E18093C4008EE0A2
:107C4000AFD093E0D92ECC24C39425E0B22E31E1FD
:107C5000A32E9AD0813471F497D0182FA7D0123860
:107C600011F481E005C0113811F488E001C083E00F
:107C700084D080C0823411F484E103C0853419F4C7
:107C800085E09CD077C0853539F47ED0C82F7CD074
:107C9000D82FCC0FDD1F6DC0863521F484E08ED047
:107CA00080E0E6CF843609F03BC06ED06DD0982ED0
:107CB0006BD0F82E00E011E067D0F80181938F01BE
:107CC0009E12FACF73D0F5E4FF120FC07E0100E0E0
:107CD00011E0901609F44EC0F80161918F01C701BF
:107CE000DDD0FFEFEF1AFF0AF4CFFE01D7BEE89513
:107CF00007B600FCFDCFFE01A0E0B1E08D919D91A3
:107D00000C01C7BEE895112432969A12F7CFFE01F6
:107D1000B7BEE89507B600FCFDCFA7BEE8952AC020
:107D20008437D1F431D030D0F82E2ED0E82E3ED08A
:107D30008E01F5E4EF1209C0FC0EC801A7D01DD0DA
:107D40000F5F1F4FF012F9CF15C0F80185918F0119
:107D500014D0FA94D1F70EC0853739F427D08EE1CC
:107D60000CD085E90AD08FE083CF813511F488E00B
:107D700017D01CD080E101D06CCF9091C00095FF4E
:107D8000FCCF8093C60008958091C00087FFFCCF90
:107D90008091C00084FD01C0A8958091C60008951F
:107DA000E0E6F0E098E1908380830895EDDF803293
:107DB00019F088E0F5DFFFCF84E1DFCFCF93C82F44
:107DC000E3DFC150E9F7CF91F1CFFC010A0167BFB2
:107DD000E895112407B600FCFDCF667029F0452B0D
:107DE00019F481E187BFE89508959F92AF92BF9201
:107DF000CF92DF92EF92FF920F931F93CF93DF9377
:107E0000B42E79014423B1F1EC01A12C6B01C81A05
:107E1000D90A40E050E063E0CE01D7DF8E01912C1B
:107E2000F601E00FF11F4591549161E0C801CDDFEB
:107E3000939493940E5F1F4F80E89812F1CF40E027
:107E400050E065E0CE01C1DFA394C058DF4FAB1016
:107E5000E0CF8FEF98E09EBF8DBFF701DF91CF910C
:107E60001F910F91FF90EF90DF90CF90BF90AF9058
:107E70009F900994DF91CF911F910F91FF90EF9008
:107E8000DF90CF90BF90AF909F900895F999FECF6B
:107E900092BD81BDF89A992780B50895262FF9994A
:107EA000FECF1FBA92BD81BD20BD0FB6F894FA9ADD
:087EB000F99A0FBE0196089536
:107EB80056657273696F6E3D382E31004F505449C4
:107EC800424F4F545F435553544F4D5645523D30E2
:107ED800004465766963653D61746D656761333239
:107EE800387000465F4350553D31363030303030C1
:107EF800304C00424947424F4F543D31004275696A
:107F08006C743A44656320323820323031383A3064
:107F1800373A30323A343600554152543D300042F7
:107F28004155445F524154453D313135323030007E
:107F38004C45443D4235004C45445F5354415254EE
:0C7F48005F464C41534845533D3000005B
:027FFE00010878
:0400000300007C007D
:00000001FF
182 changes: 182 additions & 0 deletions optiboot/examples/program_blink/optiboot.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
/*------------------------ Optiboot header file ----------------------------|
| |
| June 2015 by Marek Wodzinski, https://github.com/majekw |
| Modified June 2016 by MCUdude, https://github.com/MCUdude |
| Released to public domain |
| |
| This header file gives possibility to use SPM instruction |
| from Optiboot bootloader memory. |
| |
| There are 6 convenient functions available here: |
| * optiboot_page_erase - to erase a FLASH page |
| * optiboot_page_fill - to put words into temporary buffer |
| * optiboot_page_write - to write contents of temporary buffer into FLASH |
| * optiboot_readPage - higher level function to read a flash page and |
| store it in an array |
| * optiboot_writePage - higher level function to write content to |
| a flash page |
| * optiboot_copy - copy FLASH memory from one location to another, and |
| then call to a new address. Useful for flashing new |
| firmware on to your board. |
| |
| For some hardcore users, you could use 'do_spm' as raw entry to |
| bootloader spm function. |
|-------------------------------------------------------------------------*/


#ifndef _OPTIBOOT_H_
#define _OPTIBOOT_H_ 1

#include <avr/boot.h>
#include "Arduino.h"


/*
* Main 'magic' function - enter to bootloader do_spm function
*
* address - address to write (in bytes) but must be even number
* command - one of __BOOT_PAGE_WRITE, __BOOT_PAGE_ERASE or __BOOT_PAGE_FILL
* data - data to write in __BOOT_PAGE_FILL. In __BOOT_PAGE_ERASE or
* __BOOT_PAGE_WRITE it control if boot_rww_enable is run
* (0 = run, !0 = skip running boot_rww_enable)
*
*/

// 'typedef' (in following line) and 'const' (few lines below) are a way to define external function at some arbitrary address
typedef void (*do_spm_t)(uint16_t address, uint8_t command, uint16_t data);
typedef void(*retFunc_t)(void);
typedef void(*do_spm_copy_t)(uint16_t dst, uint16_t src, uint8_t numPages, retFunc_t retFunc);


/*
* Devices with more than 64KB of flash:
* - have larger bootloader area (1KB) (they are BIGBOOT targets)
* - have RAMPZ register :-)
* - need larger variable to hold address (pgmspace.h uses uint32_t)
*/
#ifdef RAMPZ
typedef uint32_t optiboot_addr_t;
#else
typedef uint16_t optiboot_addr_t;
#endif

#if (FLASHEND > 65534) || defined(BIGBOOT)
const do_spm_t do_spm = (do_spm_t)((FLASHEND-1023+2)>>1);
const do_spm_copy_t do_spm_copy = (do_spm_copy_t)((FLASHEND - 1023 + 4) >> 1);
#else
const do_spm_t do_spm = (do_spm_t)((FLASHEND-511+2)>>1);
#endif


/*
* The same as do_spm but with disable/restore interrupts state
* required to succesfull SPM execution
*
* On devices with more than 64kB flash, 16 bit address is not enough,
* so there is also RAMPZ used in that case.
*/
void do_spm_cli(optiboot_addr_t address, uint8_t command, uint16_t data) {
uint8_t sreg_save;

sreg_save = SREG; // save old SREG value
asm volatile("cli"); // disable interrupts
#ifdef RAMPZ
RAMPZ = (address >> 16) & 0xff; // address bits 23-16 goes to RAMPZ
do_spm((address & 0xffff), command, data); // do_spm accepts only lower 16 bits of address
#else
do_spm(address, command, data); // 16 bit address - no problems to pass directly
#endif
SREG = sreg_save; // restore last interrupts state
}


// Erase page in FLASH
void optiboot_page_erase(optiboot_addr_t address) {
do_spm_cli(address, __BOOT_PAGE_ERASE, 0);
}


// Write word into temporary buffer
void optiboot_page_fill(optiboot_addr_t address, uint16_t data) {
do_spm_cli(address, __BOOT_PAGE_FILL, data);
}


//Write temporary buffer into FLASH
void optiboot_page_write(optiboot_addr_t address) {
do_spm_cli(address, __BOOT_PAGE_WRITE, 0);
}



/*
* Higher level functions for reading and writing from flash
* See the examples for more info on how to use these functions
*/

// Function to read a flash page and store it in an array (storage_array[])
void optiboot_readPage(const uint8_t allocated_flash_space[], uint8_t storage_array[], uint16_t page, char blank_character)
{
uint8_t read_character;
for(uint16_t j = 0; j < SPM_PAGESIZE; j++)
{
read_character = pgm_read_byte(&allocated_flash_space[j + SPM_PAGESIZE*(page-1)]);
if(read_character != 0 && read_character != 255)
storage_array[j] = read_character;
else
storage_array[j] = blank_character;
}
}


// Function to read a flash page and store it in an array (storage_array[]), but without blank_character
void optiboot_readPage(const uint8_t allocated_flash_space[], uint8_t storage_array[], uint16_t page)
{
uint8_t read_character;
for(uint16_t j = 0; j < SPM_PAGESIZE; j++)
{
read_character = pgm_read_byte(&allocated_flash_space[j + SPM_PAGESIZE*(page-1)]);
if(read_character != 0 && read_character != 255)
storage_array[j] = read_character;
}
}


// Function to write data to a flash page
void optiboot_writePage(const uint8_t allocated_flash_space[], uint8_t data_to_store[], uint16_t page)
{
uint16_t word_buffer = 0;

// Erase the flash page
optiboot_page_erase((optiboot_addr_t)(void*) &allocated_flash_space[SPM_PAGESIZE*(page-1)]);

// Copy ram buffer to temporary flash buffer
for(uint16_t i = 0; i < SPM_PAGESIZE; i++)
{
if(i % 2 == 0) // We must write words
word_buffer = data_to_store[i];
else
{
word_buffer += (data_to_store[i] << 8);
optiboot_page_fill((optiboot_addr_t)(void*) &allocated_flash_space[i + SPM_PAGESIZE*(page-1)], word_buffer);
}
}

// Writing temporary buffer to flash
optiboot_page_write((optiboot_addr_t)(void*) &allocated_flash_space[SPM_PAGESIZE*(page-1)]);
}


#ifdef BIGBOOT
// Copy from one part of FLASH to another
void optiboot_copy(optiboot_addr_t dst, optiboot_addr_t src, uint8_t numPages, retFunc_t retFunc) {
uint8_t sreg_save;

sreg_save = SREG; // save old SREG value
asm volatile("cli"); // disable interrupts
do_spm_copy(dst, src, numPages, retFunc);
SREG = sreg_save; // restore last interrupts state
}
#endif

#endif /* _OPTIBOOT_H_ */
Loading