Using the Sipeed JTAG Debugger with a Blue Pill

I recently got a Sipeed USB-JTAG/TTL debugger - mainly because I was looking for a JTAG adapter and it looked compact and somewhat sturdy.

You can find these in the usual places (Seedstudio, Aliexpress, etc.) for around 10$. The documentation seems a bit sparse or rather non-existent though. There is a schematic on Github that is as far as I can tell reasonably accurate.

Plugging it in reveals:

$ lsusb
Bus 001 Device 006: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC

which matches the schematic linked above as well.

So what's this FTDI chip?

The FT2232C (datasheet) the debugger uses seems like an interesting chip: It's a USB to serial bridge with 2 channels. The first channel has some extra features: You can configure it in "Multi-Protocol Synchronous Serial Engine (MPSSE)"-mode (application note). With that, you can implement serial protocols with clocking like SPI or JTAG.

Additionally, there are GPIO pins that can be used together with the fixed data in/out and clock pins. The Sipeed debugger connects GPIOL1 aka ADBUS5 to the pin labelled "RST". You could in principle use this pin for anything - but it's of course ideal for controlling the reset signal of your chip.


OpenOCD supports several different FTDI-based adapters with the ftdi interface type but does not define any presets for the Sipeed adapter in particular. It is however configurable and we can make it work for us. To talk to a "Blue Pill" (STM32 F1 family MCU) dev board, we can use a config like this:

# Tell OpenOCD to use the ftdi interface
interface ftdi

# Find the device based on the USB vendor/product ID
ftdi_vid_pid 0x0403 0x6010

# FT2232C IO bits per schematic:
# 0: TCK, Output
# 1: TDO, Output
# 2: TDO, Input
# 3: TMS, Output
# 4: Not connected
# 5: RST, Output
# The first 16bit value is the initial IO state. Just make TMS and RST high
# The second 16bit value is data direction for each pin, 1 = Output
ftdi_layout_init 0x0028 0x2b

# We'll use RST for the system reset, not the JTAG reset. Thus, disable nTRST
# by setting data and enable mask to 0. If you want to use
# the RST pin for nTRST instead, switch this and the nSRST line.
ftdi_layout_signal nTRST -data 0x0 -oe 0x0

# RST is on bit 5, so the mask is 0x20. The pin is directly connected, so
# we don't have an output-enable pin -> set the same mask
ftdi_layout_signal nSRST -data 0x0020 -oe 0x0020

# JTAG mode
transport select jtag

# And finally include the config for the target we're using. You could
# also skip this here and instead pass it via commandline arguments to openocd
source [find target/stm32f1x.cfg]

Finally launching OpenOCD: openocd -f sipeed.cfg. Or to flash an ELF binary: openocd -f sipeed.cfg -c "program thebinarytoflash.elf verify reset exit"

In parallel, you can still use the second serial port as usual.