From d85cd81e2e7b0938018224382f2a9485b3cdad3d Mon Sep 17 00:00:00 2001 From: William Ransohoff <> Date: Mon, 25 Mar 2019 18:45:53 -0700 Subject: [PATCH 1/3] Add simple read/write support for STM32WB55 chips. --- include/stlink.h | 1 + include/stlink/chipid.h | 3 +- src/chipid.c | 11 +++ src/common.c | 161 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 175 insertions(+), 1 deletion(-) diff --git a/include/stlink.h b/include/stlink.h index fedeb1bf4..d5e8270ac 100644 --- a/include/stlink.h +++ b/include/stlink.h @@ -77,6 +77,7 @@ extern "C" { STLINK_FLASH_TYPE_L4, STLINK_FLASH_TYPE_F1_XL, STLINK_FLASH_TYPE_G0, + STLINK_FLASH_TYPE_WB }; struct stlink_reg { diff --git a/include/stlink/chipid.h b/include/stlink/chipid.h index dda437ce7..a4f4be4c0 100644 --- a/include/stlink/chipid.h +++ b/include/stlink/chipid.h @@ -71,7 +71,8 @@ enum stlink_stm32_chipids { STLINK_CHIPID_STM32_F410 = 0x458, STLINK_CHIPID_STM32_F413 = 0x463, STLINK_CHIPID_STM32_L4RX = 0x470, // taken from the STM32L4R9I-DISCO board - STLINK_CHIPID_STM32_G0X1 = 0x460 + STLINK_CHIPID_STM32_G0X1 = 0x460, + STLINK_CHIPID_STM32_WB55 = 0x495 }; /** diff --git a/src/chipid.c b/src/chipid.c index 4e04f00cc..88d727377 100644 --- a/src/chipid.c +++ b/src/chipid.c @@ -518,6 +518,17 @@ static const struct stlink_chipid_params devices[] = { .bootrom_base = 0x1fff0000, .bootrom_size = 0x7800 // 30K (table 2) }, + { + // STM32WB55 (from RM0434) + .chip_id = STLINK_CHIPID_STM32_WB55, + .description = "WB55 device", + .flash_type = STLINK_FLASH_TYPE_WB, + .flash_size_reg = 0x1FFF75E0, + .flash_pagesize = 0x1000, // 4K + .sram_size = 0x40000, + .bootrom_base = 0x1fff0000, // See the memory map + .bootrom_size = 0x7000 + }, { // unknown .chip_id = STLINK_CHIPID_UNKNOWN, diff --git a/src/common.c b/src/common.c index 9bb2c2c4e..867284cc2 100644 --- a/src/common.c +++ b/src/common.c @@ -105,6 +105,28 @@ #define STM32G0_FLASH_CR_OPTLOCK 30 /* Options Lock */ #define STM32G0_FLASH_CR_LOCK 31 /* FLASH_CR Lock*/ +// WB (RM0434) +#define STM32WB_FLASH_REGS_ADDR ((uint32_t)0x58004000) +#define STM32WB_FLASH_ACR (STM32WB_FLASH_REGS_ADDR + 0x00) +#define STM32WB_FLASH_KEYR (STM32WB_FLASH_REGS_ADDR + 0x08) +#define STM32WB_FLASH_OPT_KEYR (STM32WB_FLASH_REGS_ADDR + 0x0C) +#define STM32WB_FLASH_SR (STM32WB_FLASH_REGS_ADDR + 0x10) +#define STM32WB_FLASH_CR (STM32WB_FLASH_REGS_ADDR + 0x14) +#define STM32WB_FLASH_ECCR (STM32WB_FLASH_REGS_ADDR + 0x18) +#define STM32WB_FLASH_OPTR (STM32WB_FLASH_REGS_ADDR + 0x20) +#define STM32WB_FLASH_PCROP1ASR (STM32WB_FLASH_REGS_ADDR + 0x24) +#define STM32WB_FLASH_PCROP1AER (STM32WB_FLASH_REGS_ADDR + 0x28) +#define STM32WB_FLASH_WRP1AR (STM32WB_FLASH_REGS_ADDR + 0x2C) +#define STM32WB_FLASH_WRP1BR (STM32WB_FLASH_REGS_ADDR + 0x30) +#define STM32WB_FLASH_PCROP1BSR (STM32WB_FLASH_REGS_ADDR + 0x34) +#define STM32WB_FLASH_PCROP1BER (STM32WB_FLASH_REGS_ADDR + 0x38) +#define STM32WB_FLASH_IPCCBR (STM32WB_FLASH_REGS_ADDR + 0x3C) +#define STM32WB_FLASH_C2ACR (STM32WB_FLASH_REGS_ADDR + 0x5C) +#define STM32WB_FLASH_C2SR (STM32WB_FLASH_REGS_ADDR + 0x60) +#define STM32WB_FLASH_C2CR (STM32WB_FLASH_REGS_ADDR + 0x64) +#define STM32WB_FLASH_SFR (STM32WB_FLASH_REGS_ADDR + 0x80) +#define STM32WB_FLASH_SRRVR (STM32WB_FLASH_REGS_ADDR + 0x84) + //32L4 register base is at FLASH_REGS_ADDR (0x40022000) #define STM32L4_FLASH_KEYR (FLASH_REGS_ADDR + 0x08) #define STM32L4_FLASH_SR (FLASH_REGS_ADDR + 0x10) @@ -1687,6 +1709,49 @@ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr) stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); val |= 0x80000000; stlink_write_debug32(sl, STM32G0_FLASH_CR, val); + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + // TODO: So far, this looks identical to the G0 logic, and the + // core registers also have the same offsets. + uint32_t val; + /* check if the locks are set */ + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + if ((val & (1<<31))) { + /* disable flash write protection. */ + stlink_write_debug32(sl, STM32WB_FLASH_KEYR, 0x45670123); + stlink_write_debug32(sl, STM32WB_FLASH_KEYR, 0xCDEF89AB); + /* check that the lock is no longer set. */ + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + if ((val & (1 << 31))) { + WLOG("pecr.pelock not clear (%#x)\n", val); + return -1; + } + } + /* Set PER (erase) bit. */ + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + val |= (1 << 1); + stlink_write_debug32(sl, STM32WB_FLASH_CR, val); + /* Set the page to erase. */ + uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz); + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + // sec 3.10.5 - PNB[7:0] is offset by 3. PER is 0x2. + val = ((flash_page & 0xFF) << 3) | (2); + stlink_write_debug32(sl, STM32WB_FLASH_CR, val); + /* Set the 'start' bit. */ + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + val |= (1 << 16); + stlink_write_debug32(sl, STM32WB_FLASH_CR, val); + /* Wait for 'busy' bit in FLASH_SR to clear. */ + do { + stlink_read_debug32(sl, STM32WB_FLASH_SR, &val); + } while ((val & (1 << 16)) != 0); + /* Clear PER ('erase enable') bit. */ + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + val &= ~(1 << 1); + stlink_write_debug32(sl, STM32WB_FLASH_CR, val); + /* Re-lock the flash. */ + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + val |= (1 << 31); + stlink_write_debug32(sl, STM32WB_FLASH_CR, val); } else if ((sl->flash_type == STLINK_FLASH_TYPE_F0) || ((sl->flash_type == STLINK_FLASH_TYPE_F1_XL) && (flashaddr < FLASH_BANK2_START_ADDR))) { /* wait for ongoing op to finish */ wait_flash_busy(sl); @@ -1755,6 +1820,41 @@ int stlink_erase_flash_mass(stlink_t *sl) { fflush(stdout); } fprintf(stdout, "\n"); + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + uint32_t val; + /* check if the locks are set */ + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + if ((val & (1<<31))) { + /* disable flash write protection. */ + stlink_write_debug32(sl, STM32WB_FLASH_KEYR, 0x45670123); + stlink_write_debug32(sl, STM32WB_FLASH_KEYR, 0xCDEF89AB); + /* check that the lock is no longer set. */ + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + if ((val & (1 << 31))) { + WLOG("pecr.pelock not clear (%#x)\n", val); + return -1; + } + } + /* Set MER (mass erase) bit. */ + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + val |= (1 << 2); + stlink_write_debug32(sl, STM32WB_FLASH_CR, val); + /* Set the 'start' bit. */ + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + val |= (1 << 16); + stlink_write_debug32(sl, STM32WB_FLASH_CR, val); + /* Wait for 'busy' bit in FLASH_SR to clear. */ + do { + stlink_read_debug32(sl, STM32WB_FLASH_SR, &val); + } while ((val & (1 << 16)) != 0); + /* Clear MER bit. */ + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + val &= ~(1 << 2); + stlink_write_debug32(sl, STM32WB_FLASH_CR, val); + /* Re-lock the flash. */ + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + val |= (1 << 31); + stlink_write_debug32(sl, STM32WB_FLASH_CR, val); } else { /* wait for ongoing op to finish */ wait_flash_busy(sl); @@ -2084,6 +2184,67 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t val |= 0x80000000; stlink_write_debug32(sl, STM32G0_FLASH_CR, val); } + else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + fprintf(stdout, "Writing\r\n"); + fflush(stdout); + uint32_t val; + /* Unlock flash. */ + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + if ((val & (1 << 31))) { + /* disable flash write protection. */ + stlink_write_debug32(sl, STM32WB_FLASH_KEYR, 0x45670123); + stlink_write_debug32(sl, STM32WB_FLASH_KEYR, 0xCDEF89AB); + /* check that the lock is no longer set. */ + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + if ((val & (1 << 31))) { + WLOG("pecr.pelock not clear (%#x)\n", val); + return -1; + } + } + /* Set PG 'allow programming' bit. */ + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + val |= (1 << 0); + stlink_write_debug32(sl, STM32WB_FLASH_CR, val); + /* Write all words. */ + off = 0; + fprintf(stdout, "Starting %3u page write\r\n", (unsigned int)(len/sl->flash_pgsz)); + fflush(stdout); + for ( ; off < len; off += sizeof(uint32_t)) { + uint32_t data; + if (off > 254) + fprintf(stdout, "\r"); + + if ((off % sl->flash_pgsz) > (sl->flash_pgsz -5)) { + fprintf(stdout, "\r%3u/%3u pages written", + (unsigned int)(off/sl->flash_pgsz), + (unsigned int)(len/sl->flash_pgsz)); + fflush(stdout); + } + write_uint32((unsigned char*) &data, *(uint32_t*) (base + off)); + stlink_write_debug32(sl, addr + (uint32_t) off, data); + /* Wait for 'busy' bit in FLASH_SR to clear. */ + do { + stlink_read_debug32(sl, STM32WB_FLASH_SR, &val); + } while ((val & (1 << 16)) != 0); + } + /* (Flash writes happen 2 words at a time.) */ + if ((off / sizeof(uint32_t)) % 2 != 0) { + /* Write a single word of zeros. */ + stlink_write_debug32(sl, addr + (uint32_t) off, 0); + /* Wait for 'busy' bit in FLASH_SR to clear. */ + do { + stlink_read_debug32(sl, STM32WB_FLASH_SR, &val); + } while ((val & (1 << 16)) != 0); + } + /* Reset PG bit. */ + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + val &= ~(1 << 0); + stlink_write_debug32(sl, STM32WB_FLASH_CR, val); + /* Re-lock flash. */ + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + val |= (1 << 31); + stlink_write_debug32(sl, STM32WB_FLASH_CR, val); + } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { /* use fast word write. todo: half page. */ uint32_t val; From d21471650543cc9071ed3821298bcd8c35f5a603 Mon Sep 17 00:00:00 2001 From: William Ransohoff <> Date: Sun, 31 Mar 2019 09:28:45 -0700 Subject: [PATCH 2/3] Clean up and unify G0/WB erase/program operations. --- src/common.c | 352 +++++++++++++++++++-------------------------------- 1 file changed, 133 insertions(+), 219 deletions(-) diff --git a/src/common.c b/src/common.c index 867284cc2..b46b6ea87 100644 --- a/src/common.c +++ b/src/common.c @@ -103,7 +103,9 @@ #define STM32G0_FLASH_CR_ERRIE 25 /* Error interrupt enable */ #define STM32G0_FLASH_CR_OBL_LAUNCH 27 /* Forces the option byte loading */ #define STM32G0_FLASH_CR_OPTLOCK 30 /* Options Lock */ -#define STM32G0_FLASH_CR_LOCK 31 /* FLASH_CR Lock*/ +#define STM32G0_FLASH_CR_LOCK 31 /* FLASH_CR Lock */ +// GO FLASH status register +#define STM32G0_FLASH_SR_BSY 16 /* FLASH_SR Busy */ // WB (RM0434) #define STM32WB_FLASH_REGS_ADDR ((uint32_t)0x58004000) @@ -127,6 +129,12 @@ #define STM32WB_FLASH_SFR (STM32WB_FLASH_REGS_ADDR + 0x80) #define STM32WB_FLASH_SRRVR (STM32WB_FLASH_REGS_ADDR + 0x84) +// WB Flash control register. +#define STM32WB_FLASH_CR_STRT (16) /* FLASH_CR Start */ +#define STM32WB_FLASH_CR_LOCK (31) /* FLASH_CR Lock */ +// WB Flash status register. +#define STM32WB_FLASH_SR_BSY (16) /* FLASH_SR Busy */ + //32L4 register base is at FLASH_REGS_ADDR (0x40022000) #define STM32L4_FLASH_KEYR (FLASH_REGS_ADDR + 0x08) #define STM32L4_FLASH_SR (FLASH_REGS_ADDR + 0x10) @@ -241,6 +249,10 @@ static inline uint32_t read_flash_cr(stlink_t *sl) { reg = FLASH_F4_CR; else if (sl->flash_type == STLINK_FLASH_TYPE_L4) reg = STM32L4_FLASH_CR; + else if (sl->flash_type == STLINK_FLASH_TYPE_G0) + reg = STM32G0_FLASH_CR; + else if (sl->flash_type == STLINK_FLASH_TYPE_WB) + reg = STM32WB_FLASH_CR; else reg = FLASH_CR; @@ -269,6 +281,10 @@ static inline unsigned int is_flash_locked(stlink_t *sl) { cr_lock_shift = FLASH_F4_CR_LOCK; else if (sl->flash_type == STLINK_FLASH_TYPE_L4) cr_lock_shift = STM32L4_FLASH_CR_LOCK; + else if (sl->flash_type == STLINK_FLASH_TYPE_G0) + cr_lock_shift = STM32G0_FLASH_CR_LOCK; + else if (sl->flash_type == STLINK_FLASH_TYPE_WB) + cr_lock_shift = STM32WB_FLASH_CR_LOCK; else cr_lock_shift = FLASH_CR_LOCK; @@ -286,6 +302,10 @@ static void unlock_flash(stlink_t *sl) { key_reg = FLASH_F4_KEYR; else if (sl->flash_type == STLINK_FLASH_TYPE_L4) key_reg = STM32L4_FLASH_KEYR; + else if (sl->flash_type == STLINK_FLASH_TYPE_G0) + key_reg = STM32G0_FLASH_KEYR; + else if (sl->flash_type == STLINK_FLASH_TYPE_WB) + key_reg = STM32WB_FLASH_KEYR; else key_reg = FLASH_KEYR; @@ -321,6 +341,12 @@ static void lock_flash(stlink_t *sl) { } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { cr_reg = STM32L4_FLASH_CR; cr_lock_shift = STM32L4_FLASH_CR_LOCK; + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0) { + cr_reg = STM32G0_FLASH_CR; + cr_lock_shift = STM32G0_FLASH_CR_LOCK; + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + cr_reg = STM32WB_FLASH_CR; + cr_lock_shift = STM32WB_FLASH_CR_LOCK; } else { cr_reg = FLASH_CR; cr_lock_shift = FLASH_CR_LOCK; @@ -348,6 +374,12 @@ static void set_flash_cr_pg(stlink_t *sl) { cr_reg = STM32L4_FLASH_CR; x &= ~STM32L4_FLASH_CR_OPBITS; x |= 1 << STM32L4_FLASH_CR_PG; + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0) { + cr_reg = STM32G0_FLASH_CR; + x |= (1 << FLASH_CR_PG); + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + cr_reg = STM32WB_FLASH_CR; + x |= (1 << FLASH_CR_PG); } else { cr_reg = FLASH_CR; x = 1 << FLASH_CR_PG; @@ -363,6 +395,10 @@ static void clear_flash_cr_pg(stlink_t *sl) { cr_reg = FLASH_F4_CR; else if (sl->flash_type == STLINK_FLASH_TYPE_L4) cr_reg = STM32L4_FLASH_CR; + else if (sl->flash_type == STLINK_FLASH_TYPE_G0) + cr_reg = STM32G0_FLASH_CR; + else if (sl->flash_type == STLINK_FLASH_TYPE_WB) + cr_reg = STM32WB_FLASH_CR; else cr_reg = FLASH_CR; @@ -371,8 +407,18 @@ static void clear_flash_cr_pg(stlink_t *sl) { } static void set_flash_cr_per(stlink_t *sl) { - const uint32_t n = 1 << FLASH_CR_PER; - stlink_write_debug32(sl, FLASH_CR, n); + uint32_t cr_reg, val; + + if (sl->flash_type == STLINK_FLASH_TYPE_G0) + cr_reg = STM32G0_FLASH_CR; + else if (sl->flash_type == STLINK_FLASH_TYPE_WB) + cr_reg = STM32WB_FLASH_CR; + else + cr_reg = FLASH_CR; + + stlink_read_debug32(sl, cr_reg, &val); + val |= (1 << FLASH_CR_PER); + stlink_write_debug32(sl, cr_reg, val); } static void set_flash_cr2_per(stlink_t *sl) { @@ -380,9 +426,18 @@ static void set_flash_cr2_per(stlink_t *sl) { stlink_write_debug32(sl, FLASH_CR2, n); } -static void __attribute__((unused)) clear_flash_cr_per(stlink_t *sl) { +static void clear_flash_cr_per(stlink_t *sl) { + uint32_t cr_reg; + + if (sl->flash_type == STLINK_FLASH_TYPE_G0) + cr_reg = STM32G0_FLASH_CR; + else if (sl->flash_type == STLINK_FLASH_TYPE_WB) + cr_reg = STM32WB_FLASH_CR; + else + cr_reg = FLASH_CR; + const uint32_t n = read_flash_cr(sl) & ~(1 << FLASH_CR_PER); - stlink_write_debug32(sl, FLASH_CR, n); + stlink_write_debug32(sl, cr_reg, n); } static void set_flash_cr_mer(stlink_t *sl, bool v) { @@ -396,6 +451,14 @@ static void set_flash_cr_mer(stlink_t *sl, bool v) { cr_reg = STM32L4_FLASH_CR; cr_mer = (1 << STM32L4_FLASH_CR_MER1) | (1 << STM32L4_FLASH_CR_MER2); cr_pg = 1 << STM32L4_FLASH_CR_PG; + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0) { + cr_reg = STM32G0_FLASH_CR; + cr_mer = (1 << FLASH_CR_MER); + cr_pg = (1 << FLASH_CR_PG); + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + cr_reg = STM32WB_FLASH_CR; + cr_mer = (1 << FLASH_CR_MER); + cr_pg = (1 << FLASH_CR_PG); } else { cr_reg = FLASH_CR; cr_mer = 1 << FLASH_CR_MER; @@ -458,6 +521,12 @@ static void set_flash_cr_strt(stlink_t *sl) { } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { cr_reg = STM32L4_FLASH_CR; cr_strt = 1 << STM32L4_FLASH_CR_STRT; + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0) { + cr_reg = STM32G0_FLASH_CR; + cr_strt = 1 << STM32G0_FLASH_CR_STRT; + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + cr_reg = STM32WB_FLASH_CR; + cr_strt = 1 << STM32WB_FLASH_CR_STRT; } else { cr_reg = FLASH_CR; cr_strt = 1 << FLASH_CR_STRT; @@ -483,6 +552,10 @@ static inline uint32_t read_flash_sr(stlink_t *sl) { sr_reg = FLASH_F4_SR; else if (sl->flash_type == STLINK_FLASH_TYPE_L4) sr_reg = STM32L4_FLASH_SR; + else if (sl->flash_type == STLINK_FLASH_TYPE_G0) + sr_reg = STM32G0_FLASH_SR; + else if (sl->flash_type == STLINK_FLASH_TYPE_WB) + sr_reg = STM32WB_FLASH_SR; else sr_reg = FLASH_SR; @@ -505,6 +578,10 @@ static inline unsigned int is_flash_busy(stlink_t *sl) { sr_busy_shift = FLASH_F4_SR_BSY; else if (sl->flash_type == STLINK_FLASH_TYPE_L4) sr_busy_shift = STM32L4_FLASH_SR_BSY; + else if (sl->flash_type == STLINK_FLASH_TYPE_G0) + sr_busy_shift = STM32G0_FLASH_SR_BSY; + else if (sl->flash_type == STLINK_FLASH_TYPE_WB) + sr_busy_shift = STM32WB_FLASH_SR_BSY; else sr_busy_shift = FLASH_SR_BSY; @@ -1668,90 +1745,39 @@ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr) stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); val |= (1 << 0) | (1 << 1) | (1 << 2); stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); - } else if (sl->flash_type == STLINK_FLASH_TYPE_G0) { - uint32_t val; - /* check if the locks are set */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - if ((val & (1<<31))) { - /* disable flash write protection. */ - stlink_write_debug32(sl, STM32G0_FLASH_KEYR, 0x45670123); - stlink_write_debug32(sl, STM32G0_FLASH_KEYR, 0xCDEF89AB); - /* check that the lock is no longer set. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - if ((val & (1 << 31))) { - WLOG("pecr.pelock not clear (%#x)\n", val); - return -1; - } - } - /* Set PER (erase) bit. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - val |= 0x00000002; - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); - /* Set the page to erase. */ - uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz); - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - // sec 3.7.5 - PNB[5:0] is offset by 3. PER is 0x2. - val = ((flash_page & 0x3F) << 3) | (2); - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); - /* Set the 'start' bit. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - val |= (1 << 16); - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); - /* Wait for 'busy' bit in FLASH_SR to clear. */ - do { - stlink_read_debug32(sl, STM32G0_FLASH_SR, &val); - } while ((val & (1 << 16)) != 0); - /* Clear PER ('erase enable') bit. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - val &= ~(0x00000002); - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); - /* Re-lock the flash. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - val |= 0x80000000; - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); - } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { - // TODO: So far, this looks identical to the G0 logic, and the - // core registers also have the same offsets. + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB || + sl->flash_type == STLINK_FLASH_TYPE_G0) { uint32_t val; - /* check if the locks are set */ - stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); - if ((val & (1<<31))) { - /* disable flash write protection. */ - stlink_write_debug32(sl, STM32WB_FLASH_KEYR, 0x45670123); - stlink_write_debug32(sl, STM32WB_FLASH_KEYR, 0xCDEF89AB); - /* check that the lock is no longer set. */ + // Wait for any ongoing Flash operation to finish. + wait_flash_busy(sl); + // Unlock Flash if necessary. + unlock_flash_if(sl); + // Set the 'enable Flash erase' bit. + set_flash_cr_per(sl); + + // Set the page to erase. + if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz); stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); - if ((val & (1 << 31))) { - WLOG("pecr.pelock not clear (%#x)\n", val); - return -1; - } + // sec 3.10.5 - PNB[7:0] is offset by 3. + val |= ((flash_page & 0xFF) << 3); + stlink_write_debug32(sl, STM32WB_FLASH_CR, val); + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0) { + uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz); + stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); + // sec 3.7.5 - PNB[5:0] is offset by 3. PER is 0x2. + val |= ((flash_page & 0x3F) << 3); + stlink_write_debug32(sl, STM32G0_FLASH_CR, val); } - /* Set PER (erase) bit. */ - stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); - val |= (1 << 1); - stlink_write_debug32(sl, STM32WB_FLASH_CR, val); - /* Set the page to erase. */ - uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz); - stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); - // sec 3.10.5 - PNB[7:0] is offset by 3. PER is 0x2. - val = ((flash_page & 0xFF) << 3) | (2); - stlink_write_debug32(sl, STM32WB_FLASH_CR, val); - /* Set the 'start' bit. */ - stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); - val |= (1 << 16); - stlink_write_debug32(sl, STM32WB_FLASH_CR, val); - /* Wait for 'busy' bit in FLASH_SR to clear. */ - do { - stlink_read_debug32(sl, STM32WB_FLASH_SR, &val); - } while ((val & (1 << 16)) != 0); - /* Clear PER ('erase enable') bit. */ - stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); - val &= ~(1 << 1); - stlink_write_debug32(sl, STM32WB_FLASH_CR, val); - /* Re-lock the flash. */ - stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); - val |= (1 << 31); - stlink_write_debug32(sl, STM32WB_FLASH_CR, val); + + // Set the 'start operation' bit. + set_flash_cr_strt(sl); + // Wait for the 'busy' bit to clear. + wait_flash_busy(sl); + // Clear the 'enable page erase' bit. + clear_flash_cr_per(sl); + // Re-lock the flash. + lock_flash(sl); } else if ((sl->flash_type == STLINK_FLASH_TYPE_F0) || ((sl->flash_type == STLINK_FLASH_TYPE_F1_XL) && (flashaddr < FLASH_BANK2_START_ADDR))) { /* wait for ongoing op to finish */ wait_flash_busy(sl); @@ -1805,8 +1831,8 @@ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr) } int stlink_erase_flash_mass(stlink_t *sl) { - /* TODO: User MER bit to mass-erase G0 series. */ - if (sl->flash_type == STLINK_FLASH_TYPE_L0 || sl->flash_type == STLINK_FLASH_TYPE_G0) { + /* TODO: User MER bit to mass-erase G0, WB series. */ + if (sl->flash_type == STLINK_FLASH_TYPE_L0 || sl->flash_type == STLINK_FLASH_TYPE_G0 || sl->flash_type == STLINK_FLASH_TYPE_WB) { /* erase each page */ int i = 0, num_pages = (int) sl->flash_size/sl->flash_pgsz; for (i = 0; i < num_pages; i++) { @@ -1820,41 +1846,6 @@ int stlink_erase_flash_mass(stlink_t *sl) { fflush(stdout); } fprintf(stdout, "\n"); - } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { - uint32_t val; - /* check if the locks are set */ - stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); - if ((val & (1<<31))) { - /* disable flash write protection. */ - stlink_write_debug32(sl, STM32WB_FLASH_KEYR, 0x45670123); - stlink_write_debug32(sl, STM32WB_FLASH_KEYR, 0xCDEF89AB); - /* check that the lock is no longer set. */ - stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); - if ((val & (1 << 31))) { - WLOG("pecr.pelock not clear (%#x)\n", val); - return -1; - } - } - /* Set MER (mass erase) bit. */ - stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); - val |= (1 << 2); - stlink_write_debug32(sl, STM32WB_FLASH_CR, val); - /* Set the 'start' bit. */ - stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); - val |= (1 << 16); - stlink_write_debug32(sl, STM32WB_FLASH_CR, val); - /* Wait for 'busy' bit in FLASH_SR to clear. */ - do { - stlink_read_debug32(sl, STM32WB_FLASH_SR, &val); - } while ((val & (1 << 16)) != 0); - /* Clear MER bit. */ - stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); - val &= ~(1 << 2); - stlink_write_debug32(sl, STM32WB_FLASH_CR, val); - /* Re-lock the flash. */ - stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); - val |= (1 << 31); - stlink_write_debug32(sl, STM32WB_FLASH_CR, val); } else { /* wait for ongoing op to finish */ wait_flash_busy(sl); @@ -2126,86 +2117,17 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t lock_flash(sl); } //STM32F4END - else if (sl->flash_type == STLINK_FLASH_TYPE_G0) { - uint32_t val; - /* Unlock flash. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - if ((val & (1<<31))) { - /* disable flash write protection. */ - stlink_write_debug32(sl, STM32G0_FLASH_KEYR, 0x45670123); - stlink_write_debug32(sl, STM32G0_FLASH_KEYR, 0xCDEF89AB); - /* check that the lock is no longer set. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - if ((val & (1 << 31))) { - WLOG("pecr.pelock not clear (%#x)\n", val); - return -1; - } - } - /* Set PG 'allow programming' bit. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - val |= 0x00000001; - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); - /* Write all words. */ - off = 0; - for ( ; off < len; off += sizeof(uint32_t)) { - uint32_t data; - if (off > 254) - fprintf(stdout, "\r"); - - if ((off % sl->flash_pgsz) > (sl->flash_pgsz -5)) { - fprintf(stdout, "\r%3u/%3u pages written", - (unsigned int)(off/sl->flash_pgsz), - (unsigned int)(len/sl->flash_pgsz)); - fflush(stdout); - } - write_uint32((unsigned char*) &data, *(uint32_t*) (base + off)); - stlink_write_debug32(sl, addr + (uint32_t) off, data); - /* Wait for 'busy' bit in FLASH_SR to clear. */ - do { - stlink_read_debug32(sl, STM32G0_FLASH_SR, &val); - } while ((val & (1 << 16)) != 0); - } - /* Do we need a dummy write? See sec 3.3.8 of RM0444. */ - /* (Flash writes happen 2 words at a time.) */ - if ((off / sizeof(uint32_t)) % 2 != 0) { - /* Write a single word of zeros. */ - stlink_write_debug32(sl, addr + (uint32_t) off, 0); - /* Wait for 'busy' bit in FLASH_SR to clear. */ - do { - stlink_read_debug32(sl, STM32G0_FLASH_SR, &val); - } while ((val & (1 << 16)) != 0); - } - /* Reset PG bit. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - val &= ~(0x00000001); - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); - /* Re-lock flash. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - val |= 0x80000000; - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); - } - else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + else if (sl->flash_type == STLINK_FLASH_TYPE_WB || + sl->flash_type == STLINK_FLASH_TYPE_G0) { fprintf(stdout, "Writing\r\n"); fflush(stdout); - uint32_t val; - /* Unlock flash. */ - stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); - if ((val & (1 << 31))) { - /* disable flash write protection. */ - stlink_write_debug32(sl, STM32WB_FLASH_KEYR, 0x45670123); - stlink_write_debug32(sl, STM32WB_FLASH_KEYR, 0xCDEF89AB); - /* check that the lock is no longer set. */ - stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); - if ((val & (1 << 31))) { - WLOG("pecr.pelock not clear (%#x)\n", val); - return -1; - } - } - /* Set PG 'allow programming' bit. */ - stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); - val |= (1 << 0); - stlink_write_debug32(sl, STM32WB_FLASH_CR, val); - /* Write all words. */ + // Wait for any ongoing operations to finish. + wait_flash_busy(sl); + // Unlock flash if necessary. + unlock_flash_if(sl); + // Set PG 'allow programming' bit. + set_flash_cr_pg(sl); + // Write all words. off = 0; fprintf(stdout, "Starting %3u page write\r\n", (unsigned int)(len/sl->flash_pgsz)); fflush(stdout); @@ -2222,28 +2144,20 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t } write_uint32((unsigned char*) &data, *(uint32_t*) (base + off)); stlink_write_debug32(sl, addr + (uint32_t) off, data); - /* Wait for 'busy' bit in FLASH_SR to clear. */ - do { - stlink_read_debug32(sl, STM32WB_FLASH_SR, &val); - } while ((val & (1 << 16)) != 0); + // Wait for 'busy' bit in FLASH_SR to clear. + wait_flash_busy(sl); } - /* (Flash writes happen 2 words at a time.) */ + // (Flash writes happen 2 words at a time.) if ((off / sizeof(uint32_t)) % 2 != 0) { - /* Write a single word of zeros. */ + // Write a single word of zeros. stlink_write_debug32(sl, addr + (uint32_t) off, 0); - /* Wait for 'busy' bit in FLASH_SR to clear. */ - do { - stlink_read_debug32(sl, STM32WB_FLASH_SR, &val); - } while ((val & (1 << 16)) != 0); + // Wait for 'busy' bit in FLASH_SR to clear. + wait_flash_busy(sl); } - /* Reset PG bit. */ - stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); - val &= ~(1 << 0); - stlink_write_debug32(sl, STM32WB_FLASH_CR, val); - /* Re-lock flash. */ - stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); - val |= (1 << 31); - stlink_write_debug32(sl, STM32WB_FLASH_CR, val); + // Reset PG bit. + clear_flash_cr_pg(sl); + // Re-lock flash. + lock_flash(sl); } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { /* use fast word write. todo: half page. */ From 2117226105187d75ce05a3a8ebed9e2a42793b17 Mon Sep 17 00:00:00 2001 From: William Ransohoff <> Date: Thu, 25 Apr 2019 22:14:23 -0700 Subject: [PATCH 3/3] Fix apparent issue with STM32G0 flashing. --- src/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common.c b/src/common.c index b46b6ea87..63de8415c 100644 --- a/src/common.c +++ b/src/common.c @@ -1766,7 +1766,7 @@ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr) uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz); stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); // sec 3.7.5 - PNB[5:0] is offset by 3. PER is 0x2. - val |= ((flash_page & 0x3F) << 3); + val = ((flash_page & 0x3F) << 3) | ( 1 << FLASH_CR_PER ); stlink_write_debug32(sl, STM32G0_FLASH_CR, val); }