diff --git a/flashloaders/stm32l4.s b/flashloaders/stm32l4.s new file mode 100644 index 0000000..4b90863 --- /dev/null +++ b/flashloaders/stm32l4.s @@ -0,0 +1,39 @@ +.global start +.syntax unified + +@ Adapted from stm32f4.s +@ STM32L4's flash controller expects double-word writes, has the flash +@ controller mapped in a different location with the registers we care about +@ moved down from the base address, and has BSY moved to bit 16 of SR. +@ r0 = source +@ r1 = target +@ r2 = wordcount +@ r3 = flash_base +@ r4 = temp +@ r5 = temp + +start: + ldr r3, flash_base +next: + cbz r2, done + ldr r4, [r0] /* copy doubleword from source to target */ + ldr r5, [r0, #4] + str r4, [r1] + str r5, [r1, #4] + +wait: + ldrh r4, [r3, #0x12] /* high half of status register */ + tst r4, #1 /* BSY = bit 16 */ + bne wait + + add r0, #8 + add r1, #8 + sub r2, #2 + b next +done: + bkpt + +.align 2 + +flash_base: + .word 0x40022000 diff --git a/src/stlink-common.c b/src/stlink-common.c index 07b8d67..37beb90 100644 --- a/src/stlink-common.c +++ b/src/stlink-common.c @@ -1503,6 +1503,25 @@ int write_loader_to_sram(stlink_t *sl, stm32_addr_t* addr, size_t* size) { 0x00, 0x3c, 0x02, 0x40, }; + static const uint8_t loader_code_stm32l4[] = { + // flashloaders/stm32l4.s + 0x08, 0x4b, // start: ldr r3, [pc, #32] ; + 0x72, 0xb1, // next: cbz r2, + 0x04, 0x68, // ldr r4, [r0, #0] + 0x45, 0x68, // ldr r5, [r0, #4] + 0x0c, 0x60, // str r4, [r1, #0] + 0x4d, 0x60, // str r5, [r1, #4] + 0x5c, 0x8a, // wait: ldrh r4, [r3, #18] + 0x14, 0xf0, 0x01, 0x0f, // tst.w r4, #1 + 0xfb, 0xd1, // bne.n + 0x00, 0xf1, 0x08, 0x00, // add.w r0, r0, #8 + 0x01, 0xf1, 0x08, 0x01, // add.w r1, r1, #8 + 0xa2, 0xf1, 0x02, 0x02, // add.w r2, r2, #2 + 0xef, 0xe7, // b.n + 0x00, 0xbe, // done: bkpt 0x0000 + 0x00, 0x20, 0x02, 0x40 // flash_base: .word 0x40022000 + }; + const uint8_t* loader_code; size_t loader_size; @@ -1535,6 +1554,9 @@ int write_loader_to_sram(stlink_t *sl, stm32_addr_t* addr, size_t* size) { } else if (sl->chip_id == STM32_CHIPID_L0) { loader_code = loader_code_stm32l0; loader_size = sizeof(loader_code_stm32l0); + } else if (sl->chip_id == STM32_CHIPID_L4) { + loader_code = loader_code_stm32l4; + loader_size = sizeof(loader_code_stm32l4); } else { ELOG("unknown coreid, not sure what flash loader to use, aborting!: %x\n", sl->core_id); return -1; @@ -1710,10 +1732,11 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t (sl->chip_id == STM32_CHIPID_F4_LP) || (sl->chip_id == STM32_CHIPID_F4_HD) || (sl->chip_id == STM32_CHIPID_F411RE) || - (sl->chip_id == STM32_CHIPID_F446)) { + (sl->chip_id == STM32_CHIPID_F446) || + (sl->chip_id == STM32_CHIPID_L4)) { /* todo: check write operation */ - ILOG("Starting Flash write for F2/F4\n"); + ILOG("Starting Flash write for F2/F4/L4\n"); /* flash loader initialization */ if (init_flash_loader(sl, &fl) == -1) { ELOG("init_flash_loader() == -1\n"); @@ -1724,14 +1747,23 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t unlock_flash_if(sl); /* TODO: Check that Voltage range is 2.7 - 3.6 V */ - /* set parallelisim to 32 bit*/ - int voltage = stlink_target_voltage(sl); - if (voltage > 2700) { - printf("enabling 32-bit flash writes\n"); - write_flash_cr_psiz(sl, 2); + if (sl->chip_id != STM32_CHIPID_L4) { + /* set parallelisim to 32 bit*/ + int voltage = stlink_target_voltage(sl); + if (voltage > 2700) { + printf("enabling 32-bit flash writes\n"); + write_flash_cr_psiz(sl, 2); + } else { + printf("Target voltage (%d mV) too low for 32-bit flash, using 8-bit flash writes\n", voltage); + write_flash_cr_psiz(sl, 0); + } } else { - printf("Target voltage (%d mV) too low for 32-bit flash, using 8-bit flash writes\n", voltage); - write_flash_cr_psiz(sl, 0); + /* L4 does not have a byte-write mode */ + int voltage = stlink_target_voltage(sl); + if (voltage <= 2700) { + printf("Target voltage (%d mV) too low for flash writes!\n", voltage); + return -1; + } } /* set programming mode */ @@ -1960,10 +1992,13 @@ int run_flash_loader(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, cons } else if (sl->chip_id == STM32_CHIPID_F2 || sl->chip_id == STM32_CHIPID_F4 || (sl->chip_id == STM32_CHIPID_F4_DE) || sl->chip_id == STM32_CHIPID_F4_LP || sl->chip_id == STM32_CHIPID_F4_HD || (sl->chip_id == STM32_CHIPID_F411RE) || - (sl->chip_id == STM32_CHIPID_F446)) { + (sl->chip_id == STM32_CHIPID_F446) || (sl->chip_id == STM32_CHIPID_L4)) { size_t count = size / sizeof(uint32_t); if (size % sizeof(uint32_t)) ++count; + if (sl->chip_id == STM32_CHIPID_L4) { + if (count % 2) ++count; + } /* setup core */ stlink_write_reg(sl, fl->buf_addr, 0); /* source */ @@ -2021,7 +2056,7 @@ int run_flash_loader(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, cons } else if (sl->chip_id == STM32_CHIPID_F2 || sl->chip_id == STM32_CHIPID_F4 || (sl->chip_id == STM32_CHIPID_F4_DE) || sl->chip_id == STM32_CHIPID_F4_LP || sl->chip_id == STM32_CHIPID_F4_HD || (sl->chip_id == STM32_CHIPID_F411RE) || - (sl->chip_id == STM32_CHIPID_F446)) { + (sl->chip_id == STM32_CHIPID_F446) || (sl->chip_id == STM32_CHIPID_L4)) { stlink_read_reg(sl, 2, &rr); if (rr.r[2] != 0) {