Need to write to Arduino flash runtime

Hi all,

I need to know how to write to Arduino flash memory at runtime. I plan to see how large my sketch ends up being, then write data after that point (but stopping before the bootloader!).

This is going to be for a data logger circuit and I see no need to use external memory or limit myself to EEPROM when I will have close to 30K of flash available.

There is no need for speed... I will be writing 2 bytes of data every second... that's all.

Note that I want to use the flash in the 328P processor (of an UNO R3 board). Suggestions to use something else will be pointless.

Thanks!

-- Roger

Only the bootloader can write to flash. Code running from non-boot area is not allowed to write there.

CrossRoads:
Only the bootloader can write to flash. Code running from non-boot area is not allowed to write there.

I know the lock bits can be setup to allow or deny reads or writes to the BOOTLOADER area, but what about the rest of the flash?

And, if the bootloader can write to flash, then why can't I do the same thing the bootloader does?

I'm sure that I'll probably need to read an entire page, modify the byte(s) that I want to change, then write the page back (I've dealt with flash memory on other systems), but I can't believe that it's impossible to write Arduino flash at runtime.

If the bootloader can do it, then I should be able to do it.... (which leads me to an idea...... examine how the bootloader does it!).

I am convinced that there should be a way to write a little "driver" or library where I can write to any flash address I wish.

Really... what can the bootloader do that I can't do?

if the bootloader can write to flash, then why can't I do the same thing the bootloader does?

It's a (memory protection) feature. From the CPU overview:

Program Flash memory space is divided in two sections, the Boot Program section and the Application Program section. Both sections have dedicated Lock bits for write and read/write protection. The SPM instruction that writes into the Application Flash memory section must reside in the Boot Program section.

You can "solve" this by putting a subroutine to write flash in the boot section, with a carefully designed API, or by relocating your program so that part of it ends up residing in the boot section. AMForth does this, so as to be able to write user-defined "words" to flash; you might want to look at what they do.

Also keep in mind that program flash is only spec'ed to support 10k write operations...

westfw:
The SPM instruction that writes into the Application Flash memory section must reside in the Boot Program section.

[/quote]
I've seen this talked about many times but where is this in the m328 document? I've never been able to locate this.
And if that is the case, what would be the point of setting BLB0 mode bits to 1s? (both BLB02 and BLB01)
It was my assumption that BLB01 allowed SPM to work from the application space.

And what about when there is no bootloader?

--- bill

In the current datasheet, it's in "Section 7.1" ("Overview")
As to why this is a chip-level limitation, rather than something controlled by a lock bit ... I have no idea.

hmmm. Well the latest doc is very different from the one I had from 2010 (revB vs revE).
Sad part is that depending on how you lookup the atmega328 document you can
still get a link to the old one from the Atmel site.

So.... bummer.

But..... There does look to be about 10 bytes left in optiboot.
What about using 4 of those bytes to put in:
SPM
ret
directly before the boot loader version numbers?

Flash update routines in application space could
set up the registers and call it to do the actual SPM.
Kind like cloning all the __boot_xxx() routines in boot.h but using a call to the bootloader rather than the inline LPM
instruction.
Would that work?

There could even be a routine or wrappers around the boot_xxx() functions to
check for the SPM and RET opcodes to make sure the bootloader supported this functionality.

--- bill

I have this link bookmarked to be able to quickly find avr doc's.

Atmel.com not responding at all at the moment.

bperrybap:
But..... There does look to be about 10 bytes left in optiboot.

You can also set the fuses to allow for more flash ram to be aside for the bootloader. That would give much more room to play around in. I think optiboot fits in the smallest reserved space?

As long as you can engineer a jump or call to the bootloader address space, should be quite doable, in principle. Could be interesting if you decide to modify the address you are going to return to...

As for the 10K write cycles, that would suggest you'd really want to cache your writes a much as possible. Writing 2 bytes every second might lead to running out of write cycles pretty quickly. How big is a page?

westfw:

if the bootloader can write to flash, then why can't I do the same thing the bootloader does?

It's a (memory protection) feature. From the CPU overview:

Program Flash memory space is divided in two sections, the Boot Program section and the Application Program section. Both sections have dedicated Lock bits for write and read/write protection. The SPM instruction that writes into the Application Flash memory section must reside in the Boot Program section.

You can "solve" this by putting a subroutine to write flash in the boot section, with a carefully designed API, or by relocating your program so that part of it ends up residing in the boot section. AMForth does this, so as to be able to write user-defined "words" to flash; you might want to look at what they do.

Also keep in mind that program flash is only spec'ed to support 10k write operations...

Yes I know about the write limitations. What I am trying to make is a quick and dirty data logger (for temperature). The flash will only be written a few tens of times at most.

As far as the bootloader is concerned, I've been looking at the code and there is a function that writes flash pages. I should be able to simply use that function since (1) it already exists and (2) it resides in the bootloader.

Or, I can change the fuses to say that the bootloader is 1024 bytes instead of 512 then write my own low level functions in the extra 1/2K......

Ugh... maybe it WILL be easier just to stick an SPI eeprom on the board..

bperrybap:
I've seen this talked about many times but where is this in the m328 document? I've never been able to locate this.
And if that is the case, what would be the point of setting BLB0 mode bits to 1s? (both BLB02 and BLB01)
It was my assumption that BLB01 allowed SPM to work from the application space.

And what about when there is no bootloader?

--- bill

If I read the datasheet correctly, the bootloader protected space must be at least 512 bytes (256 words == BOOTSZ=11) so as long as the flash writing code resides within that space, it should work... even if there is no actual bootloader (I assume).

the BLB bits (again, as I understand them) only control if the bootloader area can be read or written. For example, the default "BOARDS.TXT" file sets the BLB bits to 11 (0x3F) to write the bootloader, then to 00 (0x0F) to prevent writing AND reading the bootloader. The bootloader reads back as all 0x00. If I change the lock fuse to 0x2F, then the bootloader is protected from writes, but I can READ it.

There does look to be about 10 bytes left in optiboot.
What about using 4 of those bytes to put in:
SPM
ret
directly before the boot loader version numbers?

I don't see any reason that that would not work, at least in principle.
There's an added complication that you need to do a an OUT to the SPM control register less than 4 clocks before the SPM instruction (so now you're up to at least 6 bytes...)

I've been looking at the [bootloader] code and there is a function that writes flash pages. I should be able to simply use that function since (1) it already exists and (2) it resides in the bootloader.

I think that you'll find that those are actually macros that produce inline code without any clean entry/exit points.

Krupski:
Or, I can change the fuses to say that the bootloader is 1024 bytes instead of 512 then write my own low level functions in the extra 1/2K......

OR if your code is less 4k you could remove the bootloader and make your code the bootloader.

I think the issue with any of these types of solutions is that it is going to take special linker options
to get code or code sections to live in the correct location (up in the bootloader section).
You can't set any linker options using the currently released Arduino IDE.
Setting these options is possible with the new 1.5 IDE but the 1.5 IDE still has many issues.
You could jettison the IDE in favor of something like using your own makefiles.

Ugh... maybe it WILL be easier just to stick an SPI eeprom on the board..

I would think so if the code doing the data storage is an arduino sketch
being built with the current IDE.
And particularly so if you want to preserver the data across firmware updates.

--- bill