try to fix submodule

This commit is contained in:
2023-11-09 19:02:15 -05:00
parent c1d45aa443
commit deea94b076
366 changed files with 40228 additions and 2 deletions

View File

@@ -0,0 +1,143 @@
# SimpleFOC Settings Storage
Code to persist calibration data and motor settings to and from storage. The SettingsStorage is abstract, and different implementations exist for different concete storage media.
The SettingsStorage is based on the SimpleFOCRegisters abstraction, so this means you can load or store any of the registers (representing SimpleFOC settings) that is both readable and writeable (e.g. while the current shaft velocity is available as a register, you can't store it as a setting because its read-only).
The SettingsStorage can save the settings for one or more motors, and you can customize which settings are saved. If you don't customize, only the motor
calibration will be stored (REG_ZERO_ELECTRIC_ANGLE, REG_SENSOR_DIRECTION).
## Hardware requirements
Obviously, to save settings you need a place to store them where they won't be lost when you power down. There can be many solutions to this question, and we attempt to provide some simple drivers for the common storage solutions people might want.
But its also quite easy to extend the system to support your specific needs.
Supported hardware:
- [SAMD NVM](samd/) \
Some SAMD chips have a built-in NVRAM flash, which can be written from user code.
- [CAT24 I2C Flash EEPROMs](i2c/) \ :warning: UNFINISHED
Simple programmable memories with I2C interface. Memory space is quite limited, but enough for storing settings.
See Roadmap, below, for systems we may support in the future.
## Basic Usage
Using SettingsStorage is simple. Just add a `settings.loadSettings()` after setting up your defaults, but before calling init() on the objects. And call `saveSettings()` after initialization of the motor has (successfully) completed.
This example saves just the motor calibration, but you might want to add additional code to save other registers, or make your solution more user-friendly. See the other examples below.
```c++
#include "settings/samd/SAMDNVMSettingsStorage.h"
SAMDNVMSettingsStorage settings = SAMDNVMSettingsStorage();
BLDCMotor motor = BLDCMotor(...);
void setup() {
SimpleFOCDebug::enable(); // show debug messages from settings
// initialize the settings early in the setup
settings.addMotor(&motor);
settings.init();
// first set your defaults
driver.voltage_power_supply = 12.0f;
driver.voltage_limit = 12.0f; // 12V driver limit, like PSU
motor.voltage_limit = 6.0f; // 6V motor limit
// then try to load the settings
SettingsStatus loadStatus = settings.loadSettings();
// driver init code, etc...
...
// then init the motor
motor.init();
motor.initFOC();
// and if the settings were not loaded earlier, then save them
if (motor.motor_status == FOCMotorStatus::motor_ready && loadStatus != SFOC_SETTINGS_SUCCESS) {
settings.saveSettings();
}
// any other initialization
...
}
```
### Choosing registers
By default, only the calibration data (motor native direction, electrical zero position) are saved. To save additional registers, you can choose them before calling `SettingsStorage.init()`, as in the example below:
```c++
SimpleFOCRegister settingsRegisters[] = { REG_ZERO_ELECTRIC_ANGLE, REG_SENSOR_DIRECTION, REG_VEL_PID_P, REG_VEL_PID_I, REG_VEL_PID_D, REG_VEL_LPF_T, REG_VEL_LIMIT, REG_VEL_MAX_RAMP, REG_VOLTAGE_LIMIT, REG_MOTION_DOWNSAMPLE, REG_CONTROL_MODE, REG_TORQUE_MODE, REG_PHASE_RESISTANCE, REG_KV, REG_INDUCTANCE };
CAT24I2CFlashSettingsStorage settings = CAT24I2CFlashSettingsStorage(0xA0);
BLDCMotor motor = BLDCMotor(...);
void setup() {
SimpleFOCDebug::enable(); // show debug messages from settings
// initialize the settings early in the setup
settings.setRegisters(mySettingsRegisters, sizeof(mySettingsRegisters));
settings.addMotor(&motor);
settings.init();
...
}
```
### Using settings with commander
You can easily interact with the settings via the commander, for example to save your PID tuning values:
```c++
SimpleFOCRegister settingsRegisters[] = { REG_ZERO_ELECTRIC_ANGLE, REG_SENSOR_DIRECTION, REG_VEL_PID_P, REG_VEL_PID_I, REG_VEL_PID_D, REG_VEL_LPF_T };
CAT24I2CFlashSettingsStorage settings = CAT24I2CFlashSettingsStorage(0xA0);
Commander commander;
void doSaveSettings(char *cmd) { settings.saveSettings(); }
void doLoadSettings(char *cmd) { settings.loadSettings(); }
void setup() {
...
settings.setRegisters(settingsRegisters, sizeof(settingsRegisters));
settings.addMotor(&motor);
settings.init();
...
commander.addCommand('s', doSaveSettings, "Save settings");
commander.addCommand('l', doLoadSettings, "Load settings");
...
}
void run() {
motor.move();
motor.loopFOC();
commander.run();
}
```
## Roadmap
The following ideas for storage backends are on the roadmap, with no definate schedule for implementation:
- ESP32 SPIFFs Filesystem
- ESP32 Preferences
- Arduino EEPROM library
- In-Memory Buffer (for use with other libraries or abstractions)
- JSON String (for printing to console)

View File

@@ -0,0 +1,120 @@
#include "./SettingsStorage.h"
#include "communication/SimpleFOCDebug.h"
SettingsStorage::SettingsStorage() {
};
SettingsStorage::~SettingsStorage() {
};
void SettingsStorage::addMotor(BLDCMotor* motor) {
if (numMotors < SIMPLEFOC_SETTINGS_MAX_MOTORS) {
motors[numMotors] = motor;
numMotors++;
}
else
SimpleFOCDebug::println("SS: too many motors");
};
void SettingsStorage::setRegisters(SimpleFOCRegister* registers, int numRegisters){
this->registers = registers;
this->numRegisters = numRegisters;
};
void SettingsStorage::init() {
// make sure we have motors and registers
if (numMotors < 1) {
SimpleFOCDebug::println("SS: no motors");
return;
}
if (registers==NULL || numRegisters < 1) {
SimpleFOCDebug::println("SS: no registers");
return;
}
};
SettingsStatus SettingsStorage::loadSettings() {
SimpleFOCDebug::println("Loading settings...");
beforeLoad();
uint8_t magic; readByte(&magic);
if (magic != SIMPLEFOC_SETTINGS_MAGIC_BYTE) {
SimpleFOCDebug::println("No settings found ");
return SFOC_SETTINGS_NONE;
}
uint8_t rversion; readByte(&rversion);
if (rversion != SIMPLEFOC_REGISTERS_VERSION) {
SimpleFOCDebug::println("Registers version mismatch");
return SFOC_SETTINGS_OLD;
}
uint8_t version; readByte(&version);
if (version != settings_version) {
SimpleFOCDebug::println("Settings version mismatch");
return SFOC_SETTINGS_OLD;
}
for (int m = 0; m < numMotors; m++) {
if (numMotors>1)
SimpleFOCDebug::println("Loading settings for motor ", m);
startLoadMotor(m);
for (int i = 0; i < numRegisters; i++) {
SimpleFOCRegister reg = registers[i];
startLoadRegister(reg);
setRegister(reg, motors[m]);
endLoadRegister();
}
endLoadMotor();
}
afterLoad();
SimpleFOCDebug::println("Settings loaded");
return SFOC_SETTINGS_SUCCESS;
};
SettingsStatus SettingsStorage::saveSettings() {
SimpleFOCDebug::println("Saving settings...");
beforeSave();
writeByte(SIMPLEFOC_SETTINGS_MAGIC_BYTE);
writeByte(SIMPLEFOC_REGISTERS_VERSION);
writeByte(settings_version);
for (int m = 0; m < numMotors; m++) {
if (numMotors>1)
SimpleFOCDebug::println("Saving settings for motor ", m);
startSaveMotor(m);
for (int i = 0; i < numRegisters; i++) {
SimpleFOCRegister reg = registers[i];
startSaveRegister(reg);
sendRegister(reg, motors[m]);
endSaveRegister();
}
endSaveMotor();
}
afterSave();
SimpleFOCDebug::println("Settings saved");
return SFOC_SETTINGS_SUCCESS;
};
// empty implementation for these
void SettingsStorage::startSaveMotor(uint8_t num) {};
void SettingsStorage::endSaveMotor() {};
void SettingsStorage::startSaveRegister(SimpleFOCRegister reg) {};
void SettingsStorage::endSaveRegister() {};
void SettingsStorage::startLoadMotor(uint8_t num) {};
void SettingsStorage::endLoadMotor() {};
void SettingsStorage::startLoadRegister(SimpleFOCRegister reg) {};
void SettingsStorage::endLoadRegister() {};
void SettingsStorage::beforeLoad() {};
void SettingsStorage::afterLoad() {};
void SettingsStorage::beforeSave() {};
void SettingsStorage::afterSave() {};

View File

@@ -0,0 +1,70 @@
#pragma once
#include "../comms/SimpleFOCRegisters.h"
#include "../comms/RegisterReceiver.h"
#include "../comms/RegisterSender.h"
#include "BLDCMotor.h"
#define SIMPLEFOC_SETTINGS_MAGIC_BYTE 0x42
#define SIMPLEFOC_SETTINGS_VERSION 0x01
#define SIMPLEFOC_SETTINGS_REGISTERS_MINIMAL { REG_ZERO_ELECTRIC_ANGLE, REG_SENSOR_DIRECTION }
#if !defined(SIMPLEFOC_SETTINGS_MAX_MOTORS)
#define SIMPLEFOC_SETTINGS_MAX_MOTORS 4
#endif
typedef enum : uint8_t {
SFOC_SETTINGS_SUCCESS = 0, // settings loaded/saved successfully
SFOC_SETTINGS_NONE = 1, // no settings found to load
SFOC_SETTINGS_OLD = 2, // settings found, but version is old
SFOC_SETTINGS_ERROR = 3 // other error
} SettingsStatus;
class SettingsStorage : public RegisterReceiver, public RegisterSender {
public:
SettingsStorage();
~SettingsStorage();
void addMotor(BLDCMotor* motor);
void setRegisters(SimpleFOCRegister* registers, int numRegisters);
virtual void init();
SettingsStatus loadSettings();
SettingsStatus saveSettings();
/*
Change this value if you make changes to the registers saved in code, and have saved settings on existing devices.
This will cause the device to reset to defaults on the next boot.
*/
uint8_t settings_version = SIMPLEFOC_SETTINGS_VERSION;
protected:
virtual void startSaveMotor(uint8_t num);
virtual void endSaveMotor();
virtual void startSaveRegister(SimpleFOCRegister reg);
virtual void endSaveRegister();
virtual void startLoadMotor(uint8_t num);
virtual void endLoadMotor();
virtual void startLoadRegister(SimpleFOCRegister reg);
virtual void endLoadRegister();
virtual void beforeLoad();
virtual void afterLoad();
virtual void beforeSave();
virtual void afterSave();
FOCMotor* motors[SIMPLEFOC_SETTINGS_MAX_MOTORS];
int numMotors = 0;
SimpleFOCRegister* registers = NULL;
int numRegisters = 0;
};

View File

@@ -0,0 +1,98 @@
#include "./CAT24I2CFlashSettingsStorage.h"
CAT24I2CFlashSettingsStorage::CAT24I2CFlashSettingsStorage(uint8_t address, uint16_t offset) {
_address = address;
_offset = offset;
};
CAT24I2CFlashSettingsStorage::~CAT24I2CFlashSettingsStorage() {};
void CAT24I2CFlashSettingsStorage::init(TwoWire* wire) {
SettingsStorage::init();
_wire = wire;
reset();
};
uint8_t CAT24I2CFlashSettingsStorage::readByte(uint8_t* valueToSet) {
return readBytes(valueToSet, 1);
};
uint8_t CAT24I2CFlashSettingsStorage::readFloat(float* valueToSet) {
return readBytes(valueToSet, 4);
};
uint8_t CAT24I2CFlashSettingsStorage::readInt(uint32_t* valueToSet) {
return readBytes(valueToSet, 4);
};
uint8_t CAT24I2CFlashSettingsStorage::writeByte(uint8_t value) {
return writeBytes(&value, 1);
};
uint8_t CAT24I2CFlashSettingsStorage::writeFloat(float value) {
return writeBytes(&value, 4);
};
uint8_t CAT24I2CFlashSettingsStorage::writeInt(uint32_t value) {
return writeBytes(&value, 4);
};
void CAT24I2CFlashSettingsStorage::beforeSave() {
reset();
};
void CAT24I2CFlashSettingsStorage::beforeLoad() {
reset();
_wire->beginTransmission(_address);
_wire->write(_currptr >> 8);
_wire->write(_currptr & 0xFF);
_wire->endTransmission(false);
};
void CAT24I2CFlashSettingsStorage::reset() {
_currptr = _offset;
};
int CAT24I2CFlashSettingsStorage::readBytes(void* valueToSet, int numBytes) {
int read = _wire->requestFrom((uint8_t)_address, (uint8_t)numBytes, (uint8_t)true);
_currptr += read;
if (read==numBytes)
_wire->readBytes((uint8_t*)valueToSet, numBytes);
return read;
};
int CAT24I2CFlashSettingsStorage::writeBytes(void* value, int numBytes) {
_wire->beginTransmission(_address);
_wire->write(_currptr >> 8);
_wire->write(_currptr & 0xFF);
size_t written = _wire->write((uint8_t*)value, numBytes);
_wire->endTransmission(true);
_currptr += written;
delay(5); // write-cycle time
return written;
};

View File

@@ -0,0 +1,35 @@
#pragma once
#include "../SettingsStorage.h"
#include "Wire.h"
class CAT24I2CFlashSettingsStorage : public SettingsStorage {
public:
CAT24I2CFlashSettingsStorage(uint8_t address = 0xA0, uint16_t offset = 0x0);
~CAT24I2CFlashSettingsStorage();
void init(TwoWire* wire = &Wire);
protected:
uint8_t readByte(uint8_t* valueToSet) override;
uint8_t readFloat(float* valueToSet) override;
uint8_t readInt(uint32_t* valueToSet) override;
uint8_t writeByte(uint8_t value) override;
uint8_t writeFloat(float value) override;
uint8_t writeInt(uint32_t value) override;
void beforeSave() override;
void beforeLoad() override;
void reset();
int readBytes(void* valueToSet, int numBytes);
int writeBytes(void* value, int numBytes);
TwoWire* _wire;
uint8_t _address; // i2c address
uint16_t _offset; // offset into NVRAM to store settings
uint16_t _currptr = 0; // pointer to current location in NVRAM
};

View File

@@ -0,0 +1,26 @@
# I2C memories settings drivers
Store settings to I2C EEPROMs.
## CAT24C64 I2C EEPROMs
:warning: not yet finished or tested!
Datasheet describes the CAT24C64 as: _The CAT24C64 is a 64 Kb CMOS Serial EEPROM device, internally organized as 8192 words of 8 bits each._
Provide I2C address in constructor:
`CAT24I2CFlashSettingsStorage settings = CAT24I2CFlashSettingsStorage(0xA0);`
If you want to use a different I2C bus than the default, you can pass it to the constructor:
`settings.init(&Wire2);`
You can use multiple settings objects in the same EEPROM, by providing an offset to the constructor:
```c++
CAT24I2CFlashSettingsStorage settings = CAT24I2CFlashSettingsStorage(0xA0);
CAT24I2CFlashSettingsStorage settings = CAT24I2CFlashSettingsStorage(0xA0, 80);
CAT24I2CFlashSettingsStorage settings = CAT24I2CFlashSettingsStorage(0xA0, 160);
```

View File

@@ -0,0 +1,49 @@
# SAMD21 settings driver
Driver for storing settings on SAMD21 chips.
There are two options:
1. **RWW Flash** \
Some SAMD21 chips have a seperate RWW flash area, of 2kB-8kB size. This area is seperate from the main flash array. \
Note: this method is implemented and tested.
2. **EEPROM emulation** \
All SAMD21s support EEPROM emulation, where an area of the main flash is reserved for the application storage. \
:warning: This method is not yet implemented fully, and untested.
## Using RWW flash
To use the RWW flash to store settings, you have to make sure the flash region is not locked (you can set the lock fuses using MCP Studio or other SAM development tools).
Otherwise there is nothing special to do. When reprogramming the chip, be careful not to erase the RWW area.
You can use multiple settings objects to store to different areas of the RWW.
To do so, specify an offset to the constructor:
```c++
SAMDNVMSettingsStorage settings0 = SAMDNVMSettingsStorage();
SAMDNVMSettingsStorage settings1 = SAMDNVMSettingsStorage(NVMCTRL_ROW_SIZE);
SAMDNVMSettingsStorage settings2 = SAMDNVMSettingsStorage(NVMCTRL_ROW_SIZE*2);
```
Note: the offset must be a multiple of the flash memory row size, typically 256 bytes.
## Using EEPROM emulation
TODO implement and test this method
To use the EEPROM emulation, use a tool like MCP Studio to set the chip fuses to reserve an area of flash for EEPROM emulation:
![](eeprom_emulation_screenshot.jpg)
Normally 256 bytes (one flash page) should be plenty for SimpleFOC settings... Obviously, the area you reserve for EEPROM can't be used for your main program.
Add a build-flag to your build to set the base address of your EEPROM memory:
`-DSIMPLEFOC_SAMDNVMSETTINGS_BASE=0x003FF800`
Then use the settings as normal.
You'll have to adjust your board files to exclude the EEPROM area in the ldscript to prevent it being erased when you re-program, if you care to keep your settings when reflashing.

View File

@@ -0,0 +1,164 @@
#include "./SAMDNVMSettingsStorage.h"
#if defined(_SAMD21_)
#include "communication/SimpleFOCDebug.h"
SAMDNVMSettingsStorage::SAMDNVMSettingsStorage(uint32_t offset) {
_offset = offset;
};
SAMDNVMSettingsStorage::~SAMDNVMSettingsStorage(){};
void SAMDNVMSettingsStorage::init(){
SettingsStorage::init();
reset();
};
void SAMDNVMSettingsStorage::reset(){
_currptr = (uint8_t*) SIMPLEFOC_SAMDNVMSETTINGS_BASE + _offset; // add offset to NVM base address
};
void SAMDNVMSettingsStorage::beforeLoad(){
reset();
};
void SAMDNVMSettingsStorage::beforeSave(){
reset();
_writeIndex = 0;
// set manual write mode
_ctlB = NVMCTRL->CTRLB.reg;
NVMCTRL->CTRLB.reg |= NVMCTRL_CTRLB_MANW;
while (NVMCTRL->INTFLAG.bit.READY == 0) {};
// unlock region - user can do it with fuses
// erase rows
// TODO handle case that it is more than one row
NVMCTRL->ADDR.reg = ((uint32_t)_currptr - RWWEE_BASE) / 2;
NVMCTRL->STATUS.reg |= NVMCTRL_STATUS_MASK;
NVMCTRL->INTFLAG.bit.ERROR = 0;
NVMCTRL->CTRLA.reg = 0x1A | NVMCTRL_CTRLA_CMDEX_KEY;
delay(1);
while (NVMCTRL->INTFLAG.bit.READY == 0) {};
if (NVMCTRL->INTFLAG.bit.ERROR == 1)
SimpleFOCDebug::println("NVM erase error ", NVMCTRL->STATUS.reg);
else
SimpleFOCDebug::println("NVM erased row @", (int)_currptr);
};
void SAMDNVMSettingsStorage::afterSave() {
if (_writeIndex>0)
flushPage();
// restore ctlb
delay(1);
NVMCTRL->CTRLB.reg =_ctlB;
while (NVMCTRL->INTFLAG.bit.READY == 0) {};
}
void SAMDNVMSettingsStorage::flushPage(){
// if we have an odd number of bytes, pad with 0xFF
if (_writeIndex%2==1) {
_writeBuffer[_writeIndex++] = 0xFF;
}
// erase page buffer
// NVMCTRL->ADDR.reg = ((uint32_t)_currptr - RWWEE_BASE) / 2;
// NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMD_PBC | NVMCTRL_CTRLA_CMDEX_KEY;
// while (NVMCTRL->INTFLAG.bit.READY == 0) {};
// copy writeBuffer to NVM, using 16-bit writes
uint16_t* src = (uint16_t*)_writeBuffer;
uint16_t* dst = (uint16_t*)_currptr;
for (int i=0;i<_writeIndex/2;i++) {
*dst++ = *src++;
}
// write page
NVMCTRL->ADDR.reg = ((uint32_t)_currptr - RWWEE_BASE) / 2;
NVMCTRL->STATUS.reg |= NVMCTRL_STATUS_MASK;
NVMCTRL->INTFLAG.bit.ERROR = 0;
NVMCTRL->CTRLA.reg = 0x1C | NVMCTRL_CTRLA_CMDEX_KEY;
delay(1);
while (NVMCTRL->INTFLAG.bit.READY == 0) {};
if (NVMCTRL->INTFLAG.bit.ERROR == 1)
SimpleFOCDebug::println("NVM write error ", NVMCTRL->STATUS.reg);
else
SimpleFOCDebug::println("NVM wrote page @", (int)_currptr);
// reset writeBuffer pointer and advance currptr to next page
_writeIndex = 0;
_currptr+=NVMCTRL_PAGE_SIZE;
}
int SAMDNVMSettingsStorage::readBytes(void* valueToSet, int numBytes) {
uint8_t* bytes = (uint8_t*)valueToSet;
for (int i=0;i<numBytes;i++) {
uint8_t val = *_currptr++;
bytes[i] = val;
}
return numBytes;
}
int SAMDNVMSettingsStorage::writeBytes(void* value, int numBytes) {
uint8_t* bytes = (uint8_t*)value;
for (int i=0;i<numBytes;i++) {
_writeBuffer[_writeIndex] = *bytes++;
_writeIndex++;
if (_writeIndex==NVMCTRL_PAGE_SIZE)
flushPage();
}
return numBytes;
}
uint8_t SAMDNVMSettingsStorage::readByte(uint8_t* valueToSet){
uint8_t val;
uint8_t num = readBytes(&val, 1);
if (num==1)
*valueToSet = val;
return num;
};
uint8_t SAMDNVMSettingsStorage::readFloat(float* valueToSet){
float val;
uint8_t num = readBytes(&val, 4);
if (num==4)
*valueToSet = val;
return num;
};
uint8_t SAMDNVMSettingsStorage::readInt(uint32_t* valueToSet){
uint32_t val;
uint8_t num = readBytes(&val, 4);
if (num==4)
*valueToSet = val;
return num;
};
uint8_t SAMDNVMSettingsStorage::writeByte(uint8_t value){
return writeBytes(&value, 1);
};
uint8_t SAMDNVMSettingsStorage::writeFloat(float value){
return writeBytes(&value, 4);
};
uint8_t SAMDNVMSettingsStorage::writeInt(uint32_t value){
return writeBytes(&value, 4);
};
#endif

View File

@@ -0,0 +1,85 @@
#pragma once
/**
* SAMD can write to their onboard NVM (flash). This class implements the SettingsStorage interface
* for storing settings in NVM.
*
* There are two suggested strategies for using the NVM for storing settings:
*
* 1. On chips which have it, use the RWWEE (Read While Write EEPROM) section of the NVM. This is
* a small section of the NVM which can be written to while the rest of the NVM is being read.
* This is the default strategy used by this class. The size of the RWWEE section varies by chip,
* but is at least 2kB. It is seperate from the main flash memory, so doesn't reduce the amount
* of flash available for your program.
*
* 2. On chips which don't have a RWWEE section, you can configure a EEPROM section in the NVM. This
* will be at the end of the main NVM, and therefore reduces the flash available for your program.
*
* In either case, you must make sure your board definition file has the correct NVM settings to prevent
* the configuration from being overwritten by the Arduino IDE / your programmer.
*
* By default, this class will use the RWWEE section at address 0x00400000.
* To change it, use the build flag SIMPLEFOC_SAMDNVMSETTINGS_BASE to set the base address of your choice.
*
* You can pass an offset to the constructor of this class. This allows you to store multiple sets of
* settings in the NVM. The offset should be a multiple of the ROWSIZE (256 bytes).
*
* The memory rows (normally 1 row, but could be more if you save a *lot*) containing settings are always
* erased before writing. Don't store other data within the same memory rows.
*
* Don't save to NVM unnecessarily. It has a limited number of write cycles, and writing takes time.
*
*
*
*/
#include <Arduino.h>
#if defined(_SAMD21_)
#include "../SettingsStorage.h"
#define RWWEE_BASE 0x00400000
#if !defined(SIMPLEFOC_SAMDNVMSETTINGS_BASE)
#define SIMPLEFOC_SAMDNVMSETTINGS_BASE RWWEE_BASE
#endif
class SAMDNVMSettingsStorage : public SettingsStorage {
public:
SAMDNVMSettingsStorage(uint32_t offset = 0x0);
~SAMDNVMSettingsStorage();
void init() override;
protected:
uint8_t readByte(uint8_t* valueToSet) override;
uint8_t readFloat(float* valueToSet) override;
uint8_t readInt(uint32_t* valueToSet) override;
uint8_t writeByte(uint8_t value) override;
uint8_t writeFloat(float value) override;
uint8_t writeInt(uint32_t value) override;
void beforeSave() override;
void afterSave() override;
void beforeLoad() override;
void reset();
int readBytes(void* valueToSet, int numBytes);
int writeBytes(void* value, int numBytes);
void flushPage();
uint32_t _offset; // offset into NVRAM to store settings
uint32_t _ctlB;
uint8_t* _currptr; // pointer to current location in NVM
int _writeIndex; // index into current page being written
uint8_t _writeBuffer[NVMCTRL_PAGE_SIZE]; // buffer for writing to NVM
};
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB