Skip to content

F() Flash Macro No Longer Recognized #62

Closed
@woolseyj

Description

@woolseyj

The F() flash macro used for storing strings in flash memory no longer appears to be working as of the 1.8.5 version. The following error is reported during compile for each use.

error: cannot convert 'const char*' to 'const __FlashStringHelper*' in return
#define F(str) (str)

Activity

facchinm

facchinm commented on Dec 3, 2019

@facchinm
Member

F() is useless in megaAVR architecture (it only increases flash occupation). Which code are you trying to compile?

matthijskooijman

matthijskooijman commented on Dec 3, 2019

@matthijskooijman
Collaborator

F() is useless in megaAVR architecture (it only increases flash occupation). Which code are you trying to compile?

But for compatibility with existing sketches, all other cores have a working F() macro as well, even when they do not actually need.

facchinm

facchinm commented on Dec 3, 2019

@facchinm
Member

Also this core has it, this is why I'm asking for the code 🙂

woolseyj

woolseyj commented on Dec 3, 2019

@woolseyj
Author

The code is the Adafruit_IO_Arduino library.

facchinm

facchinm commented on Dec 3, 2019

@facchinm
Member

I just compiled one random example from that library and I didn't get any error. Could you provide more info?

woolseyj

woolseyj commented on Dec 3, 2019

@woolseyj
Author

Here is an example sketch that uses the library.

facchinm

facchinm commented on Dec 3, 2019

@facchinm
Member

Got it. This patch makes the project compile again

diff --git a/cores/arduino/Arduino.h b/cores/arduino/Arduino.h
index 1f02a58..3891105 100644
--- a/cores/arduino/Arduino.h
+++ b/cores/arduino/Arduino.h
@@ -28,6 +28,7 @@
 
 #undef F
 #define F(str) (str)
+#define __FlashStringHelper char
 
 #ifdef __cplusplus
 extern "C"{

But I'm not 100% sure it is the right approach.
@MCUdude do you think it could work as is?

woolseyj

woolseyj commented on Dec 3, 2019

@woolseyj
Author

Confirmed.

MCUdude

MCUdude commented on Dec 3, 2019

@MCUdude
Contributor

@facchinm even though it would fix this exact issue, it's not a very elegant solution. Will this mess up other libraries that use __FlashStringHelper in some way?

matthijskooijman

matthijskooijman commented on Dec 3, 2019

@matthijskooijman
Collaborator

I think it will, since libraries might overload a method for both char* and __FlashStringHelper*. It might be better to make this a separate type and heave F() cast to __FlashStringHelper* as well.

How does SAM and SAMD solve this? I suspect like above?

woolseyj

woolseyj commented on Dec 3, 2019

@woolseyj
Author

@facchinm, could you please explain a little further why the F() macro is useless for the megaAVR architecture? I did not understand what you meant by "only increases flash occupation". Both the Uno R3 and the WiFi R2 have flash memory; are they used differently?

facchinm

facchinm commented on Dec 3, 2019

@facchinm
Member

Classic AVR architecture is referred as modified Harward, because data and memory are in different address spaces (so address 0 could refer to ram or flash, and there are different functions to access them).
New AVR (rebranded megaAVR) architecture is instead more conventional as flash and ram share the same address space (like ARM) so there's no need for special treatment if a variable is only in flash (adding const modifier is enough).

woolseyj

woolseyj commented on Dec 3, 2019

@woolseyj
Author

Great, thanks!

facchinm

facchinm commented on Dec 3, 2019

@facchinm
Member

Anyway, __FlashStringHelper is clearly not intended to be used as-is but as an helper to print/compare strings in Flash with strings in RAM on a very peculiar architecture via the F() macro. Clearly it's too late to hide it but I have no better idea than defining it as const char or char.

22 remaining items

matthijskooijman

matthijskooijman commented on Sep 8, 2020

@matthijskooijman
Collaborator

Cool!

Re option 1, the performance overhead might actually be even smaller than I thought. I was thinking lpm is three cycles and ld only 2, but that's only for loads for RAM. Apparently ld from the mapped flash is also three cycles (maybe even more, documentation is unclear). Using the mapped flash might still be faster since ld has more addressing modes and lds can be used when the address is known at compiletime, though.

As for the cycle time, the AVR Instruction Set Manual says:

Cycle time for data memory access assumes internal RAM access, and are not valid for access to NVM. A
minimum of one extra cycle must be added when accessing NVM. The additional time varies dependent on
the NVM module implementation. See the NVMCTRL section in the specific devices data sheet for more
information.

So that makes at least 3 cycles for ld from flash. However, the NVMCTRL section of the Atmega4808/9 datasheet does not seem to say anything about the number of cycles to read from mapped flash...

matthijskooijman

matthijskooijman commented on Nov 4, 2020

@matthijskooijman
Collaborator

Giving this a bit more thought, and seeing the PRs that try to implement both approaches, I suspect that maybe option 1. is the better one after all. There is some overhead, but it should really work with all code out there (AFAICS) and does not complicate the include path even more, which is worth a few cycles IMHO.

aentinger

aentinger commented on Dec 11, 2020

@aentinger
Contributor

I've been going through all those issues (#53, #62), PRs (#54, #82, #85, #87) and commits (a0f6beb) again and frankly, my head hurts 🤕. All in all it seems to me that by @facchinm 's commit a0f6beb we've implemented (restored actually) option 1 as described by @matthijskooijman here. @matthijskooijman can you confirm that I copy you correctly?

Also @giulcioffi's PRs are outdated a bit by #62 (comment) (this muddled the water when investigating this issue) - but no fault of her own, rather result of the long-standing PR we failed to integrate.

matthijskooijman

matthijskooijman commented on Dec 11, 2020

@matthijskooijman
Collaborator

All in all it seems to me that by @facchinm 's commit a0f6beb we've implemented (restored actually) option 1 as described by @matthijskooijman here

Yes, I agree. Now, -API includes the main avr-libc pgmspace.h for PROGMEM and PSTR, and defines __FlashStringHelper and F() as on all platforms, and megaavr doesn't seem to change these, so I think now progmem stuff just works as it does on AVR, which I think is the indeed the safest approach. If we want to go for option 1, I think we're done and the issues and PRs can be closed.

There were some alternative PRs to compare the impact of this approach (but of those, I think only #85, implementing option 2, is relevant, since #87 has major compatibility problems, and #82 essentially just does what current master does with a bunch of duplicated code). So if we still want to consider option 2, we might want to look at the result of #85, but to really compare, that should be rebased on current master so it really compares option 1 with option 2 (it now compares the older, broken no-op F() version with option 2). Also, I think #85 (or rather, the https://github.com/giulcioffi/ArduinoCore-API/commits/FmacroIssue branch) needs some more work to really be ready for merging, but it looks ok for testing now.

aentinger

aentinger commented on Dec 14, 2020

@aentinger
Contributor

Thank you very much for your feedback @matthijskooijman. Let's go with option #1 for now and schedule another look for this issue at a later point in time 🙏 .

woolseyj

woolseyj commented on Dec 26, 2020

@woolseyj
Author

When is the next version expected to be released that will include this fix?

aentinger

aentinger commented on Jan 8, 2021

@aentinger
Contributor

@facchinm What do you reckon?

facchinm

facchinm commented on Jan 8, 2021

@facchinm
Member

@aentinger version 1.8.7 was released with the fix just before the end of the year 🙂

aentinger

aentinger commented on Jan 8, 2021

@aentinger
Contributor

Totally true, I was deceived because it was released via cli git tag therefore not showing up in the release section of the repo main page 😊

Screenshot from 2021-01-08 09-58-25

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @matthijskooijman@PaulStoffregen@woolseyj@MCUdude@aentinger

        Issue actions

          F() Flash Macro No Longer Recognized · Issue #62 · arduino/ArduinoCore-megaavr