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 aString
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:
is roughly equivalent to this:PSTR_ARRAY(myText, "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:char myText[ALIGNED_SIZE] = "some text";
sizeof(PSTR_myText) - 1
Note
Must not contain embedded NUL characters