mirror of
https://github.com/Optiboot/optiboot.git
synced 2025-07-07 21:01:06 +03:00
optiboot.h needs to be part of the test_dospm example,
not (just) off as part of the MCUdud cores..
This commit is contained in:
164
optiboot/examples/test_dospm/optiboot.h
Normal file
164
optiboot/examples/test_dospm/optiboot.h
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
/*------------------------ 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 5 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 |
|
||||||
|
| |
|
||||||
|
| 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);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
const do_spm_t do_spm = (do_spm_t)((FLASHEND-1023+2)>>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)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _OPTIBOOT_H_ */
|
Reference in New Issue
Block a user