I was looking at ReadAndWrite's example from the MRC522 library and found this code on line 54:
Serial.println(F("Scan a MIFARE Classic PICC to demonstrate read and write."));
my question is:
what is this 'F' function inside println?
I was looking at ReadAndWrite's example from the MRC522 library and found this code on line 54:
Serial.println(F("Scan a MIFARE Classic PICC to demonstrate read and write."));
my question is:
what is this 'F' function inside println?
I believe this should explain it:
Thnaks alot!
F(...) is explained here:
The gory details!
On the AVR processor the SRAM, FLASH, and EEPROM are in separate address spaces. Instructions are fetched from FLASH (a.k.a. Program Memory or PROGMEM). Data is read from and written to SRAM. You have to use special machine instructions for reading (or writing) FLASH or reading or writing EEPROM. Any initialized variables will be initialized by copying the data from FLASH to the variable's location in SRAM before the sketch starts. This is great for initialized variables that will be modified by the sketch but for constant (read-only) variables it is a waste of precious SRAM space. For larger initialized read-only variables, such as lookup tables, it is good to tell the compiler to keep the data in FLASH. (Note: The special instructions for writing into FLASH can only be executed from the BOOTLOADER area of the FLASH memory. Your sketch can't write into FLASH.)
Unfortunately, the compiler will only keep track of the address of the variable, not which address space it is in. It won't remember that your variable is in FLASH and if you try to use it like you would any other variable it will use that FLASH address to fetch data from SRAM and get the wrong data. It is up to you to add the special function calls to fetch data from FLASH whenever you want to fetch data from that variable.
String literals are a special case of initialized variables. They are treated like initialized read-only variables and their space in SRAM is initialized by copying the data from FLASH. Because they are often used for text output to Serial, LCD, Ethernet, WiFi, etc. there is a special trick used to make keeping them out of SRAM easier.
There is a macro named "F" in the standard include file Wstring.h:
class __FlashStringHelper;
#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))
The F() macro uses the macro PSTR() to tell the compiler to keep the string in FLASH and then changes the value type from 'char *' (character pointer) to a '__FlashStringHelper *'. The class __FlashStringHelper has no body, just a type. The "reinterpret_cast" tells the compiler that you know that the value being cast is not compatible with the destination type. Unlike a regular cast, no conversion is done. The ONLY safe operation is to cast the value BACK to what it was before.
In the Print class there are .print() and .println() methods similar to the 'char *' methods that accept a '__FlashStringHelper *' instead. The compiler chooses those methods when you pass the '__FlashStringHelper *' created by the F() macro. The methods then cast the __FlashStringHelper pointer BACk to a character pointer and fetch each character of the string from FLASH. Serial, LCD, Ethernet, WiFi, etc are all objects that inherit behavior from the Print class so their .print() and .println() methods can all accept the '__FlashStringHelper *' type and fetch the string from the FLASH address space.
If you write your own function and one of the arguments is often a fairly large string literal you might want to make a version of the function that accepts the '__FlashStringHelper *' type. Then you can use the F() macro to keep those string literals in FLASH. See Print.cpp in the Arduino core sources for examples of how you would treat the argument differently.
Sadly, you can't use the F() macro to initialize a global pointer. The PSTR() macro it uses has to be inside a function to work.
Thank you, johnwasser.
That fills in the gaps left by the standard Arduino reference information !