The hidden Arduino Macro F() fixes random lock ups

It’s 3am but you are not going to bed until you squash this last bug. You sprinkle Serial.print() statements everywhere you can think of, and then that’s when all hell breaks loose:  Your code randomly locks up, the LEDs go crazy, and you’ve had it. What’s going on?  You’ve run out of RAM!

All of those Serial.print() statements are composed of c-style strings. Which are “constant character arrays.”  In order for those arrays to work properly, they get loaded into the ATmega’s RAM before your code starts running. Which can be a problem because 2,048 bytes of RAM doesn’t allow for much.

Introducing the F() Macro

Search the entire Arduino Reference Page, and you won’t find a single mention of the F() macro. Which is unfortunate because it is one of the most powerful functions, which was added with the 1.0 release of the IDE. I keep mixing the terms “macro” and “function.”  F() really isn’t a function, it is a #define macro which lives in WString.h

WString.h:#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))

That long string of code tells the compiler to keep a string inside of PROGMEM and not allow it to consume RAM.

Using the F() Macro

Here’s an example of how you would use the F() macro with Serial.print() or Lcd.print().

Serial.println(F(“Hello World”));
Lcd.print(F(“W”));

That’s all there is to it. Simply wrap your string (const character array) with F().

Why is the F() Macro Needed?

Remember that the Arduino Uno (and it’s cousins) are based on the ATmega328. This microcontroller only offers 2,048 bytes of RAM. 2k, that’s it. Even the Uno’s big brother, the Mega2560, only has 8K of RAM.

What about using the “const” keyword?

From the #define vs const post, the const keyword will tell a compiler that a variable is a constant and can’t change. Depending on the optimizations used, the avr-gcc compiler will avoid putting that value into RAM since it knows it’ll never change. But, that technique won’t work with c-style strings or,well, arrays. Since arrays are based around pointers, the compiler needs to put the array into RAM so that pointers work correctly. Which means, all strings need to be put into RAM before they can be used.

What the F() macro Does

The F() macro tells the compiler to leave this particular array in PROGMEM. Then when it is time to access it, one byte of the data is copied to RAM at a time. There’s a small performance overhead for this extra work. However, printing strings over Serial or to a LCD is a really slow process, so a few extra clock cycles really won’t matter.

Tradeoffs to Consider

#1:  Can’t Change Data

The key tradeoff to using the F() Macro is that you can’t use it for data you want to change. Anything stored in PROGMEM cannot be changed by the running program. In fact, you would never want that. The only code that can change PROGMEM is code stored in the boot partition, which is where the bootloader lives.

#2:  Only works on Strings

Another tradeoff is that this macro only works for strings. While it is useful to use PROGMEM to store stuff like bit-patterns for characters, this macro isn’t going to help with that. If that’s the kind of thing you are trying to store, then you’ll need to use the traditional PROGMEM statements to do so. Which makes this reference on PROGMEM from the Arduino.cc site a great read.

#3:  Not good for big blocks of text (like HTML)

Storing HTML pages is another example where you probably want to keep the bulk of the text in PROGMEM. Unless that HTML is wrapped around Serial.print() or Client.print(), you aren’t going to be able to use the F() macro.

#4:  Optimization

There is no optimization of memory usage with the F() macro. If you use the same string over and over in your code, each instance will consume some PROGMEM. If you’re running short on PROGMEM, you might have to consider not using the F() macro .

Conclusion

Don’t wait until your code starts acting weird. Whenever you use strings in a print() method, get into the habit of wrapping the string with a F() macro. This way you don’t have to worry about RAM getting wasted on something that can’t be changed anyway.

Long comments, URLs, and code tend to get flagged for spam moderation. No need to resubmit.

Leave a comment

12 thoughts on “The hidden Arduino Macro F() fixes random lock ups

  1. Oops, the comment shings that WString.h was a html tag or something. Since you seem to moderate the comments anyways maybe you can fix it because now the comment doesn’t make sense 🙂

  2. I had exact the same thing! I was pulling my hairs out to find out why all of the sudden my code wouldn’t work anymore. By commenting and uncommenting lines of code over and over again I finally found out that a Serial.print() was causing this issue. Then I found out about the F() macro.

    I couldn’t get it to work immediately though, but I suppose I need do use #include at the top of my code? Or is it part of Arduino.h?

    I eventually just removed the serial prints because the code was complete anyways. And boy did I miss a debugger during this process 🙁

    Nice to read I am not the only one who made this mistake.

  3. Many, many, many thanks for this article.

    My Arduino project (a Lasertag system) had ground to a halt over the weekend due to running out of memory, and I was considering upgrading to a Mega, as I could not find any other solution.

    I went through my code this morning and altered all my Serial.print statements to use the F macro and I recovered 60% of my available RAM.

    So your article saved the day 🙂

  4. Hello, Great piece of information.

    If i change an existing string such as:
    ” Serial.print(“Initializing SD card…”); ”
    and change this to read:
    ” Serial.print(F(“Initializing SD card…”)); ”

    The program compiles with no issues however neither the RAM or program storage used changes on my Uno.

    Do i need to initialise somewhere first?

    • This is a good example of how the RAM usage reported by the compiler isn’t always “right.” Character-const arrays don’t consume RAM until they are copied at run time. The RAM usage reported by the compiler only reports static usage, like how many variables are defined. The F() macro keeps the string from being copied.

      • I don’t think this is correct – the data is copied into RAM at startup, but the space for this is already reserved at compiletime and should be included in the IDE memory usage output. I just tried this with an empty sketch with just one serial print, and adding `F()` lowers the memory usage for me. Not sure why the original commenters code does not work like this, though.

  5. Thanks also. I found this page when looking for an explantion of the F() macro. Even after looking at the source for the macro I had no idea what it was for, yet it was used constantly in supplied examples. Baffling until now.

  6. Thnaks so much for your thorough explanation of the F() function/macro. I was also shocked for not being able to find any information about it anywhre in the “oficial” arduino pages.