nRF52840 + S140 (SDK 17.1): app_usbd MSC reaches USB STARTED but USBPULLUP stays 0 — host never enumerates

Custom nRF52840 board running S140 (SDK 17.1.0). I'm adding USB Mass Storage (SD card exposed as a removable drive) to existing firmware that already does BLE (NUS) + SD-card recording. The USB stack initializes and runs all the way to APP_USBD_EVT_STARTED, but the host never sees a device — no enumeration, no "device connected" chime, nothing in Windows Device Manager (not even an unknown/error device).

I read the USB registers from inside the firmware right after start, and the D+ pull-up is never asserted:

USBREGSTATUS = 0x00000003   (bit0 VBUSDETECT = 1, bit1 OUTPUTRDY = 1)
USBD->ENABLE  = 0x00000001
USBD->USBPULLUP = 0x00000000   <-- never becomes 1

So VBUS is detected, the USB regulator output is ready, and the peripheral is enabled — but USBPULLUP stays 0, which is presumably why the host sees nothing.

What works

  • Firmware boots fully, BLE + SD recording function normally.
  • On USB plug-in I get, in order (my log strings): USB POWER DETECTED -> USB POWER READY -> SD Card Relinquished -> APP_USBD_START finished -> USB STARTED.
  • USBREGSTATUS = 0x3 confirms VBUS + regulator ready.
  • USBD->ENABLE = 1 confirms the peripheral is enabled.

The problem

USBD->USBPULLUP remains 0x0 even after app_usbd_start(). The device therefore never signals its presence on D+ and the host does not enumerate.

Hardware (believed OK)

  • nRF52840, USB D+/D- routed to the dedicated USB pins (verified against schematic).
  • VBUS routed to the chip; USBREGSTATUS shows VBUSDETECT=1, so VBUS is present.
  • SD card is on SPI (nrf_block_dev_sdc), same instance used by FatFS for recording.

Init sequence (SoftDevice-aware ordering)

Clock and power drivers are initialized BEFORE the SoftDevice is enabled (nrf_drv_power_init returns INVALID_STATE if called after SD enable):

// in power_management_init(), called before ble_stack_init():
nrf_drv_clock_init();
nrf_drv_power_init(NULL);
nrf_pwr_mgmt_init();

// SoftDevice enabled later via nrf_sdh_enable_request() in ble_stack_init()

// after services/SoftDevice up, request HFCLK and wait:
sd_clock_hfclk_request();
uint32_t running = 0;
while (!running) { sd_clock_hfclk_is_running(&running); }

// USB init:
app_usbd_init(&usbd_config);              // returns NRF_ERROR_INVALID_STATE (0x08),
                                          // which I tolerate (does not appear fatal)
app_usbd_class_append(msc_class);
app_usbd_power_events_enable();

app_usbd_init() returns NRF_ERROR_INVALID_STATE (0x08) on this SoftDevice build. I currently treat that as non-fatal (a colleague's working-to-STARTED project does the same). Is that correct, or is that INVALID_STATE the root cause?

sdk_config.h (USB-related)

APP_USBD_ENABLED = 1
APP_USBD_MSC_ENABLED = 1
USBD_ENABLED = 1
NRFX_USBD_ENABLED = 1
APP_USBD_CONFIG_EVENT_QUEUE_ENABLE = 1
APP_USBD_CONFIG_POWER_EVENTS_PROCESS = 1
NRF_BLOCK_DEV_SDC_ENABLED / APP_SDCARD_ENABLED = 1
POWER_ENABLED = 1, NRFX_POWER_ENABLED = 1
NRF_SDH_ENABLED = 1, NRF_SDH_SOC_ENABLED = 1

Handoff (drive mode) — where app_usbd_start() is called

Recording/BLE stop, FatFS is unmounted, then USB is started from the main loop when the device is idle. After start I pump the event queue and check USBPULLUP:

c
f_mount(NULL, "", 0);        // unmount FatFS (I do NOT nrf_blk_dev_uninit)
app_usbd_start();
for (uint32_t i = 0; i < 100; i++) {
    while (app_usbd_event_queue_process()) { }
    if (NRF_USBD->USBPULLUP & 1u) break;
    nrf_delay_ms(1);
}
// USBPULLUP still reads 0x00000000 here
  • My working code here runs app_usbd_init(...) before initializing ble (and the softdevice stack). The error return code likely indicates that the stack won't work.

    The stack included in the SDK does not support removable devices IIRC.

    I believe you needed a recent NCS SDK version in order to have support for removable media in the USB mass storage driver.

Related