MCUdude/MightyCore

[optiboot] Add feature to write to flash memory from app

sunnyque opened this issue ยท 14 comments

Hi, looks like this feature working well with MightyCore. Tested with provided example sketch and with my app that writes to flash memory and then reuse it in code later. Optiboot itself working as expected too.

About bootloader size, just compiled it for atmega328 and it fits to 512 bytes I supposed it should work fine

so here is changes to optiboot.c
also you need to include example and header that need to be used to access optiboot functions from app code

Also I think it's nice to give a credit to @majekw as the author of this feature

Thanks a ton! I've tried to compile the modified version of optiboot using avr-gcc v4.8.1, and the binary file compiles to 512b exactly! I'm going to do some testing, and hopefully I'll manage to add it to the master branch soon.

It works beautifully on the ATmega16! But I still need to know "the rules" about self writing.

  • Is it possible to "change page"? I wrote 128 characters to the first page, but what if I got more data to store?
  • Do i have to fill a page completely?
  • Do I have to store 128b of data at once, or can I just add a character or two to the string?

I think this must be perfect for JSON data storage for permanently saving settings!

Great. Just change memory offset to write next page, i.e. you can write 128 byte page starting from any offset you want

ex.

const char flash_mem[SPM_PAGESIZE*2] __attribute__ ((aligned(SPM_PAGESIZE))) PROGMEM;
...
int offset = 0;
optiboot_page_erase((optiboot_addr_t)(void*) &flash_mem[offset]);
[i=0..127] optiboot_page_fill((optiboot_addr_t)(void*) &flash_mem[offset + i], w);
optiboot_page_write((optiboot_addr_t)(void*) &flash_mem[offset]);
offset += SPM_PAGESIZE;
//..go on with the next page..

I suppose there is no reason to fill page entirely (I mean optiboot_page_fill call), but anyway you still need to write full page even if you want to update just one bit

Flash is usable when data changes not too often (remember about 10000 rewrite cycles) and fast read access is required, otherway internal or external EEPROM is a better choice

Great! I'll give it a try ๐Ÿ˜ƒ

I'be been thinking; if this bootloader version are working like a treat, and is less than 512b (in most cases, where it's necessary), are there any reason not to replace the current bootloader with this one? I don't see any drawbacks except that it's a "new" and "untested" feature

Im thinking about creating a simple library for reading and writing data to flash, to lower the bar a little. It will incorporate the optiboot.h file. Here's what the header file is supposed to look like (together with a cpp file):

#include "Arduino.h"

#ifndef Optiflash_h
#define Optiflash_h

class Optiflash 
{
    public:
        Optiflash(void);

        uint8_t readByte(uint8_t place, uint16_t page); // Returns a byte
        uint8_t *readSection(uint8_t start, uint8_t end, uint16_t page); // Retuns a pointer to an array
        uint8_t *readPage(uint16_t page); // Retuns a pointer to an array

        void writePage(uint8_t data[], uint16_t page);

        uint8_t pageSize(void);

    private:
        const char flash_buffer[SPM_PAGESIZE * NUMBER_OF_PAGES] __attribute__ (( aligned(SPM_PAGESIZE) )) PROGMEM= {""};
        uint8_t ram_buffer[SPM_PAGESIZE * NUMBER_OF_PAGES];
        uint16_t w;

};

#endif

any thoughts?

Well, flash write do not changes optiboot default behavior so I think it can be just replaced, also changes not so difficult to rollback in case of bugs.

library is a good idea, but better idea to keep this class work with any flash_buffer provided

library is a good idea, but better idea to keep this class work with any flash_buffer provided

OK, so it might be a better idea to place the flash buffer outside of the class? the flash_buffer is needed for writing to flash, or is it just it's address?

check this to get an idea what is a flash buffer. so yeah it just an address marked as 'flash'

Hi, flash_buffer is a place in flash to write in. In example I used const with PROGMEM to make things easy, but this is not mandatory. You could also just write to any address above program code, but you must be aware of program size to not overwrite it (I use it this way). You could also replace program code on the fly if you are brave enough :-)
About library: ๐Ÿ‘ I would be also happy to backport it to my Optiboot fork when it's done.
But:

  • it should work with any address or variable set to store things in flash
  • ram_buffer should be limited to only one page and can be reused during writing next page, in fact it's not necessary to have it at all

For me, library (object) should work as this:

  • init with address and size of flash area (2 variables to hold it), or address/length could be guessed from variable (2 versions of init?)
  • put byte for write and increment address (1 word variable)
  • (private) put 2 bytes together before write to temporary buffer
  • (private) if temporary buffer is full, write it/flush to flash
  • (private) if it's first write to new page, erase it first
  • explicit flush (to write not fully populated flash page)
  • maybe some kind of seek? (with automatic flush when page boundary is crossed)
  • it should export also optiboot_addr_t type as address length vary on chip
  • maybe expose also direct functions for advanced users?

Don't mind me that I joined discussion with my 2 cents :-)

Hi @majekw, thanks for joining the discussion! ๐Ÿ˜ƒ I'm not that experienced with low level AVR programming, I'm just a poor student with a tech hobby ๐Ÿ˜‰ I'm currently busy working on my bachelor thesis, so I don't got much time to work with this this month. It would be REALLY nice if you want to help me out on this one; it seems like you know this stuff really well! I'll happily give you all the credits you deserve ๐Ÿ‘
Here are the the files I started working on:
Optiflash.zip

I'll get some time next week to continue working on this. The dream would be a library similar to the new official EEPROM library! It's super tight, almost unreadable, and use very little resources!

The modified bootloader is now added to the master branch, and I've created an example where the user can read or write different pages!

EDIT:
I've now tested this bootloader on all supported microcontrollers, and writing to flash works for very microcontroller except the ATmega644p! How can that be? The ATmega1284p works fine, and both got 256b page size..

It seems like the only real difference between the ATmega644p and the ATmega1284p bootloader (except from the address offset) is located at line 232 for the ATmega644p, and line 232 for the ATmega1284p.

Do you have any idea why this isn't working on the ATmega644p @majekw ?