When does the F() macro write its strings to flash?

I have googled and searched for this information but I can't find it anywhere.

When I use the F() macro in an Arduino sketch, at what point in time are the bytes actually written to the Arduino's flash memory?

Example:

I have written a "Log" function which prints things to the Arduino USB/Serial port. If I use the function this way:

Log(F("Startup sequence is complete."));

...then at what point in time is that string of characters written into the Arduino chip's flash memory?

It would make most sense if the write happened at the time when the Arduino sketch was initially uploaded into the Arduino. Since F() only works with constant strings, I could imagine that the macro is being helpful and compiling those strings in such a way that they are stored alongside the program itself, so that the act of uploading the program to the Arduino just brings those strings right along with it. Once they're in there, the same strings are only read from flash memory at runtime, and no further writing needs to occur during runtime. That would make the most sense to me.

However none of the documentation on the F() macro (that I've been able to find) explicitly states this. All docs say that the strings are stored in flash, but they don't say when.

If, for example, the strings were written to the flash at runtime, or even when the Arduino sketch first starts up and begins running, or something like that, then I could envision a situation where such usage "wears out" the write cycles of the flash memory over many runs of the program.

I'd like to know for sure, because my current Arduino project depends heavily on the F() macro to save heap space. I want to be confident that my sketch isn't consuming new write cycles in the flash memory every time it runs.

Does anyone know the answer to this question?

They're written when you program the AVR

If, for example, the strings were written to the flash at runtime, or even when the Arduino sketch first starts up and begins running,

Where would the strings come from if that were the case?

The F() macro doesn't tell it to store the string in flash. Whether or not you use F(), the string is stored in flash.

F() tells it not to copy the string from flash to RAM on startup, and casts it to a _FlashStringHelper, which several functions (like Serial.print() ) will recognize, and know to use the appropriate methods to read straight from flash.

The linker puts the strings into the .hex file and when you upload the .hex file into the FLASH memory of the Arduino the strings are part of that upload. The strings are put in flash at the same time as the rest of your sketch. The strings are in FLASH before the sketch begins execution.

All constant data, like character string data is always stored in FLASH.
The compiler generates the data and the linker ensures that the data is in section that is eventually programmed into flash.

The reason for the F() macro is due to a h/w limitation in the AVR.
The AVR cannot directly access data stored in FLASH.
The AVR has a split memory Harvard architecture. (different address spaces for RAM, FLASH, EEPROM, ...)
C does not understand this as it expects a single address space.
Nearly all the other processors that use a Harvard architecture provided a mechanism to read flash using normal data reads. The AVR did not. (big mistake IMO)

In order to be compatible with the single address space that C/C++ expects, the AVR compiler, linker, and startup code, by default, will copy constant data like strings to SRAM where they can be accessed the way C/C++ expects.
The data is stored in flash, but the linker tells the code accessing it that it is stored in RAM.
The startup code copies the data to RAM before the sketch runs so that the data will be ther.
The sketch code then access the data by getting it from RAM instead of FLASH since the processor can directly access from in RAM.
But because the RAM is so limited on the AVR parts, this extra RAM usage is often undesirable.
To work around this, the avr-libC and Arduino has lots of funky AVR proprietary stuff to keep the data from being copied to RAM. This includes things like PROGMEM, and the Arduino F() macro.
While setting things up to not make this extra copy to RAM saves RAM, it complicates things since the AVR still can not access the data directly.
It takes extra code to read the data from FLASH.
libC provides functions like pgm_read_xxx(). i.e. pgm_read_byte() pgm_read_word() etc...
Arduino tries to hide this by using the F() macro which sets things up with the link to avoid the data copy and also assigns a type to the data so that Print class functions know that they need to jump through hoops to access the data vs being able to access it directly.

All this kind of stuff is not necessary on the ARM, pic32, or ESP8266 parts as their h/w supports accessing constant data the way C/C++ expects.
On those parts you don't have to worry about all this and life is much simpler.

--- bill

1 Like