-
|
So for the need of my application i want to upgrade the firmware of the STM32G431CBU6 from another SoC which UART is connected to PC4 PA10 (UART1). Apparently the ROM bootloader cannot use these GPIOs for download, so i am integrating the function directly into my firmware, handling the same protocol as the ROM bootloader. and this IAP firmware. https://github.com/Arksine/katapult/blob/b0bf421069e2aab810db43d6e15f38817d981451/src/stm32/flash.c This is my output log bool eraseFlashPages(uint32_t startPage, uint32_t numPages) {
logHex("Erasing pages from", startPage);
logHex("Number of pages", numPages);
uint32_t totalPages = (FLASH_SIZE / FLASH_PAGE_SIZE);
if (startPage >= totalPages) {
log("Invalid start page");
return false;
}
if ((startPage + numPages) > totalPages) {
log("Too many pages to erase");
return false;
}
delay(50);
//__disable_irq();
// Unlock flash using direct register access
if (FLASH->CR & FLASH_CR_LOCK) {
FLASH->KEYR = 0x45670123UL;
FLASH->KEYR = 0xCDEF89ABUL;
}
while (FLASH->SR & FLASH_SR_BSY) {} // wait flash rdy
bool success = true;
uint32_t startAddress = FLASH_BASE + (startPage * FLASH_PAGE_SIZE);
for (uint32_t i = 0; i < numPages; i++) {
uint32_t pageAddress = startAddress + (i * FLASH_PAGE_SIZE);
uint32_t pidx = (pageAddress - FLASH_BASE) / FLASH_PAGE_SIZE;
logHex("Erasing page at address", pageAddress);
logHex("Page index", pidx);
// STM32G4 128KB flash, bank wrapping
if (pidx >= 64) {
// Check actual flash size
uint16_t flash_size_kb = *(uint16_t*)0x1FFF75E0; // STM32G4 FLASH_SIZE
if (flash_size_kb <= 256) {
pidx = pidx + 256 - 64;
} else {
pidx = pidx < 128 ? pidx : pidx + 256 - 128;
}
}
pidx = pidx > 0x3ff ? 0x3ff : pidx;
// Clear error flags
FLASH->SR = FLASH_SR_OPTVERR | FLASH_SR_RDERR | FLASH_SR_FASTERR |
FLASH_SR_MISERR | FLASH_SR_PGSERR | FLASH_SR_SIZERR |
FLASH_SR_PGAERR | FLASH_SR_WRPERR | FLASH_SR_PROGERR |
FLASH_SR_OPERR;
// Start erase
FLASH->CR = FLASH_CR_PER | FLASH_CR_STRT | (pidx << FLASH_CR_PNB_Pos);
// Wait for completion
while (FLASH->SR & FLASH_SR_BSY) {dbg.print(".");}
// Check for errors
if (FLASH->SR & (FLASH_SR_PROGERR | FLASH_SR_WRPERR | FLASH_SR_OPERR)) {
log("Flash erase error");
if (FLASH->SR & FLASH_SR_WRPERR) log("Write protection error");
if (FLASH->SR & FLASH_SR_PROGERR) log("Programming error");
if (FLASH->SR & FLASH_SR_OPERR) log("Operation error");
success = false;
break;
}
// Verify erase
uint32_t* ptr = (uint32_t*)pageAddress;
bool erased = true;
for (uint32_t j = 0; j < (FLASH_PAGE_SIZE / 4); j++) {
if (ptr[j] != 0xFFFFFFFF) {
logHex("Not erased at offset", j * 4);
logHex("Value", ptr[j]);
erased = false;
break;
}
}
if (!erased) {
log("Page not properly erased");
success = false;
break;
}
}
// Lock flash
FLASH->CR = FLASH_CR_LOCK;
//__enable_irq();
if (success) {
log("Erase successful");
} else {
log("Erase failed");
}
return success;
}Second version with HAL APIs, which did not had better success. bool eraseFlashPagesHAL(uint32_t startPage, uint32_t numPages) {
logHex("Erasing pages from", startPage);
logHex("Number of pages", numPages);
uint32_t totalPages = (FLASH_SIZE / FLASH_PAGE_SIZE);
if (startPage >= totalPages) {
log("Invalid start page");
return false;
}
if ((startPage + numPages) > totalPages) {
log("Too many pages to erase");
return false;
}
delay(50);
// __disable_irq();
#if defined(ICACHE) && defined (HAL_ICACHE_MODULE_ENABLED) && !defined(HAL_ICACHE_MODULE_DISABLED)
bool icache_enabled = false;
if (HAL_ICACHE_IsEnabled() == 1) {
icache_enabled = true;
/* Disable instruction cache prior to internal cacheable memory update */
if (HAL_ICACHE_Disable() != HAL_OK) {
Error_Handler();
}
}
#endif
if (HAL_FLASH_Unlock() != HAL_OK) {
log("Failed to unlock flash");
__enable_irq();
return false;
}
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
FLASH_EraseInitTypeDef eraseInit;
uint32_t pageError = 0;
memset(&eraseInit, 0, sizeof(eraseInit));
eraseInit.TypeErase = FLASH_TYPEERASE_PAGES;
eraseInit.Banks = FLASH_BANK_1;
eraseInit.Page = startPage;
eraseInit.NbPages = numPages;
log("Starting erase...");
uint32_t startTime = HAL_GetTick();
bool timeout = false;
HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&eraseInit, &pageError);
uint32_t elapsed = HAL_GetTick() - startTime;
logHex("Erase took (ms)", elapsed);
HAL_FLASH_Lock();
#if defined(ICACHE) && defined (HAL_ICACHE_MODULE_ENABLED) && !defined(HAL_ICACHE_MODULE_DISABLED)
if (icache_enabled) {
/* Re-enable instruction cache */
if (HAL_ICACHE_Enable() != HAL_OK) {
Error_Handler();
}
}
#endif
// __enable_irq();
if (status != HAL_OK || timeout) {
if (timeout) {
log("Erase timeout!");
} else {
logHex("Erase failed", status);
logHex("Page error", pageError);
}
return false;
}
log("Erase successful");
return true;
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 8 replies
-
|
The code hangs because the flash erase operation makes the entire flash bank unreadable while erasing, but your code executing the erase is itself running from flash. Fix: Move the erase function to RAM using |
Beta Was this translation helpful? Give feedback.
You have to defined the flash_offset like it is done here:
Arduino_Core_STM32/boards.txt
Line 3894 in fc48ab0
You can use the boards_local.txt feature of Arduino:
https://docs.arduino.cc/arduino-cli/platform-specification/#boardslocaltxt
Example with the generic STM32G431CB
GenG4.menu.pnum.GENERIC_G431CBTX.build.flash_offset=0x...