Published on July 2, 2025 · Reading time: 6 minutes
Waveshare Core52840 is a small (18 × 13.5 mm) breakout board featuring a Nordic nRF52840 microcontroller and some additional components (decoupling capacitors, crystal oscillator, antenna circuitry), all in an easy-to-solder form factor with castellated pads.

The microcontroller itself has a 32-bit ARM CPU running at 64 MHz, 256 kB of RAM, 1 MB of flash memory, basic communication protocols, analog-to-digital converter, cryptography engine and Secure Boot, and a variety of wireless technologies such as Bluetooth, NFC or Zigbee. The total power consumption can be as low as 10 mA with BLE on, according to the datasheet.
My goal is to make the damn thing run CircuitPython, no matter (sic!) how limited. I can figure out all the missing parts once I get to the REPL.
Table of Contents
Problem #1: how to wire it
The module is designed to be tested with Waveshare’s evaluation kit, which is a large carrier board with LEDs, buttons, LDR, buzzer, voltage regulator, USB-to-UART adapter, CR2032 battery retainer, SD card slot, and a lot of expansion headers for compatibility with Arduino shields and Raspberry Pi HATs.
But I need none of that. Since there’s a schematic available, I can eliminate all the unnecessary components one by one.


It’s good news because I own both USB-C and voltage regulator breakout boards. Interesting that both 5 V and 3.3 V are supplied; maybe one of these can be removed.
The pads aren’t that small (1.1 mm pitch), so with enough patience, I was able to make this:

Unfortunately, it didn’t work. No messages shown in dmesg
. Voltages looked
fine, and there were no shorts. This means there’s no useful firmware
preinstalled (for the general audience).
Problem #2: finding the bootloader
Core52840 is not supported by CircuitPython. Well, there are no compatible Waveshare nRF52 boards as of now (July 2025).

But, when browsing through the list of all nRF52 boards, one of these caught my attention: ADM_52840 Breakout board for Holyiot_18010. I’ve found some 18010 modules on AliExpress, and they look suspiciously similar to the Core52840. I don’t know who cloned who, but I think you may know the answer.

Okay, so now I have a (potentially working) CircuitPython UF2 image, but there’s still no UF2 bootloader. Luckily, Adafruit has me covered – there’s a GitHub repo with bootloader binaries for all nRF52 boards that officially run CircuitPython.
Problem #3: installing the bootloader
If only I had a hardware debugger… I don’t want to buy anything for a one-time operation.
Previously, I was using Raspberry Pi with OpenOCD, and decided to give it a try once again.
Raspberry Pi 5 is incompatible because it uses the RP1 coprocessor for GPIO.
This adds three more wires to my cable spaghetti. Pi’s GPIO24 is connected to nRF’s SWDIO, GPIO25 to SWCLK, and there’s a common ground.

There’s an ongoing myth that OpenOCD needs to be built from source, but it’s no longer true. All the necessary packages can be installed directly from Raspberry Pi OS repositories:
sudo apt install openocd telnet wget
Download the firmware:
wget -O bootloader.hex https://github.com/adafruit/Adafruit_nRF52_Bootloader/releases/download/0.9.2/adm_b_nrf52840_1_bootloader-0.9.2_s140_6.1.1.hex
Start the OpenOCD. This configuration will emulate a hardware debugger (OpenOCD can also work with commercially available debuggers), set the nRF52 target, and choose valid pins:
sudo openocd \
-f "interface/raspberrypi-native.cfg" \
-c "transport select swd" \
-f "target/nrf52.cfg" \
-c "adapter gpio swclk 25" \
-c "adapter gpio swdio 24"
Open On-Chip Debugger 0.12.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
swd
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : BCM2835 GPIO JTAG/SWD bitbang driver
Info : clock speed 1006 kHz
Info : SWD DPIDR 0x2ba01477
Info : [nrf52.cpu] Cortex-M4 r0p1 processor detected
Info : [nrf52.cpu] target has 6 breakpoints, 4 watchpoints
Info : starting gdb server for nrf52.cpu on 3333
Info : Listening on port 3333 for gdb connections
Open another terminal and connect to the debugger session via telnet
:
telnet localhost 4444
Trying ::1...
Connection failed: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
>
Stop the execution of the currently running program:
> halt
[nrf52.cpu] halted due to breakpoint, current mode: Handler External Interrupt(22)
xPSR: 0x81000026 pc: 0x00026c24 msp: 0x20005938
Create a backup of existing data, just in case:
> dump_image factory.bin 0 0x100000
dumped 1048576 bytes in 11.661472s (87.811 KiB/s)
As a side quest, I’ve opened the file in hex editor. The original data is
0x2CAC0
bytes long (everything else is 0xFF
) and contains some strings, such
as “The requested TX/RX packet length is too long by %u/%u octets”. Maybe there
is some UART echo program preinstalled?
Erase the flash memory:
> nrf5 mass_erase
nRF52840-xxAA(build code: D0) 1024kB Flash, 256kB RAM
Mass erase completed.
Finally, flash the bootloader:
> program bootloader.hex verify
[nrf52.cpu] halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0xfffffffe msp: 0xfffffffc
** Programming Started **
Padding image section 0 at 0x00000b00 with 1280 bytes
Flash write discontinued at 0x00025de8, next section at 0x000f4000
Adding extra erase range, 0x00025de8 .. 0x00025fff
Flash write discontinued at 0x000fbd10, next section at 0x000fd800
Adding extra erase range, 0x000fbd10 .. 0x000fbfff
Adding extra erase range, 0x000fd000 .. 0x000fd7ff
Adding extra erase range, 0x000fd858 .. 0x000fdfff
Adding extra erase range, 0x10001000 .. 0x10001013
Adding extra erase range, 0x1000101c .. 0x10001fff
** Programming Finished **
** Verify Started **
** Verified OK **
And reset the device:
> reset
That’s it. A new USB device will be detected, and CircuitPython can be installed as usual by dragging a UF2 file onto the virtual drive.

Problem #4: actually using it
This is not really a problem, but I’d like to keep the headings consistent :)
CircuitPython’s REPL works great, feels snappier than on SAMD21 and comparable to RP2040. The write speeds are kinda slow, which is very noticeable when copying new files onto a 256 kB user partition. I’ve read in the nRF52840 datasheet that erasing a single 4 kB block can take as long as 85 ms, maybe that’s the cause.
The standard library includes all the necessary bits (displayio
, json
,
keypad
, etc.). Bluetooth support is provided by the first-party
adafruit_ble
package. Every single pin seems to be available, so I can start testing the
board with extra peripherals, both wired and wireless.
0;🐍BLE:Off | REPL | 10.0.0-alpha.7
Adafruit CircuitPython 10.0.0-alpha.7 on 2025-06-17; AtelierDuMaker nRF52840 Breakout with nRF52840
>>> import board
>>> for p in dir(board): print(p)
...
__class__ __name__ P0_02 P0_03 P0_04 P0_05 P0_06 P0_07
P0_08 P0_09 P0_10 P0_11 P0_12 P0_13 P0_14 P0_15
P0_16 P0_17 P0_19 P0_20 P0_21 P0_22 P0_23 P0_24
P0_25 P0_26 P0_27 P0_28 P0_29 P0_30 P0_31 P1_00
P1_01 P1_02 P1_03 P1_04 P1_05 P1_06 P1_07 P1_08
P1_09 P1_10 P1_11 P1_12 P1_13 P1_14 P1_15 __dict__
board_id
>>>
Check out other blog posts:
-
Restarting unhealthy Compose containers with a one-liner
2025-05-12 · 3 min read
Adding the essential feature Docker Compose does and does not have at the same time.
-
EclairM0, the pocket notepad
2025-04-24 · 14 min read
Tiny device with great performance, long battery life, open hardware design and many use cases. Software written in TinyGo.
-
Tracking libadwaita adoption in Fedora (updated for F42)
2025-04-15 · 2 min read
The complete list of software preinstalled in Fedora, including apps using libadwaita.