How Do You Use the nRF52840 USB Port and Update Firmware Over DFU?
Last updated 28 June 2026 · 9 min read
Direct Answer
The nRF52840 includes a native USB 2.0 Full Speed (12 Mbps) interface — the only nRF52 variant with USB. Enable it in Zephyr NCS with CONFIG_USB_DEVICE_STACK=y and CONFIG_USB_CDC_ACM=y for a virtual serial port, or CONFIG_MCUBOOT_USB_DFU=y in the child image Kconfig for DFU-class firmware updates. MCUboot DFU requires dual-slot flash partitioning (MCUboot bootloader + primary slot + secondary slot), image signing with imgtool, and triggering the update from the application with boot_request_upgrade() before a reset. On the hardware side, the nRF52840 USB requires an external 32 MHz crystal, series resistors on D+/D−, VBUS detection, and ESD protection diodes.
Detailed Explanation
The nRF52840 is the only device in the nRF52 family with a native USB 2.0 Full Speed interface. It supports USB device mode at 12 Mbps and can implement standard USB classes: CDC ACM (virtual serial port), HID (keyboard, mouse, custom), MSC (mass storage), and DFU class for firmware updates. This page covers both the USB hardware requirements for a custom design and the Zephyr NCS firmware configuration for CDC serial and MCUboot DFU over USB.
USB Hardware Requirements
Before configuring the firmware, the hardware must meet these requirements. Omitting any of them is a common cause of USB enumeration failures on custom nRF52840 boards.
32 MHz crystal: The nRF52840 generates its USB 48 MHz clock from the 64 MHz HFCLK. The HFCLK must run from an external 32 MHz crystal (XTAL) or DCXO — the internal RC oscillator is not accurate enough for USB. The 32 MHz crystal is shared with the BLE radio, so if your design already uses BLE, the crystal is already present. The crystal must meet the nRF52840 product specification requirements for load capacitance (typically 7 pF internal load capacitance per the nRF52840 PS) and ESR. Review the reference circuit in the nRF52840 Product Specification.
Series resistors on D+/D−: Place 22–27 Ω series resistors on both USB D+ and D− lines between the nRF52840 GPIO pads and the USB connector. These resistors reduce reflection and EMC emissions on the USB differential pair at the transition frequency (~12 Mbps). Omitting them increases radiated emissions on the 480 MHz harmonics of the USB signal.
VBUS detection: The nRF52840 needs to know when USB power (5 V VBUS) is present so the firmware can enable the USB stack. Connect VBUS to a GPIO (via a voltage divider to keep the GPIO within 3.3 V logic levels, or through a dedicated VBUS detect circuit) and use it to gate usb_enable() calls. Without VBUS detection, the USB stack will attempt to enumerate without a host connected.
ESD protection: Place TVS diodes on both D+ and D− lines near the USB connector to protect against ESD events during hot-plug cycles. Use TVS diodes rated for USB 2.0 (typically 5 V working voltage, low capacitance < 2 pF to avoid distorting the USB signal eye diagram). Common choices include PRTR5V0U2X, USBLC6-2SC6, or equivalent.
USB connector: For new designs, use USB-C (USB 2.0 Alt Mode). USB-A and USB Micro-B are common in existing designs. Ensure the connector footprint correctly routes D+, D−, VBUS, GND, and (for USB-C) the CC pins with the appropriate 5.1 kΩ pull-downs for device-mode detection.
Zephyr Kconfig for USB CDC ACM
USB CDC ACM creates a virtual serial port (COM port on Windows, /dev/ttyACM0 on Linux) over USB. It is the most common use case for nRF52840 USB in development — it replaces a USB-to-UART bridge chip for logging and UART communication with a host.
CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_CDC_ACM=y
CONFIG_UART_LINE_CTRL=y
CONFIG_LOG=y
CONFIG_LOG_BACKEND_USB_CDC_ACM=y
Application code: In NCS, the USB stack is initialised with:
#include <zephyr/usb/usb_device.h>
int main(void)
{
int ret = usb_enable(NULL);
if (ret) {
/* USB failed to enable — likely no VBUS or hardware issue */
return ret;
}
/* USB is now active; CDC ACM port is enumerated on the host */
}
After usb_enable(), the CDC ACM device appears on the host. Log output via LOG_INF() routes automatically to the CDC ACM port when CONFIG_LOG_BACKEND_USB_CDC_ACM=y is set.
Note on NCS v2.x vs USB stack v2: NCS v2.x introduces the Zephyr USB device stack v2 (CONFIG_USB_DEVICE_STACK_NEXT=y). The v1 and v2 APIs differ; check the NCS release notes for your version to determine which is the default and whether migration is required. The concepts in this page apply to both; API calls may differ slightly.
MCUboot Dual-Slot Partitioning
MCUboot DFU requires dividing the nRF52840's 1 MB flash into three regions: MCUboot bootloader, primary image slot, and secondary image slot. NCS uses the Partition Manager to configure this layout.
Typical partition layout for the nRF52840 (1 MB flash):
| Region | Start address | Size | Purpose |
|---|---|---|---|
| MCUboot bootloader | 0x00000000 | 48 KB | MCUboot itself |
| Primary slot | 0x0000C000 | 464 KB | Active (running) firmware |
| Secondary slot | 0x00080000 | 464 KB | DFU image staging area |
| Scratch (optional) | 0x000F4000 | 24 KB | Swap scratch buffer |
| Settings / Storage | 0x000F6000 | 8 KB | Non-volatile key-value store |
These sizes are typical starting values from Nordic's nRF52840 MCUboot examples; adjust primary and secondary slot sizes to match your application image size, ensuring both slots are equal. All addresses are for illustration — verify against the Partition Manager output for your NCS version and project configuration.
Configure in pm_static.yml (static partition manager, recommended for deterministic builds):
mcuboot:
address: 0x0
size: 0xC000 # 48 KB for MCUboot
mcuboot_primary:
address: 0xC000
size: 0x74000 # 464 KB primary slot
mcuboot_secondary:
address: 0x80000
size: 0x74000 # 464 KB secondary slot
settings_storage:
address: 0xF6000
size: 0x2000 # 8 KB NVS/settings
Place pm_static.yml in your project's root or boards/ directory. NCS detects it automatically during the build.
MCUboot Kconfig (child_image/mcuboot.conf):
CONFIG_MCUBOOT_USB_DFU=y
CONFIG_MCUBOOT_CLEANUP_ARM_CORE=y
CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_CDC_ACM=y
CONFIG_USB_DFU_CLASS=y
These settings configure MCUboot itself (not the application) to expose a USB DFU class interface when it enters DFU mode.
Image Signing with imgtool
MCUboot validates firmware images using asymmetric cryptography before booting them. Every image that goes into a slot must be signed with the MCUboot signing key.
Development key (insecure — dev/testing only):
NCS ships a development signing key at bootloader/mcuboot/root-rsa-2048.pem. This key is public knowledge and must never be used in production. Use it only to verify the DFU workflow end-to-end during development.
Production key generation:
python -m imgtool keygen -k production_key.pem -t ecdsa-p256
python -m imgtool getpub -k production_key.pem > production_key_pub.pem
Store production_key.pem offline and securely — loss of this key means signed firmware can never be created for this product.
Signing the application image:
The NCS build system can sign images automatically if CONFIG_MCUBOOT_SIGNATURE_KEY_FILE is set. For manual signing:
python -m imgtool sign \
--key production_key.pem \
--version 1.2.0 \
--align 4 \
--slot-size 0x74000 \
build/zephyr/zephyr.bin \
build/zephyr/app_signed.bin
The signed binary (app_signed.bin) is the file to transfer via DFU. NCS also produces a dfu_application.zip during the build if MCUboot signing is configured — this is the format used by the nRF Connect mobile app for BLE DFU.
Triggering a DFU Update from the Application
The application must signal to MCUboot that a firmware update is ready before resetting:
#include <zephyr/dfu/mcuboot.h>
void trigger_dfu_update(void)
{
/* Request MCUboot to enter firmware update mode on next boot.
* boot_request_upgrade() sets the swap request flag in flash. */
int err = boot_request_upgrade(BOOT_UPGRADE_TEST);
if (err) {
LOG_ERR("Failed to request upgrade: %d", err);
return;
}
/* Initiate a system reset; MCUboot will handle the rest */
sys_reboot(SYS_REBOOT_COLD);
}
BOOT_UPGRADE_TEST requests a test swap — MCUboot swaps the images, boots the new image, and if the application does not call boot_write_img_confirmed() within a defined number of boots, MCUboot reverts to the previous image. BOOT_UPGRADE_PERM makes the swap permanent without a revert option. Always use BOOT_UPGRADE_TEST in the field so a bad update can be recovered automatically.
MCUboot USB DFU mode: With CONFIG_MCUBOOT_USB_DFU=y, MCUboot exposes a USB DFU class interface when it starts. A host tool (dfu-util or nrfutil) transfers the signed image into the secondary slot over USB. MCUboot then validates the image, performs the swap, and boots the new firmware.
Transfer the image using dfu-util (cross-platform, open source):
dfu-util -d <vid:pid> -a 0 -D app_signed.bin
Or using nrfutil (Nordic's tool):
nrfutil device x-dfu-upload --firmware app_update.zip --serial-number <SNR>
USB vs BLE for Firmware Updates
| Update method | When to use |
|---|---|
| USB DFU (this page) | Factory programming, device physically connected to a computer; fastest transfer rate (~300–400 KB/s at USB FS) |
| BLE DFU (nRF DFU service + nRF Connect app) | Field updates; no USB cable required; user triggers via smartphone |
| SWD / J-Link | Development and production programming; requires debug probe |
See How Does OTA Firmware Update Work? for the full MCUboot OTA workflow over BLE, including the A/B partition model, swap logic, and rollback confirmation process.
Common Mistakes
- No 32 MHz crystal on custom board — the most common cause of USB enumeration failure on custom nRF52840 designs. The internal RC oscillator (
HFINT) cannot maintain USB timing. Ensure the 32 MHz crystal is present in the schematic, correctly loaded, and meets the product specification. - Missing VBUS detection — calling
usb_enable()before VBUS is present wastes power and may cause USB enumeration errors. Gate the USB enable call on a VBUS present signal from a GPIO. - Mismatched slot sizes between partition manager and imgtool — the
--slot-sizeparameter in the imgtool sign command must match the slot size defined inpm_static.yml. A mismatch produces a valid-looking signed image that MCUboot rejects at validation time. - Using the development signing key in production — the MCUboot root RSA key shipped with NCS is public. Any image signed with it can be installed on any device using that key. Generate a unique key pair before shipping; treat the private key as a production secret.
- Not calling
boot_write_img_confirmed()— if the application triggers an upgrade withBOOT_UPGRADE_TESTbut never callsboot_write_img_confirmed()after confirming the new firmware works, MCUboot will revert to the previous image on the next reset. Call this function after the application has passed its own self-test.
Design Considerations
The nRF52840's native USB eliminates the need for a USB-to-UART bridge IC (CP2102, CH340, FT232) in designs that need both BLE and USB serial access — a meaningful cost and BOM reduction. The USB Full Speed interface is sufficient for most firmware update and logging use cases; for high-speed data streaming requirements, the interface (12 Mbps) may be a bottleneck, in which case BLE 2M PHY or a dedicated USB bridge may be more appropriate.
For nRF52840 designs that incorporate USB, see nRF52 Variants: Which Should You Choose? for the hardware capability differences that make the 52840 the only viable choice when USB is required. For MCUboot partition configuration and image signing as they apply across all nRF52 and ESP32 platforms, see How Does OTA Firmware Update Work?.
For nRF52840 firmware development including USB device stack integration, MCUboot DFU over USB and BLE, and signed image production workflows, Zeus Design delivers complete firmware stacks for wearable and IoT products.
Frequently Asked Questions
- Can the nRF52832 or nRF52833 use USB?
- No. The nRF52832 and nRF52833 do not have a native USB interface — they are BLE/802.15.4 SoCs without a USB peripheral. Only the nRF52840 (and the newer nRF5340 dual-core SoC) includes native USB 2.0 Full Speed in the nRF52 product family. If USB is required and you need an nRF52-family device, the nRF52840 is the only option. For designs that must use the nRF52832, add a USB-to-UART bridge IC (e.g. CP2102, CH340) for serial communication, or use DFU over BLE using the Nordic DFU Service.
- Is a 32 MHz crystal mandatory for USB on the nRF52840?
- Yes, for accurate USB operation. The USB Full Speed clock requires a precise 48 MHz clock, generated internally from the 64 MHz HFCLK. The nRF52840's HFCLK can run from either a 32 MHz crystal (most designs) or a DCXO (direct crystal oscillator). The internal RC oscillator (HFINT) is not precise enough for USB — the USB host will detect sync errors and the device will enumerate unreliably or not at all. The 32 MHz crystal must meet the specifications in the nRF52840 product specification: load capacitance, ESR, and frequency accuracy as required by the crystal oscillator circuit. The same crystal is shared with the BLE radio, so there is no additional component cost over a standard BLE design.
- What is the difference between USB DFU class and Nordic DFU protocol?
- USB DFU class is a standard USB device class defined by the USB Implementers Forum (USB DFU specification). MCUboot in NCS can expose a DFU class interface during a bootloader update session, allowing any DFU-capable tool (dfu-util, nrfutil) to transfer a firmware image. Nordic DFU protocol is Nordic's proprietary DFU protocol, typically used over BLE (using the Nordic DFU GATT service and the nRF Connect mobile app). The two are separate transport mechanisms for the same underlying MCUboot dual-slot update process. The signed image format and flash partition layout are shared; only the transfer mechanism differs.
References
Related Questions
nRF52 Variants Compared: Which Should You Choose for Your BLE Product?
Compare nRF52 variants: nRF52840 (USB, 802.15.4), nRF52833 (Thread, no USB), nRF52832 (most widely deployed), and entry-level nRF52811/nRF52810. How to choose.
How Do You Set Up the nRF Connect SDK and Zephyr RTOS for nRF52 Development?
Set up nRF Connect SDK (NCS) for nRF52 development: install tools, create a west workspace, configure Kconfig, build a Zephyr project, and flash with J-Link.
How Does an OTA Firmware Update Work?
OTA firmware updates require dual-bank flash, image verification, and rollback. Covers MCUboot swap, ESP32 OTA API, image signing, and power-loss-safe design.
What Is a Bootloader in an Embedded System?
A bootloader is the first code a microcontroller runs — it validates and launches the application, and enables field firmware updates without a debug probe.
How Do You Implement a BLE Peripheral with Custom GATT Services on nRF52 Using Zephyr?
Implement a BLE peripheral with custom GATT services on nRF52 using Zephyr NCS: service definition, UUIDs, read/write handlers, and notifications.
Nordic nRF Series Compared: nRF52 vs nRF53 vs nRF91
Compare Nordic nRF series: nRF52 (BLE/Thread), nRF53 (dual-core, LE Audio), and nRF91 (cellular LTE-M/NB-IoT/GNSS) — when to choose each for your product.
Related Forum Discussions
nRF5340 network core not starting — BLE stack hangs on bt_enable after migrating from nRF52840
Trying to bring up an nRF5340 DK for the first time. I've done a few nRF52840 projects before so I figured the NCS migration would be fairly
Global variable initialized to non-zero value but always reads as zero in main() — bare-metal STM32
Bit of a basic question maybe, but I'm genuinely stuck. Moving from ESP32/Arduino to bare-metal STM32 (STM32G031, Makefile project, arm-none
nRF52840 BLE advertising not starting — device not showing up in scanner after bt_enable completes
Trying my first Zephyr/NCS project on an nRF52840 DK after mostly doing ESP32 stuff. Following the [BLE GATT peripheral guide](/questions/nr