From e56de83ec50e2e1c7f9c9f19b69c543deb2d6d21 Mon Sep 17 00:00:00 2001 From: Adrian Imboden Date: Fri, 6 Sep 2019 18:23:37 +0200 Subject: [PATCH] added support for writing option bytes on STM32L0 --- README.md | 2 +- include/stm32.h | 1 + src/common.c | 99 +++++++++++++++++++++++++++++++++++++++++------ src/tools/flash.c | 2 +- 4 files changed, 91 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 9aa7e6b..1146cf2 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ then it would be written to the memory. ## Writing Option Bytes -Example to read and write option bytes (currently writing only supported for STM32G0) +Example to read and write option bytes (currently writing only supported for STM32G0 and STM32L0) ``` ./st-flash --debug --reset --format binary --flash=128k read option_bytes_dump.bin 0x1FFF7800 4 ./st-flash --debug --reset --format binary --flash=128k write option_bytes_dump.bin 0x1FFF7800 diff --git a/include/stm32.h b/include/stm32.h index f5dbe4b..a19707b 100644 --- a/include/stm32.h +++ b/include/stm32.h @@ -15,5 +15,6 @@ #define STM32_FLASH_BASE ((uint32_t)0x08000000) #define STM32_SRAM_BASE ((uint32_t)0x20000000) #define STM32_G0_OPTION_BYTES_BASE ((uint32_t)0x1FFF7800) +#define STM32_L0_CAT2_OPTION_BYTES_BASE ((uint32_t)0x1FF80000) #endif /* STM32_H */ diff --git a/src/common.c b/src/common.c index 4f1a3d6..25900ab 100644 --- a/src/common.c +++ b/src/common.c @@ -165,6 +165,9 @@ //same as 32L1 above // RM0090 - DM00031020.pdf #define STM32L0_FLASH_REGS_ADDR ((uint32_t)0x40022000) +#define STM32L0_FLASH_PELOCK_BIT (1u << 0) +#define STM32L0_FLASH_OPTLOCK_BIT (1u << 2) +#define STM32L0_FLASH_OBL_LAUNCH_BIT (1u << 18) #define FLASH_ACR_OFF ((uint32_t) 0x00) #define FLASH_PECR_OFF ((uint32_t) 0x04) #define FLASH_PDKEYR_OFF ((uint32_t) 0x08) @@ -2507,7 +2510,7 @@ int stlink_fwrite_flash(stlink_t *sl, const char* path, stm32_addr_t addr) { * @param base option bytes to write * @return 0 on success, -ve on failure. */ -int stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t len) { +static int stlink_write_option_bytes_g0x1(stlink_t *sl, uint8_t* base, uint32_t len) { uint32_t val; @@ -2516,15 +2519,6 @@ int stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t* base, ui return -1; } - // Make sure we've loaded the context with the chip details - stlink_core_id(sl); - - /* Check if chip is supported and for correct address */ - if((sl->chip_id != STLINK_CHIPID_STM32_G0X1) || (addr != STM32_G0_OPTION_BYTES_BASE)) { - ELOG("Option bytes writing is currently only supported for the STM32G0\n"); - return -1; - } - /* Unlock flash if necessary (ref manuel page 52) */ stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); if ((val & (1u << STM32G0_FLASH_CR_LOCK))) { @@ -2561,7 +2555,6 @@ int stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t* base, ui uint32_t data; write_uint32((unsigned char*) &data, *(uint32_t*) (base)); WLOG("Writing option bytes 0x%04x\n", data); - //stlink_write_debug32(sl, addr, data); stlink_write_debug32(sl, STM32G0_FLASH_OPTR, data); /* Set Options Start bit */ @@ -2591,6 +2584,90 @@ int stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t* base, ui return 0; } + +/** + * Write option bytes + * @param sl + * @param addr of the memory mapped option bytes + * @param base option bytes to write + * @return 0 on success, -ve on failure. + */ +static int stlink_write_option_bytes_l0_cat2(stlink_t *sl, uint8_t* base, uint32_t len) { + + uint32_t val; + + if(len != 4) { + ELOG("Wrong length for writting option bytes, must be 4 is %d\n", len); + return -1; + } + stlink_read_debug32(sl, STM32L0_FLASH_REGS_ADDR + FLASH_PECR_OFF, &val); + if (val & STM32L0_FLASH_PELOCK_BIT) { + WLOG("Unlocking flash\n"); + //Unlock data EEPROM and the FLASH_PECR register (reference page 74) + stlink_write_debug32(sl, STM32L0_FLASH_REGS_ADDR + FLASH_PEKEYR_OFF, 0x89ABCDEF); + stlink_write_debug32(sl, STM32L0_FLASH_REGS_ADDR + FLASH_PEKEYR_OFF, 0x02030405); + + stlink_read_debug32(sl, STM32L0_FLASH_REGS_ADDR + FLASH_PECR_OFF, &val); + if (val & STM32L0_FLASH_PELOCK_BIT) { + ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n"); + return -1; + } + } + + stlink_read_debug32(sl, STM32L0_FLASH_REGS_ADDR + FLASH_PECR_OFF, &val); + if ((val & (STM32L0_FLASH_OPTLOCK_BIT))) { + WLOG("Unlocking options\n"); + //Unlock the Option bytes area (reference page 76) + stlink_write_debug32(sl, STM32L0_FLASH_REGS_ADDR + FLASH_OPTKEYR_OFF, 0xFBEAD9C8); + stlink_write_debug32(sl, STM32L0_FLASH_REGS_ADDR + FLASH_OPTKEYR_OFF, 0x24252627); + + stlink_read_debug32(sl, STM32L0_FLASH_REGS_ADDR + FLASH_PECR_OFF, &val); + if (val & STM32L0_FLASH_OPTLOCK_BIT) { + ELOG("Options unlock failed! System reset required to be able to unlock it again!\n"); + return -1; + } + } + + /* Write options bytes */ + uint32_t data; + write_uint32((unsigned char*) &data, *(uint32_t*) (base)); + WLOG("Writing option bytes 0x%04x\n", data); + stlink_write_debug32(sl, STM32_L0_CAT2_OPTION_BYTES_BASE, data); + + /* Reload options */ + stlink_read_debug32(sl, STM32L0_FLASH_REGS_ADDR + FLASH_PECR_OFF, &val); + val |= (STM32L0_FLASH_OBL_LAUNCH_BIT); + stlink_write_debug32(sl, STM32L0_FLASH_REGS_ADDR + FLASH_PECR_OFF, val); + + return 0; +} + +/** + * Write option bytes + * @param sl + * @param addr of the memory mapped option bytes + * @param base option bytes to write + * @return 0 on success, -ve on failure. + */ +int stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t len) { + + // Make sure we've loaded the context with the chip details + stlink_core_id(sl); + + /* Check if chip is supported and for correct address */ + if((sl->chip_id == STLINK_CHIPID_STM32_G0X1) && (addr == STM32_G0_OPTION_BYTES_BASE)) { + return stlink_write_option_bytes_g0x1(sl, base, len); + } + else if((sl->chip_id == STLINK_CHIPID_STM32_L0_CAT2) && (addr == STM32_L0_CAT2_OPTION_BYTES_BASE)) { + return stlink_write_option_bytes_l0_cat2(sl, base, len); + } + else { + ELOG("Option bytes writing is currently only supported for the STM32G0 and STM32L0\n"); + return -1; + } + +} + /** * Write the given binary file with option bytes * @param sl diff --git a/src/tools/flash.c b/src/tools/flash.c index b926a8f..1a02b4f 100644 --- a/src/tools/flash.c +++ b/src/tools/flash.c @@ -164,7 +164,7 @@ int main(int ac, char** av) goto on_error; } } - else if (o.addr == STM32_G0_OPTION_BYTES_BASE) { + else if (o.addr == STM32_G0_OPTION_BYTES_BASE || o.addr == STM32_L0_CAT2_OPTION_BYTES_BASE) { err = stlink_fwrite_option_bytes(sl, o.filename, o.addr); if (err == -1) {