Questions about the F() Macro and PROGMEM on SAMD processors

I'm building an application on a Nano 33 IOT. It has a complex UI and uses a lot of SRAM. I have tried using the F() macro on the literal serial.print and serial.println statements. In addition I have declared most of my string literals like this:

const char String_0[] PROGMEM = "On"; // "String 0" etc are strings to store - change to suit.
const char String_1[] PROGMEM = "Off";

The problem is that I'm not seeing any change in the dynamic memory. (eg. Global variables use 23648 bytes of dynamic memory.).

I came across this comment in an old discussion of PROGMEM

If the SAMD (Arduino Zero) is anything like the SAM3X (Arduino Due), you can just use the
 C++ "const" keyword, and forget all about the AVR's PROGMEM keyword. Even better, flash memory is 
completely mapped to main memory map, meaning no special calls are required to access it.
 More efficient, and more readable! For instance, you can just do:

So my questions include:

  1. How do I know if the F() macro and the PROGMEM functions are actually moving things to Flash? Wouldn't things like literals be part of global variables?

  2. Is there anything more in the SRAM than the "dynamic memory"? What does dynamic memory mean anyway. Do I assume that the only other things are the stack and the heap?

There's plenty of program space (aka flash) on the Nano 33 IOT. The problem will be SRAM, even at 32K for my application. So any guidance on this issue is very welcome.

David

As stated in the discussion you quoted, you don't need to use PROGMEM or F() with the SAMD. If able, the linker will leave const variables in flash which is mapped into the same address space as RAM.

Now, if you have a struct or class with const and non-const members, it obviously can't do that since it must occupy contiguous memory locations.

Except that I want to force things into Flash because I am running out of room in SRAM. It does appear that the PROGMEM designation can have that effect. I ran an experiment with a GUI tool called GUI_Slice and GUISliceBuilder GUIslice: GUIslice library. That tool comes with examples that both use and don't use PROGMEM to reduce SRAM size. So I ran them to see what would happen on a SAMD processor. The _P functions use PROGMEM.

  1. Using the _P functions.
    Sketch uses 63904 bytes (24%) of program storage space. Maximum is 262144 bytes.
    Global variables use 5020 bytes of dynamic memory.
  2. Normal
    Sketch uses 65308 bytes (24%) of program storage space. Maximum is 262144 bytes.
    Global variables use 6700 bytes of dynamic memory.

I’m not sure I understand why the _P version would be lower in both program storage and Global variables, unless PROGMEM is not considered part of program storage space. I'm also not sure why my limited use of F() and PROGMEM on string literals has had no effect on my own code, making me think I'm doing something wrong, though you see the declaration above.

Perhaps because the compiler / linker is outsmarting you and already allocating to flash constants that can be kept there.

Are there tools to help figure that out?

I did a few experiments by printing out the addresses of the variables. The memory map of
the Nano 33 IOT has flash strarting at 0 and SRAM at 0x20000000.
When I started the variable was at 0x20000CE. After I moved it, it was at 0x171B0.
The problem is that the
Global variables use 23688 bytes of dynamic memory.
did not change.

So I wonder what and how it's counting.

Is there a way to have the tool chain report out the addresses of all the variables?

Unfortunately I can not help. But I wanted to share my experience with the Nano IoT33 and PRGOGMEM.

My setup already included a LCD Display with some text, and a WebClient that was sending some text. All of this I wrote as "const char arrays[] PROGMEM" It worked fine for the moment.

Then I added a WebServer with some styles buttons and functions, nothing big, also in PROGMEM.

When I tried the whole thing, it was not working. I looked at the html that my browser was receiving, and only half of it was readable text; the rest was just random junk. Hence I changed the 200 const char arrays[] to "client.println(F("")); :confused: and voila, it was sent and received correctly. But on my LCD display only random junk was displayed. So I changed that, too, to lcd.print(F(""); and everything fine.

Something is not working the way Arduino sais. I mean, It would not be a big deal, to just write here Arduino PROGMEM that it's not working with the IoT33. Or else, there is something wrong....