9 years, 4 months ago.

NUCLEO-F401RE writing to flash from program?

I had this simple class for reading/writing to flash. It worked fine until the program grew. Now it overwrites the program in flash, crashing the whole thing. Is there any way I can access bank number 2? The NUCLEO-F401RE has 512KB flash, so there should be plenty of space. I could also leave 'a hole' in my program (with a magic marker at the beginning), in case the whole flash will always be overwritten eventually. Btw., FLASH_SECTOR_5 doesn't seem to be working either. I didn't find much on accessing flash. Therefore, this was the best I could come up with:

persiststor.h

class PersistentStorage {
public:
	static const int StorageSize = 64;
	static unsigned int storage[ StorageSize ] __attribute__((aligned(32)));

	enum StorageOffsets { RandomSeed = 0 };

	static void readStorageFromFlash();
	static bool writeStorageToFlash();

	static inline unsigned int get( int offs )		{ return offs >= StorageSize ? 0x77777777 : storage[ offs ]; }
	static inline void set( int offs, unsigned int x )	{ offs < StorageSize ? storage[ offs ] = x : true; }
private:
	PersistentStorage();
};

persiststor.cpp

#include "mbed.h"
#include "persiststor.h"
#include "stm32f4xx.h"
#include "stm32f4xx_hal_flash.h"
#include <stdlib.h>


struct Sector {
	uint32_t address, sector;
};
Sector FlashMem[ 7 ] = {
	{ 0x08000000, FLASH_SECTOR_0 },	// 16 KB
	{ 0x08004000, FLASH_SECTOR_1 },	// 16 KB
	{ 0x08008000, FLASH_SECTOR_2 },	// 16 KB
	{ 0x0800C000, FLASH_SECTOR_3 },	// 16 KB
	{ 0x08010000, FLASH_SECTOR_4 },	// 64 KB
	{ 0x08020000, FLASH_SECTOR_5 }	// 128 KB
};
const int USE_FLASH_SECTOR = 4;


unsigned int PersistentStorage::storage[ StorageSize ] __attribute__((aligned(32)));
				
				
void PersistentStorage::readStorageFromFlash() {
	HAL_FLASH_Unlock();
	memcpy( (uint32_t*)storage, (uint32_t*)FlashMem[ USE_FLASH_SECTOR ].address, StorageSize );
	HAL_FLASH_Lock();
}


bool PersistentStorage::writeStorageToFlash() {
	HAL_FLASH_Unlock();
	__HAL_FLASH_CLEAR_FLAG( FLASH_FLAG_EOP | FLASH_FLAG_OPERR |FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR );
	FLASH_EraseInitTypeDef eraser;
	eraser.TypeErase = TYPEERASE_SECTORS;
	eraser.Banks = FLASH_BANK_1;
	eraser.Sector = FlashMem[ USE_FLASH_SECTOR ].sector;
	eraser.NbSectors = 1;
	eraser.VoltageRange = VOLTAGE_RANGE_3;
	uint32_t sectorerr = 0;
	if( HAL_OK != HAL_FLASHEx_Erase( &eraser, &sectorerr ) || sectorerr != 0xFFFFFFFF ) {
		HAL_FLASH_Lock();
		return false;
	}
	for( int i = 0; i < StorageSize; ++i ) {
		if( HAL_OK != HAL_FLASH_Program( TYPEPROGRAM_WORD, FlashMem[ USE_FLASH_SECTOR ].address + i * sizeof( storage[ i ] ), storage[ i ] ) ) {
	      		HAL_FLASH_Lock();
	      		return false;
	  	}
	}
	HAL_FLASH_Lock();
	return true;
}

I found this library for reading/writing to flash:

I rewrote my code to use this library and read/write to sector 7 (the last flash sector of the NUCLEO-F401RE). It now works nicely. Thank you Hill Kim for your library! The NUCLEO-F401RE doesn't have a second bank. Here's the flash layout in case anybody wonders:

Flash layout of NUCLEO-F401RE (note: everything is in hexadecimal!):

Sector:0 Size:0x4000 at addr: 0x08000000
Sector:1 Size:0x4000 at addr: 0x08004000
Sector:2 Size:0x4000 at addr: 0x08008000
Sector:3 Size:0x4000 at addr: 0x0800c000
Sector:4 Size:0x10000 at addr: 0x08010000
Sector:5 Size:0x20000 at addr: 0x08020000
Sector:6 Size:0x20000 at addr: 0x08040000
Sector:7 Size:0x20000 at addr: 0x08060000
posted by L. Volpato 14 Aug 2015
Be the first to answer this question.