cancel
Showing results for 
Search instead for 
Did you mean: 

Flash erase is not working properly on STM32L4A6RGT6

HA.4
Associate II

I'm trying to use flash erase to erase the address 0x08040000, its not erasing. I think I'm giving the values wrong for Bank and Pages.

#include "main.h"
#include "stdbool.h"
typedef enum {
	NONE,
	PREPARATION,
	FLASH_ERASING,
	FLASH_ERASE_DONE,
	FLASH_WRITE_IN_PROGRESS,
	FLASH_WRITE_DONE,
	UPDATE_DONE,
} updateState_t;
#define NUM_PAGES 100
#define NUM_BYTES       NUM_PAGES * FLASH_PAGE_SIZE
#define NUM_DOUBLEWORDS NUM_BYTES / 8
volatile updateState_t updateState = NONE;
 
void HAL_GPIO_EXTI_Callback(uint16_t pin) {
	if (pin == GPIO_PIN_2) {
		printf("Button is pressed");
		if (updateState == NONE) {
			updateState = PREPARATION;
		}
	}
 
void HAL_FLASH_EndOfOperationCallback(uint32_t ReturnValue) {
	if (updateState == FLASH_ERASING && ReturnValue==0xffffffff) {
	updateState = FLASH_ERASE_DONE;
	} else if (updateState == FLASH_WRITE_IN_PROGRESS) {
		updateState = FLASH_WRITE_DONE;
	}
}
 
void toggleBankAndReset() {
	FLASH_OBProgramInitTypeDef OBInit;
	HAL_FLASH_Unlock();
	__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
	HAL_FLASH_OB_Unlock();
	HAL_FLASHEx_OBGetConfig(&OBInit);
 
	OBInit.OptionType = OPTIONBYTE_USER;
	OBInit.USERType = OB_USER_BFB2;
 
	if (((OBInit.USERConfig) & (OB_BFB2_ENABLE)) == OB_BFB2_ENABLE) {
		OBInit.USERConfig = OB_BFB2_DISABLE;
	} else {
		OBInit.USERConfig = OB_BFB2_ENABLE;
	}
	if (HAL_FLASHEx_OBProgram(&OBInit) != HAL_OK) {
		// uint32_t errorCode = HAL_FLASH_GetError();
		while (1) {
			printf("1s delay is running::OB Program ");
			HAL_Delay(1000);
			HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);
		}
	}
	if (HAL_FLASH_OB_Launch() != HAL_OK) {
		//uint32_t errorCode = HAL_FLASH_GetError();
		while (1) {
			printf("0.1s delay is running::OB launch ");
			HAL_Delay(100);
			HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);
		}
	}
	HAL_FLASH_OB_Lock();
	HAL_FLASH_Lock();
}
 
uint8_t getActiveBank() {
volatile uint32_t remap = READ_BIT(SYSCFG->MEMRMP, 0x1 << 8);
	return remap == 0 ? 1 : 2;
}
}
 
int main(void)
{
	uint8_t bank = getActiveBank();
 
	uint32_t last = HAL_GetTick();
 
	uint32_t delay;
	if (bank == 1) {
		printf("delay: 1000, when bank==1");
		delay = 1000;
	} else {
		printf("delay: 500, else");
		delay = 500;
	}
while (1) {
		uint32_t now = HAL_GetTick();
		if (now - last > delay) {
			HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5);
			last = now;
		}
		switch (updateState) {
		case NONE:
			break;
		case PREPARATION: {
			FLASH_EraseInitTypeDef erase = { 0 };
			erase.TypeErase = FLASH_TYPEERASE_PAGES;
			erase.Banks = bank == 1 ? FLASH_BANK_2 : FLASH_BANK_1;
			erase.NbPages = NUM_PAGES;
			erase.Page = 0;
 
			HAL_FLASH_Unlock();
			HAL_StatusTypeDef status = HAL_FLASHEx_Erase_IT(&erase);
			if (status != HAL_OK) {
				// TODO error case
			}
 
			updateState = FLASH_ERASING;
		}
			break;
 
		case FLASH_ERASING:
		case FLASH_WRITE_IN_PROGRESS:
			delay = 200;
//			updateState = FLASH_ERASE_DONE;
			break;
 
		case FLASH_ERASE_DONE:
		case FLASH_WRITE_DONE: {
			delay = 50;
			static size_t index = 0;
 
			uint32_t dest = 0x08010000;
			uint8_t *src = (uint8_t*) 0x08000000;
 
			if (index < NUM_DOUBLEWORDS) {
			     uint64_t doubleword = *(uint64_t*) (src + (index * 8));
 
				updateState = FLASH_WRITE_IN_PROGRESS;
				HAL_StatusTypeDef progStatus;
				progStatus= HAL_FLASH_Program_IT(
				FLASH_TYPEPROGRAM_DOUBLEWORD, dest + index * 8, doubleword);
				if (progStatus == HAL_OK)
					index++;
			} else {
				updateState = UPDATE_DONE;
			}
		}
			break;
 
		case UPDATE_DONE:
			toggleBankAndReset();
			break;
		}
       }
}

4 REPLIES 4
WojtekP1
Associate III

I may be able to help you as i wrote few programs for STM32L4 and did use flash erase/programming in i t - worked fine.

But don't use HAL libraries, nor i am able to understand anything writing in this useless abstraction layer. If you like below is my code for erasing flash page.

//a is temporary variable, page is page number

//subsctract 0x8000000 from flash address (flash begins at 0x8000000)

//and divide by page size which is 2kB

//page=((unsigned)address)-0x8000000;

//page>>=11;

//change my register names with whatever definition you use.

//last FLUSH is not needed if you don't do another flash operation just after.

#define FLUSH asm("dsb");

 FLASH_KEYR=0x45670123; FLASH_KEYR=0xCDEF89AB; FLUSH;

 while(FLASH_SR&0x10000); 

 FLASH_CR=a=2|(page<<3); FLUSH;

 FLASH_CR=a|0x10000;

 while(FLASH_SR&0x10000); 

 FLASH_CR=0xC0000000; FLUSH;

Promise it works fine.

HA.4
Associate II

Nope, THis is not working still.

WojtekP1
Associate III

There is no reason why your MCU should work different than mine.

But check if:

  • clock is enabled for flash (unlikely unless you run from RAM and disabled flash clock)
  • add debug after FLASH_CR write to display actual content of FLASH_CR
  • add debug to display FLASH_SR state what it contain after  while(FLASH_SR&0x10000); 

Why do you not use the normal register and bit field definitions provided by ST? And the same for CMSIS functions and macros provided by ARM like __DSB()? By the way, your FLUSH macro lacks the compiler barrier... And actually the flash erase code doesn't need any compiler or memory barriers at all, because all accesses are volatile and on a device memory.

https://community.st.com/s/question/0D50X0000C4Nk4GSQS/bug-missing-compiler-and-cpu-memory-barriers

Also double assignments are not recommended because there is an undefined behavior - no sequence points defined between the assignments. For example, if the middle variable is of a volatile type, then it is not defined whether it must be re-read from memory after the first (right) assignment or not.