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
Parents Reply Children
  • Porting to NCS is not exactly equal to starting from scratch but its very close indeed.

    I did implement removable device support in the old SDK, but I can't share the source. What I can tell you is that porting to NCS is likely much easier than messing with the SCSI mass storage stuff. The changes were surprisingly many and difficult.

    There is another way: MTP, the stuff that mobile phones use when you plug them into a PC. There are open source implementations which you could try porting to NRF USB driver infrastructure.

    But since you have trouble to get USB running at all with the old SDK that is no longer fully supported here, it may be time to move to the NCS SDK...

Related