seeed studio xiao nrf52840 eeprom

Hello, my problem is, I could not succeed in seeinged studio xiao nrf52840 eeprom memory writing, reading and writing EEEPROM. Isn’t there a library for this? Can you help me with this?

Hi there,
The Nrf52 series has FLASH memory not EEprom. There are several examples for this, Do you want a file system, a USB drive emulation or just read and write memory locations?, Also the RTC has some NV registers too.
HTH
GL :slight_smile: PJ

Are you able to post a link to these examples? It might be able to provide more insight into my issue here.

Thank you in advance!

You can found some basic code there (I tested it and it works fine).

//
// XIAO Acces to the on board QSPI Memrory
//
// Author: fbd38
// Release: 1.0.0
// Date: 17/11/2023
//
// Basic routines using a “MagicNumber” to check the block validity.
// each configuration uses a single 4KByte block memory (not optimal for size)
//
// !! warning !!: size must of write be a multiple of 4
//
// QSPI Pin assignation as per the XIAO Seeed nRF52840 (sense) Module
static nrfx_qspi_config_t QSPI_mem_config = NRFX_QSPI_DEFAULT_CONFIG(21, 25, 20, 24, 22, 23);
static const uint32_t magicValue = 0xCAFE3501;

bool QSPI_mem_connect() {
return (nrfx_qspi_init(&QSPI_mem_config, NULL, NULL) == NRFX_SUCCESS);
}

void QSPI_mem_disconnect() {
nrfx_qspi_uninit();
}

// bool QSPI_mem_ready() {
// return (nrfx_qspi_mem_busy_check() == NRFX_SUCCESS);
// }

// bool QSPI_mem_wait_ready() {
// while (!QSPI_mem_ready()) {
// /* Wait */
// }
// return (true);
// }

bool QSPI_mem_erase_all() {
return (nrfx_qspi_chip_erase() == NRFX_SUCCESS);
}

bool QSPI_mem_erase_4KB(uint32_t QSPI_addr) {
return (nrfx_qspi_erase(NRF_QSPI_ERASE_LEN_4KB, QSPI_addr) == NRFX_SUCCESS);
}

// bool QSPI_mem_erase_64KB(uint32_t QSPI_addr) {
// return (nrfx_qspi_erase(NRF_QSPI_ERASE_LEN_64KB, QSPI_addr) == NRFX_SUCCESS);
// }

bool QSPI_mem_read(uint32_t QSPI_addr, void *p_buffer, size_t byte_size) {
return (nrfx_qspi_read(p_buffer, byte_size, QSPI_addr) == NRFX_SUCCESS);
}

bool QSPI_mem_write(uint32_t QSPI_addr, void const *p_buffer, size_t byte_size) {
return (nrfx_qspi_write(p_buffer, byte_size, QSPI_addr) == NRFX_SUCCESS);
}

bool QSPI_mem_writeConfig(int16_t numBlock4K, void current, size_t bsize) {
uint32_t magicNumber = magicValue;
/
Compute Addresses /
uint32_t qaddr = numBlock4K * 4096;
uint32_t daddr = qaddr + sizeof(magicNumber);
/
first erase the 4K block /
if (QSPI_mem_erase_4KB(qaddr)) {
/
then write the data /
if (QSPI_mem_write(daddr, current, bsize)) {
/
then the magic number /
return (QSPI_mem_write(qaddr, &magicNumber, sizeof(magicNumber)));
}
}
/
in all other cases */
Serial.println("[ERR] QSP Memory write config");
return (false);
}

// Basic routine to read the configuration
bool QSPI_mem_readConfig(int16_t numBlock4K, void *current, void factory, size_t bsize) {
memcpy(current, factory, bsize); // in case of current an memory get corrupted
if (bsize > 4000) return (false);
uint32_t magicNumber;
uint32_t qaddr = numBlock4K * 4096;
uint32_t daddr = qaddr + sizeof(magicNumber);
/
Read magic number /
if (QSPI_mem_read(qaddr, &magicNumber, sizeof(magicNumber))) {
/
Test value of magicNumber /
if (magicNumber == magicValue) {
/
Already correct, so reload the value /
return (QSPI_mem_read(daddr, current, bsize));
} else {
/
need to write the factory values /
return (QSPI_mem_writeConfig(numBlock4K, factory, bsize));
}
}
/
in all other cases */
Serial.println("[ERR] QSPI Memory read config");
return (false);
}

void QSPI_mem_dump(int16_t numBlock4K, int16_t line) {
static char qval[4096];
char str[128], st[16];
uint32_t qaddr = numBlock4K * 4096;
// Serial.println(“QSPI_mem_dump”);
QSPI_mem_connect();
QSPI_mem_read(qaddr, &qval, sizeof(qval));
QSPI_mem_disconnect();
// print values
for (int16_t ii = 0; ii < line; ii++) {
// Display in HEX
sprintf(str, "[%06X] ", qaddr + ii * 8);
for (int16_t iii = 0; iii < 8; iii++) {
sprintf(st, “%02X “, qval[ii * 8 + iii]);
strcat(str, st);
}
// Display as char
strcat(str, " [”);
for (int16_t iii = 0; iii < 8; iii++) {
char q = qval[ii * 8 + iii];
int16_t iq = (int16_t)q;
q = (iq >= 32) && (iq <= 126)
? q
: ‘.’;
sprintf(st, “%c”, q);
strcat(str, st);
}
strcat(str, “]”);
// Display as int16_t
strcat(str, " (”);
for (int16_t iii = 0; iii < 8; iii++) {
int16_t iv;
if ((iii % 2) == 1) {
iv = (((int16_t)qval[ii * 8 + iii - 1]) & 0x00FF) | (((int16_t)qval[ii * 8 + iii]) << 8);
sprintf(st, "%6d, ", iv);
strcat(str, st);
}
}
strcat(str, “)”);
Serial.println(str);
}
}

Yes, you are right, I realized that there is no EEPROM, I want to write and read data to the flash memory.

A couple questions

  • What are you needing to write to the flash (config file, data, etc)?
  • Are you writing to the on chip 1MB flash or the onboard 2MB flash?

I ask because I feel we may be trying to do similar things. I’m trying to write a config file to the external 2MB flash chip


@PJ_Glasso had a very helpful response in my thread below on getting started with writing to the external flash.



Here’s some adapted code sourced from the post below (one that he linked me)

Code:

// Author: cam
#include <Arduino.h>
#include <SPI.h>
#include <Wire.h>
#include <SdFat.h>
#include <Adafruit_SPIFlash.h>
#include <LSM6DS3.h>

// Flash Chip declerations, made up from Data Sheets.
// https://files.seeedstudio.com/wiki/github_weiruanexample/Flash_P25Q16H-UXH-IR_Datasheet.pdf
SPIFlash_Device_t const p25q16h{
.total_size = (1UL << 21), // 2MiB
.start_up_time_us = 10000,
.manufacturer_id = 0x85,
.memory_type = 0x60,
.capacity = 0x15,
.max_clock_speed_mhz = 55,
.quad_enable_bit_mask = 0x02,
.has_sector_protection = 1,
.supports_fast_read = 1,
.supports_qspi = 1,
.supports_qspi_writes = 1,
.write_status_register_split = 1,
.single_status_byte = 0,
.is_fram = 0,
};

//Create a instance of class LSM6DS3
LSM6DS3 myIMU(I2C_MODE, 0x6A);
#define int2Pin PIN_LSM6DS3TR_C_INT1

#define SS_SPI1 25 // Defaul SS or CS for the Onboard QSPI Flash Chip

SPIClass SPI_2(NRF_SPIM0, PIN_QSPI_IO1, PIN_QSPI_SCK, PIN_QSPI_IO0); // Onboard QSPI Flash chip
Adafruit_FlashTransport_SPI QflashTransport(PIN_QSPI_CS, SPI_2); // CS for QSPI Flash
Adafruit_SPIFlash Qflash(&QflashTransport);

void setup() {
Serial.begin(9600);
while (!Serial) {
delay(100); // waits for serial
}
Serial.println(“Starting up”);

if (!Qflash.begin(&p25q16h, 1)) {
Serial.println(F(“Error, failed to initialize QSPI flash chip!”));
while (1)
;
}
Serial.println(Qflash.getJEDECID(), HEX);

Serial.print(Qflash.size() / 1024);
Serial.println(F(" KB"));

Serial.println(Qflash.read8(0x000500));
Serial.print("page size ");
Serial.println(Qflash.pageSize());
Serial.print("num page ");
Serial.println(Qflash.numPages());
Serial.print("sector count ");
Serial.print(Qflash.sectorCount());
}

/*

0x1FF000:

read8
Starting up
856015
2048 KB
255

read16
Starting up
856015
2048 KB
65535

read32
Starting up
856015
2048 KB
4294967295

*/
void loop() {
}



Additionally, there are some ways to create a file system on the board using littlefs, but I haven’t gotten anything working yet as I need to find a solution that doesn’t use mbed os.

If there are any parallels between our projects let me know and we can look for a solution together!

I want to save and read 2 MB onboard Flash persistent data

I am sending the data via bluetooth. I want to save the data I send permanently in an onboard 2MB flash.

This might be able to help you.

Are you using the mbed board definitions?

Yes I am using the Mbed definition. I will look into your suggestion

Hi there,
Keep in mind the most power saving if on battery is definitely with the NON Mbed BSP’s , if that’s high on the checklist , then Bluefruit will be the BLE Lib. AFAIK.
HTH
GL :slight_smile: pj :v:

btw, The Adafruit_SPIFlash lib has some reading and writing examples, check those for some easy leg up stuff too :pinching_hand: