0

Saving Data in Flash
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Saving Data in Flash

by pkonigsberg on Tue Mar 16, 2021 11:52 pm

I have a feather M0 with Wifi and there is no EEPROM but there is 256KB FLASH, 32KB SRAM. I would like a user to be able to connect to the feather via Wifi AP (access point), enter the wifi network name and password, have the feather store the wifi network name and password, and then be able to run a sketch that reads that data to connect to the wifi. (I can code my network info into my sketch, but that won't work when someone else wants to use the device somewhere else.)
I looked at this page:
https://learn.adafruit.com/how-to-fuse- ... -pre-check
to see if I could use the flash memory but when I ran the sensor_calibration_read example I got "Failed to initialize calibration helper".
Am I going down the right path on how to store values on the device or is there a better way?
Thank you.

pkonigsberg
 
Posts: 41
Joined: Wed Apr 11, 2018 1:35 pm

Re: Saving Data in Flash

by adafruit_support_mike on Wed Mar 17, 2021 9:53 pm

The SAMD architecture allows you to read and write the Flash array from normal code, so you can use that instead of EEPROM. We usually suggest the FlashStorage library for that:

https://github.com/cmaglie/FlashStorage

The tutorial page you linked uses the external QSPI Flash chip on our Express boards, and uses our Adafruit_SPIFlash library:

https://github.com/adafruit/Adafruit_SPIFlash

Either option will work.

adafruit_support_mike
 
Posts: 63728
Joined: Thu Feb 11, 2010 2:51 pm

Re: Saving Data in Flash

by pkonigsberg on Thu Mar 18, 2021 3:50 pm

Hi thank you for the link to the Github library. That library appeared to only save uint8 and uint16 data types and I need to save Strings or char[] arrays for wifi credentials. So I found an example for Flash Storage of a struct of char[] here:
https://github.com/cmaglie/FlashStorage ... urname.ino

My problem when I tried to implement this is that I keep reading false for the bool and blank or empty data for my char[] after writing to them (multiple times.) Here is the output I get:

Reading wifi credentials from Flash.
Here are the credentials I read:
0


Writing wifi to flash.
1
***************
*****************
Attempting to connect to SSID: ******************
Connected to wifi
SSID: ***************
IP Address: ********************
signal strength (RSSI):-48 dBm
Found SHT4x sensor
Serial number 0x1044FF87
Temp format: F
High precision
No heater

And that comes from this code:
Code: Select all | TOGGLE FULL SIZE
#include "Adafruit_SHT4x.h"
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
#include <Fonts/FreeSerif9pt7b.h>
#include <WiFi101.h>
//#include <FlashAsEEPROM.h>
#include <FlashStorage.h>

typedef struct {
  boolean valid;
  char ssid[100];
  char pass[100];
} WifiCredentials;

FlashStorage(stored_wifi_credentials, WifiCredentials);
WifiCredentials my_wifi_credentials;

char ssid[] = "********";        // your network SSID (name)
char pass[] = "********************";    // your network password (use for WPA, or use as key for WEP)
String ssid_str = "******************";
String pass_str = "*********************";

int keyIndex = 0;            // your network key Index number (needed only for WEP)
int status = WL_IDLE_STATUS;
char server[] = "***********.com";
WiFiClient client;

Adafruit_SHT4x sht4 = Adafruit_SHT4x();
Adafruit_SH110X display = Adafruit_SH110X(64, 128, &Wire);

// Max temp for Fahrenheit.
#define MAX_TEMP_F 73.0
#define alert_Time_Interval_In_Minutes 2

// Variable to track alert.
bool never_Sent_Alert = true;
uint64_t begin_Time = millis();

// These are buttons on the OLED board.
#define BUTTON_A  9
#define BUTTON_B  6
#define BUTTON_C  5

char temp_format = 'F';

void setup() {
  //Configure pins for Adafruit ATWINC1500 Feather
  WiFi.setPins(8,7,4,2);

  Serial.begin(115200);

  int waitcnt = 0;   // wait two seconds
  while (!Serial && (waitcnt++ < 20))  // wait (only so long).
    delay(100);
   
  Serial.println("Reading wifi credentials from Flash.");
  // Read the wifi credentials from Flash memory.
  my_wifi_credentials = stored_wifi_credentials.read();
  Serial.println("Here are the credentials I read:");
  Serial.println(my_wifi_credentials.valid);
  Serial.println(my_wifi_credentials.ssid);
  Serial.println(my_wifi_credentials.pass);
  if (my_wifi_credentials.valid == false) {
    // Get and store the credentials. 
    Serial.println("Writing wifi to flash.");
    ssid_str.toCharArray(my_wifi_credentials.ssid, 100);
    pass_str.toCharArray(my_wifi_credentials.pass, 100);
    my_wifi_credentials.valid = true;
    Serial.println(my_wifi_credentials.valid);
    Serial.println(my_wifi_credentials.ssid);
    Serial.println(my_wifi_credentials.pass);
    stored_wifi_credentials.write(my_wifi_credentials);
  }
  display.begin(0x3C, true); // Address 0x3C default

  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  } 
  // attempt to connect to WiFi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    //status = WiFi.begin(ssid, pass);
    status = WiFi.begin(my_wifi_credentials.ssid, my_wifi_credentials.pass);

    // wait 10 seconds for connection:
    delay(10000);
  }
  Serial.println("Connected to wifi");
  printWiFiStatus();
 
  // Clear the buffer.
  display.clearDisplay();
  display.display();
  display.setRotation(1);
 
  pinMode(BUTTON_A, INPUT_PULLUP);
  pinMode(BUTTON_B, INPUT_PULLUP);
  pinMode(BUTTON_C, INPUT_PULLUP);
 
  if (! sht4.begin()) {
    Serial.println("Couldn't find SHT4x");
    while (1) delay(1);
  }
  display.setTextSize(1);
  display.setFont();
  display.setTextColor(SH110X_WHITE);
  display.setCursor(0,20);
  display.println("");
  display.println("        Hello!");
  display.display(); // actually display all of the above
  delay(2000);
  display.clearDisplay();
  display.setCursor(0,20);
  display.println(" Sensing temperature");
  display.println("");
  display.println("    & humidity...");
  display.display(); // actually display all of the above
  delay(1500);  // Let the user read the welcome message.
  display.setFont(&FreeSerif9pt7b);
  Serial.println("Found SHT4x sensor");
  Serial.print("Serial number 0x");
  Serial.println(sht4.readSerial(), HEX);
  Serial.print("Temp format: ");Serial.println(temp_format);

  // You can have 3 different precisions, higher precision takes longer
  sht4.setPrecision(SHT4X_HIGH_PRECISION);
  switch (sht4.getPrecision()) {
     case SHT4X_HIGH_PRECISION:
       Serial.println("High precision");
       break;
     case SHT4X_MED_PRECISION:
       Serial.println("Med precision");
       break;
     case SHT4X_LOW_PRECISION:
       Serial.println("Low precision");
       break;
  }

  // You can have 6 different heater settings
  // higher heat and longer times uses more power
  // and reads will take longer too!
  sht4.setHeater(SHT4X_NO_HEATER);
  switch (sht4.getHeater()) {
     case SHT4X_NO_HEATER:
       Serial.println("No heater");
       break;
     case SHT4X_HIGH_HEATER_1S:
       Serial.println("High heat for 1 second");
       break;
     case SHT4X_HIGH_HEATER_100MS:
       Serial.println("High heat for 0.1 second");
       break;
     case SHT4X_MED_HEATER_1S:
       Serial.println("Medium heat for 1 second");
       break;
     case SHT4X_MED_HEATER_100MS:
       Serial.println("Medium heat for 0.1 second");
       break;
     case SHT4X_LOW_HEATER_1S:
       Serial.println("Low heat for 1 second");
       break;
     case SHT4X_LOW_HEATER_100MS:
       Serial.println("Low heat for 0.1 second");
       break;
  }
 
}

pkonigsberg
 
Posts: 41
Joined: Wed Apr 11, 2018 1:35 pm

Re: Saving Data in Flash

by adafruit_support_mike on Thu Mar 18, 2021 4:12 pm

For the sake of testing, switch over to a toy sketch that just reads and writes stuff to memory.

To handle arbitrary data types, put everything in a data structure and create an array of bytes the same size.. we generally use sizeof(structure) to guarantee a match.

Then use memcpy() to flatten the data (copy the data structure to the byte array) or inflate it (copy the byte array to the data structure). Technically that’s abuse of the type system because it assumes a specific relationship between a variable and the binary representation of its value, but it works reliably when the same device is doing the conversions both directions.

adafruit_support_mike
 
Posts: 63728
Joined: Thu Feb 11, 2010 2:51 pm

Re: Saving Data in Flash

by pkonigsberg on Thu Mar 18, 2021 9:49 pm

A toy sketch was definitely a good suggestion. Thank you. My code was fine. The problem was that in my testing, I was uploading the sketch to see if the read would work. You can't do that. I think each sketch upload wipes the flash memory that I wrote to. Instead, you need to hit the reset button to run the sketch again and the read worked fine.

pkonigsberg
 
Posts: 41
Joined: Wed Apr 11, 2018 1:35 pm

Re: Saving Data in Flash

by adafruit_support_mike on Sat Mar 20, 2021 8:15 pm

Glad to hear you got it working. Happy hacking!

adafruit_support_mike
 
Posts: 63728
Joined: Thu Feb 11, 2010 2:51 pm

Re: Saving Data in Flash

by RuntimeException on Thu Sep 16, 2021 2:47 pm

Hi folks,

I'm using an Adafruit Feather M0 with WINC1500. Similar to OP I want the Feather to emit an access point where I can navigate to an IP via my phone and enter WiFi credentials which would then be saved into Flash storage.

I'm having some difficulties in the execution. Initially, I tried to use a library meant to do this exact thing https://github.com/khoih-prog/WiFiManager_Generic_Lite. But it doesn't seem to work on the Feather M0 and there are Issues raised on the repo from another user with the similar experience.

I am trying to adapt the AP_SimpleWebServer example but cannot figure out how to get html user input data back into a variable.

pkonigsberg: Did you reach a solution for your original sketch? I would greatly appreciate any help.

RuntimeException
 
Posts: 1
Joined: Thu Sep 16, 2021 2:42 pm

Please be positive and constructive with your questions and comments.