cancel
Showing results for 
Search instead for 
Did you mean: 

How to use flash memory as a EEPROM in STM32G071CBT6

suriya
Associate II

Hello! I'm using the STM32G071CBT6 controller for my project. I need to store certain values in EEPROM for my project, but unfortunately, this controller doesn't have built-in EEPROM functionality. Despite this limitation, I'm determined to find a solution to store data effectively. I've searched extensively, but I haven't been able to find any example code specifically for the STM32G0 series. If anyone has example code that demonstrates how to use the flash memory as EEPROM, I would greatly appreciate your suggestions and guidance.

STM32G0 Series

5 REPLIES 5
TDK
Guru
CharlieMangold
Associate III

We use this type of storage for both the F series and the G series. Couple questions before you dig yourself in deep.

- How frequently do you need to write the data? ST micro flash can only be erased approximately 1000 times(this number is hard to find) as flash on these devices is really designed for holding code(older flash could be erased in the 100K range.) If the data is only configuration stuff that is updated infrequently you'll be fine. If your writing out error logs the code will have to be much more complex as you will need to track the number of sector erases(the G series refers to these as Pages.)

- If you decide that you will not burn the flash out by writing to many times, then find how big the Page(or Sector) sizes are and how large do the flash writes need to be. F series allowed you to write 4 bytes at a time where the G series that we use need to be 8 bytes at a time. Size your data structures accordingly so you keep everything aligned.

Some code below will give you an idea of storing configuration data that is NOT written to frequently.It's just basic stuff but should give you some idea of storing configuration information.

void __attribute__((optimize("O0"))) flash_config_init(void)
{
uint32_t seedValue, crcLength, crcTemp, pageNumber, *addr_p;
FLASH_Status status;

	seedValue = CRC32_SEED_VALUE;
	crcLength = (sizeof(flash_config_struct)-sizeof(uint32_t));

	// Read out the Magic number...
	addr_p				= (uint32_t *)FLASH_CONFIG_START_ADDR;
	data.magicNum		= *(__IO uint32_t *)addr_p;
	addr_p++;
	data.softwareRev	= *(__IO uint32_t *)addr_p;
 	if ((data.magicNum == EZTEMP_MAGIC_NUMBER) && (data.softwareRev == SOFTWARE_REV))
	{
		flash_read_x_uint32((uint32_t *)&flashData, (uint32_t *)FLASH_CONFIG_START_ADDR, sizeof(flash_config_struct));
	}
	else
	{
		// There is no flash data, or the software revision has changed. Set
		// the flash data to default values.
		memset(&data, 0, sizeof(flash_config_struct));
		data.magicNum			= EZTEMP_MAGIC_NUMBER;
		data.xxx				= 0xAA5500FF;
		data.xxx2				= 0xFF00AA55;
		data.softwareRev		= SOFTWARE_REV;
		
		// Calculate the CRC value going in...
		//crcTemp = crc_check((uint8_t *)&data, (sizeof(flash_config_struct)-sizeof(uint32_t)));
		CRC_SetInitRegister(CRC32_SEED_VALUE);
		CRC_ResetDR();
		crcTemp = flash_calculate_crc32((uint32_t *)&data, crcLength, (uint32_t *)&seedValue);
		if(crcTemp)
		{
			data.crcValue = crcTemp;

			// Erase/Clear the page/sector and program the default values...
			HAL_FLASH_Unlock();
			__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_PROGERR | FLASH_FLAG_WRPERR);

			// New HAL based driver code needs the page number, not address. It also starts
			// a page erase and had used interrupts to finish the erase cycle. We don't use
			// interrupts so we added a call to wait for the last operation to finish.
			addr_p		= (uint32_t *)FLASH_CONFIG_START_ADDR;
			pageNumber	= (FLASH_CONFIG_START_ADDR-FLASH_BANK2_START_ADDR)/FLASH_PAGE_SIZE;
			status 		= FLASH_ErasePage(FLASH_BANK2, pageNumber);

			if (status != FLASH_COMPLETE)
			{
				HAL_FLASH_Lock();
				shut_down(ERROR_CRC_FAIL);
			}
			HAL_FLASH_Lock();

			// Write out the configuration information.
			flash_write_x_uint32( (uint32_t *)&data, (uint32_t *)(FLASH_CONFIG_START_ADDR), sizeof(flash_config_struct));

			// Data has been written into flash, read it out.
			// Valid data in flash. Read it out.
			flash_read_x_uint32((uint32_t *)&flashData, (uint32_t *)FLASH_CONFIG_START_ADDR, sizeof(flash_config_struct));
		}
	}

	// Verify the CRC value..
	//crcTemp = crc_check((uint8_t *)&flashData, (sizeof(flash_config_struct)-sizeof(uint32_t)));
	seedValue = CRC32_SEED_VALUE;
	crcLength = (sizeof(flash_config_struct)-sizeof(uint32_t));

	crcTemp = flash_calculate_crc32((uint32_t *)&flashData, crcLength, (uint32_t *)&seedValue);

	if (crcTemp != flashData.crcValue)
	{
		// Default CRC is failing. Need to shut down...
		shut_down(ERROR_CRC_FAIL);
	}

	crcTemp = verify_config(&flashData);
	if (crcTemp != FUNCTION_SUCCESS)
	{
		// Flash configuration has failed the range check...
		shut_down(crcTemp);
	}

}

uint32_t flash_read_x_uint32(uint32_t *data_p, uint32_t *addr_p, uint32_t readSize)
{
uint32_t *tempAddr_p, *tempData_p, *end_p;
uint32_t rc = 0;

	if ( (data_p != 0) && (readSize != 0) )
	{
		tempAddr_p	= addr_p;
		tempData_p	= data_p;
		end_p		= (uint32_t *)(((uint8_t *)tempAddr_p)+readSize);

		// We are reading 4 bytes at a time from flash
		while (tempAddr_p < end_p)
		{
			*tempData_p = *(__IO uint32_t *)tempAddr_p;
			tempAddr_p++;
			tempData_p++;
		}
	}
	else
	{
		rc = 1;
	}
	return(rc);
}

uint32_t flash_write_x_uint32(uint32_t *data_p, uint32_t *addr_p, uint32_t writeSize)
{
uint32_t *tempAddr_p, *end_p, rc = 0;
uint64_t *tempData_p;

	if ( (data_p != 0) && (writeSize != 0) && (writeSize <= FLASH_PAGE_SIZE))
	{

		HAL_FLASH_Unlock();
		__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_PROGERR | FLASH_FLAG_WRPERR);

		tempAddr_p	= addr_p;
		tempData_p	= data_p;
		end_p		= (uint32_t *)(((uint8_t *)tempAddr_p)+writeSize);

		// We are writing 8 bytes at a time to flash because the STM32G0B0RE can
		// only write 8 bytes at a time.
		while (tempAddr_p < end_p)
		{
			// We are writing 8 bytes at a time to flash because the STM32G0B0RE can
			// only write 8 bytes at a time.
			HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, (uint32_t)tempAddr_p, *tempData_p);
			tempAddr_p += 2;
			tempData_p ++;
		}

		// Both the image header and configuration have been written out, lock the flash.
		HAL_FLASH_Lock();
	}
	else
	{
		rc = 1;
	}
	return(rc);

}

 

 

 

CharlieMangold
Associate III

What type of data do you wish to store in flash? The flash on ST micro's can only be written/erased about 1000 times. If you only need to store something like configuration information that is not written a lot, then you should be fine. If your looking to store error logs then you code base will have to be much larger as you will need to track how many times you have erased the flash Pages(used to be called sectors.)

The code below is an example of the basics for storing configuration information in flash and is CRC'd to insure there are no errors. You have to be careful to insure all your data structures are properly aligned as writing to flash is done in 8 byte chunks on a G series micro.

 

void __attribute__((optimize("O0"))) flash_config_init(void)
{
uint32_t seedValue, crcLength, crcTemp, pageNumber, *addr_p;
FLASH_Status status;

	seedValue = CRC32_SEED_VALUE;
	crcLength = (sizeof(flash_config_struct)-sizeof(uint32_t));

	// Read out the Magic number...
	addr_p				= (uint32_t *)FLASH_CONFIG_START_ADDR;
	data.magicNum		= *(__IO uint32_t *)addr_p;
	addr_p++;
	data.softwareRev	= *(__IO uint32_t *)addr_p;
 	if ((data.magicNum == EZTEMP_MAGIC_NUMBER) && (data.softwareRev == SOFTWARE_REV))
	{
		flash_read_x_uint32((uint32_t *)&flashData, (uint32_t *)FLASH_CONFIG_START_ADDR, sizeof(flash_config_struct));
	}
	else
	{
		// There is no flash data, or the software revision has changed. Set
		// the flash data to default values.
		memset(&data, 0, sizeof(flash_config_struct));
		data.magicNum			= EZTEMP_MAGIC_NUMBER;
		data.xxx				= 0xAA5500FF;
		data.xxx2				= 0xFF00AA55;
		data.softwareRev		= SOFTWARE_REV;
		
		// Calculate the CRC value going in...
		//crcTemp = crc_check((uint8_t *)&data, (sizeof(flash_config_struct)-sizeof(uint32_t)));
		CRC_SetInitRegister(CRC32_SEED_VALUE);
		CRC_ResetDR();
		crcTemp = flash_calculate_crc32((uint32_t *)&data, crcLength, (uint32_t *)&seedValue);
		if(crcTemp)
		{
			data.crcValue = crcTemp;

			// Erase/Clear the page/sector and program the default values...
			HAL_FLASH_Unlock();
			__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_PROGERR | FLASH_FLAG_WRPERR);

			// New HAL based driver code needs the page number, not address. It also starts
			// a page erase and had used interrupts to finish the erase cycle. We don't use
			// interrupts so we added a call to wait for the last operation to finish.
			addr_p		= (uint32_t *)FLASH_CONFIG_START_ADDR;
			pageNumber	= (FLASH_CONFIG_START_ADDR-FLASH_BANK2_START_ADDR)/FLASH_PAGE_SIZE;
			status 		= FLASH_ErasePage(FLASH_BANK2, pageNumber);

			if (status != FLASH_COMPLETE)
			{
				HAL_FLASH_Lock();
				shut_down(ERROR_CRC_FAIL);
			}
			HAL_FLASH_Lock();

			// Write out the configuration information.
			flash_write_x_uint32( (uint32_t *)&data, (uint32_t *)(FLASH_CONFIG_START_ADDR), sizeof(flash_config_struct));

			// Data has been written into flash, read it out.
			// Valid data in flash. Read it out.
			flash_read_x_uint32((uint32_t *)&flashData, (uint32_t *)FLASH_CONFIG_START_ADDR, sizeof(flash_config_struct));
		}
	}

	// Verify the CRC value..
	//crcTemp = crc_check((uint8_t *)&flashData, (sizeof(flash_config_struct)-sizeof(uint32_t)));
	seedValue = CRC32_SEED_VALUE;
	crcLength = (sizeof(flash_config_struct)-sizeof(uint32_t));

	crcTemp = flash_calculate_crc32((uint32_t *)&flashData, crcLength, (uint32_t *)&seedValue);

	if (crcTemp != flashData.crcValue)
	{
		// Default CRC is failing. Need to shut down...
		shut_down(ERROR_CRC_FAIL);
	}

	crcTemp = verify_config(&flashData);
	if (crcTemp != FUNCTION_SUCCESS)
	{
		// Flash configuration has failed the range check...
		shut_down(crcTemp);
	}

}

uint32_t flash_read_x_uint32(uint32_t *data_p, uint32_t *addr_p, uint32_t readSize)
{
uint32_t *tempAddr_p, *tempData_p, *end_p;
uint32_t rc = 0;

	if ( (data_p != 0) && (readSize != 0) )
	{
		tempAddr_p	= addr_p;
		tempData_p	= data_p;
		end_p		= (uint32_t *)(((uint8_t *)tempAddr_p)+readSize);

		// We are reading 4 bytes at a time from flash
		while (tempAddr_p < end_p)
		{
			*tempData_p = *(__IO uint32_t *)tempAddr_p;
			tempAddr_p++;
			tempData_p++;
		}
	}
	else
	{
		rc = 1;
	}
	return(rc);
}

uint32_t flash_write_x_uint32(uint32_t *data_p, uint32_t *addr_p, uint32_t writeSize)
{
uint32_t *tempAddr_p, *end_p, rc = 0;
uint64_t *tempData_p;

	if ( (data_p != 0) && (writeSize != 0) && (writeSize <= FLASH_PAGE_SIZE))
	{

		HAL_FLASH_Unlock();
		__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_PROGERR | FLASH_FLAG_WRPERR);

		tempAddr_p	= addr_p;
		tempData_p	= data_p;
		end_p		= (uint32_t *)(((uint8_t *)tempAddr_p)+writeSize);

		// We are writing 8 bytes at a time to flash because the STM32G0B0RE can
		// only write 8 bytes at a time.
		while (tempAddr_p < end_p)
		{
			// We are writing 8 bytes at a time to flash because the STM32G0B0RE can
			// only write 8 bytes at a time.
			HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, (uint32_t)tempAddr_p, *tempData_p);
			tempAddr_p += 2;
			tempData_p ++;
		}

		// Both the image header and configuration have been written out, lock the flash.
		HAL_FLASH_Lock();
	}
	else
	{
		rc = 1;
	}
	return(rc);

}

Hi 

I tried to use your code but i get few errors.

'CRC32_SEED_VALUE' undeclared (first use in this function) 

Description Resource Path Location Type
'CRC32_SEED_VALUE' undeclared (first use in this function) main.c /EEPROM/Core/Src line 64 C/C++ Problem
'data' undeclared (first use in this function) main.c /EEPROM/Core/Src line 69 C/C++ Problem
'ERROR_CRC_FAIL' undeclared (first use in this function) main.c /EEPROM/Core/Src line 109 C/C++ Problem
'EZTEMP_MAGIC_NUMBER' undeclared (first use in this function) main.c /EEPROM/Core/Src line 72 C/C++ Problem
'FLASH_BANK2_START_ADDR' undeclared (first use in this function) main.c /EEPROM/Core/Src line 103 C/C++ Problem
'FLASH_BANK2' undeclared (first use in this function); did you mean 'FLASH_BANK_1'? main.c /EEPROM/Core/Src line 104 C/C++ Problem
'FLASH_COMPLETE' undeclared (first use in this function); did you mean 'FLASH_CR_PER'? main.c /EEPROM/Core/Src line 106 C/C++ Problem
'FLASH_CONFIG_START_ADDR' undeclared (first use in this function) main.c /EEPROM/Core/Src line 68 C/C++ Problem
'flash_config_struct' undeclared (first use in this function); did you mean 'flash_config_init'? main.c /EEPROM/Core/Src line 65 C/C++ Problem
'FLASH_EraseInitTypeDef' has no member named 'PageAddress' FlASH_PAGE_F1.c /EEPROM/Core/Src line 93 C/C++ Problem
'flashData' undeclared (first use in this function) main.c /EEPROM/Core/Src line 74 C/C++ Problem
'FUNCTION_SUCCESS' undeclared (first use in this function); did you mean 'NOR_SUCCESS'? main.c /EEPROM/Core/Src line 136 C/C++ Problem
'SOFTWARE_REV' undeclared (first use in this function) main.c /EEPROM/Core/Src line 72 C/C++ Problem
conflicting types for 'flash_read_x_uint32'; have 'uint32_t(uint32_t *, uint32_t *, uint32_t)' {aka 'long unsigned int(long unsigned int *, long unsigned int *, long unsigned int)'} main.c /EEPROM/Core/Src line 144 C/C++ Problem
conflicting types for 'flash_write_x_uint32'; have 'uint32_t(uint32_t *, uint32_t *, uint32_t)' {aka 'long unsigned int(long unsigned int *, long unsigned int *, long unsigned int)'} main.c /EEPROM/Core/Src line 170 C/C++ Problem

 Do we need to  add or import any files to execute this functions.

 

The code was to show the basic things needed to write/read flash. The specific code was designed for a STM32G0B0 which has a huge amount of flash and requires 8 byte writes and the use of page numbers when writing. To simplify things I would remove the CRC checking as that is just adding another layer of complication at this point. The data sheet on your chip shows a 10000 erase cycle endurance and the reference manual shows you have 1 bank of flash with a page size of 2048(2k) bytes.

Capture2.JPG

Capture.JPG

 

 

 

#define	FUNCTION_SUCCESS		0
#define CRC32_SEED_VALUE		0xFFFFFFFF
define	MAGIC_NUMBER			0x20160321
#define	SOFTWARE_REV			0x00020003 // Major 16 bits(upper), minor 8 bits, internal 8 bits
#define FLASH_BANK2_START_ADDR	((uint32_t)0x08040000)


typedef struct __attribute__((__packed__))
{
	// First 16 Bytes
	uint32_t	magicNum;
	uint32_t	softwareRev;
	uint32_t	value1;
	uint32_t	value2;

	// Second 16 Bytes
	uint32_t	value3;
	uint32_t	value4;
	uint32_t	value5;
	uint32_t	value6;

	// Third 16 Bytes
	uint32_t	spare1;
	uint32_t	spare2;
	uint32_t	spare3;
	uint32_t	crcValue;
}flash_config_struct;