XIAO BLE nrf52840 requires reset after each flash

Hi everyone,

I’m trying to use SeeedStudio XIAO-nRF52840 Sense with platformIO framework.

I’ve setup the project successfully using this instruction, but now I’m running into a pretty problematic issue.

Every time when I’m changing the code, after uploading it to the board it unplugs and then requires a reset (via double-click on the button on the board).

This essentially means that I cannot communicate over the serial port, since after flashing the port closes and I need to reset it every time to continue working.

I’m using a macOS 13.4.1 with 2,2 GHz 6-Core Intel Core i7 and a USB-C to USB-C connector from Amazon (this one).

I also have the XIAO-nRF52840 (without Sense capabilities), and it pretty much runs into the same issue.
Some other clues that I have (step-by-step):

  1. hard-resetting the device and then connecting it to the USB-C - the port becomes visible:
> ls -la /dev/{tty,cu}.*
  1. Also, the device is visible as a disk
    Screenshot 2023-06-25 at 21.26.03

  2. After flashing (platformIO → build), the port closes, and the disk ejects:

> ls -la /dev/{tty,cu}.*
# no output
  1. The disk also ejects after flashing.

The upload log from platformIO:

 *  Executing task: platformio run --target upload --upload-port /dev/cu.usbmodem14101 

Processing adafruit_feather_nrf52840 (platform: nordicnrf52; board: xiao_ble_sense; framework: arduino)
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/nordicnrf52/xiao_ble_sense.html
PLATFORM: Nordic nRF52 (9.6.0) > Seeed Xiao BLE Sense
HARDWARE: NRF52840 64MHz, 243KB RAM, 796KB Flash
DEBUG: Current (blackmagic) External (blackmagic, cmsis-dap, jlink, stlink)
 - framework-arduinoadafruitnrf52 @ 1.10300.0 (1.3.0) 
 - framework-cmsis @ 2.50700.210515 (5.7.0) 
 - tool-adafruit-nrfutil @ 1.503.0 (5.3) 
 - tool-bossac-nordicnrf52 @ 1.10901.201022 (1.9.1) 
 - tool-openocd @ 2.1100.211028 (11.0) 
 - tool-sreccat @ 1.164.0 (1.64) 
 - toolchain-gccarmnoneeabi @ 1.70201.0 (7.2.1)
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 14 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
Checking size .pio/build/adafruit_feather_nrf52840/firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [          ]   1.2% (used 3084 bytes from 248832 bytes)
Flash: [          ]   2.6% (used 21036 bytes from 815104 bytes)
Configuring upload protocol...
AVAILABLE: blackmagic, cmsis-dap, jlink, nrfjprog, nrfutil, stlink
CURRENT: upload_protocol = nrfutil
Looking for upload port...
Using manually specified: /dev/cu.usbmodem14101
Forcing reset using 1200bps open/close on port /dev/cu.usbmodem14101
Waiting for the new upload port...
Uploading .pio/build/adafruit_feather_nrf52840/firmware.zip
Upgrading target on /dev/cu.usbmodem14101 with DFU package /Users/renarde/Documents/PlatformIO/Projects/sample_nrf52840/.pio/build/adafruit_feather_nrf52840/firmware.zip. Flow control is disabled, Single bank, Touch disabled
Activating new firmware
Device programmed.
==================================================== [SUCCESS] Took 9.35 seconds ====================================================
 *  Terminal will be reused by tasks, press any key to close it. 

Would be nice to get some clear guidance on whenever this is expected behaviour, or if something is misconfigured.

On windows I solved that issue on uninstalling Arduino IDD and installing an older Arduino IDE version
Good luck.

Update - I was able to solve this issue with platformio by doing the following:

  1. Plug-in the board via USB-C
  2. Enter bootloader mode
  3. Unplug
  4. Plug-in again

Verify that port is open via:

ls -la /dev/{tty,cu}.*

Now, use the extra scripts in platformio:

# scripts/monitor_delay.py

# see https://github.com/platformio/platformio-core/issues/3742#issuecomment-1003454439
def wait_for_monitor_port(source, target, env):
    port = env.GetProjectOption("monitor_port")
    if port is None: return

    print(f"Waiting for monitor port {port}...")
    import serial
    while True:

env.AddPostAction("upload", wait_for_monitor_port)

Add this script to your project into scripts/scripts/monitor_delay.py.
Reference this script in platformio.ini file:

extra_scripts = scripts/monitor_delay.py


platformio run --target upload --target monitor

This will provide you almost instant dev loop (change code - run the command - see the changes).
Not sure why such a basic thing is not documented though.

1 Like