Skip to content

Commit

Permalink
refactor: flash driver
Browse files Browse the repository at this point in the history
  • Loading branch information
raphaelcoeffic committed Jul 16, 2024
1 parent 35077eb commit 3360675
Show file tree
Hide file tree
Showing 9 changed files with 203 additions and 166 deletions.
2 changes: 2 additions & 0 deletions radio/src/io/bootloader_flash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

#include "bootloader_flash.h"
#include "timers_driver.h"
#include "flash_driver.h"

#include "hal/watchdog_driver.h"

#if defined(LIBOPENUI)
Expand Down
18 changes: 13 additions & 5 deletions radio/src/targets/common/arm/stm32/bootloader/boot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@
* GNU General Public License for more details.
*/

#if !defined(SIMU)
#include "stm32_hal_ll.h"
#include "stm32_hal.h"
#include "stm32_timer.h"
#endif
// #if !defined(SIMU)
// #include "stm32_hal_ll.h"
// #include "stm32_hal.h"
// #include "stm32_timer.h"
// #endif

#include "hal/usb_driver.h"

Expand All @@ -39,6 +39,8 @@
#include "debug.h"

#include "timers_driver.h"
#include "flash_driver.h"

#include "hal/abnormal_reboot.h"
#include "hal/rotary_encoder.h"

Expand All @@ -64,6 +66,12 @@ const uint8_t bootloaderVersion[] __attribute__ ((section(".version"), used)) =
{'B', 'O', 'O', 'T', '1', '0'};
#endif

#if defined(SIMU)
#define __weak
#elif !defined(__weak)
#define __weak __attribute__((weak))
#endif

volatile tmr10ms_t g_tmr10ms;
volatile uint8_t tenms = 1;

Expand Down
2 changes: 2 additions & 0 deletions radio/src/targets/common/arm/stm32/f2/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ if(NOT NATIVE_BUILD)
${STM32CUBE_DIR}/Src/stm32f2xx_hal_i2c.c
${STM32CUBE_DIR}/Src/stm32f2xx_hal_pcd.c
${STM32CUBE_DIR}/Src/stm32f2xx_hal_pcd_ex.c
${STM32CUBE_DIR}/Src/stm32f2xx_hal_flash.c
${STM32CUBE_DIR}/Src/stm32f2xx_hal_flash_ex.c
)

target_compile_options(stm32cube_ll PRIVATE -DUSE_FULL_LL_DRIVER)
Expand Down
265 changes: 136 additions & 129 deletions radio/src/targets/common/arm/stm32/flash_driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,172 +22,179 @@
#include "stm32_cmsis.h"
#include "stm32_hal.h"

#include "board.h"
#include "hal/watchdog_driver.h"
uint32_t stm32_flash_get_size_kb()
{
uint32_t flash_size_kb = *(const uint32_t*)FLASHSIZE_BASE;
return flash_size_kb;
}

#if defined(STM32F2) || defined(STM32F4)

#if defined(STM32H7)
#define FLASH_CR FLASH->CR1
#define FLASH_SR FLASH->SR1
#else
#define FLASH_CR FLASH->CR
#define FLASH_SR FLASH->SR
#endif
uint32_t stm32_flash_get_sector(uint32_t address)
{
uint32_t sector;
uint32_t sector_addr = address & 0xFFFFF;

#if !defined(FLASH_CR_START)
# define FLASH_CR_START FLASH_CR_STRT
#endif
if (sector_addr < 0x10000) {
sector = sector_addr / 0x4000;
} else {
sector = (sector_addr / 0x20000) + 4;
}

#if !defined(FLASH_SR_BUSY)
# define FLASH_SR_BUSY FLASH_SR_BSY
#endif
// bank 2
if (address & 0x100000) {
sector += 12;
}

return sector;
}

void waitFlashIdle()
static uint32_t _flash_sector_address(uint32_t sector, uint32_t bank)
{
do {
WDG_RESET();
} while (FLASH_SR & FLASH_SR_BUSY);
(void)bank;

uint32_t addr = FLASH_BASE;
if (sector >= 12) addr += 0x100000;

if (sector < 4) {
addr += sector * 0x4000;
} else {
addr += (sector - 4) * 0x10000;
}

return addr;
}

//After reset, write is not allowed in the Flash control register (FLASH_CR) to protect the
//Flash memory against possible unwanted operations due, for example, to electric
//disturbances. The following sequence is used to unlock this register:
//1. Write KEY1 = 0x45670123 in the Flash key register (FLASH_KEYR)
//2. Write KEY2 = 0xCDEF89AB in the Flash key register (FLASH_KEYR)
//Any wrong sequence will return a bus error and lock up the FLASH_CR register until the
//next reset.
//The FLASH_CR register can be locked again by software by setting the LOCK bit in the
//FLASH_CR register.
void unlockFlash()
uint32_t stm32_flash_get_sector_size(uint32_t sector)
{
#if defined(STM32H7)
FLASH->KEYR1 = FLASH_KEY1;
FLASH->KEYR1 = FLASH_KEY2;
#else
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
// bank 2
if (sector >= 12) sector -= 12;

// first 4: 16KB
if (sector < 4) return 16 * 1024;
// sector 4: 64KB
if (sector == 4) return 64 * 1024;
// others: 128KB
return 128 * 1024;
}

#elif defined(STM32H7) || defined(STM32H7RS)

uint32_t stm32_flash_get_sector(uint32_t address)
{
uint32_t sector_addr = address & 0xFFFFF;
return sector_addr / FLASH_SECTOR_SIZE;
}

static uint32_t _flash_sector_address(uint32_t sector, uint32_t bank)
{
uint32_t addr = FLASH_BASE;
#if defined(DUAL_BANK)
if (bank != FLASH_BANK_1) addr += 0x100000;
#endif
addr += sector * FLASH_SECTOR_SIZE;
return addr;
}

void lockFlash()
uint32_t stm32_flash_get_sector_size(uint32_t sector)
{
waitFlashIdle();
FLASH_CR |= FLASH_CR_LOCK;
(void)sector;
return FLASH_SECTOR_SIZE;
}

#define SECTOR_MASK ((uint32_t)0xFFFFFF07)
#endif

void eraseSector(uint32_t sector)
uint32_t stm32_flash_get_bank(uint32_t address)
{
WDG_ENABLE(3000); // some sectors may take > 1s to erase
#if defined(DUAL_BANK)
return ((address & 0x100000) != 0x100000) ? FLASH_BANK_1 : FLASH_BANK_2;
#elif defined(FLASH_BANK_1)
(void)address;
return FLASH_BANK_1;
#else
(void)address;
return 1UL;
#endif
}

void stm32_flash_unlock() { HAL_FLASH_Unlock(); }
void stm32_flash_lock() { HAL_FLASH_Lock(); }

waitFlashIdle();
int stm32_flash_erase_sector(uint32_t address)
{
FLASH_EraseInitTypeDef eraseInit;
eraseInit.TypeErase = FLASH_TYPEERASE_SECTORS;
eraseInit.Sector = stm32_flash_get_sector(address);
eraseInit.NbSectors = 1UL;

#if defined(FLASH_CR_PSIZE)
FLASH_CR &= ~FLASH_CR_PSIZE;
FLASH_CR |= FLASH_CR_PSIZE_1;
#if defined(FLASH_BANK_1)
eraseInit.Banks = stm32_flash_get_bank(address);
#endif
FLASH_CR &= SECTOR_MASK;
FLASH_CR |= FLASH_CR_SER | (sector << 3);
FLASH_CR |= FLASH_CR_START;

/* Wait for operation to be completed */
waitFlashIdle();
#if defined(FLASH_VOLTAGE_RANGE_3)
eraseInit.VoltageRange = FLASH_VOLTAGE_RANGE_3;
#endif

/* if the erase operation is completed, disable the SER Bit */
FLASH_CR &= (~FLASH_CR_SER);
FLASH_CR &= SECTOR_MASK;
uint32_t sector_errors = 0;
if (HAL_FLASHEx_Erase(&eraseInit, &sector_errors) != HAL_OK) {
return -1;
}

WDG_ENABLE(WDG_DURATION);
return 0;
}

void flashWrite(uint32_t * address, const uint32_t * buffer) // page size is 256 bytes
#if defined(STM32H7)
#define FLASH_PROG_WORDS FLASH_NB_32BITWORD_IN_FLASHWORD
#define _FLASH_PROGRAM(address, p_data) \
HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, address, (uintptr_t)p_data)
#elif defined(STM32H7RS)
#define FLASH_PROG_WORDS 4UL
#define _FLASH_PROGRAM(address, p_data) \
HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, address, (uintptr_t)p_data)
#else
#define FLASH_PROG_WORDS 1UL
#define _FLASH_PROGRAM(address, p_data) \
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, *p_data)
#endif

int stm32_flash_program(uint32_t address, uint8_t* data, uint32_t len)
{
#define SECTOR_ADDRESS (((uint32_t)address) & 0xFFFFF)

// Please note that there is an offset of 4 between
// sector 11 and 12
#define FLASH_BANK ((((uint32_t)address) & 0x100000) ? 16 : 0)

// test for possible flash sector boundary
if ((((uint32_t)address) & 0x1FFFF) == 0) {
// test first 16KB sectors
if (SECTOR_ADDRESS == 0x00000) {
eraseSector(0 + FLASH_BANK);
}
// test 128KB sectors
else if (SECTOR_ADDRESS == 0x20000) {
eraseSector(5 + FLASH_BANK);
}
else if (SECTOR_ADDRESS == 0x40000) {
eraseSector(6 + FLASH_BANK);
}
else if (SECTOR_ADDRESS == 0x60000) {
eraseSector(7 + FLASH_BANK);
}
else if (SECTOR_ADDRESS == 0x80000) {
eraseSector(8 + FLASH_BANK);
}
else if (SECTOR_ADDRESS == 0xA0000) {
eraseSector(9 + FLASH_BANK);
}
else if (SECTOR_ADDRESS == 0xC0000) {
eraseSector(10 + FLASH_BANK);
}
else if (SECTOR_ADDRESS == 0xE0000) {
eraseSector(11 + FLASH_BANK);
}
}
// test 64KB sector
else if (SECTOR_ADDRESS == 0x10000) {
eraseSector(4 + FLASH_BANK);
}
else if ((((uint32_t)address) & 0x3FFF) == 0) {
// test other 16KB sectors
if (SECTOR_ADDRESS == 0x04000) {
eraseSector(1 + FLASH_BANK);
}
else if (SECTOR_ADDRESS == 0x08000) {
eraseSector(2 + FLASH_BANK);
}
else if (SECTOR_ADDRESS == 0x0C000) {
eraseSector(3 + FLASH_BANK);
}
uint32_t* p_data = (uint32_t*)data;
uint32_t end_addr = address + len;

while (address < end_addr) {
if (_FLASH_PROGRAM(address, p_data) != HAL_OK) {
return -1;
}

#undef SECTOR_ADDRESS
#undef FLASH_BANK
address += sizeof(uint32_t) * FLASH_PROG_WORDS;
p_data += FLASH_PROG_WORDS;
}

for (uint32_t i=0; i<FLASH_PAGESIZE/4; i++) {
/* Device voltage range supposed to be [2.7V to 3.6V], the operation will
be done by word */
return 0;
}

// Wait for last operation to be completed
waitFlashIdle();
// Legacy API

#if defined(FLASH_CR_PSIZE)
FLASH_CR &= ~FLASH_CR_PSIZE;
FLASH_CR |= FLASH_CR_PSIZE_1;
#endif
FLASH_CR |= FLASH_CR_PG;
#define FLASH_PAGESIZE 256

*address = *buffer;
void unlockFlash() { stm32_flash_unlock(); }
void lockFlash() { stm32_flash_lock(); }

/* Wait for operation to be completed */
waitFlashIdle();
FLASH_CR &= ~FLASH_CR_PG;
void flashWrite(uint32_t* address, const uint32_t* buffer)
{
// check first if the address is on a sector boundary
uint32_t sector = stm32_flash_get_sector((uintptr_t)address);
uint32_t bank = stm32_flash_get_bank((uintptr_t)address);

/* Check the written value */
if (*address != *buffer) {
/* Flash content doesn't match SRAM content */
return;
}
/* Increment FLASH destination address */
address += 1;
buffer += 1;
if ((uintptr_t)address == _flash_sector_address(sector, bank)) {
if (stm32_flash_erase_sector((uintptr_t)address) < 0) return;
}

stm32_flash_program((uintptr_t)address, (uint8_t*)buffer, FLASH_PAGESIZE);
}

// TODO: move this somewhere else, as it depends on firmware layout
uint32_t isFirmwareStart(const uint8_t * buffer)
{
const uint32_t * block = (const uint32_t *)buffer;
Expand Down
Loading

0 comments on commit 3360675

Please sign in to comment.