Page 1 of 2

eeprom in flash memory for STM32F401

Posted: Wed Nov 03, 2021 3:14 pm
by picclock
I'm trying to get this to work, but there does not seem to be a library which is compatible (FlashStorage_STM32F1 will not work with 32F401).
I need about 100 bytes or so of EEProm memory, or flash memory which can be written to under program control. 401 has 256k which seems to be in a large chunk. The data sheet indicates erases can be as small as 8 to 32bits, or in blocks starting at 16k.

Can anyone point me in the direction of an eeprom library and/or example of this ?.


Best Regards

picclock

Re: eeprom in flash memory for STM32F401

Posted: Wed Nov 03, 2021 7:51 pm
by GonzoG
No. Those "x8/16/32" does not mean bits that you can erase. It's operation size.
It can be erased only by full sectors and those are 16kiB, 64kiB or 128kiB and because of this, you need at least twice as much flash memory as you need virtual EEPROM.

Also flash memory life is very limited. ST says that it's 10k erase cycles, so if your program need to often change data in EEPROM it will destroy flash really fast.

I would look at EEPROM chips. They are quite cheap, about $2 for 128kiB (1Mbit).

Re: eeprom in flash memory for STM32F401

Posted: Thu Nov 04, 2021 8:01 am
by picclock
@GonzoG
Thanks for the clarification, the datasheet was a bit ambiguous about that ( at least to me ).
I can live with a 16k block, and 10k erase write cycles is plenty for my purpose.

So any info on how to implement this much appreciated ;)

Best Regards

picclock

Re: eeprom in flash memory for STM32F401

Posted: Thu Nov 04, 2021 9:25 am
by ag123
first you need to keep the ref manual handy
https://www.st.com/resource/en/referenc ... ronics.pdf

note here is that for flash, you need to pretty much erase a 'sector' it can be pretty big especially the higher block of flash memory like 64k or 128k.
Another note here is for flash, the bits are set to 1 in the erased state. Programming it changes it to zero.
So you could devise a scheme that does erase once and write to successive chunks for your data.

A code that works for libmaple (roger's / steve's) f4 core looks like this.
For STM core, find in the header files for the appropriate register references in the includes and change them accordingly.
Review the relevant sections in the ref manual for the details.

Code: Select all

#include <Arduino.h>
#include <flash.h>

void sleep(uint16_t msecs);
void doread();
void dowrite();
void doerase();

#define SECT5 0x08020000UL

#define BUFSIZE 512
uint8_t buf[BUFSIZE];
bool basc = false;

void setup() {
	Serial.begin();
	pinMode(LED_BUILTIN, OUTPUT);
	memset(buf,' ',BUFSIZE);
	basc = true;
}

uint8_t nl = 0;

void loop() {
	if (nl > 5) {
		toggleLED();
		nl = 0;
	} else
		nl++;
	if(Serial.available()) {
		uint8_t c = Serial.read();
		switch(c) {
		case 'r':
			doread();
			break;
		case 'W':
			dowrite();
			break;
		case 'E':
			doerase();
			break;
		default:
			break;
		}
	}
	sleep(200);
}


void doread() {
	//Serial.write(buf,BUFSIZE);
	Serial.write((const uint8 *)SECT5,BUFSIZE);
	Serial.write('\n');
}

void dowrite() {
	uint8_t c = ' ';

	// this fills the buffer first with space ' ' and write them to flash
	// when you call this again, it fills the buffer with ascii printable characters
	// this is so that you can verify that flash and erase works in successive attempts
	// e.g. from serial monitor enter 'E' erase
	// then 'W' write
	// next 'r' read the data and print it in the serial monitor - all blanks
	// 'E' erase again
	// 'W' write again
	// 'r' read again - a block of printable ascii characters shows in the serial monitor
	if(basc) {
		for(uint16_t i=0; i<BUFSIZE; i++) {
			buf[i] = c++;
			if(c > 126)
				c = ' ';
		}
		basc = false;
	} else {
		memset(buf,' ',BUFSIZE);
		basc = true;
	}

	if (FLASH->CR & FLASH_CR_LOCK) {
		Serial.println("Unlock flash...");
		while(FLASH->SR & FLASH_SR_BSY);
		FLASH->KEYR = 0x45670123UL;
		delay(1);
		FLASH->KEYR = 0xCDEF89ABUL;
		while(FLASH->SR & FLASH_SR_BSY);
		while(FLASH->CR & FLASH_CR_LOCK);
	}
	Serial.println("Write data...");
	FLASH->CR |= FLASH_CR_PG;
	for(uint16_t i=0;i<BUFSIZE;i++) {
		while(FLASH->SR & FLASH_SR_BSY);
		*((uint8 *)SECT5+i) = buf[i];
		Serial.write('.');
	}
	Serial.println();
	Serial.println("Write complete");
	FLASH->CR &= ~FLASH_CR_PG;

}

void doerase() {
	// unlock flash
	if (FLASH->CR & FLASH_CR_LOCK) {
		Serial.println("Unlock flash...");
		while(FLASH->SR & FLASH_SR_BSY);
		FLASH->KEYR = 0x45670123UL;
		delay(1);
		FLASH->KEYR = 0xCDEF89ABUL;
		while(FLASH->SR & FLASH_SR_BSY);
		while(FLASH->CR & FLASH_CR_LOCK);
	}
	Serial.println("Erase flash...");
	uint32_t reg = FLASH->CR;
	//sector 5
	reg |= 5U << FLASH_CR_SNB_Pos;
	reg |= FLASH_CR_SER;
	reg |= FLASH_CR_STRT;
	FLASH->CR = reg;
	while(FLASH->SR & FLASH_SR_BSY);
	Serial.println("Erase complete");
}


void sleep(uint16_t msecs) {
	for(uint16_t i=0; i<=msecs; i++)
		asm("wfi");
}

Re: eeprom in flash memory for STM32F401

Posted: Thu Nov 04, 2021 10:30 am
by fpiSTM
Try the builtin EEPROM library

Re: eeprom in flash memory for STM32F401

Posted: Thu Nov 04, 2021 12:32 pm
by picclock
fpiSTM wrote: Thu Nov 04, 2021 10:30 am Try the builtin EEPROM library
I thought I was onto a winner when EEProm.size reported 16384, but trying to write or put anything crashes the code. Can read lots of ff's though :?

Will try ag123 solution.

Many Thanks

picclock

Re: eeprom in flash memory for STM32F401

Posted: Sat Nov 06, 2021 6:35 am
by picclock
@ag123 This solution resulted in an unrecognised F401, which I recovered using STLINK V2 and releasing the reset whilst pressing connect on the Cube programmer.

Reading more info I have discovered that this chip has 2k of battery backed up RAM. This seems like a simpler approach and requires only a supercapacitor and diode. It also removes any write limitations and the pin has no other uses.

Hopefully this will resolve my storage issues.

Best Regards

picclock

Re: eeprom in flash memory for STM32F401

Posted: Sat Nov 06, 2021 6:45 am
by ag123
Those are backup registers. Note that it seemed backup sram is not available for stm32f401, u'd need to check that in the manual.
That is probably a better approach, to use that use a coin cell and power up VBAT. This keeps your RTC running while VDD is not connected as well.

I'd suggest to use the RTC library from STM core as well.
https://github.com/stm32duino/STM32RTC

That would initialize the RTC for you and can then update additional registers to use the backup registers.
The backup registers has similar requirements as using flash, you need to 'unlock' the backup registers prior to writing to it.
Check in the ref manual about it.
The differences from flash is that that is sram, so the contents is lost if VBAT power is lost. And that it doesn't need to be erased.

For backup registers, there is a PR for libmaple F4 that isn't (yet) committed.
https://github.com/rogerclarkmelbourne/ ... 2/pull/850

The updates (for libmaple F4) are attached here. For backup registers, there are some dependencies on RTC, i.e. RTC needs to be initialized first.
I've not tried these codes out for STM core, It would likely need some fixes, but I've attached it here, just in case it helps.

Re: eeprom in flash memory for STM32F401

Posted: Sat Nov 06, 2021 7:55 am
by fpiSTM

Re: eeprom in flash memory for STM32F401

Posted: Sat Nov 06, 2021 10:25 am
by picclock
@ag123
Thanks for the info. I had realised after further reading that I can only access the 80bytes (20 words) of the rtc area. 80 bytes is pushing it for my storage needs but I think its possible with a bit of careful programming (fudging ;) ), converting the 32 bit words to 8/16 bit integers and using 1 bit flags where possible.

The vbat current is low and I think I can turn off the clock to reduce it further, so a super capacitor or 2032 battery are good options. The battery is simpler and will last well over 10 years so I'll probably opt for that.

Not sure why its necessary to initialise rtc for ram access but it seems that most examples do so.

Thanks again for the info.

Best Regards

picclock