blackmagic-debug / blackmagic

In application debugger for ARM Cortex microcontrollers.
GNU General Public License v3.0
3.2k stars 764 forks source link

Loading firmware onto APM32F103CB fails ... #1200

Closed djix123 closed 2 years ago

djix123 commented 2 years ago

Loading firmware onto APM32F103CB fails with firmware 1.8.2. The load command hangs, though regular debugging is possible.

This is another pseudo drop-in replacement for the STM32F103CB.

dragonmux commented 2 years ago

It would be useful if you could enable GDB protocol debugging (set debug remote 1) and get a trace of where it hangs - is it vFlashErase, or vFlashWrite - to help pinpoint what's different about that part vs a real STM32F1.

djix123 commented 2 years ago

Here you go - just hangs after the 'vFlashErase' packet.

Reading symbols from ./cmake-build-debug/APM32F103CB_CMake.elf...
Remote debugging using /dev/cu.usbmodem98B6B8C21
(gdb) set debug remote 1
(gdb) mon tpwr enable
Sending packet: $qRcmd,7470777220656e61626c65#07...Ack
Packet received: O456e61626c696e672074617267657420706f7765720a
Enabling target power
Packet received: OK
(gdb) mon freq 1000k
Sending packet: $qRcmd,6672657120313030306b#52...Ack
Packet received: O4d61782053574a20667265712030303135323061370a
Max SWJ freq 001520a7
Packet received: OK
(gdb) mon swdp_scan
Sending packet: $qRcmd,737764705f7363616e#3c...Ack
Packet received: O54617267657420766f6c746167653a20332e33560a
Target voltage: 3.3V
Packet received: O417661696c61626c6520546172676574733a0a
Available Targets:
Packet received: O4e6f2e20417474204472697665720a
No. Att Driver
Packet received: O2031202020202020434833324631206d656469756d2064656e73697479202873746d3332663120636c6f6e6529204d330a
 1      CH32F1 medium density (stm32f1 clone) M3
Packet received: OK
(gdb) att 1
Attaching to program: /Users/jgiles/SynologyDrive/Documents/MCU/projects/APM32F103CB_CMake/cmake-build-debug/APM32F103CB_CMake.elf, Remote target
Sending packet: $vAttach;1#37...Ack
Packet received: T05thread:1;
Packet vAttach (attach) is supported
Sending packet: $qC#b4...Ack
Packet received: QC1
Sending packet: $Hg1#e0...Ack
Packet received: OK
Sending packet: $qXfer:features:read:target.xml:0,3fb#46...Ack
Packet received: m<?xml version="1.0"?><!DOCTYPE target SYSTEM "gdb-target.dtd"><target>  <architecture>arm</architecture>  <feature name="org.gnu.gdb.arm.m-profile">    <reg name="r0" bitsize="32"/>    <reg name="r1" bitsize="32"/>    <reg name="r2" bitsize="32"/>    <reg name="r3" bitsize="32"/>    <reg name="r4" bitsize="32"/>    <reg name="r5" bitsize="32"/>    <reg name="r6" bitsize="32"/>    <reg name="r7" bitsize="32"/>    <reg name="r8" bitsize="32"/>    <reg name="r9" bitsize="32"/>    <reg name="r10" bitsize="32"/[508 bytes omitted]
Sending packet: $qXfer:features:read:target.xml:3fb,3fb#11...putpkt: Junk: 
Ack
Packet received: mme="faultmask" bitsize="8" save-restore="no"/>    <reg name="control" bitsize="8" save-restore="no"/>  </feature></target>
Sending packet: $qXfer:features:read:target.xml:475,3fb#b6...Ack
Packet received: l
Sending packet: $g#67...Ack
Packet received: e80300007e466cc0b9690000c6680000000000809c550ec0c4a8582ec04f0020cc001000300e0a0d25d173039c9668d6feeefec1c04f00206f170008f017000800000021c04f00204007441200000000
Sending packet: $qOffsets#4b...Ack
Packet received: 
Sending packet: $qSymbol::#5b...Ack
Packet received: 
Packet qSymbol (symbol-lookup) is NOT supported
Sending packet: $qfThreadInfo#bb...Ack
Packet received: m1
Sending packet: $qsThreadInfo#c8...Ack
Packet received: l
Sending packet: $qXfer:memory-map:read::0,3fb#e5...Ack
Packet received: m<memory-map><memory type="ram" start="0x20000000" length="0x5000"/><memory type="flash" start="0x08000000" length="0x20000"><property name="blocksize">0x80</property></memory></memory-map>
Sending packet: $qXfer:memory-map:read::bc,3fb#7a...Ack
Packet received: l
Sending packet: $m80017f0,4#63...Ack
Packet received: 054b1b68
0x080017f0 in Delay (Sending packet: $m800176e,4#68...Ack
Packet received: 00f0b7f8
Sending packet: $m20004fc0,40#ec...Ack
Packet received: 7e466cc0e80300007e466cc0b9690000b3170008e04f0020000000200e5fe33f4d96a98d71f81a3f7e466cc01a0000006250680541300040600d260177140008
ms=1000) at /Users/jgiles/SynologyDrive/Documents/MCU/projects/APM32F103CB_CMake/Src/main.c:113
113     while(delay > ticks);
(gdb) load
Sending packet: $vFlashErase:08000000,00008900#d3...Ack
dragonmux commented 2 years ago

ah, fun.. that's going into the CH32F1 code which means it might by a hybrid between the CH32F1 and STM32F1 for flashing - finding a way to uniquely identify that part is going to be the trick there.

djix123 commented 2 years ago

So I wonder if it went via the STM32F1 code it would work. Maybe I can hack a firmware that pushes it directly through the STM32F1 code.

djix123 commented 2 years ago

Ok, so commenting out the PROBE(ch32f1_probe); line in cortexm.c and allowing a fall through to the PROBE(stm32f1_probe) /* Care for other STM32F1 clones (?) */ successfully allows firmware flashing.

djix123 commented 2 years ago

Checking the APM32F103CB user manual ... the DBGMCU_IDCODE is also 0x410 which is why the part gets caught by ch32f1_probe since that assumes id 0x410 is unique to the CH32F103 ...

dragonmux commented 2 years ago

we're going to have to create some kind of key for the CH32F1 then to distinguish it from the APM32F1 - glad our hunch was right though

djix123 commented 2 years ago

Yup - I had a look through the CH32F1 user manual (assuming its the part from WCH) and its silent on the DBGMCU_IDCODE as far as I could tell

djix123 commented 2 years ago

so, just to add some more spice - I tried out some China Key Systems (CKS32F1s) - these also get detected as CH32F1s and the load fails like the APM32F1s, but then I also tried some 'fake' STM32F1s (i.e. clones that have been labelled as STM32F1s, as opposed to the APM32F1/CKS32F1/CH32F1s that are marked correctly) and these fall through the CH32F1 probe to the subsequent test for non-genuine STM32F1s.

djix123 commented 2 years ago

According to this could maybe use the REV_ID or JDEC_ID to differentiate (or at least the page suggests those are the same for APM and CKS parts) https://mecrisp-stellaris-folkdoc.sourceforge.io/bluepill-diagnostics-v1.6.html

dragonmux commented 2 years ago

oh, interesting - if you think you could make a patch based on that to try and detect between the different clone variants and route them appropriately to the CH32F1, STM32F1 and any other device-specific probe/erase/flash routines required, we'd be happy to test it works with both the v2.1 and v2.3 BMP hardware and merge it in so we can fix this for the time being

djix123 commented 2 years ago

Ok - I'll do a bit more playing around - maybe key off JDEC ID. I don't have a CH32F103 but I do have a CH32V103 (a RISC-V version). They share the same user manual ... so will make the assumption that the reported JDEC ID is the same between the parts (assuming I can find it).

dragonmux commented 2 years ago

That seems like a reasonable assumption to make

djix123 commented 2 years ago

I've put together a minimally invasive patch (vs 1.8.2) that will prevent CKS32F103 and APM32F103 parts being identified as CH32F103 parts based on the JEDEC ID (see below). I'm sure there's a more elegant way of doing this.

BUT I wasn't able to retrieve the JEDEC ID from the CH32V103 part I have. It Hard Faults when trying to read those memory addresses, so I am unable to confirm the JEDEC ID of the CH32F103 part. Thus, it is not sure that this patch is actually valid hence I have not submitted it as a patch request.

I have, though, ordered a CH32F103 development board. When that arrives (I guess 3-4 weeks) I'll test and confirm. In the meantime, if there is someone else who could test, then the patch itself is self explanatory.

diff --git a/src/target/ch32f1.c b/src/target/ch32f1.c
index b9b2588d..b1f5eb48 100644
--- a/src/target/ch32f1.c
+++ b/src/target/ch32f1.c
@@ -55,6 +55,9 @@ static int ch32f1_flash_write(struct target_flash *f,
 #define SR_EOP                                                 0x20
 #define DBGMCU_IDCODE                                  0xE0042000
 #define FLASHSIZE                                              0x1FFFF7E0
+#define JEDEC_IDCODE_BASE                                      0xE00FFFE0
+#define JEDEC_IDCODE_P1                                                (JEDEC_IDCODE_BASE + 0x04)
+#define JEDEC_IDCODE_P2                                                (JEDEC_IDCODE_BASE + 0x08)

 // these are specific to ch32f1
 #define FLASH_MAGIC                                            (FPEC_BASE + 0x34)
@@ -161,6 +164,16 @@ bool ch32f1_probe(target *t)
 {
        if ((t->cpuid & CPUID_PARTNO_MASK) != CORTEX_M3)
                return false;
+
+       uint32_t jedec_p1 = target_mem_read32(t, JEDEC_IDCODE_P1);
+       uint32_t jedec_p2 = target_mem_read32(t, JEDEC_IDCODE_P2);
+       uint8_t jedec_id = ((jedec_p1 & 0xf0) >> 4) | ((jedec_p2 & 0x7) << 4);
+
+       DEBUG_WARN("JEDEC ID: %x \n", jedec_id);
+
+       if (0x3b == jedec_id) // CKS32F103 & APM32F103 have jedec id = 0x3b
+               return false;
+
        const uint32_t idcode = target_mem_read32(t, DBGMCU_IDCODE) & 0x00000fffU;
        if (idcode != 0x410) // only ch32f103
                return false;
djix123 commented 2 years ago

I realized that I actually have a CH32F103 available that I can test ... and this is what I found: the IDCODE = 0x410 and the JEDEC ID = 0x3B exactly like the APM32F103 and CKS32F103 parts but the REVID (upper 16 bits of the DBGMCU_IDCODE) is 0x2000 rather than 0x2003 for the APM32F103 and CKS32F103 parts (or at least the ones I have to hand). Thus, will re-work the patch ... probably still not perfect but hopefully moving in the wright direction.

djix123 commented 2 years ago

I've submitted a patch - tested on STM32F103, APM32F103 and CH32F103 parts. Let me know if you'd like me to rework etc ...

djix123 commented 2 years ago

I've received the CH32F103 board I ordered from Aliexpress (a WeAct BluePlil+). I can confirm that the board identifies correctly as a CH32F103 (e.g. DEVID = 0x410 and REVID=0x2000 per patch). So thats good. One thing to note: if the CH32F103 has a locked flash (as this board did when it arrived) it will be mis-identified as the line subsequent to the REVID check will fail. The code attempts to lock the flash as a check, but that doesn't work for some reason as so fails (hence the mis-identification).

Unlocking the flash and performing a mass-erase then allows the code to identify correctly as a CH32F103 since the flash lock check now works.