Skip to content

Commit

Permalink
Add preliminary support for some STM32G0 chips.
Browse files Browse the repository at this point in the history
  • Loading branch information
William Ransohoff committed Jan 12, 2019
1 parent 7651d21 commit c1ad2cf
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 2 deletions.
1 change: 1 addition & 0 deletions include/stlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ extern "C" {
STLINK_FLASH_TYPE_F4,
STLINK_FLASH_TYPE_L4,
STLINK_FLASH_TYPE_F1_XL,
STLINK_FLASH_TYPE_G0,
};

struct stlink_reg {
Expand Down
3 changes: 2 additions & 1 deletion include/stlink/chipid.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ enum stlink_stm32_chipids {
STLINK_CHIPID_STM32_L011 = 0x457,
STLINK_CHIPID_STM32_F410 = 0x458,
STLINK_CHIPID_STM32_F413 = 0x463,
STLINK_CHIPID_STM32_L4RX = 0x470 // taken from the STM32L4R9I-DISCO board
STLINK_CHIPID_STM32_L4RX = 0x470, // taken from the STM32L4R9I-DISCO board
STLINK_CHIPID_STM32_G0X1 = 0x460
};

/**
Expand Down
11 changes: 11 additions & 0 deletions src/chipid.c
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,17 @@ static const struct stlink_chipid_params devices[] = {
.bootrom_base = 0x1ff00000,
.bootrom_size = 0x2000
},
{
// STM32G071/081 (from RM0444)
.chip_id = STLINK_CHIPID_STM32_G0X1,
.description = "G071/G081 device",
.flash_type = STLINK_FLASH_TYPE_G0,
.flash_size_reg = 0x1FFF75E0, // Section 38.2
.flash_pagesize = 0x800, // 2K (sec 3.2)
.sram_size = 0x9000, // 36K (sec 2.3)
.bootrom_base = 0x1fff0000,
.bootrom_size = 0x7800 // 30K (table 2)
},
{
// unknown
.chip_id = STLINK_CHIPID_UNKNOWN,
Expand Down
118 changes: 117 additions & 1 deletion src/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,23 @@
#define FLASH_L1_FPRG 10
#define FLASH_L1_PROG 3

// 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)
#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)
#define STM32G0_FLASH_WRP1BR (STM32G0_FLASH_REGS_ADDR + 0x30)
#define STM32G0_FLASH_PCROP1BSR (STM32G0_FLASH_REGS_ADDR + 0x34)
#define STM32G0_FLASH_PCROP1BER (STM32G0_FLASH_REGS_ADDR + 0x38)
#define STM32G0_FLASH_SECR (STM32G0_FLASH_REGS_ADDR + 0x80)

//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)
Expand Down Expand Up @@ -1601,6 +1618,47 @@ 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.
val |= (flash_page & 0x3F) << 3;
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_F0) || ((sl->flash_type == STLINK_FLASH_TYPE_F1_XL) && (flashaddr < FLASH_BANK2_START_ADDR))) {
/* wait for ongoing op to finish */
wait_flash_busy(sl);
Expand Down Expand Up @@ -1654,7 +1712,8 @@ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr)
}

int stlink_erase_flash_mass(stlink_t *sl) {
if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
/* TODO: User MER bit to mass-erase G0 series. */
if (sl->flash_type == STLINK_FLASH_TYPE_L0 || sl->flash_type == STLINK_FLASH_TYPE_G0) {
/* erase each page */
int i = 0, num_pages = (int) sl->flash_size/sl->flash_pgsz;
for (i = 0; i < num_pages; i++) {
Expand Down Expand Up @@ -1925,7 +1984,64 @@ 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_L0) {
/* use fast word write. todo: half page. */
uint32_t val;
Expand Down

0 comments on commit c1ad2cf

Please sign in to comment.