I found this sketch on GitHub. BLESenseFlash authored by tom@tjpetz.com.
It seems like it should accomplish what I have been trying to figure out for a while now but my programming knowledge is very limited and I do not want to render my Arduino Nano 33 BLE Sense useless if I make a big mistake.
#include <Arduino.h>
// 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)
// lets put some memory in a specific location. We'll put it in a specific section as we explore
// how the linker might manage it and move it about.
byte page1 [0x1000] __attribute__ ((section("FLASH"), aligned (0x1000)));
byte page2 [255] __attribute__ ((section("FLASH")));
byte page2a [255] __attribute__((section("FLASH")));
byte page3 [0x1000] __attribute__ ((section("FLASH"), aligned (0x1000)));
// From this experiment we learn that the variables must be const. And when const the linker will
// automatically put them in flash. This way we do not need to worry about the specific layout
// in memory as the linker will handle that automatically for us.
const int flash __attribute__ ((section("FLASH2"), aligned (0x1000))) = 100;
const uint32_t flash2 __attribute__ ((section("FLASH2"), aligned (0x1000))) = 0x09090909;
typedef struct flash_mem {
char ssid[64];
char pwd[64];
char devname[64];
} flash_mem_t;
const flash_mem_t myFlash __attribute__ ((section("FLASH2"), aligned (0x1000))) = {
"test", "secret", "fred"
};
// These are available for the linker and help us understand how memory is getting layed out.
extern "C" unsigned long __heap_start;
extern "C" unsigned long __heap_size;
extern "C" unsigned long __bss_start__;
extern "C" unsigned long __bss_end__;
extern "C" unsigned long FLASH; // While available this always ends up being zero, showing us that
// we can't get the link address location this way from the linker.
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
delay(2500);
pinMode(LED_BUILTIN, OUTPUT);
Serial.println("Starting...");
Serial.print("__heap_start: "); Serial.println(__heap_start, HEX);
Serial.print("__heap_size: "); Serial.println(__heap_size, HEX);
Serial.print("&page1: "); Serial.println((unsigned long)(&page1), HEX);
Serial.print("&page2: "); Serial.println((unsigned long)(&page2), HEX);
Serial.print("&page2a: "); Serial.println((unsigned long)(&page2a), HEX);
Serial.print("&page3: "); Serial.println((unsigned long)(&page3), HEX);
Serial.print("&flash: "); Serial.println((unsigned long)(&flash), HEX);
Serial.print("&myFlash: "); Serial.println((unsigned long)(&myFlash), HEX);
Serial.print("__bss_start__: "); Serial.println(__bss_start__, HEX);
Serial.print("__bss_end__: "); Serial.println(__bss_end__, HEX);
Serial.print("FLASH: "); Serial.println(FLASH, HEX);
Serial.flush();
Serial.print("NVMC READY: "); Serial.println(*(uint32_t *)(NVMC_READY), HEX);
Serial.print("NVMC READY NEXT: "); Serial.println(*(uint32_t *)(NVMC_READYNEXT), HEX);
hexDumpMemory((uint8_t *)(&flash2), 64);
hexDumpMemory((uint8_t *)(&myFlash), 256);
Serial.print("Config = "); Serial.println(*(int32_t *)(NVMC_CONFIG), HEX);
if (*(uint32_t *)NVMC_READY == 1) {
Serial.println("Flashing...");
// Write into myFlash
*(uint32_t *)NVMC_CONFIG = 0x01;
*(uint32_t *)(&myFlash) = 0x00;
while(*(uint32_t *)NVMC_READY == 0)
delayMicroseconds(50);
*(uint32_t *)NVMC_CONFIG = 0x00;
Serial.println("...Flashed");
} else {
Serial.println("... Flash Not Ready! ...");
}
hexDumpMemory((uint8_t *)(&myFlash), 256);
if(*(uint32_t *)NVMC_READY == 1) {
Serial.println("Erasing...");
*(uint32_t *)NVMC_CONFIG = 0x02;
*(uint32_t *)NVMC_ERASEPAGE = (uint32_t)(&myFlash);
while(*(uint32_t *)NVMC_READY == 0)
delay(85);
*(uint32_t *)NVMC_CONFIG = 0x00;
Serial.println("...Erased");
} else {
Serial.println("... Flash Not Ready to Erase! ...");
}
hexDumpMemory((uint8_t *)(&myFlash), 256);
hexDumpMemory((uint8_t *)(&flash2), 64);
}
void loop() {
// put your main code here, to run repeatedly:
digitalWrite(LED_BUILTIN, HIGH);
delay(250);
digitalWrite(LED_BUILTIN, LOW);
delay(750);
}
void hexDumpMemory(uint8_t *memStart, const unsigned int nbrOfBytes) {
/* hex dump memory to the serial interface starting at memStart for nbrOfBytes */
uint8_t *ptr;
int bytesPerLine = 15;
int bytesOnLine = 0;
ptr = memStart;
Serial.print("Memory dump of: "); Serial.println((unsigned long)(memStart), HEX);
for (unsigned int i = 0; i < nbrOfBytes; i++) {
if (bytesOnLine == 0) {
Serial.print((unsigned long)(ptr+i), HEX);
Serial.print(": ");
}
if (*(ptr+i) < 0x10) // print a leading 0
Serial.print("0");
Serial.print(*(ptr+i), HEX); Serial.print(" ");
if (bytesOnLine == bytesPerLine) {
Serial.println(" ");
bytesOnLine = 0;
} else {
bytesOnLine += 1;
}
}
Serial.println("");
}
I created a sketch that is used to move 2 stepper motors according to input by a user. There is a 2 row by 13 column array that contains default x & y coordinates (steps cw from home/zero). The user has the ability to modify the default coordinates if they wish. Currently, any modified coordinates are lost once the arduino is disconnected from the laptop. I was hoping to be able to use the code contained in the BLESenseFlash sketch within my sketch (or vice-versa) and use it to save any modified data contained in the coordinate array to flash memory. The user can start from where they left off, without having to modify the coordinates over and over. I believe this can be done but I have no idea how.
This is my sketch:
#include <AccelStepper.h>
const int SERIAL_BAUD_RATE = 9600;
const int HOME_SWITCH_X = 9;
const int HOME_SWITCH_Y = 10;
const int NUM_TARGETS = 13;
AccelStepper stepperX(1, 3, 2); // Sets up the pins for stepper X
AccelStepper stepperY(1, 5, 4); // Sets up the pins for stepper Y
long initialHomingX = -1; // Used to Home X Stepper at startup
long initialHomingY = -1; // Used to Home Y Stepper at startup
int targetCoordinatesX[NUM_TARGETS] = {120, 110, 100, 90, 80, 70, 60, 50, 40, 30, 20, 10, 0};
int targetCoordinatesY[NUM_TARGETS] = {30, 25, 20, 15, 12, 10, 8, 6, 4, 3, 2, 1, 0};
bool modified[NUM_TARGETS] = {false}; // Indicates whether each coordinate has been modified
void moveSteppersToTarget(int targetIndex);
void updateArrays(int columnIndex, int xValue, int yValue);
void printArrays();
void setupStepper(AccelStepper& stepper, long& initialHoming);
void setup() {
Serial.begin(SERIAL_BAUD_RATE);
pinMode(HOME_SWITCH_X, INPUT_PULLUP);
pinMode(HOME_SWITCH_Y, INPUT_PULLUP);
delay(5); // Wait for EasyDriver wake up
setupStepper(stepperX, initialHomingX);
setupStepper(stepperY, initialHomingY);
Serial.println("Homing Completed");
Serial.println("Select Target ");
}
void loop() {
int targetIndex = -1;
if (Serial.available() > 0) {
char command = Serial.read();
if (command == 'k') {
Serial.println("Modifying Coordinates");
printArrays();
Serial.println("Enter the changes in the format 'index=x,y'.");
while (!Serial.available()) {
// Wait for user input
}
char input[50];
Serial.readBytesUntil('\n', input, sizeof(input));
input[sizeof(input) - 1] = '\0';
if (validateInput(input)) {
int columnIndex, xValue, yValue;
sscanf(input, "%d=%d,%d", &columnIndex, &xValue, &yValue);
if (columnIndex >= 0 && columnIndex < NUM_TARGETS) {
updateArrays(columnIndex, xValue, yValue);
printArrays();
// Call moveSteppersToTarget after updating the arrays
moveSteppersToTarget(columnIndex);
} else {
Serial.println("Invalid column index. Please enter a valid index.");
}
} else {
Serial.println("Invalid input format. Please enter in the format 'index=x,y'.");
}
} else if (command >= '1' && command <= '9') {
targetIndex = command - '1';
if (Serial.available() > 0) {
char secondDigit = Serial.read();
if (secondDigit >= '0' && secondDigit <= '9') {
targetIndex = targetIndex + 9 + (secondDigit - '0');
}
}
moveSteppersToTarget(targetIndex);
}
}
stepperX.run();
stepperY.run();
}
void moveSteppersToTarget(int targetIndex) {
if (targetIndex >= 0 && targetIndex < NUM_TARGETS) {
Serial.print("Moving to Target ");
Serial.println(targetIndex + 1);
stepperX.moveTo(0);
stepperY.moveTo(0);
while (stepperX.distanceToGo() != 0 || stepperY.distanceToGo() != 0) {
stepperX.run();
stepperY.run();
}
int xToMove = modified[targetIndex] ? targetCoordinatesX[targetIndex] : targetCoordinatesX[targetIndex];
int yToMove = modified[targetIndex] ? targetCoordinatesY[targetIndex] : targetCoordinatesY[targetIndex];
stepperX.moveTo(xToMove);
stepperY.moveTo(yToMove);
modified[targetIndex] = false; // Reset modified flag after moving
}
}
void updateArrays(int columnIndex, int xValue, int yValue) {
targetCoordinatesX[columnIndex] = xValue;
targetCoordinatesY[columnIndex] = yValue;
modified[columnIndex] = true; // Mark the coordinate as modified
}
void printArrays() {
Serial.println("Updated Arrays:");
for (int i = 0; i < NUM_TARGETS; i++) {
Serial.print("X[" + String(i) + "]: " + String(targetCoordinatesX[i]) + "\t");
Serial.print("Y[" + String(i) + "]: " + String(targetCoordinatesY[i]) + "\t");
Serial.println("Modified: " + String(modified[i]));
}
Serial.println();
}
void setupStepper(AccelStepper& stepper, long& initialHoming) {
stepper.setMaxSpeed(100.0);
stepper.setAcceleration(100.0);
Serial.print("Stepper is Homing . . . . . . . . . . . ");
for (; digitalRead(HOME_SWITCH_X); initialHoming--) {
stepper.moveTo(initialHoming);
stepper.run();
delay(5);
}
stepper.setCurrentPosition(0);
initialHoming = 1;
while (!digitalRead(HOME_SWITCH_X)) {
stepper.moveTo(initialHoming);
stepper.run();
initialHoming++;
delay(5);
}
stepper.setCurrentPosition(0);
Serial.println("Homing Completed");
Serial.println("");
stepper.setMaxSpeed(100.0);
stepper.setAcceleration(100.0);
}
bool validateInput(char* input) {
return strchr(input, '=') != NULL && strchr(input, ',') != NULL;
}
If someone can help me out, it would be greatly appraciated.