tl;dr: In the code below, why does the Serial.println(value);
statement change the behaviour of the code, and how can I make the code work properly without it ?
I need to save some values on a microcontroller that doesn't have any eeprom (an Arduino 33 BLE sense)
I have found a way to do that by declaring a const variable to reserve a region in the flash memory, and write to it using the microcontroller's NVMC (Non Volatile Memory Controller). This solution works fine but there is some weirdness I'd like to get rid of:
To read the values, I use the following function:
float getFloat(float *ptr) {
float value = *ptr;
Serial.println(value);
return value;
}
This works, but whenever I try to simplify this by
- removing the
Serial.println
statement - not using the function at all and doing what it does inline:
something.floatvalue = *ptr
...the code behaves as if the saved values were always 0 (A memory dump shows this is not the case)
I suspect the compiler is optimising stuff in a way I don't understand (I'm not too familiar with c++). How can I avoid that ?
Here ny current code:
#include <Arduino.h>
#include <stdbool.h>
// https://infocenter.nordicsemi.com/pdf/nRF52840_PS_v1.2.pdf
// nFR52 NVMC registers
#define NVMC_BASE (0x4001E000U)
#define NVMC_READY (NVMC_BASE + 0x400U)
#define NVMC_READYNEXT (NVMC_BASE + 0x408U)
#define NVMC_CONFIG (NVMC_BASE + 0x504U)
#define NVMC_ERASEPAGE (NVMC_BASE + 0x508U)
#define NVMC_ERASEALL (NVMC_BASE + 0x50CU)
#define NVMC_ERASEUICR (NVMC_BASE + 0x514U)
#define NVMC_ERASEPAGEPARTIAL (NVMC_BASE + 0X518U)
#define NVMC_ERASEPAGEPARTIALCFG (NVMC_BASE + 0X51CU)
#define NVMC_ICACHECNF (NVMC_BASE + 0x540U)
#define NVMC_IHIT (NVMC_BASE + 0x548U)
#define NVMC_IMISS (NMVC_BASE + 0x54cU)
// nFR52 MVMC values
#define MVMC_READ_MODE 0x00
#define MVMC_WRITE_MODE 0x01
#define MVMC_ERASE_MODE 0x02
typedef struct flash_mem {
float val_1;
float val_2;
// We want to fill a whole page of memory.
// A page is 4096 bytes, each float takes 4 bytes.
char filler[4096 - (4+4) ];
} flash_mem_t;
// This will reserve a space in flash memory for the values we need to save.
const flash_mem_t _values __attribute__((section("FLASH"), aligned(0x1000))) = {};
// A regular, in-memory instance of our values for easy manipulations.
// we'll use the load() and save() functions to move data between values and _values
flash_mem_t values;
void setup() {
// Initialize serial
Serial.begin(115200);
while (!Serial.ready()) { }
delay(500);
// Load and show saved values
load();
Serial.println(values.val_1);
Serial.println(values.val_2);
// Update and save values
values.val_1 += 1;
values.val_2 += 0.642;
save();
}
// Arduino expects this
void loop() {}
void load () {
// TODO: find a way to do this for all values in our struct automatically
values.val_1 = getFloat((float *)&_values.val_1);
values.val_2 = getFloat((float *)&_values.val_2);
}
void writeValues () {
// TODO: find a way to do this for all values in our struct automatically
*(float *)(&_values.val_1) = values.val_1;
*(float *)(&_values.val_2) = values.val_2;
}
bool save() {
// NVMC can only write on "deleted" bytes, so we delete the page _values sits on
deletePage((void *)&_values);
// make sure NVMC is ready
if (*(uint32_t *)NVMC_READY == false) return false;
// write values to flash
*(uint32_t *)NVMC_CONFIG = MVMC_WRITE_MODE;
writeValues();
while(*(uint32_t *)NVMC_READY == false) delayMicroseconds(50);
*(uint32_t *)NVMC_CONFIG = MVMC_READ_MODE;
return true;
}
bool deletePage(void *pageStart) {
if (*(uint32_t *)NVMC_READY == false) return false;
*(uint32_t *)NVMC_CONFIG = MVMC_ERASE_MODE;
*(uint32_t *)NVMC_ERASEPAGE = (uint32_t)pageStart;
while (*(uint32_t *)NVMC_READY == false) delay(85);
*(uint32_t *)NVMC_CONFIG = MVMC_READ_MODE;
return true;
}
float getFloat(float *ptr) {
float value = *ptr;
// This is the weird part: everything works properly whem the following line is here,
// but value is always 0 when it is commented out
Serial.println(value);
return value;
}
I didn't tag this question with the "arduino" tag because I feel like it's not really an arduino problem. If you disagree, I'll be happy to update the tags.
Thanks for any help!