compuphase / Black-Magic-Probe-Book

A guide plus associated utilities for the Black Magic Probe.
Apache License 2.0
145 stars 27 forks source link

BMFlash: erase failed #46

Open ALTracer opened 2 months ago

ALTracer commented 2 months ago

Hello again. BMFlash is unusable (without tweaks) against blackpill-f411ce platform and AT32F403A target.

Problem 1. vFlashErase throws an "Flash erase failed" error before even proceeding to vFlashWrite. https://github.com/compuphase/Black-Magic-Probe-Book/blob/6010ef300f9c09aec53272c98f06d548f82f7ee7/source/bmp-support.c#L920-L924 I enabled -Ddebug_output=true and adjusted DEBUG_TARGET to get complete in-probe diagnostic logging. Per grabserial a page erase took 38ms on average -- 2048 byte pages, 512+512 KiB in two banks. I wrote a test project in AT32IDE and experimented with .rodata blob sizes to iterate quickly (this is also a flash readback test I used to validate some of my upstream AT32F4 PRs), and around 60 KiB is the bug trigger threshold. Basically BMFlash issues a RSP packet of vFlashErase:8000000:5800 then times out waiting 500ms for a response, despite the probe being actively busy polling on FPEC registers. Judging by ttyBmpTarg output it completes erasing all requested pages, so that target layer engine works -- but the target stays erased (and halted), with BMP awaiting further instructions. I measured ~10 seconds during a per-page erase (effectively mass erase, but that'd be a different command), which is 20 times more than this timeout. Consider either increasing this erase timeout, which postpones the problem, or write a loop to issue vFlashErase commands per single page, these will likely complete fast enough.

Problem 2. I was using highest frequency in SWD mode that is available in-tree, around 6-8 MHz, but it's only relevant for write and readback phases, if any. Of course, after writing a big project (ELF file with 512 KiB of loadable content), then BMFlash throws another error right at the end of verification pass, but I wanted to measure timings. https://github.com/compuphase/Black-Magic-Probe-Book/blob/6010ef300f9c09aec53272c98f06d548f82f7ee7/source/bmp-support.c#L1015-L1023

At the best read speed (bmd_crc32 in-probe reporting) of 125-150 KiB/s it takes about 4 seconds per bank to verify, which is slightly more than 3000ms. Please bump timeout.

Problem 3. There is a stray clock() remaining in bmflash.c whereas everything else was migrated to custom timestamp(). https://github.com/compuphase/Black-Magic-Probe-Book/blob/6010ef300f9c09aec53272c98f06d548f82f7ee7/source/bmflash.c#L1924-L1925 At minimum, please replace to timestamp(), I tried it and this works. At maximum, consider also refactoring timestamp() from gettimeofday() to clock_gettime(CLOCK_MONOTONIC, ) because otherwise timestamp could jump during daylight savings time switch and from NTP adjtime corrections.

Problem 4. Blackpill-f4 in default in-tree configuration does not support qRcmd,tpwr monitor commands, and per RSP returns a Nak with 0 length payload, this triggers an assert somewhere, I had to #if 0 out this block. There is an optional shield with enables this command, so behaviour is not universal.

bmp-bmflash.log

Success screenshot

Worktree differences ```diff diff --git a/source/Makefile.linux b/source/Makefile.linux index e06972e..8642602 100644 --- a/source/Makefile.linux +++ b/source/Makefile.linux @@ -52,11 +52,11 @@ LFLAGS := $(GLFW_LIB) ifdef NDEBUG # retail version - CFLAGS += -DNDEBUG + CFLAGS += -DNDEBUG -O2 LFLAGS += -s else # development version - CFLAGS += -g + CFLAGS += -g -Og LFLAGS += -g endif diff --git a/source/bmflash.c b/source/bmflash.c index 6101d61..bd322bb 100644 --- a/source/bmflash.c +++ b/source/bmflash.c @@ -1284,6 +1284,7 @@ static bool probe_set_options(APPSTATE *state) ok = false; } } +#if 0 strcpy(cmd, "tpwr "); strlcat(cmd, state->tpwr ? "enable" : "disable", sizearray(cmd)); if (bmp_monitor(cmd)) { @@ -1297,6 +1298,7 @@ static bool probe_set_options(APPSTATE *state) bmp_callback(BMPERR_MONITORCMD, "Power to target failed"); ok = false; } +#endif state->set_probe_options = false; } return ok; @@ -1924,7 +1926,7 @@ static bool handle_stateaction(APPSTATE *state, enum nk_collapse_states tab_stat SETSTATE(*state, STATE_IDLE); if (state->download_success && state->print_time) { char msg[100]; - clock_t tstamp_stop = clock(); + unsigned long tstamp_stop = timestamp(); sprintf(msg, "Completed in %.1f seconds\n", (tstamp_stop - state->tstamp_start) / 1000.0); log_addstring(msg); } diff --git a/source/bmp-support.c b/source/bmp-support.c index f299776..5115d0b 100644 --- a/source/bmp-support.c +++ b/source/bmp-support.c @@ -919,7 +919,7 @@ bool bmp_download(void) (unsigned)rgn->address, (unsigned)(flashsectors * rgn->blocksize)); sprintf(cmd, "vFlashErase:%x,%x", (unsigned)rgn->address, (unsigned)(flashsectors * rgn->blocksize)); gdbrsp_xmit(cmd, -1); - size_t rcvd = gdbrsp_recv(cmd, pktsize, 500); + size_t rcvd = gdbrsp_recv(cmd, pktsize, 15000); if (!testreply(cmd, rcvd, "OK")) { notice(BMPERR_FLASHERASE, "Flash erase failed"); free(cmd); @@ -1016,7 +1016,7 @@ bool bmp_verify(void) char cmd[100]; sprintf(cmd, "qCRC:%lx,%lx", saddr, ssize); gdbrsp_xmit(cmd, -1); - size_t rcvd = gdbrsp_recv(cmd, sizearray(cmd), 3000); + size_t rcvd = gdbrsp_recv(cmd, sizearray(cmd), 9000); cmd[rcvd] = '\0'; unsigned crc_tgt = (rcvd >= 2 && cmd[0] == 'C') ? strtoul(cmd + 1, NULL, 16) : 0; if (crc_tgt != crc_src) { ```
compuphase commented 1 month ago

Thank you for the detailed analysis. The last two commits (95cb88c08f7d5640941ec31c96def6cfdb840ed8 and 6797c3e2b17b175381aa9aa74580cf57af858522) address these issues.