As part of a series on Zephyr with Adafruit hardware, this guide shows how I made a pogo pin SWD debug probe adapter for the CLUE board so I can conveniently program it with Zephyr firmware. My other SWD option was soldering wires to the test points, but I like how pogo pins are neater and less fragile. This guide is meant for people interested in adding support for Adafruit boards to Zephyr. It might also be useful for folks who want to fix a bricked bootloader.
A press fit style a pogo pin adapter would probably be unsuitable for a factory tester, but it's perfect for me as a developer. To work on Zephyr firmware, I want to leave the CLUE on my desk, connected to a debug probe, with easy access to the front panel.
To make this SWD pogo pin adapter for my CLUE board, I designed and 3D printed a base that holds a perma-proto board and CLUE together with precise horizontal and vertical spacing. When the adapter is fully assembled, the perma-proto board connects the CLUE test points to a 0.1" header by way of the pogo pins. For 3D modeling, I used Blender. To get the measurements right, I referred to two CAD models, perma-proto and CLUE, from the Adafruilt_CAD_Parts repository on GitHub.
My procedure was:
- Assemble and test fit the pogo pins with the perma-proto board and CLUE
- Solder the pogo pins, header strip, and battery cable (you can omit the extra reset button stuff)
- Take measurements from the perma-proto with my calipers and from the CLUE .brd file with KiCAD
- Import perma-proto and CLUE CAD models into Blender along with an image from KiCAD showing the testpoint locations
- Arrange the perma-proto and CLUE models floating in space, but with the right relative locations
- Make a model of the negative space where the boards will fit into the plastic base, adding 0.1mm clearance around the PCB models with Blender's Solidify modifier
- Use a Boolean modifier to remove the negative space model from a rectangular prism.
- Clean up glitches in the geometry and bevel most of the edges
- Export to STL and print on a Bambu Lab P1S, using calibrated X-Y Compensation for dimensional accuracy
Note: The pictures here of the assembled perma-proto board show a button, yellow hookup wire, and a pogo pin for the CLUE board's RESET test point. You can ignore those because they don't work and they aren't necessary anyway. I misaligned the pogo pin for the reset test point so it's on solder mask instead of copper. It doesn't matter because OpenOCD can reset the board over SWD. If you want a to do a manual reset, poking the button on the bottom of the board with a guitar pick works well.
Solder Perma-Proto Board
This first photo shows what the top of the board looks like. The power wire plugs into the CLUE's battery jack to get a GND connection (VBAT is NC; I only soldered it in for strain relief). The Kapton tape on the battery cable is also for strain relief.
NOTES:
- You can ignore the button, yellow wires, and upper pogo pins connected to the breadboard row for the yellow wires. The extra reset button it doesn't work because the pogo pin is misaligned on solder mask instead of copper.
- For the battery cable, I cut 15cm off the end of a 50cm battery extension cable. Adafruit sells a 100mm JST PH 2-Pin single ended battery cable, but it would be a little short to turn the corner comfortably. I like having the 5cm of extra slack to help avoid putting strain on the connections.
This photo shows the bottom of the perma-proto board.
Note: I prepared this photo before I realized that the reset pogo pin was slightly misaligned. So, the circuit for the extra reset button doesn't work. You can ignore it. If you omit the reset circuit, then cutting the trace is also not necessary.
Use the "DOWNLOAD STL FILE" button to download the printable 3D model.
3D printing suggestions:
- High speed PLA (I used Bambu Lab PLA Basic on a P1S)
- 0.2mm layer height
- 4 walls
- 15% line infill
- Calibrated X-Y compensation
This is what my print looked like:
Press Fit Perma-Proto
My model uses 0.1mm of clearance around the envelope of the Adafruit_CAD_Parts model for the perma-proto PCB. Since all the edges of the PCB are routed cleanly, the fit should be snug without needing to sand the PCB (assuming your X-Y compensation is well calibrated).
This is how the perma-proto looks assembled with the base:
Press Fit CLUE & Wire SWD Probe
The next picture shows how the final assembly looks with the CLUE board press fit into the base and a Raspberry Pi Debug Probe connected to the SWD header pins. To get the press fit right, I had to remove a small amount of rough fiberglass left on one side of the CLUE's PCB from when it was de-panelized.
Pin header connections from top to bottom:
- GND (connects to CLUE GND by black battery cable wire and Pi Debug Probe by black GND wire)
- RESET (this doesn't work, you can ignore it)
- SWDIO (connects to Pi Debug Probe Yellow RX/SD wire)
- SWCLK (connects to Pi Debug Probe Orange TX/SC wire)
- VBAT (you can ignore this; connects to CLUE VBAT by red battery cable wire)
This closeup shows how the SWD pogo pins connect to the CLUE board once the programmer is fully assembled.
OpenOCD Example: Flash Bootloader
This uses OpenOCD and a Pi Debug Probe to program the the Adafruit CLUE bootloader into the CLUE's nRF52840 flash over SWD. Under normal circumstances, you would use a different method to program the bootloader. Doing it this way can let you recover from a bricked or missing bootloader, when DFU over USB with nrfutil is not possible. Also, as I haven't written a Zephyr board definition for the CLUE yet, using the bootloader as a test case gave me a way to verify that the SWD adapter and openocd work for programming the CLUE's nRF52840 flash.
Here is a terminal capture showing what it looked like when I programmed the Adafruit bootloader onto my bricked CLUE:
$ wget wget https://github.com/adafruit/Adafruit_nRF52_Bootloader/releases/download/0.9.2/clue_nrf52840_bootloader-0.9.2_s140_6.1.1.hex
$ openocd -f interface/cmsis-dap.cfg -f target/nrf52.cfg \
-c "adapter speed 5000" -c init -c targets -c "reset halt" \
-c "program clue_nrf52840_bootloader-0.9.2_s140_6.1.1.hex verify reset exit" \
-c shutdown
Open On-Chip Debugger 0.12.0+dev-gcf9c0b41c (2025-02-09-09:00)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "swd". To override use 'transport select <transport>'.
adapter speed: 5000 kHz
Info : Using CMSIS-DAPv2 interface with VID:PID=0x2e8a:0x000c, serial=E6625888175D0D2C
Info : CMSIS-DAP: SWD supported
Info : CMSIS-DAP: Atomic commands supported
Info : CMSIS-DAP: Test domain timer supported
Info : CMSIS-DAP: FW Version = 2.0.0
Info : CMSIS-DAP: Interface Initialised (SWD)
Info : SWCLK/TCK = 0 SWDIO/TMS = 0 TDI = 0 TDO = 0 nTRST = 0 nRESET = 0
Info : CMSIS-DAP: Interface ready
Info : clock speed 5000 kHz
Info : SWD DPIDR 0x2ba01477
Info : [nrf52.cpu] Cortex-M4 r0p1 processor detected
Info : [nrf52.cpu] target has 6 breakpoints, 4 watchpoints
Info : [nrf52.cpu] Examination succeed
Info : starting gdb server for nrf52.cpu on 3333
Info : Listening on port 3333 for gdb connections
TargetName Type Endian TapName State
-- ------------------ ---------- ------ ------------------ ------------
0* nrf52.cpu cortex_m little nrf52.cpu unknown
[nrf52.cpu] halted due to breakpoint, current mode: Thread
xPSR: 0x01000000 pc: 0x00000a80 msp: 0x20000400
[nrf52.cpu] halted due to breakpoint, current mode: Thread
xPSR: 0x01000000 pc: 0x00000a80 msp: 0x20000400
** Programming Started **
Info : nRF52840-QI/CAAA(build code: D0) 1024kB Flash, 256kB RAM
Info : Padding image section 0 at 0x00000b00 with 1280 bytes
Info : Flash write discontinued at 0x00025de8, next section at 0x000f4000
Warn : Adding extra erase range, 0x00025de8 .. 0x00025fff
Info : Padding image section 2 at 0x000fc6b8 with 4424 bytes
Warn : Adding extra erase range, 0x000fd858 .. 0x000fdfff
Warn : Adding extra erase range, 0x10001000 .. 0x10001013
Warn : Adding extra erase range, 0x1000101c .. 0x10001fff
** Programming Finished **
** Verify Started **
** Verified OK **
** Resetting Target **
shutdown command invoked
$
And, this is how the CLUE looked when openocd reset the board after successfully flashing the bootloader to the nRF52840 internal flash. At this point, the external QSPI flash chip does not contain a working copy of CircuitPython, so the bootloader shows a message about how to install the CircuitPython UF2 file:
Context: Why bother with SWD?
Maybe you're wondering, why would anybody bother to do this when you can just program these boards with UF2 files or nrfutil? There are three main reasons:
- Printf debugging goes a long way, but sometimes debuggers are nice. With an SWD connection, you can use
gdbwithopenocd. - Sometimes UF2 doesn't work. If your flash is erased or corrupted to the point that the firmware can't provide USB connectivity (no mass storage, no serial, no DFU), SWD programming can potentially get you back to a working bootloader.
- Programming with a debug probe makes it so you don't have to press buttons on the microcontroller board to activate the bootloader. Skipping the button pushing can be nice if you compile and flash frequently.
This page (Zephyr Quest: SWD Pogo Adapter for CLUE ) was last updated on February 15, 2025.
Text editor powered by tinymce.