Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BMFlash: erase failed #46

Open
ALTracer opened this issue Jun 29, 2024 · 1 comment
Open

BMFlash: erase failed #46

ALTracer opened this issue Jun 29, 2024 · 1 comment
Assignees

Comments

@ALTracer
Copy link

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.

sprintf(cmd, "vFlashErase:%x,%x", (unsigned)rgn->address, (unsigned)(flashsectors * rgn->blocksize));
gdbrsp_xmit(cmd, -1);
size_t rcvd = gdbrsp_recv(cmd, pktsize, 500);
if (!testreply(cmd, rcvd, "OK")) {
notice(BMPERR_FLASHERASE, "Flash erase failed");

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.

/* request CRC from Black Magic Probe */
char cmd[100];
sprintf(cmd, "qCRC:%lx,%lx", saddr, ssize);
gdbrsp_xmit(cmd, -1);
size_t rcvd = gdbrsp_recv(cmd, sizearray(cmd), 3000);
cmd[rcvd] = '\0';
unsigned crc_tgt = (rcvd >= 2 && cmd[0] == 'C') ? strtoul(cmd + 1, NULL, 16) : 0;
if (crc_tgt != crc_src) {
notice(BMPERR_FLASHCRC, "Segment %d data mismatch", segment);

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().

clock_t tstamp_stop = clock();
sprintf(msg, "Completed in %.1f seconds\n", (tstamp_stop - state->tstamp_start) / 1000.0);

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 --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 pushed a commit that referenced this issue Jul 20, 2024
BMFlash: when file given on the command line is not found, flag this as an error, but do not drop back to most recent file.
BMSerial: option for "presets" file (for quickly changing between configurations).
Adaptive timeouts om lengthy GDB-RSP operations, addresses issue #46.
Help dialogs: fix for line-break, better calculation for vertical scrolling.

Signed-off-by: Thiadmer Riemersma <thiadmer@compuphase.com>
@compuphase compuphase self-assigned this Jul 20, 2024
compuphase pushed a commit that referenced this issue Jul 24, 2024
Fix timestamp function used for printing time spent uploading (courtesy ALTracer, issue #46).
Use monotonic timer (in Linux) for timestamp function (courtesy ALTracer, issue #46).
Adaptive timeout for firmware CRC calculation (issue #46).
Avoid 'enumeration value not used' warnings.

Signed-off-by: Thiadmer Riemersma <thiadmer@compuphase.com>
@compuphase
Copy link
Owner

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants