I am afraid there is no good solution to this problem. One option I do
like is to use the __flash
qualifier instead of PROGMEM
:
const uint8_t ram_array[] = { 1, 2, 3, 4 };
__flash const uint8_t flash_array[] = { 5, 6, 7, 8 };
void function_reading_ram(const uint8_t *array)
{
uint8_t secondElement = array[1];
// ...
}
void function_reading_flash(__flash const uint8_t *array)
{
uint8_t secondElement = array[1];
// ...
}
int main(void)
{
function_reading_ram(ram_array); // OK
function_reading_flash(flash_array); // OK
function_reading_ram(flash_array); // Warning
function_reading_flash(ram_array); // Warning
}
Note that, with __flash
, you don't need pgm_read_byte_near()
or
anything similar. You just use the array like you would use any regular
array, and the compiler is smart enough to generate the code required to
access the Flash memory.
The warnings generated by gcc are:
warning: conversion from address space ‘__flash’ to address space ‘generic’ [-Waddr-space-convert]
function_reading_ram(flash_array);
^
warning: conversion from address space ‘generic’ to address space ‘__flash’ [-Waddr-space-convert]
function_reading_flash(ram_array);
^
Given how nice this solution is, you may wonder why I wrote “there is no
good solution”. Well, this comes with two caveats, one small and one
huge. The small caveat is that you need to explicitly pass the option
-Waddr-space-convert
to the compiler if you want it to generate the warnings. It
It is not implied even with
-Wall -Wextra
. The huge caveat is that this only works in plain C.
If you try to use this trick in C++ you get:
error: ‘__flash’ does not name a type
This is an implementation of the “named address spaces” extension to the standard C. Since nothing like this is standardized in C++, the authors of gcc assumed it would not be useful to users of C++. :-( You can mix C and C++ sources in Arduino, but you can't call class methods from C.