From d85cd81e2e7b0938018224382f2a9485b3cdad3d Mon Sep 17 00:00:00 2001 From: William Ransohoff <> Date: Mon, 25 Mar 2019 18:45:53 -0700 Subject: [PATCH 1/4] 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/4] 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/4] 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); } From 8c8285f47e183d8e7e93bce0ce31d2f13590a701 Mon Sep 17 00:00:00 2001 From: William Ransohoff <> Date: Fri, 26 Jul 2019 20:31:24 -0700 Subject: [PATCH 4/4] Add support for STM32G4 series --- include/stlink.h | 1 + include/stlink/chipid.h | 2 + src/chipid.c | 13 ++- src/common.c | 197 +++++++++++++++++++++++----------------- 4 files changed, 130 insertions(+), 83 deletions(-) diff --git a/include/stlink.h b/include/stlink.h index 96be91033..c664e2e66 100644 --- a/include/stlink.h +++ b/include/stlink.h @@ -79,6 +79,7 @@ extern "C" { STLINK_FLASH_TYPE_L4, STLINK_FLASH_TYPE_F1_XL, STLINK_FLASH_TYPE_G0, + STLINK_FLASH_TYPE_G4, STLINK_FLASH_TYPE_WB }; diff --git a/include/stlink/chipid.h b/include/stlink/chipid.h index a4f4be4c0..e9cb48167 100644 --- a/include/stlink/chipid.h +++ b/include/stlink/chipid.h @@ -72,6 +72,8 @@ enum stlink_stm32_chipids { STLINK_CHIPID_STM32_F413 = 0x463, STLINK_CHIPID_STM32_L4RX = 0x470, // taken from the STM32L4R9I-DISCO board STLINK_CHIPID_STM32_G0X1 = 0x460, + STLINK_CHIPID_STM32_G4_CAT2 = 0x468, // See: RM 0440 s46.6.1 "MCU device ID code". + STLINK_CHIPID_STM32_G4_CAT3 = 0x469, STLINK_CHIPID_STM32_WB55 = 0x495 }; diff --git a/src/chipid.c b/src/chipid.c index d627849a3..938cc1f30 100644 --- a/src/chipid.c +++ b/src/chipid.c @@ -530,7 +530,18 @@ static const struct stlink_chipid_params devices[] = { .flash_pagesize = 0x800, // 2K (sec 3.2) .sram_size = 0x9000, // 36K (sec 2.3) .bootrom_base = 0x1fff0000, - .bootrom_size = 0x7800 // 30K (table 2) + .bootrom_size = 0x7000 // 28K (table 2) + }, + { + // STM32G431/441 (from RM0440) + .chip_id = STLINK_CHIPID_STM32_G4_CAT2, + .description = "G4 Category-2 device", + .flash_type = STLINK_FLASH_TYPE_G4, + .flash_size_reg = 0x1FFF75E0, // Section 47.2 + .flash_pagesize = 0x800, // 2K (sec 3.3.1) + .sram_size = 0x8000, // 32K (sec 2.4) + .bootrom_base = 0x1fff0000, + .bootrom_size = 0x7000 // 28K (table 2) }, { // STM32WB55 (from RM0434) diff --git a/src/common.c b/src/common.c index b4741a585..d253e2b24 100644 --- a/src/common.c +++ b/src/common.c @@ -74,15 +74,20 @@ #define FLASH_L1_FPRG 10 #define FLASH_L1_PROG 3 +// Flash registers common to STM32G0 and STM32G4 series. +#define STM32Gx_FLASH_REGS_ADDR ((uint32_t)0x40022000) +#define STM32Gx_FLASH_ACR (STM32G0_FLASH_REGS_ADDR + 0x00) +#define STM32Gx_FLASH_KEYR (STM32G0_FLASH_REGS_ADDR + 0x08) +#define STM32Gx_FLASH_OPTKEYR (STM32G0_FLASH_REGS_ADDR + 0x0c) +#define STM32Gx_FLASH_SR (STM32G0_FLASH_REGS_ADDR + 0x10) +#define STM32Gx_FLASH_CR (STM32G0_FLASH_REGS_ADDR + 0x14) +#define STM32Gx_FLASH_ECCR (STM32G0_FLASH_REGS_ADDR + 0x18) +#define STM32Gx_FLASH_OPTR (STM32G0_FLASH_REGS_ADDR + 0x20) + // G0 (RM0444 Table 1, sec 3.7) -#define STM32G0_FLASH_REGS_ADDR ((uint32_t)0x40022000) -#define STM32G0_FLASH_ACR (STM32G0_FLASH_REGS_ADDR + 0x00) -#define STM32G0_FLASH_KEYR (STM32G0_FLASH_REGS_ADDR + 0x08) -#define STM32G0_FLASH_OPTKEYR (STM32G0_FLASH_REGS_ADDR + 0x0c) -#define STM32G0_FLASH_SR (STM32G0_FLASH_REGS_ADDR + 0x10) -#define STM32G0_FLASH_CR (STM32G0_FLASH_REGS_ADDR + 0x14) -#define STM32G0_FLASH_ECCR (STM32G0_FLASH_REGS_ADDR + 0x18) -#define STM32G0_FLASH_OPTR (STM32G0_FLASH_REGS_ADDR + 0x20) +// Mostly the same as G4 chips, but the notation +// varies a bit after the 'OPTR' register. +#define STM32G0_FLASH_REGS_ADDR (STM32Gx_FLASH_REGS_ADDR) #define STM32G0_FLASH_PCROP1ASR (STM32G0_FLASH_REGS_ADDR + 0x24) #define STM32G0_FLASH_PCROP1AER (STM32G0_FLASH_REGS_ADDR + 0x28) #define STM32G0_FLASH_WRP1AR (STM32G0_FLASH_REGS_ADDR + 0x2C) @@ -91,21 +96,39 @@ #define STM32G0_FLASH_PCROP1BER (STM32G0_FLASH_REGS_ADDR + 0x38) #define STM32G0_FLASH_SECR (STM32G0_FLASH_REGS_ADDR + 0x80) -// GO FLASH control register -#define STM32G0_FLASH_CR_PG 0 /* Program */ -#define STM32G0_FLASH_CR_PER 1 /* Page erase */ -#define STM32G0_FLASH_CR_MER1 2 /* Mass erase */ -#define STM32G0_FLASH_CR_PNB 3 /* Page number (5 bits) */ -#define STM32G0_FLASH_CR_STRT 16 /* Start */ -#define STM32G0_FLASH_CR_OPTSTRT 17 /* Start of modification of option bytes */ -#define STM32G0_FLASH_CR_FSTPG 18 /* Fast programming */ -#define STM32G0_FLASH_CR_EOPIE 24 /* End of operation interrupt enable */ -#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 */ -// GO FLASH status register -#define STM32G0_FLASH_SR_BSY 16 /* FLASH_SR Busy */ +// G4 (RM0440 Table 17, sec 3.7.19) +// Mostly the same as STM32G0 chips, but there are a few extra +// registers because 'cat 3' devices can have two Flash banks. +#define STM32G4_FLASH_REGS_ADDR (STM32Gx_FLASH_REGS_ADDR) +#define STM32G4_FLASH_PDKEYR (STM32G4_FLASH_REGS_ADDR + 0x04) +#define STM32G4_FLASH_PCROP1SR (STM32G4_FLASH_REGS_ADDR + 0x24) +#define STM32G4_FLASH_PCROP1ER (STM32G4_FLASH_REGS_ADDR + 0x28) +#define STM32G4_FLASH_WRP1AR (STM32G4_FLASH_REGS_ADDR + 0x2C) +#define STM32G4_FLASH_WRP1BR (STM32G4_FLASH_REGS_ADDR + 0x30) +#define STM32G4_FLASH_PCROP2SR (STM32G4_FLASH_REGS_ADDR + 0x44) +#define STM32G4_FLASH_PCROP2ER (STM32G4_FLASH_REGS_ADDR + 0x48) +#define STM32G4_FLASH_WRP2AR (STM32G4_FLASH_REGS_ADDR + 0x4C) +#define STM32G4_FLASH_WRP2BR (STM32G4_FLASH_REGS_ADDR + 0x50) +#define STM32G4_FLASH_SEC1R (STM32G4_FLASH_REGS_ADDR + 0x70) +#define STM32G4_FLASH_SEC2R (STM32G4_FLASH_REGS_ADDR + 0x74) + +// G0/G4 FLASH control register +#define STM32Gx_FLASH_CR_PG (0) /* Program */ +#define STM32Gx_FLASH_CR_PER (1) /* Page erase */ +#define STM32Gx_FLASH_CR_MER1 (2) /* Mass erase */ +#define STM32Gx_FLASH_CR_PNB (3) /* Page number */ +#define STM32G0_FLASH_CR_PNG_LEN (5) /* STM32G0: 5 page number bits */ +#define STM32G4_FLASH_CR_PNG_LEN (7) /* STM32G4: 7 page number bits */ +#define STM32Gx_FLASH_CR_STRT (16) /* Start */ +#define STM32Gx_FLASH_CR_OPTSTRT (17) /* Start of modification of option bytes */ +#define STM32Gx_FLASH_CR_FSTPG (18) /* Fast programming */ +#define STM32Gx_FLASH_CR_EOPIE (24) /* End of operation interrupt enable */ +#define STM32Gx_FLASH_CR_ERRIE (25) /* Error interrupt enable */ +#define STM32Gx_FLASH_CR_OBL_LAUNCH (27) /* Forces the option byte loading */ +#define STM32Gx_FLASH_CR_OPTLOCK (30) /* Options Lock */ +#define STM32Gx_FLASH_CR_LOCK (31) /* FLASH_CR Lock */ +// G0/G4 FLASH status register +#define STM32Gx_FLASH_SR_BSY (16) /* FLASH_SR Busy */ // WB (RM0434) #define STM32WB_FLASH_REGS_ADDR ((uint32_t)0x58004000) @@ -249,8 +272,8 @@ 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_G0 || sl->flash_type == STLINK_FLASH_TYPE_G4) + reg = STM32Gx_FLASH_CR; else if (sl->flash_type == STLINK_FLASH_TYPE_WB) reg = STM32WB_FLASH_CR; else @@ -281,8 +304,8 @@ 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_G0 || sl->flash_type == STLINK_FLASH_TYPE_G4) + cr_lock_shift = STM32Gx_FLASH_CR_LOCK; else if (sl->flash_type == STLINK_FLASH_TYPE_WB) cr_lock_shift = STM32WB_FLASH_CR_LOCK; else @@ -302,8 +325,8 @@ 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_G0 || sl->flash_type == STLINK_FLASH_TYPE_G4) + key_reg = STM32Gx_FLASH_KEYR; else if (sl->flash_type == STLINK_FLASH_TYPE_WB) key_reg = STM32WB_FLASH_KEYR; else @@ -341,9 +364,9 @@ 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_G0 || sl->flash_type == STLINK_FLASH_TYPE_G4) { + cr_reg = STM32Gx_FLASH_CR; + cr_lock_shift = STM32Gx_FLASH_CR_LOCK; } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { cr_reg = STM32WB_FLASH_CR; cr_lock_shift = STM32WB_FLASH_CR_LOCK; @@ -374,8 +397,8 @@ 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; + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || sl->flash_type == STLINK_FLASH_TYPE_G4) { + cr_reg = STM32Gx_FLASH_CR; x |= (1 << FLASH_CR_PG); } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { cr_reg = STM32WB_FLASH_CR; @@ -395,8 +418,8 @@ 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_G0 || sl->flash_type == STLINK_FLASH_TYPE_G4) + cr_reg = STM32Gx_FLASH_CR; else if (sl->flash_type == STLINK_FLASH_TYPE_WB) cr_reg = STM32WB_FLASH_CR; else @@ -409,8 +432,8 @@ static void clear_flash_cr_pg(stlink_t *sl) { static void set_flash_cr_per(stlink_t *sl) { uint32_t cr_reg, val; - if (sl->flash_type == STLINK_FLASH_TYPE_G0) - cr_reg = STM32G0_FLASH_CR; + if (sl->flash_type == STLINK_FLASH_TYPE_G0 || sl->flash_type == STLINK_FLASH_TYPE_G4) + cr_reg = STM32Gx_FLASH_CR; else if (sl->flash_type == STLINK_FLASH_TYPE_WB) cr_reg = STM32WB_FLASH_CR; else @@ -429,8 +452,8 @@ static void set_flash_cr2_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; + if (sl->flash_type == STLINK_FLASH_TYPE_G0 || sl->flash_type == STLINK_FLASH_TYPE_G4) + cr_reg = STM32Gx_FLASH_CR; else if (sl->flash_type == STLINK_FLASH_TYPE_WB) cr_reg = STM32WB_FLASH_CR; else @@ -451,8 +474,8 @@ 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; + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 || sl->flash_type == STLINK_FLASH_TYPE_G4) { + cr_reg = STM32Gx_FLASH_CR; cr_mer = (1 << FLASH_CR_MER); cr_pg = (1 << FLASH_CR_PG); } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { @@ -521,9 +544,9 @@ 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_G0 || sl->flash_type == STLINK_FLASH_TYPE_G4) { + cr_reg = STM32Gx_FLASH_CR; + cr_strt = 1 << STM32Gx_FLASH_CR_STRT; } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { cr_reg = STM32WB_FLASH_CR; cr_strt = 1 << STM32WB_FLASH_CR_STRT; @@ -552,8 +575,8 @@ 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_G0 || sl->flash_type == STLINK_FLASH_TYPE_G4) + sr_reg = STM32Gx_FLASH_SR; else if (sl->flash_type == STLINK_FLASH_TYPE_WB) sr_reg = STM32WB_FLASH_SR; else @@ -578,8 +601,8 @@ 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_G0 || sl->flash_type == STLINK_FLASH_TYPE_G4) + sr_busy_shift = STM32Gx_FLASH_SR_BSY; else if (sl->flash_type == STLINK_FLASH_TYPE_WB) sr_busy_shift = STM32WB_FLASH_SR_BSY; else @@ -1746,7 +1769,8 @@ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr) 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_WB || - sl->flash_type == STLINK_FLASH_TYPE_G0) { + sl->flash_type == STLINK_FLASH_TYPE_G0 || + sl->flash_type == STLINK_FLASH_TYPE_G4) { uint32_t val; // Wait for any ongoing Flash operation to finish. wait_flash_busy(sl); @@ -1767,10 +1791,18 @@ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr) 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); + stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val); // sec 3.7.5 - PNB[5:0] is offset by 3. PER is 0x2. - val = ((flash_page & 0x3F) << 3) | ( 1 << FLASH_CR_PER ); - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); + val &= ~(0x3F << 3); + val |= ((flash_page & 0x3F) << 3) | ( 1 << FLASH_CR_PER ); + stlink_write_debug32(sl, STM32Gx_FLASH_CR, val); + } else if (sl->flash_type == STLINK_FLASH_TYPE_G4) { + uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz); + stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val); + // sec 3.7.5 - PNB[6:0] is offset by 3. PER is 0x2. + val &= ~(0x7F << 3); + val |= ((flash_page & 0x7F) << 3) | ( 1 << FLASH_CR_PER ); + stlink_write_debug32(sl, STM32Gx_FLASH_CR, val); } // Set the 'start operation' bit. @@ -1834,8 +1866,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, WB series. */ - if (sl->flash_type == STLINK_FLASH_TYPE_L0 || sl->flash_type == STLINK_FLASH_TYPE_G0 || sl->flash_type == STLINK_FLASH_TYPE_WB) { + /* TODO: User MER bit to mass-erase G0, G4, WB series. */ + if (sl->flash_type == STLINK_FLASH_TYPE_L0 || sl->flash_type == STLINK_FLASH_TYPE_G0 || sl->flash_type == STLINK_FLASH_TYPE_G4 || 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++) { @@ -2121,7 +2153,8 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t } //STM32F4END else if (sl->flash_type == STLINK_FLASH_TYPE_WB || - sl->flash_type == STLINK_FLASH_TYPE_G0) { + sl->flash_type == STLINK_FLASH_TYPE_G0 || + sl->flash_type == STLINK_FLASH_TYPE_G4) { fprintf(stdout, "Writing\r\n"); fflush(stdout); // Wait for any ongoing operations to finish. @@ -2526,32 +2559,32 @@ int stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t* base, ui } /* Unlock flash if necessary (ref manuel page 52) */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - if ((val & (1u << STM32G0_FLASH_CR_LOCK))) { + stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val); + if ((val & (1u << STM32Gx_FLASH_CR_LOCK))) { /* disable flash write protection. */ - stlink_write_debug32(sl, STM32G0_FLASH_KEYR, 0x45670123); - stlink_write_debug32(sl, STM32G0_FLASH_KEYR, 0xCDEF89AB); + stlink_write_debug32(sl, STM32Gx_FLASH_KEYR, 0x45670123); + stlink_write_debug32(sl, STM32Gx_FLASH_KEYR, 0xCDEF89AB); // check that the lock is no longer set. - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - if ((val & (1u << STM32G0_FLASH_CR_LOCK))) { + stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val); + if ((val & (1u << STM32Gx_FLASH_CR_LOCK))) { ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n"); return -1; } } /* Unlock option bytes if necessary (ref manuel page 61) */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - if ((val & (1 << STM32G0_FLASH_CR_OPTLOCK))) { + stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val); + if ((val & (1 << STM32Gx_FLASH_CR_OPTLOCK))) { /* disable option byte write protection. */ - stlink_write_debug32(sl, STM32G0_FLASH_OPTKEYR, 0x08192A3B); - stlink_write_debug32(sl, STM32G0_FLASH_OPTKEYR, 0x4C5D6E7F); + stlink_write_debug32(sl, STM32Gx_FLASH_OPTKEYR, 0x08192A3B); + stlink_write_debug32(sl, STM32Gx_FLASH_OPTKEYR, 0x4C5D6E7F); /* check that the lock is no longer set. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - if ((val & (1 << STM32G0_FLASH_CR_OPTLOCK))) { + stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val); + if ((val & (1 << STM32Gx_FLASH_CR_OPTLOCK))) { ELOG("Options bytes unlock failed! System reset required to be able to unlock it again!\n"); return -1; } @@ -2562,31 +2595,31 @@ int stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t* base, ui 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); + stlink_write_debug32(sl, STM32Gx_FLASH_OPTR, data); /* Set Options Start bit */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - val |= (1 << STM32G0_FLASH_CR_OPTSTRT); - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); + stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val); + val |= (1 << STM32Gx_FLASH_CR_OPTSTRT); + stlink_write_debug32(sl, STM32Gx_FLASH_CR, val); /* Wait for 'busy' bit in FLASH_SR to clear. */ do { - stlink_read_debug32(sl, STM32G0_FLASH_SR, &val); + stlink_read_debug32(sl, STM32Gx_FLASH_SR, &val); } while ((val & (1 << 16)) != 0); /* apply options bytes immediate */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - val |= (1 << STM32G0_FLASH_CR_OBL_LAUNCH); - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); + stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val); + val |= (1 << STM32Gx_FLASH_CR_OBL_LAUNCH); + stlink_write_debug32(sl, STM32Gx_FLASH_CR, val); /* Re-lock option bytes */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - val |= (1u << STM32G0_FLASH_CR_OPTLOCK); - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); + stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val); + val |= (1u << STM32Gx_FLASH_CR_OPTLOCK); + stlink_write_debug32(sl, STM32Gx_FLASH_CR, val); /* Re-lock flash. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - val |= (1u << STM32G0_FLASH_CR_LOCK); - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); + stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val); + val |= (1u << STM32Gx_FLASH_CR_LOCK); + stlink_write_debug32(sl, STM32Gx_FLASH_CR, val); return 0; }