Skip to content

Conversation

@mean00
Copy link

@mean00 mean00 commented Dec 21, 2025

Hi, finally had a bit of time:
This is a request for comment regarding the native support of the two wire protocol / rvswdp as used on WCH chips
(at least CH32V1xx/CH32V2xx/CH32V3XX). As far as i could tell it's not present in the current bmp codebase.
I've been using another flavor of that implementaion for a couple of years and afaik without major issues.

It is piggybacking a bit on the SWD implementation by reusing the SWDIO and SWCLK pins.
To avoid duplication a swdptap_common.h file contain the small common part .

I'm fairly sure the integration with the build system and meson setup is not complete.
I've also created a new target for testing cross/swlink-riscv.ini

In short, it implements the rvswd_scan command in native mode, on top of the work done by @perigoso for the wch-link.

Known Limitation/ things that will be reverted when everything else is okay :
1- the CH32 chips will work up to ~ 1.6Mbit/s only.
2- the errors are not necessarily managed correctly, but it seems "good enough"
4- I added temporarily a nop in the loop clock_on/clock_off macro for debug purpose . Those macros are there for readibility sake, i know they are not necessarily loved.
5- i had to change a bit the swlink platform temporarily to suit my test env, please ignore these changes
6- the implementation is very straightforward and use partially reverse engineered information , probably incomplete

Tested with a CH32V307, output is :

rvswdp_scan

Explain the details for making this change.

  • Is a new feature implemented? Yes
  • What existing problem(s) does the pull request solve? Native support of WCH protocol for CH32V1/2/3xx
  • How does the pull request solve these problems? Implement protocol

Your checklist for this pull request

Closing issues

@mean00 mean00 force-pushed the wch_two_wire_protocol branch from 4d803d0 to 235fcaf Compare December 21, 2025 14:44
@dragonmux dragonmux added this to the v2.1 release milestone Dec 22, 2025
@ALTracer
Copy link
Contributor

Hi @mean00. I've checked out this PR as git fetch origin pull/2172/head:feature/wch_two_wire_protocol, added a #define PLATFORM_HAS_RVSWD in blackpill-f4.h, compiled with meson configure -Drvswd_support=true, flashed to blackpill-f411ce, and tried scanning my boards containing CH32V307VCT6, CH32V203C8T6.

DEBUG_INFO() logs appeared on ttyBmpTarg with "WCH : found 0x40620a00 device, which is like 0x20310500 for CH32V203C8T6 per wlink/src/chips.rs, but shifted one bit. And "WCH : found 0x60e00a51 device, which is like 0x30700508 expected for CH32V307VCT6, but shifted again. I've tried changing mon freq 500k, 100k, 2M, 4M, 8M. Does this only work on swlink platform?

Status error : 0xf
Read failed Adr=0x7f Value=0x40620a00 status=0xf
WCH : found 0x40620a00 device
RISC-V debug v0.13 DM
Status error : 0xf
Read failed Adr=0x10 Value=0x3 status=0xf
riscv_dmi_read:  00000010 failed: 2

I don't currently have my WCH-LinkW pair to test with. BMDA needs BMP-remote protocol extended to talk to this new code. Swindle 0.3 (2024-08-20) running on GD32F303CC seems to discover both boards, but it's much more complicated code than BMF. When I dump x/zw 0x1ffff704, it clearly contains the expected IDCODE of 0x20310500.

Flashing a GD32F103CB to swlink and connecting to PA5, PA6 allows me to detect, attach, read/compare and step/stepi the firmware. So clearly it's working, and at 31 KiB/s no less (at max freq via BMF standard target_clk_divider).

WCH : found 0x20310500 device
RISC-V debug v0.13 DM
Hart has 2 data registers and 8 progbuf registers
Attempting 64-bit read on misa
CSR access failed: 2
CSR access failed: 2
CSR access failed: 2
CSR access failed: 2
Attempting 32-bit read on misa
Hart 0: 32-bit RISC-V (arch = dc68d882), rv32imac ISA (exts = 00901105), vendor = 0, impl = dc688001
Hart has 1 trigger slots available
-> riscv32_probe
Unrecognized CH32V003x IDCODE: 0xe339e339
CH32V003x flash size: 65536

@mean00
Copy link
Author

mean00 commented Jan 25, 2026

Thank you for checking this.
To answer your point : more or less.
This code is working (or rather very similar code) on GD32F303, CH32V307 in "swlink bitbanging mode", but also on the RP2040 in PIO mode.
For both swlink and PIO, it is the same protocol code, only the low level send N bits/ receive N bits is very different.

It could be because the reverse engineering is approximate and missed some timing information. The only thing i noticed is it barfs above about 1.6 Mb/s, but that's the speed the wch-link is working if my memory is correct.

Could it be because the blackpill is much more agressive regarding i/o and/or the code lacks barrier to avoid edge jitters ? I'm not familiar with the F4 line but i had some issues of that kind with the SWD protocol on ESP32S3 chips acting as probe.

( On a separate topic, the CH32V203 is confusing gdb because it has not hw breakpoint and the BMP logic thinks there is one)

@ALTracer
Copy link
Contributor

Could it be because the blackpill is much more agressive regarding i/o and/or the code lacks barrier to avoid edge jitters ? I'm not familiar with the F4 line but i had some issues of that kind with the SWD protocol on ESP32S3 chips acting as probe.

Yes, STM32F4 has proper AHB-attached GPIO, which can toggle (change state) every AHB cycle (96 MHz for F411) thanks to Cortex-M4F pipelined writes and a write buffer. STM32F1 only had APB-attached GPIO, and even though APB2 is same 72 MHz as it's AHB, datasheet says I/Os on APB2 with up to 18 MHz toggling speed. In practice STM32F411 is about 2x faster than STM32F103 in bitbanging. CM0+ IOPORT GPIO should also provide single cycle writes but no DMA. ESP32-C3 can perform single cycle pokes at 4 GPIO lines chosen for and via specific CSR access, see Farpatch.
I tried enabling HPRE (Hclk prescaler) of 4 and reflashing, no improvement, at HPRE=8 it stopped enumerating (Hclk>=13.2 MHz for OTG_FS, 96/8=12).

Then I reused a busy delay function from my PR1688 and appended it to IO_ON(), IO_OFF() macros, even though CLK_ON/OFF should be enough (swapped its loops, too). But thus modified firmware displayed better resuts, initial IDCODE started matching, and then I can attach to that chip, step/stepi, break/resume, and compare-sections its Flash at 36 KiB/s, nice! (at approx. 2 MHz)

WCH : found 0x20310500 device
RISC-V debug v0.13 DM
Hart has 2 data registers and 8 progbuf registers
Attempting 64-bit read on misa
CSR access failed: 2
CSR access failed: 2
CSR access failed: 2
CSR access failed: 2
Attempting 32-bit read on misa
Hart 0: 32-bit RISC-V (arch = dc68d882), rv32imac ISA (exts = 00901105), vendor = 0, impl = dc688001
Hart has 1 trigger slots available
-> riscv32_probe

and then either Probing failed, please report unknown RISC-V 32 device or

Calling ch32v003x_probe
Unrecognized CH32V003x IDCODE: 0xe339e339
Calling ch32vx_probe
CH32Vx flash size: 65536
...
stm32_crc32: 0x00000000+4 -> 0ms
stm32_crc32: 0x00000004+252 -> 7ms
stm32_crc32: 0x00000100+7824 -> 210ms, 36 KiB/s
stm32_crc32: 0x00001f90+152 -> 4ms

depending on whether I remember to rebuild with -Dtargets="riscv32,ch32v" -Drvswd_support=true.

One problem remains -- no-scan after rvswd_scan/jtag_scan/swd_scan in any order, only auto_scan works. I suppose some extra delays are missing somewhere. platform_delay(1) should produce a 1ms delay thanks to 1000 Hz SysTick, but if you need RVSWD granularity delays, then use more busy-loops. Any cheap LA should show inconsistent timings in generated digital waveform of SWCLK/SWDIO. Also drive/float matters. I will note that blackpill-f411ce is unbuffered but is smart enough to toggle slew rate at the 2 MHz margin, this is only visible on analog scopes.

DEBUG_TARGET() log from modified BMF
WCH : found 0x20310500 device
RISC-V debug v0.13 DM
Hart has 2 data registers and 8 progbuf registers
Attempting 64-bit read on misa
Reading 64-bit CSR 301
CSR access failed: 2
Reading 64-bit CSR 301
CSR access failed: 2
Reading 64-bit CSR 100a
CSR access failed: 2
Writing 64-bit CSR 100a
CSR access failed: 2
Attempting 32-bit read on misa
Reading 32-bit CSR 301
Reading 32-bit CSR 100a
Writing 32-bit CSR 100a
Reading 32-bit CSR f11
Reading 32-bit CSR 100a
Writing 32-bit CSR 100a
Reading 32-bit CSR f12
Reading 32-bit CSR 100a
Writing 32-bit CSR 100a
Reading 32-bit CSR f13
Reading 32-bit CSR 100a
Writing 32-bit CSR 100a
Reading 32-bit CSR f14
Reading 32-bit CSR 100a
Writing 32-bit CSR 100a
Hart 0: 32-bit RISC-V (arch = dc68d882), rv32imac ISA (exts = 00901105), vendor = 0, impl = dc688001
Writing 32-bit CSR 7a0
Reading 32-bit CSR 100a
Writing 32-bit CSR 100a
Reading 32-bit CSR 7a0
Reading 32-bit CSR 100a
Writing 32-bit CSR 100a
Hart has 1 trigger slots available
Writing 32-bit CSR 7a0
Reading 32-bit CSR 100a
Writing 32-bit CSR 100a
Reading 32-bit CSR 7a4
Reading 32-bit CSR 100a
Writing 32-bit CSR 100a
Reading 32-bit CSR 7a1
Reading 32-bit CSR 100a
Writing 32-bit CSR 100a
Hart trigger slot 0 modes: 0000
-> riscv32_probe
Calling ch32v003x_probe
Unrecognized CH32V003x IDCODE: 0xe339e339
Calling ch32vx_probe
CH32Vx flash size: 65536
Reading 32-bit CSR 7b0
Reading 32-bit CSR 100a
Writing 32-bit CSR 100a
Writing 32-bit CSR 7b0
Reading 32-bit CSR 100a
Writing 32-bit CSR 100a

@mean00
Copy link
Author

mean00 commented Jan 25, 2026

Nice job !

So it can work on the F4 with a bit of love and the time of very qualified people.

( Hart has 1 trigger slots available, no it doesn't :) )

@ALTracer
Copy link
Contributor

Compare with top commit of https://github.com/ALTracer/blackmagic/tree/feature/wch_two_wire_protocol (like so mean00/blackmagic@wch_two_wire_protocol...ALTracer:blackmagic:feature/wch_two_wire_protocol ) if you intend to make it compatible with more in-tree probe platforms, at least it fixes it for F4 by making it slower than necessary. Ignore ch32v.c edits, a full flash driver will be needed later anyway. Works (without my local extra speedup edits) with CH32V203 (stepping, no breakpoints) and CH32V307V (hw breakpoints!). You're probably missing a microsecond delay somewhere, and APB handshaking is long enough to mask it.

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

Successfully merging this pull request may close these issues.

3 participants