1
0
mirror of https://github.com/Optiboot/optiboot.git synced 2025-08-17 21:41:03 +03:00

Add optiboot_x nvmctrl support to optiboot.h

minor fixes in test_dospm itself.
test_dospm (which uses only the "high level" calls to read and
write pages) now works the same (I think) on both traditional
AVR and new mega0/xTiny chips.
This commit is contained in:
WestfW
2020-09-28 02:57:14 -07:00
parent 7975070bdc
commit eb4416a5f0
2 changed files with 125 additions and 38 deletions

View File

@@ -2,6 +2,8 @@
| | | |
| June 2015 by Marek Wodzinski, https://github.com/majekw | | June 2015 by Marek Wodzinski, https://github.com/majekw |
| Modified June 2016 by MCUdude, https://github.com/MCUdude | | Modified June 2016 by MCUdude, https://github.com/MCUdude |
| Modified Sep 2020 for mega0/xTiny (optiboot_x) |
| by Bill Westfield https://github.com/westfw |
| Released to public domain | | Released to public domain |
| | | |
| This header file gives possibility to use SPM instruction | | This header file gives possibility to use SPM instruction |
@@ -24,9 +26,18 @@
#ifndef _OPTIBOOT_H_ #ifndef _OPTIBOOT_H_
#define _OPTIBOOT_H_ 1 #define _OPTIBOOT_H_ 1
#ifdef SPMCSR
// Mega0 does not have SPMCSR
#include <avr/boot.h> #include <avr/boot.h>
#endif
#include "Arduino.h" #include "Arduino.h"
// figure out whether we have SPM or NVMCTRL
#ifdef FUSE_BOOTEND
#define USE_NVMCTRL 1
#define NVMCTRL_CMD_COPY_gc (NVMCTRL_CMD_gm+1) // one beyond existing commands.
#define SPM_PAGESIZE (PROGMEM_PAGE_SIZE)
#endif
/* /*
* Main 'magic' function - enter to bootloader do_spm function * Main 'magic' function - enter to bootloader do_spm function
@@ -42,6 +53,7 @@
// 'typedef' (in following line) and 'const' (few lines below) // 'typedef' (in following line) and 'const' (few lines below)
// are a way to define external function at some arbitrary address // 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 (*do_spm_t)(uint16_t address, uint8_t command, uint16_t data);
typedef void (*do_nvmctrl_t)(uint16_t address, uint8_t command, uint8_t data);
/* /*
@@ -56,12 +68,20 @@ typedef void (*do_spm_t)(uint16_t address, uint8_t command, uint16_t data);
typedef uint16_t optiboot_addr_t; typedef uint16_t optiboot_addr_t;
#endif #endif
#ifdef USE_NVMCTRL
// Mega0/xTiny/etc. Bootloader is in low memory.
const do_spm_t do_nvmctrl = (do_spm_t)((PROGMEM_START+2)>>1);
#else
#if FLASHEND > 65534 #if FLASHEND > 65534
const do_spm_t do_spm = (do_spm_t)((FLASHEND-1023+2)>>1); const do_spm_t do_spm = (do_spm_t)((FLASHEND-1023+2)>>1);
#else #else
const do_spm_t do_spm = (do_spm_t)((FLASHEND-511+2)>>1); const do_spm_t do_spm = (do_spm_t)((FLASHEND-511+2)>>1);
#endif #endif
#endif
#ifndef USE_NVMCTRL
// SPM-based functions
/* /*
* The same as do_spm but with disable/restore interrupts state * The same as do_spm but with disable/restore interrupts state
@@ -81,14 +101,12 @@ void do_spm_cli(optiboot_addr_t address, uint8_t command, uint16_t data) {
uint8_t eind = EIND; uint8_t eind = EIND;
EIND = FLASHEND / 0x20000; EIND = FLASHEND / 0x20000;
#endif #endif
// do_spm accepts only lower 16 bits of address do_spm((address & 0xffff), command, data); // do_spm accepts only lower 16 bits of address
do_spm((address & 0xffff), command, data);
#ifdef EIND #ifdef EIND
EIND = eind; EIND = eind;
#endif #endif
#else #else
// 16 bit address - no problems to pass directly do_spm(address, command, data); // 16 bit address - no problems to pass directly
do_spm(address, command, data);
#endif #endif
SREG = sreg_save; // restore last interrupts state SREG = sreg_save; // restore last interrupts state
} }
@@ -112,44 +130,11 @@ void optiboot_page_write(optiboot_addr_t address) {
} }
/* /*
* Higher level functions for reading and writing from flash * Higher level functions for reading and writing from flash
* See the examples for more info on how to use these functions * 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 // Function to write data to a flash page
void optiboot_writePage(const uint8_t allocated_flash_space[], void optiboot_writePage(const uint8_t allocated_flash_space[],
uint8_t data_to_store[], uint16_t page) uint8_t data_to_store[], uint16_t page)
@@ -175,5 +160,101 @@ void optiboot_writePage(const uint8_t allocated_flash_space[],
optiboot_page_write((optiboot_addr_t)(void*) &allocated_flash_space[SPM_PAGESIZE*(page-1)]); optiboot_page_write((optiboot_addr_t)(void*) &allocated_flash_space[SPM_PAGESIZE*(page-1)]);
} }
#else // Newer Mega0/xTiny chips with NVMCTRL
/*
* The same as do_nvmctrl but with disable/restore interrupts state
* required to succesfull execution
*
* Currently, there are no mega0/xTint parts with more than 64k, and when there are
* they'll need extra effort beyond just RAMPZ :-(
*/
void do_nvmctrl_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
do_nvmctrl(address, command, data); // 16 bit address - no problems to pass directly
SREG = sreg_save; // restore last interrupts state
}
// Erase page in FLASH
void optiboot_page_erase(optiboot_addr_t address)
{
// set page by writing to address.
do_nvmctrl(address+MAPPED_PROGMEM_START, NVMCTRL_CMD_COPY_gc, 0xFF);
do_nvmctrl_cli(0, NVMCTRL_CMD_PAGEERASE_gc, 0); // do actual erase
}
// Write word into temporary buffer
void optiboot_page_fill(optiboot_addr_t address, uint16_t data)
{
do_nvmctrl(address+MAPPED_PROGMEM_START, NVMCTRL_CMD_COPY_gc, data & 0xFF);
do_nvmctrl(address+MAPPED_PROGMEM_START, NVMCTRL_CMD_COPY_gc, data >> 8);
}
//Write temporary buffer into FLASH
void optiboot_page_write(optiboot_addr_t address)
{
do_nvmctrl_cli(address, NVMCTRL_CMD_PAGEWRITE_gc, 0);
}
/*
* Higher level functions for reading and writing from flash
* See the examples for more info on how to use these functions
*/
// 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)
{
const uint8_t *adjusted_address;
// Copy ram buffer to temporary flash buffer
for(uint16_t i = 0; i < SPM_PAGESIZE; i++)
{
adjusted_address = &allocated_flash_space[i + SPM_PAGESIZE*(page-1)];
adjusted_address += MAPPED_PROGMEM_START;
do_nvmctrl((optiboot_addr_t)(void*) adjusted_address,
NVMCTRL_CMD_COPY_gc, data_to_store[i]);
}
do_nvmctrl_cli(0, NVMCTRL_CMD_PAGEERASEWRITE_gc, 0);
}
#endif // USE_NVMTRL
// Function to read a flash page and store it in an array (storage_array[])
// (these can be shared between old and new AVRs.)
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;
}
}
#endif /* _OPTIBOOT_H_ */ #endif /* _OPTIBOOT_H_ */

View File

@@ -49,7 +49,7 @@ uint16_t pageNumber;
char returnToMenu; char returnToMenu;
// The temporary data (data that's read or is about to get written) is stored here // The temporary data (data that's read or is about to get written) is stored here
uint8_t ramBuffer[SPM_PAGESIZE]; uint8_t ramBuffer[SPM_PAGESIZE+1];
// This array allocates the space you'll be able to write to // This array allocates the space you'll be able to write to
const uint8_t flashSpace[SPM_PAGESIZE * NUMBER_OF_PAGES] __attribute__ (( aligned(SPM_PAGESIZE) )) PROGMEM = { const uint8_t flashSpace[SPM_PAGESIZE * NUMBER_OF_PAGES] __attribute__ (( aligned(SPM_PAGESIZE) )) PROGMEM = {
@@ -71,6 +71,11 @@ void loop()
Serial.println(); Serial.println();
Serial.println(F("|------------------------------------------------|")); Serial.println(F("|------------------------------------------------|"));
Serial.println(F("| Welcome to the Optiboot flash writer example! |")); Serial.println(F("| Welcome to the Optiboot flash writer example! |"));
#ifdef USE_NVMCTRL
Serial.println(F("| Running on mega0/xTiny with NVMCTRL support. |"));
#else
Serial.println(F("| Running on traditional AVR with SPM support. |"));
#endif
Serial.print(F("| Each flash page is ")); Serial.print(F("| Each flash page is "));
Serial.print(SPM_PAGESIZE); Serial.print(SPM_PAGESIZE);
Serial.println(F(" bytes long. |")); Serial.println(F(" bytes long. |"));
@@ -155,6 +160,7 @@ void loop()
Serial.print(F("\nContent of page ")); Serial.print(F("\nContent of page "));
Serial.print(pageNumber); Serial.print(pageNumber);
Serial.println(F(":")); Serial.println(F(":"));
ramBuffer[SPM_PAGESIZE] = 0; // null terminate!
Serial.println((char*)ramBuffer); Serial.println((char*)ramBuffer);
} }