Program Space

Support for storing and accessing data from Program Space (flash memory).

A string literal (e.g. “string”) used in code gets emitted to the .rodata segment by the compiler. That means it gets read into RAM at startup and remains there.

To avoid this, and reclaim the RAM, the data must be stored in a different segment. This is done using the PROGMEM macro.

Such strings are usually defined using the PSTR() macro, which also ensures that any duplicate strings are merged and thus avoids storing them more than once. This is particularly beneficial for debugging strings.

Templated code

Attention

PROGMEM may not work when used in templated code.

GCC silently ignores ‘section attributes’ in templated code, which means const variables will remain in the default .rodata section.

Strings defined using PSTR() (and related macros) or FlashString definitions are handled correctly because internally they use special names (__pstr__ and __fstr__) which the linker picks up on.

memcpy_aligned

Once in flash memory, string data must be read into RAM before it can be used. Accessing the flash memory directly is awkward. If locations are not strictly accessed as 4-byte words the system will probably crash; I say ‘probably’ because sometimes it just behaves weirdly if the RAM address isn’t aligned.

So, the location being accessed, the RAM buffer it’s being copied to and the length all have to be word-aligned, i.e. integer multiples of 4 bytes. If these conditions are satisfied, then it’s safe to use a regular memcpy() call. However, you are strongly discouraged from doing this. Instead, use memcpy_aligned(), which will check the parameters and raise an assertion in debug mode if they are incorrect.

FakePgmSpace

Standard string functions such as memcpy_P(), strcpy_P(), etc. are provided to enable working with P-strings. With the new arduino-provided toolchains these are now part of the standard library, however Sming has some additions and differences.

F()

Loads a String object with the given text, which is allocated to flash:

String s = F("test");

Note

The F() macro differs from the Arduino/Esp8266 implementation in that it instantiates a String object.

Since the length of the string is known at compile-time, it can be passed to the String constructor which avoids an additional call to strlen_P().

_F()

Like F() except buffer is allocated on stack. Most useful where nul-terminated data is required:

m_printf(_F("C-style string\n"));

This macro is faster than F(), but you need to be careful as the temporary stack buffer becomes invalid as soon as the containing block goes out of scope. Used as a function parameter, that means the end of the function call.

Examples:

println(_F("Debug started"));

commandOutput->print(_F("Welcome to the Tcp Command executor\r\n"));

Bad:

char* s = _F("string")

An assignment such as this will not work because the temporary will be out of scope after the statement, hence s will point to garbage. In this instance PSTR_ARRAY(s, "string") can be used.

DEFINE_PSTR()

Declares a PSTR stored in flash. The variable (name) points to flash memory so must be accessed using the appropriate xxx_P function.

LOAD_PSTR()

Loads pre-defined PSTR into buffer on stack:

// The ``_LOCAL`` macro variants include static allocation
DEFINE_PSTR_LOCAL(testFlash, "This is a test string\n");
   LOAD_PSTR(test, testFlash)
   m_printf(test);
PSTR_ARRAY()

Create and load a string into the named stack buffer. Unlike _F(), this ensures a loaded string stays in scope:

String testfunc() {
   //char * test = "This is a string"; <<- BAD
   PSTR_ARRAY(test, "This is a string");
   m_printf(test);
   ...
   return test; // Implicit conversion to String
}

Both DEFINE_PSTR() and PSTR_ARRAY() load a PSTR into a stack buffer, but using sizeof on that buffer will return a larger value than the string itself because it’s aligned. Calling sizeof on the original flash data will get the right value. If it’s a regular nul-terminated string then strlen_P() will get the length, although it’s time-consuming.

FlashString

For efficient, fast and flexible use of PROGMEM data see FlashString.

API Documentation

FLASH_MEMORY_START_ADDR
isFlashPtr(ptr)

Simple check to determine if a pointer refers to flash memory.

PROGMEM

Place entity into flash memory.

Attach to const variable declaration to have it stored in flash memory

Such variables should not be accessed like regular pointers as aligned instructions are required. Use the provided library functions, such as memcpy_P, instead.

PROGMEM_PSTR

Place NUL-terminated string data into flash memory.

Duplicate string data will be merged according to the rules laid out in https://sourceware.org/binutils/docs/as/Section.html

PSTR(str)

Define and use a NUL-terminated ‘C’ flash string inline.

Note

Uses string section merging so must not contain embedded NULs

Parameters:
  • str

Return values:

char[] – In flash memory, access using flash functions

PGM_P

Identifies a char pointer as living in flash memory Use to clarify code.

PRIPSTR

Remove ?

void *memcpy_aligned(void *dst, const void *src, unsigned len)

copy memory aligned to word boundaries

dst and src must be aligned to word (4-byte) boundaries len will be rounded up to the nearest word boundary, so the dst buffer MUST be large enough for this.

Parameters:
  • dst

  • src

  • len – Size of the source data

int memcmp_aligned(const void *ptr1, const void *ptr2, unsigned len)

compare memory aligned to word boundaries

ptr1 and ptr2 must all be aligned to word (4-byte) boundaries. len is rounded up to the nearest word boundary

Parameters:
  • ptr1

  • ptr2

  • len

Return values:

int – 0 if all bytes match

IS_ALIGNED(_x)

determines if the given value is aligned to a word (4-byte) boundary

ALIGNUP4(n)

Align a size up to the nearest word boundary.

ALIGNDOWN4(n)

Align a size down to the nearest word boundary.

printf_P_heap(f_P, ...)
printf_P_stack(f_P, ...)
printf_P(fmt, ...)
PSTR_COUNTED(str)

Define and use a counted flash string inline.

Note

Strings are treated as binary data so may contain embedded NULs, but duplicate strings are not merged.

Parameters:
  • str

Return values:

char[] – In flash memory, access using flash functions

_F(str)
DEFINE_PSTR(name, str)

define a PSTR

Parameters:
  • name – name of string

  • str – the string data

DEFINE_PSTR_LOCAL(name, str)

define a PSTR for local (static) use

Parameters:
  • name – name of string

  • str – the string data

DECLARE_PSTR(name)

Declare a global reference to a PSTR instance.

Parameters:
  • name

LOAD_PSTR(name, flash_str)

Create a local (stack) buffer called name and load it with flash data.

If defining a string within a function or other local context, must declare static.

Example:

    void testfunc() {
        static DEFINE_PSTR(test, "This is a test string\n");
        m_printf(LOAD_PSTR(test));
    }

Parameters:
  • name

  • flash_str – Content stored in flash. The compiler knows its size (length + nul), which is rounded up to multiple of 4 bytes for fast copy.

_FLOAD(pstr)
PSTR_ARRAY(name, str)

Define a flash string and load it into a named array buffer on the stack.

For example, this:

    PSTR_ARRAY(myText, "some text");
is roughly equivalent to this:
    char myText[ALIGNED_SIZE] = "some text";
where ALIGNED_SIZE is the length of the text (including NUL terminator) rounded up to the next word boundary. To get the length of the text, excluding NUL terminator, use:
    sizeof(PSTR_myText) - 1

Note

Must not contain embedded NUL characters