From 43b3fa5ddc6a1414afb503fe68f2786c87a9aecf Mon Sep 17 00:00:00 2001 From: Karl Palsson Date: Fri, 16 Oct 2020 10:35:07 +0000 Subject: [PATCH] stm32l0/l1: flash: support half page flashing Tested on L1 and L0 using the "dapboot" project, see https://github.com/devanlai/dapboot/pull/27 for L1 and https://github.com/devanlai/dapboot/pull/30 for L0 --- .../stm32/common/flash_common_l01.h | 13 ++++++++ include/libopencm3/stm32/l0/flash.h | 2 ++ include/libopencm3/stm32/l1/flash.h | 2 +- lib/stm32/common/flash_common_l01.c | 30 +++++++++++++++++++ 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/include/libopencm3/stm32/common/flash_common_l01.h b/include/libopencm3/stm32/common/flash_common_l01.h index 442c000f..4f7a5524 100644 --- a/include/libopencm3/stm32/common/flash_common_l01.h +++ b/include/libopencm3/stm32/common/flash_common_l01.h @@ -120,6 +120,19 @@ void flash_unlock_progmem(void); void flash_lock_progmem(void); void flash_lock_option_bytes(void); void flash_unlock_acr(void); +/** Erase a page in flash. + * @param page_address For L1, must be first word in page, L0 doesn't care + * Takes 1 tprog. Flash must already be unlocked! + */ +void flash_erase_page(uint32_t page_address); + +/** + * Write a half page from buf to dst. + * This function _must_ be in ram! (See the Ref Man for more details) + * @param dst where to write to, expected to be aligned and erased. + * @param buf the half page to write, size required depends on target + */ +void flash_program_half_page(uint32_t *dst, void *buf); void eeprom_program_word(uint32_t address, uint32_t data); void eeprom_program_words(uint32_t address, uint32_t *data, int length_in_words); diff --git a/include/libopencm3/stm32/l0/flash.h b/include/libopencm3/stm32/l0/flash.h index ef1d1883..a0be623b 100644 --- a/include/libopencm3/stm32/l0/flash.h +++ b/include/libopencm3/stm32/l0/flash.h @@ -55,6 +55,8 @@ /* --- FLASH_OPTR values ----------------------------------------------------- */ #define FLASH_OPTR_NBOOT1 (1 << 31) +#define FLASH_HALF_PAGE_SIZE 16 + BEGIN_DECLS END_DECLS diff --git a/include/libopencm3/stm32/l1/flash.h b/include/libopencm3/stm32/l1/flash.h index a84a55b3..2a163d0b 100644 --- a/include/libopencm3/stm32/l1/flash.h +++ b/include/libopencm3/stm32/l1/flash.h @@ -56,7 +56,7 @@ /* --- FLASH_SR values ----------------------------------------------------- */ #define FLASH_SR_OPTVERRUSR (1 << 12) -/* --- Function prototypes ------------------------------------------------- */ +#define FLASH_HALF_PAGE_SIZE 32 BEGIN_DECLS diff --git a/lib/stm32/common/flash_common_l01.c b/lib/stm32/common/flash_common_l01.c index 9fb1212b..6415f728 100644 --- a/lib/stm32/common/flash_common_l01.c +++ b/lib/stm32/common/flash_common_l01.c @@ -97,6 +97,36 @@ void flash_unlock_acr(void) FLASH_PDKEYR = FLASH_PDKEYR_PDKEY2; } +/** + * Erase a page in ram. + * @param page_address must be first word in page for L1, any address in page for L0 + */ +void flash_erase_page(uint32_t page_address) +{ + FLASH_PECR |= FLASH_PECR_ERASE | FLASH_PECR_PROG; + MMIO32(page_address) = 0; + while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY); + FLASH_PECR &= ~(FLASH_PECR_ERASE | FLASH_PECR_PROG); +} + +/* Must be run from RAM (per ref manual), and because it's in ram, more + * than 64MB away from flash address space, must be a long_call. */ +__attribute__ ((long_call, section (".ramtext"))) +void flash_program_half_page(uint32_t *dst, void *buf) +{ + uint32_t *src = buf; + + /* Enable half page writes to program memory */ + FLASH_PECR |= FLASH_PECR_FPRG | FLASH_PECR_PROG; + while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY); + for (int i = 0; i < FLASH_HALF_PAGE_SIZE; i++) { + *dst++ = *src++; + } + while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY); + FLASH_PECR &= ~(FLASH_PECR_FPRG | FLASH_PECR_PROG); +} + + /** @brief Write a word to eeprom * * @param address assumed to be in the eeprom space, no checking