Add simple read/write support for STM32WB55 chips. (#786)

* Add simple read/write support for STM32WB55 chips.

* Clean up and unify G0/WB erase/program operations.
pull/789/head
WRansohoff 2019-03-31 09:41:57 -07:00 zatwierdzone przez Jerry Jacobs
rodzic c6836b4ac9
commit 4ff515ef68
4 zmienionych plików z 173 dodań i 85 usunięć

Wyświetl plik

@ -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 {

Wyświetl plik

@ -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
};
/**

Wyświetl plik

@ -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,

Wyświetl plik

@ -103,7 +103,37 @@
#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)
#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)
// 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)
@ -219,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;
@ -247,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;
@ -264,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;
@ -299,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;
@ -326,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;
@ -341,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;
@ -349,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) {
@ -358,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) {
@ -374,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;
@ -436,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;
@ -461,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;
@ -483,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;
@ -1646,47 +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) {
} 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, 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. */
// 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);
// 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);
if ((val & (1 << 31))) {
WLOG("pecr.pelock not clear (%#x)\n", val);
return -1;
}
// 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, 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);
// 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);
@ -1740,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++) {
@ -2026,27 +2117,20 @@ 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. */
else if (sl->flash_type == STLINK_FLASH_TYPE_WB ||
sl->flash_type == STLINK_FLASH_TYPE_G0) {
fprintf(stdout, "Writing\r\n");
fflush(stdout);
// 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);
for ( ; off < len; off += sizeof(uint32_t)) {
uint32_t data;
if (off > 254)
@ -2060,29 +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, STM32G0_FLASH_SR, &val);
} while ((val & (1 << 16)) != 0);
// Wait for 'busy' bit in FLASH_SR to clear.
wait_flash_busy(sl);
}
/* Do we need a dummy write? See sec 3.3.8 of RM0444. */
/* (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, STM32G0_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, 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);
// 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. */