ProMicro nRF52840 (V1940)
A nice!nano v2 clone: nRF52840 module on a Pro Micro footprint, USB-C, factory
Adafruit UF2 bootloader with SoftDevice S140 6.1.1. Sold as ProMicro
nRF52840, SuperMini nRF52840, nRF52840 Pro Micro; the ZMK/QMK wireless
keyboard crowd is where most of the documentation lives.
Its failure modes are quiet and all look like "the board is dead": the board
is in neither PlatformIO's board list nor the Arduino core's variant list, so
half of what a tutorial tells you to type does not apply; a missing 32.768 kHz
crystal hangs the SoftDevice with USB still enumerated; and Serial does not
exist until you include a library that the code never otherwise mentions.
reference/board-hardware.md — the complete board reference: full pin map
(silkscreen → Arduino number → P0.xx/P1.xx → peripheral), power, flash and
RAM maps, bootloader layout, clocks, plus a development guide (Part II:
§7 toolchain, §8 peripheral cookbook, §9 flashing and recovery, §10 the
Zephyr board target, §11 symptom → cause → fix table).
reference/recipes.md — copy-paste code: platformio.ini, the board JSON,
variant.h/variant.cpp excerpts, USB CDC + Serial1, SAADC with the
gain math, Wire/SPI, BLE UART, InternalFS, deep sleep, UF2 conversion.
template/ — a project that builds clean, in three variants, plus a
scaffold script. See template/README.md.
Orientation
|
|
| MCU |
nRF52840 QIAA (aQFN73 module) — ARM Cortex-M4F @ 64 MHz, fixed; no PLL to configure |
| Memory |
1 MB internal flash, 256 KB RAM. With S140 6.1.1 + UF2 bootloader the app gets 815,104 B flash (0x26000–0xED000) and 237,568 B RAM (0x20006000–0x20040000) |
| LED |
P0.15 = Arduino pin 11 (LED_BUILTIN), active HIGH, not on the header. P0.26/P0.30 are the fallback candidates on other clone revisions |
| Button |
RESET only — no user button. Double-tap it to reach the bootloader |
| USB |
USB-C, native FS device (no USB-serial chip). Serial = USB CDC via TinyUSB; bootloader enumerates as a NICENANO/PROMICRO mass-storage drive |
| Radio |
BLE 5 / 802.15.4 / ANT via SoftDevice S140 6.1.1 already on the board; Bluefruit is the Arduino API |
| LF clock |
32.768 kHz crystal is often NOT populated on clones. USE_LFRC in variant.h (internal RC) is the safe default; USE_LFXO hangs a board without the crystal |
| ADC |
SAADC, 14-bit max, 10-bit by default, internal 0.6 V ref + 1/6 gain = 0–3.6 V full scale. Channels only on P0.02–P0.05, P0.28–P0.31 — A0 (P1.15) has no ADC |
| Bus defaults |
Wire = D2/D3 (P0.17/P0.20) · SPI = D14/D15/D16 + SS D10 (P1.11/P1.13/P0.10, P0.09) · Serial1 = D0/D1 (P0.08/P0.06) |
| Logic |
3.3 V, not 5 V tolerant; 15 mA per pin (high-drive), 0.5 mA standard drive |
| Power |
USB 5 V → on-board 3.3 V regulator; battery pads on the underside on most revisions. No published schematic for V1940 — treat battery-sense and charger claims as unverified |
| Debug |
SWDIO/SWCLK pads on the back, no header. J-Link, CMSIS-DAP or a WCH-LinkE in ARM mode |
| Toolchain |
PlatformIO + nordicnrf52 10.11.0 + framework-arduinoadafruitnrf52 1.10700.0 (Adafruit core 1.7.0). Zephyr also supports it as promicro_nrf52840/nrf52840/uf2 |
Rules that prevent the expensive mistakes
Each of these produces a failure that looks like something else.
- This board does not exist in PlatformIO — vendor it.
platform- nordicnrf52 10.11.0 ships 44 nRF5 boards, none of them a nice!nano or
Pro Micro clone, and the Adafruit core ships 14 variants, none with this
pin map. Every project needs boards/promicro_nrf52840.json and
boards/variants/promicro_nrf52840/ copied in. Substituting
board = adafruit_feather_nrf52840 builds and flashes — and then every
pin number is wrong and the LED is on a pin this board does not use.
Scaffold from template/ instead of hand-writing them.
"variants_dir": "boards/variants" must be in the board JSON. It is
resolved relative to the project root and is the only thing pointing the
core at your vendored variant.h. Without it the build fails deep inside
the core with cores/nRF5/Uart.h:27:10: fatal error: variant.h: No such file or directory — which reads like a broken core install, not a missing
JSON key.
- Keep
USE_LFRC in variant.h unless you have confirmed the crystal.
Many clones leave the 32.768 kHz LF crystal unpopulated. With USE_LFXO
the SoftDevice waits forever for a clock that never starts: USB still
enumerates, the LED never blinks, Serial never opens — indistinguishable
from a bad flash. USE_LFRC costs ~250 ppm of timing accuracy and a little
sleep current, and always works.
Serial only exists if you #include <Adafruit_TinyUSB.h>. The object
is defined by the TinyUSB library, not by Arduino.h. Omit the include and
the link fails with undefined reference to 'Serial' and
undefined reference to 'Adafruit_USBD_CDC::begin(unsigned long)' — an
error that points at your own setup() and looks like a toolchain problem.
- Never
while (!Serial);. USB CDC is only "open" once a host opens the
port. On a board running from a battery or a charger-only USB port that
loop never exits and the firmware appears bricked. Print unconditionally and
accept that early bytes are lost.
- The board does not enter the bootloader by itself from a cold start.
Double-tap RESET (two presses within ~0.5 s, or bridge RST to GND twice);
the LED starts a slow fade and a
NICENANO/PROMICRO drive appears. A
running sketch with working USB CDC also reboots into DFU on PlatformIO's
1200-baud touch, so repeat uploads often need no button — but if the
previous firmware crashed, hung on rule 3, or never brought USB up, the
touch does nothing and pio run -t upload fails to find a port.
- The SoftDevice FWID in the board JSON must match what is on the board.
PlatformIO packages the DFU zip with
--sd-req 0x00B6 (S140 6.1.1) from
build.softdevice.sd_fwid, and the bootloader rejects a package whose
sd-req it does not recognise. If your board came with S140 7.x, set
sd_version to 7.3.0 and sd_fwid to 0x0123 — and note that Adafruit
core 1.7.0 ships only nrf52840_s140_v6.ld, so you also need a newer core
via platform_packages before nrf52840_s140_v7.ld exists to link against.
A0 is a trap: P1.15 has no ADC channel. The nRF52840's SAADC reaches
only P0.02–P0.05 and P0.28–P0.31; nothing on port 1 is analog. analogRead(A0)
compiles, returns a meaningless number, and looks like a wiring fault. The
real analog pins on the header are A1 (P0.02/AIN0), A2 (P0.29/AIN5),
A3 (P0.31/AIN7).
analogRead returns 10-bit values by default on a 14-bit ADC, and full
scale is a fixed 3.6 V (internal 0.6 V reference × 1/6 gain), not VDD.
Two consequences: a 3.3 V signal reads ~92 % of scale, never 1023; and the
reading does not track the supply, so dividing by 1023 and multiplying by
3.3 is wrong by 9 %. analogReadResolution(12) and scale by 3600/4096 mV.
- The NFC-pins-as-GPIO flag is
CONFIG_NFCT_PINS_AS_GPIOS — with an S.
P0.09/P0.10 are D10 (SS) and D16 (MOSI), and they are NFC antenna pins
until UICR says otherwise. Most clone board JSONs in circulation (including
the one this skill was extracted from) define the singular
-DCONFIG_NFCT_PINS_AS_GPIO, which matches nothing in the core — the
only spelling system_nrf52840.c tests is the plural. Verified: adding the
S grows the build by 104 B and puts the NVMC/UICR write into SystemInit;
without it that code is not compiled at all, and whether SPI works on the
default pins is left to whatever the bootloader happened to leave in UICR.
When the flag is correct the core clears UICR->NFCPINS on first boot and
immediately calls NVIC_SystemReset() — so the first run after flashing
resets once, which looks like a crash loop if you are watching the serial
port. UICR survives reflashing and is only cleared by a full chip erase.
- The linker stops at
0xED000, not at the bootloader. The 28 KB from
0xED000 to 0xF4000 is the Adafruit InternalFS/LittleFS region
(LFS_FLASH_ADDR 0xED000, 7 × 4 KB pages) — it is reserved whether or not
you use it. Firmware larger than 815,104 B fails to link even though the
chip has 1 MB.
- PlatformIO's RAM percentage is 11 KB optimistic on stock board JSONs.
Every Adafruit nRF52840 board definition shipped with platform-nordicnrf52
10.11.0 — and every clone board JSON copied from one — sets
upload.maximum_ram_size to 248,832 B, while the linker script the same
core uses (nrf52840_s140_v6.ld) gives the application
0x20006000–0x20040000 = 237,568 B. The progress bar is computed
against the larger number, so a build reported as comfortably inside RAM
can still overflow at link time. The template's JSON is corrected to
237,568.
- The SoftDevice owns hardware once BLE starts.
Bluefruit.begin()
takes TIMER0, RTC0, several PPI channels, SWI2/SWI4 and all RAM below
0x20006000. Touching those directly after that point produces hard faults
or a silent radio; use the Bluefruit/sd_* APIs instead. Also note the
Adafruit core runs FreeRTOS underneath — loop() is a task, delay()
yields, and a tight busy-wait starves the USB and BLE stacks.
- Only three pins are missing from the header, and one is the LED. P0.15
(LED), P0.26, P0.30 and P0.28 are not broken out on this footprint; a
wiring plan that uses them compiles and does nothing visible. Conversely
P0.00/P0.01 (XL1/XL2) and P0.18 (RESET) are absent from the pin map on
purpose — do not add them.
- 3.3 V logic, not 5 V tolerant. Anything 5 V (a classic HD44780, most
NeoPixel strips at 5 V, an Uno's I2C bus) needs level shifting. This kills
boards silently over hours, not instantly.
When the task is BLE
Everything goes through Bluefruit (#include <bluefruit.h>), which drives the
S140 SoftDevice already flashed on the board — you are not compiling a radio
stack, you are calling one. Bluefruit.begin() is where a wrong LF clock
(rule 3) actually hangs, so if BLE code stops at begin() on a board whose
blink sketch worked, suspect the crystal before the BLE code.
The cost is real: the --ble template variant is 128,676 B flash / 15,588 B
RAM against 20,196 B / 3,092 B for a bare blink — Bluefruit and its LittleFS
bonding store are ~73 KB of that. Bluefruit.begin(peripheral, central) takes
connection counts, and each connection costs RAM out of the same budget.
setTxPower() accepts only −40, −20, −16, −12, −8, −4, 0, +2, +3, +4, +5, +6,
+7, +8 dBm; other values are silently clamped. Bonding data lives in InternalFS
at 0xED000 and survives a reflash — a peer that "won't reconnect after you
changed the code" is usually a stale bond, cleared with
Bluefruit.Periph.clearBonds().
For ZMK/QMK keyboard firmware, do not use this Arduino setup at all: those
build on Zephyr and already have a nice_nano_v2 board target that matches
this hardware. reference/board-hardware.md §10 covers the Zephyr route,
including the pins where upstream's promicro_nrf52840 devicetree disagrees
with the Pro Micro silkscreen.
When the task is low power
The nRF52840's advertised microamps depend on things this board makes easy to
get wrong. USE_LFRC (rule 3) recalibrates the RC oscillator periodically and
costs a few µA over a crystal — if you have the crystal and need sleep
current, that is the one reason to switch to USE_LFXO. The USB CDC stack
keeps the HFCLK and USB peripheral alive whenever a host is attached, so any
current measurement taken over USB measures the USB stack, not your firmware;
measure from battery pads with the CDC variant not even compiled in (the
--minimal template variant exists partly for this). systemOff() from the
core (or sd_power_system_off() under the SoftDevice) reaches the ~0.4 µA
System OFF state, from which only a configured pin wake or reset returns —
and it never returns to the next line, so treat it as a jump to reset.
The on-board 3.3 V regulator's quiescent current is the floor for the whole
board and is not documented for this clone; measured deep-sleep figures for
nice!nano v2 are in the tens of µA. Do not quote a number for V1940 you have
not measured.
Starting a new project
Do not hand-assemble one — the vendored board definition is the hard part.
~/.claude/skills/nrf52840-promicro/template/variants/new-project.sh <target-dir> [--full|--minimal|--ble]
cd <target-dir> && pio run
# double-tap RESET, then:
pio run -t upload -t monitor
--minimal — blink P0.15, no USB stack. 20,196 B flash / 3,092 B
RAM. Flash this first on an unfamiliar board: if the LED does not blink, the
problem is the bootloader dance or your board's LED pin, not your code.
--full (default) — heartbeat + USB-CDC status line + 12-bit ADC on A1 +
die temperature. 55,320 B / 8,772 B.
--ble — heartbeat + BLE Nordic UART Service bridged to USB CDC.
128,676 B / 15,588 B.
All three build as-is with platform-nordicnrf52 10.11.0 + Adafruit core 1.7.0
(verified). Nothing is generated and no paths are embedded, so copying the tree
by hand works identically. template/README.md maps files to subsystems.
When the user already has a project that "can't find the board", prefer copying
template/boards/ into it and setting board = promicro_nrf52840 over
rewriting their code — that is usually the whole fix.
Flashing
pio run # build
# double-tap RESET — LED fades slowly, NICENANO/PROMICRO drive appears
pio run -t upload -t monitor
PlatformIO builds firmware.hex, packages it into firmware.zip (a Nordic DFU
package with --sd-req 0x00B6), touches the port at 1200 baud, and runs
adafruit-nrfutil dfu serial --singlebank. The board reboots into the new
firmware on its own; the CDC port re-enumerates as /dev/cu.usbmodem* or a COM
port a second later, and the monitor's baud rate is ignored.
The drag-and-drop route: convert the hex with
uf2conv.py (family 0xADA52840) and drop
the .uf2 on the bootloader drive; it reboots when the copy finishes.
Recovery. The double-tap bootloader survives any application crash, so a
board that has stopped responding is almost always recoverable that way — try
a slower or faster double-tap, and check the cable carries data. If the
bootloader itself is gone (a bad SWD write, a wrong-SoftDevice flash), the only
way back is SWD on the rear pads with J-Link, pyOCD, or OpenOCD + a CMSIS-DAP
probe: nrf5 mass_erase, then flash
nice_nano_bootloader-0.9.2_s140_6.1.1.hex. Full sequence in
reference/board-hardware.md §9.
Reporting
State honestly what was verified and what was not. In this skill: all three
template variants and the compile-marked recipes build clean against
platform-nordicnrf52 10.11.0 + framework-arduinoadafruitnrf52 1.10700.0; the
board definition, g_ADigitalPinMap and the P0.15 LED come from a working
project for this exact V1940 board. The linker/flash/RAM addresses, the
InternalFS region, the SAADC defaults and the SoftDevice FWIDs were read out
of the installed core and platform sources, not guessed. No current, timing
or analog measurement here was taken with instruments, and V1940 has no
published schematic — the battery charger, battery-sense divider, regulator
quiescent current and any second LED on your revision are unverified. Say so
rather than quoting a nice!nano v2 figure as if it were this board's.
1---2name: nrf52840-promicro3description: ProMicro nRF52840 (V1940)4---56# ProMicro nRF52840 (V1940)78A nice!nano v2 clone: nRF52840 module on a Pro Micro footprint, USB-C, factory9Adafruit UF2 bootloader with SoftDevice S140 6.1.1. Sold as *ProMicro10nRF52840*, *SuperMini nRF52840*, *nRF52840 Pro Micro*; the ZMK/QMK wireless11keyboard crowd is where most of the documentation lives.1213Its failure modes are quiet and all look like "the board is dead": the board14is in neither PlatformIO's board list nor the Arduino core's variant list, so15half of what a tutorial tells you to type does not apply; a missing 32.768 kHz16crystal hangs the SoftDevice with USB still enumerated; and `Serial` does not17exist until you include a library that the code never otherwise mentions.1819- `reference/board-hardware.md` — the complete board reference: full pin map20 (silkscreen → Arduino number → P0.xx/P1.xx → peripheral), power, flash and21 RAM maps, bootloader layout, clocks, **plus** a development guide (Part II:22 §7 toolchain, §8 peripheral cookbook, §9 flashing and recovery, §10 the23 Zephyr board target, §11 symptom → cause → fix table).24- `reference/recipes.md` — copy-paste code: `platformio.ini`, the board JSON,25 `variant.h`/`variant.cpp` excerpts, USB CDC + `Serial1`, SAADC with the26 gain math, `Wire`/`SPI`, BLE UART, InternalFS, deep sleep, UF2 conversion.27- `template/` — a **project that builds clean**, in three variants, plus a28 scaffold script. See `template/README.md`.2930## Orientation3132| | |33|---|---|34| MCU | nRF52840 QIAA (aQFN73 module) — ARM Cortex-M4F @ **64 MHz, fixed**; no PLL to configure |35| Memory | 1 MB internal flash, 256 KB RAM. With S140 6.1.1 + UF2 bootloader the app gets **815,104 B flash** (`0x26000`–`0xED000`) and **237,568 B RAM** (`0x20006000`–`0x20040000`) |36| LED | **P0.15** = Arduino pin `11` (`LED_BUILTIN`), **active HIGH**, not on the header. `P0.26`/`P0.30` are the fallback candidates on other clone revisions |37| Button | **RESET only** — no user button. Double-tap it to reach the bootloader |38| USB | USB-C, native FS device (no USB-serial chip). `Serial` = **USB CDC via TinyUSB**; bootloader enumerates as a `NICENANO`/`PROMICRO` mass-storage drive |39| Radio | BLE 5 / 802.15.4 / ANT via **SoftDevice S140 6.1.1** already on the board; Bluefruit is the Arduino API |40| LF clock | **32.768 kHz crystal is often NOT populated** on clones. `USE_LFRC` in `variant.h` (internal RC) is the safe default; `USE_LFXO` hangs a board without the crystal |41| ADC | SAADC, 14-bit max, **10-bit by default**, internal 0.6 V ref + 1/6 gain = **0–3.6 V full scale**. Channels only on P0.02–P0.05, P0.28–P0.31 — **A0 (P1.15) has no ADC** |42| Bus defaults | `Wire` = D2/D3 (P0.17/P0.20) · `SPI` = D14/D15/D16 + SS D10 (P1.11/P1.13/P0.10, P0.09) · `Serial1` = D0/D1 (P0.08/P0.06) |43| Logic | 3.3 V, **not 5 V tolerant**; 15 mA per pin (high-drive), 0.5 mA standard drive |44| Power | USB 5 V → on-board 3.3 V regulator; battery pads on the underside on most revisions. **No published schematic for V1940** — treat battery-sense and charger claims as unverified |45| Debug | SWDIO/SWCLK pads on the back, no header. J-Link, CMSIS-DAP or a WCH-LinkE in ARM mode |46| Toolchain | PlatformIO + `nordicnrf52` 10.11.0 + `framework-arduinoadafruitnrf52` 1.10700.0 (Adafruit core 1.7.0). Zephyr also supports it as `promicro_nrf52840/nrf52840/uf2` |4748## Rules that prevent the expensive mistakes4950Each of these produces a failure that looks like something else.51521. **This board does not exist in PlatformIO — vendor it.** `platform-53 nordicnrf52` 10.11.0 ships 44 nRF5 boards, none of them a nice!nano or54 Pro Micro clone, and the Adafruit core ships 14 variants, none with this55 pin map. Every project needs `boards/promicro_nrf52840.json` and56 `boards/variants/promicro_nrf52840/` copied in. Substituting57 `board = adafruit_feather_nrf52840` *builds and flashes* — and then every58 pin number is wrong and the LED is on a pin this board does not use.59 Scaffold from `template/` instead of hand-writing them.602. **`"variants_dir": "boards/variants"` must be in the board JSON.** It is61 resolved relative to the project root and is the only thing pointing the62 core at your vendored `variant.h`. Without it the build fails deep inside63 the core with `cores/nRF5/Uart.h:27:10: fatal error: variant.h: No such64 file or directory` — which reads like a broken core install, not a missing65 JSON key.663. **Keep `USE_LFRC` in `variant.h` unless you have confirmed the crystal.**67 Many clones leave the 32.768 kHz LF crystal unpopulated. With `USE_LFXO`68 the SoftDevice waits forever for a clock that never starts: USB still69 enumerates, the LED never blinks, `Serial` never opens — indistinguishable70 from a bad flash. `USE_LFRC` costs ~250 ppm of timing accuracy and a little71 sleep current, and always works.724. **`Serial` only exists if you `#include <Adafruit_TinyUSB.h>`.** The object73 is defined by the TinyUSB library, not by `Arduino.h`. Omit the include and74 the link fails with `undefined reference to 'Serial'` and75 `undefined reference to 'Adafruit_USBD_CDC::begin(unsigned long)'` — an76 error that points at your own `setup()` and looks like a toolchain problem.775. **Never `while (!Serial);`.** USB CDC is only "open" once a host opens the78 port. On a board running from a battery or a charger-only USB port that79 loop never exits and the firmware appears bricked. Print unconditionally and80 accept that early bytes are lost.816. **The board does not enter the bootloader by itself from a cold start.**82 Double-tap RESET (two presses within ~0.5 s, or bridge RST to GND twice);83 the LED starts a slow fade and a `NICENANO`/`PROMICRO` drive appears. A84 *running* sketch with working USB CDC also reboots into DFU on PlatformIO's85 1200-baud touch, so repeat uploads often need no button — but if the86 previous firmware crashed, hung on rule 3, or never brought USB up, the87 touch does nothing and `pio run -t upload` fails to find a port.887. **The SoftDevice FWID in the board JSON must match what is on the board.**89 PlatformIO packages the DFU zip with `--sd-req 0x00B6` (S140 **6.1.1**) from90 `build.softdevice.sd_fwid`, and the bootloader rejects a package whose91 `sd-req` it does not recognise. If your board came with S140 7.x, set92 `sd_version` to `7.3.0` and `sd_fwid` to `0x0123` — **and note that Adafruit93 core 1.7.0 ships only `nrf52840_s140_v6.ld`**, so you also need a newer core94 via `platform_packages` before `nrf52840_s140_v7.ld` exists to link against.958. **`A0` is a trap: P1.15 has no ADC channel.** The nRF52840's SAADC reaches96 only P0.02–P0.05 and P0.28–P0.31; nothing on port 1 is analog. `analogRead(A0)`97 compiles, returns a meaningless number, and looks like a wiring fault. The98 real analog pins on the header are **A1 (P0.02/AIN0), A2 (P0.29/AIN5),99 A3 (P0.31/AIN7)**.1009. **`analogRead` returns 10-bit values by default on a 14-bit ADC,** and full101 scale is a fixed **3.6 V** (internal 0.6 V reference × 1/6 gain), not VDD.102 Two consequences: a 3.3 V signal reads ~92 % of scale, never 1023; and the103 reading does *not* track the supply, so dividing by 1023 and multiplying by104 3.3 is wrong by 9 %. `analogReadResolution(12)` and scale by 3600/4096 mV.10510. **The NFC-pins-as-GPIO flag is `CONFIG_NFCT_PINS_AS_GPIOS` — with an S.**106 P0.09/P0.10 are D10 (`SS`) and D16 (`MOSI`), and they are NFC antenna pins107 until UICR says otherwise. Most clone board JSONs in circulation (including108 the one this skill was extracted from) define the singular109 `-DCONFIG_NFCT_PINS_AS_GPIO`, which **matches nothing in the core** — the110 only spelling `system_nrf52840.c` tests is the plural. Verified: adding the111 S grows the build by 104 B and puts the NVMC/UICR write into `SystemInit`;112 without it that code is not compiled at all, and whether SPI works on the113 default pins is left to whatever the bootloader happened to leave in UICR.114 When the flag is correct the core clears `UICR->NFCPINS` on first boot and115 **immediately calls `NVIC_SystemReset()`** — so the first run after flashing116 resets once, which looks like a crash loop if you are watching the serial117 port. UICR survives reflashing and is only cleared by a full chip erase.11811. **The linker stops at `0xED000`, not at the bootloader.** The 28 KB from119 `0xED000` to `0xF4000` is the Adafruit `InternalFS`/LittleFS region120 (`LFS_FLASH_ADDR 0xED000`, 7 × 4 KB pages) — it is reserved whether or not121 you use it. Firmware larger than 815,104 B fails to link even though the122 chip has 1 MB.12312. **PlatformIO's RAM percentage is 11 KB optimistic on stock board JSONs.**124 Every Adafruit nRF52840 board definition shipped with platform-nordicnrf52125 10.11.0 — and every clone board JSON copied from one — sets126 `upload.maximum_ram_size` to 248,832 B, while the linker script the same127 core uses (`nrf52840_s140_v6.ld`) gives the application128 `0x20006000`–`0x20040000` = **237,568 B**. The progress bar is computed129 against the larger number, so a build reported as comfortably inside RAM130 can still overflow at link time. The template's JSON is corrected to131 237,568.13213. **The SoftDevice owns hardware once BLE starts.** `Bluefruit.begin()`133 takes TIMER0, RTC0, several PPI channels, SWI2/SWI4 and all RAM below134 `0x20006000`. Touching those directly after that point produces hard faults135 or a silent radio; use the Bluefruit/`sd_*` APIs instead. Also note the136 Adafruit core runs **FreeRTOS underneath** — `loop()` is a task, `delay()`137 yields, and a tight busy-wait starves the USB and BLE stacks.13814. **Only three pins are missing from the header, and one is the LED.** P0.15139 (LED), P0.26, P0.30 and P0.28 are not broken out on this footprint; a140 wiring plan that uses them compiles and does nothing visible. Conversely141 P0.00/P0.01 (XL1/XL2) and P0.18 (RESET) are absent from the pin map on142 purpose — do not add them.14315. **3.3 V logic, not 5 V tolerant.** Anything 5 V (a classic HD44780, most144 NeoPixel strips at 5 V, an Uno's I2C bus) needs level shifting. This kills145 boards silently over hours, not instantly.146147## When the task is BLE148149Everything goes through Bluefruit (`#include <bluefruit.h>`), which drives the150S140 SoftDevice already flashed on the board — you are not compiling a radio151stack, you are calling one. `Bluefruit.begin()` is where a wrong LF clock152(rule 3) actually hangs, so if BLE code stops at `begin()` on a board whose153blink sketch worked, suspect the crystal before the BLE code.154155The cost is real: the `--ble` template variant is 128,676 B flash / 15,588 B156RAM against 20,196 B / 3,092 B for a bare blink — Bluefruit and its LittleFS157bonding store are ~73 KB of that. `Bluefruit.begin(peripheral, central)` takes158connection counts, and each connection costs RAM out of the same budget.159`setTxPower()` accepts only −40, −20, −16, −12, −8, −4, 0, +2, +3, +4, +5, +6,160+7, +8 dBm; other values are silently clamped. Bonding data lives in InternalFS161at `0xED000` and survives a reflash — a peer that "won't reconnect after you162changed the code" is usually a stale bond, cleared with163`Bluefruit.Periph.clearBonds()`.164165For ZMK/QMK keyboard firmware, do not use this Arduino setup at all: those166build on Zephyr and already have a `nice_nano_v2` board target that matches167this hardware. `reference/board-hardware.md` §10 covers the Zephyr route,168including the pins where upstream's `promicro_nrf52840` devicetree disagrees169with the Pro Micro silkscreen.170171## When the task is low power172173The nRF52840's advertised microamps depend on things this board makes easy to174get wrong. `USE_LFRC` (rule 3) recalibrates the RC oscillator periodically and175costs a few µA over a crystal — if you *have* the crystal and need sleep176current, that is the one reason to switch to `USE_LFXO`. The USB CDC stack177keeps the HFCLK and USB peripheral alive whenever a host is attached, so any178current measurement taken over USB measures the USB stack, not your firmware;179measure from battery pads with the CDC variant not even compiled in (the180`--minimal` template variant exists partly for this). `systemOff()` from the181core (or `sd_power_system_off()` under the SoftDevice) reaches the ~0.4 µA182System OFF state, from which only a configured pin wake or reset returns —183and it never returns to the next line, so treat it as a jump to reset.184185The on-board 3.3 V regulator's quiescent current is the floor for the whole186board and is **not documented for this clone**; measured deep-sleep figures for187nice!nano v2 are in the tens of µA. Do not quote a number for V1940 you have188not measured.189190## Starting a new project191192Do not hand-assemble one — the vendored board definition is the hard part.193194```sh195~/.claude/skills/nrf52840-promicro/template/variants/new-project.sh <target-dir> [--full|--minimal|--ble]196cd <target-dir> && pio run197# double-tap RESET, then:198pio run -t upload -t monitor199```200201- `--minimal` — blink P0.15, no USB stack. **20,196 B** flash / **3,092 B**202 RAM. Flash this first on an unfamiliar board: if the LED does not blink, the203 problem is the bootloader dance or your board's LED pin, not your code.204- `--full` (default) — heartbeat + USB-CDC status line + 12-bit ADC on A1 +205 die temperature. **55,320 B** / **8,772 B**.206- `--ble` — heartbeat + BLE Nordic UART Service bridged to USB CDC.207 **128,676 B** / **15,588 B**.208209All three build as-is with platform-nordicnrf52 10.11.0 + Adafruit core 1.7.0210(verified). Nothing is generated and no paths are embedded, so copying the tree211by hand works identically. `template/README.md` maps files to subsystems.212213When the user already has a project that "can't find the board", prefer copying214`template/boards/` into it and setting `board = promicro_nrf52840` over215rewriting their code — that is usually the whole fix.216217## Flashing218219```sh220pio run # build221# double-tap RESET — LED fades slowly, NICENANO/PROMICRO drive appears222pio run -t upload -t monitor223```224225PlatformIO builds `firmware.hex`, packages it into `firmware.zip` (a Nordic DFU226package with `--sd-req 0x00B6`), touches the port at 1200 baud, and runs227`adafruit-nrfutil dfu serial --singlebank`. The board reboots into the new228firmware on its own; the CDC port re-enumerates as `/dev/cu.usbmodem*` or a COM229port a second later, and the monitor's baud rate is ignored.230231The drag-and-drop route: convert the hex with232[`uf2conv.py`](https://github.com/microsoft/uf2) (family `0xADA52840`) and drop233the `.uf2` on the bootloader drive; it reboots when the copy finishes.234235**Recovery.** The double-tap bootloader survives any application crash, so a236board that has stopped responding is almost always recoverable that way — try237a slower or faster double-tap, and check the cable carries data. If the238bootloader itself is gone (a bad SWD write, a wrong-SoftDevice flash), the only239way back is SWD on the rear pads with J-Link, pyOCD, or OpenOCD + a CMSIS-DAP240probe: `nrf5 mass_erase`, then flash241`nice_nano_bootloader-0.9.2_s140_6.1.1.hex`. Full sequence in242`reference/board-hardware.md` §9.243244## Reporting245246State honestly what was verified and what was not. In this skill: all three247template variants and the compile-marked recipes build clean against248platform-nordicnrf52 10.11.0 + framework-arduinoadafruitnrf52 1.10700.0; the249board definition, `g_ADigitalPinMap` and the P0.15 LED come from a working250project for this exact V1940 board. The linker/flash/RAM addresses, the251`InternalFS` region, the SAADC defaults and the SoftDevice FWIDs were read out252of the installed core and platform sources, not guessed. **No current, timing253or analog measurement here was taken with instruments,** and **V1940 has no254published schematic** — the battery charger, battery-sense divider, regulator255quiescent current and any second LED on your revision are unverified. Say so256rather than quoting a nice!nano v2 figure as if it were this board's.