Description
Here are some excerpts of the documentation of PROGMEM
(emphasis mine):
Description
Store data in flash (program) memory instead of SRAM. [...] It tells the compiler "put this information into flash memory", instead of into SRAM, where it would normally go. [...]
These statements imply that the usage of PROGMEM
is a trade-off between flash usage and RAM usage: you save some RAM at the cost of extra flash consumption. This is wrong. Any constant for which the compiler cannot optimize out the storage (which includes every string literal) is normally stored in flash memory. At program startup, the C runtime creates an extra copy of the constant in RAM, which is the copy that the program will use further on.
The purpose of PROGMEM
is not to store the data in flash “instead of” RAM: that data will be in flash no matter what. Its purpose is to avoid the extra copy in RAM: PROGMEM data is retrieved from flash on demand, only when needed, instead of being copied en masse to RAM at startup.
This may seem like nitpicking, but I think it is worth emphasizing that PROGMEM has zero cost in terms of flash usage: it is useful no matter how much free flash you have.
The page also contains this statement:
It requires special methods [...] to read the data from program memory back into SRAM, so we can do something useful with it.
This is, quite often, incorrect. The compiler is smart enough to allocate most local variables to internal CPU registers rather than RAM. The pgm_read_*()
macros then read the data from flash into the CPU, where accessing a regular constant would instead read that data from RAM. Nothing is moving from flash to RAM. That is, unless you read a whole array at a time, or have so many locals that the compiler cannot fit them into the register file.
My point is that the sentence above implies that data needs to be in RAM in order to be useful (which is wrong), and that PROGMEM incurs the cost of a flash-to-RAM copy on every access (also wrong). Truth is, PROGMEM access is very slightly slower than RAM access: 3 CPU cycles per byte instead of 2. But most times you will pay the cost of the flash access instead of – not in addition to – the cost of RAM access.
Note that there is a flash-to-RAM copy in Serial.println(F("..."))
, as the string has to land in the serial TX buffer. This copy, however, replaces a RAM-to-RAM copy you would have without the F()
macro. So there is no extra copy induced by the use of F()
.