Facts checked on 16 October 2026
Short answer
In 2026 developers reported on Qorvo’s forum that FiRa sessions on the DWM3001CDK with DW3_QM33 SDK 1.1.1 stop ranging without any notification; in one report each stop followed a late delayed transmission (HPDWARN). As of 16 October 2026 Qorvo had published no root cause or fix, and the FiRa MAC ships only as a pre-compiled library.
Forum data points to Bluetooth LE advertising and tight timing margins. Instrument the driver, count warnings, capture the air interface, check memory, soak-test against pass criteria and escalate with evidence. Meanwhile, a watchdog that restarts the whole MAC keeps devices working.
What has been reported
| Thread and date | Setup | Symptom | Status |
|---|---|---|---|
| “FiRa controller session stops producing ranging rounds silently”, July 2026 | DWM3001CDK, SDK 1.1.1 on FreeRTOS, CLI-based app, SoftDevice S113 7.2.0 advertising, one-to-many DS-TWR, channel 9, 200 ms block | Rounds stop; “No SESSION_STATUS_NTF — no state change, no reason code is ever delivered”. Mean time between failures 5–27 min on one board, about 1–4 h on another with identical firmware | Unresolved; Qorvo staff asked diagnostic questions |
| Same thread, September 2026 reply | QANI accessory as responder, iPhone as controller, S113 7.2.0 | Freezes tied to “BLE advertising while a UWB session is running” | Unresolved; workaround below |
| “FiRa Coordinator Scheduler Behavior Following Delayed-TX HPDWARN Abort”, October 2026 | Coordinator with 5 controlees, 200 ms block, FiRa library R12.7.0 | Two hangs in 8,871 blocks; each after a delayed transmission saw HPDWARN; callbacks stopped while the task stayed alive | Unanswered |
| “UWB Ranging Failure with Recovery on Reset”, January 2026 | SDK 1.1.1 QANI | “Fira Report: err 0xFF”; “Only a full device reset resolves the issue temporarily” | Qorvo staff could not reproduce; unresolved |
| “SDK v1.1.1 examples enter HardFault immediately”, June 2026 | Driver examples on the DWM3001CDK | HardFault at debug start | A community member noted the examples target other boards |
| “FiRa applications: INITF in 1.1.0 and 1.1.1”, February 2026 | Prebuilt CLI firmware | TX_FAILED after INITF | Resolved: erase the chip completely before flashing |
The September reply contains the most useful data so far. With Bluetooth LE advertising every 200 ms while connected, the developer saw about one to five freezes per hour. With advertising stopped there were none in 92 minutes, and with advertising every second there was one. “BLE connection events alone (30 ms connection interval, no advertising) do not cause it.”

Not every stop is silent. A session that goes to IDLE with a reason code is FiRa doing its job. In 2025, Qorvo staff explained one such case, “Session stopped due to inband signal”: the parameter IN_BAND_TERMINATION_ATTEMPT_COUNT “needs to be set to 0” to disable in-band termination on the initiator side.
Why a FiRa session can stop without telling you
Three layers run on the DWM3001CDK’s nRF52833: Qorvo’s DW3000 driver, delivered as source; the MCPS layer; and the FiRa MAC, delivered as a library. Qorvo staff are explicit: “We do not provide source code to the FiRa MAC.” Another Qorvo engineer described the MCPS layer as “the interface between the driver and the higher level stack”, adding that it “is not especially documented because it is mainly used by the Qorvo library”. When the MAC stops scheduling rounds, your code sees nothing unless you look for it.
Ranging rounds depend on exact timing. The MAC programs the DW3000 to transmit or receive at a precise future time. If the host is late, the chip cannot comply, and Qorvo’s API guide describes the result:
- HPDWARN, the half-period warning. “The IC has a status flag warning when the specified start time is more than a half period (of the system clock) away.” The system counter wraps every 17.20 seconds, so a start time “half a period away” in practice means the moment has already passed.
- Aborted transmission. If the host calls
dwt_starttx()too late, “the transmission is aborted (transceiver off) and the dwt_starttx() function returns the -1 error indication.”
The October report shows this chain: HPDWARN set, the driver returns an error, the layer above turns it into a timeout error, and ranging callbacks stop. Whether the MAC should recover by itself is exactly the question the thread asks. Qorvo has not answered it.
What UCI notifications can and cannot tell you
In FiRa’s UCI, SESSION_STATUS_NTF carries the session ID or handle, the new state and a reason code. Android’s open-source UCI definitions list the states INIT (0x00), DEINIT (0x01), ACTIVE (0x02) and IDLE (0x03), and reasons such as 0x01 (maximum ranging round retries reached). Results arrive in SESSION_INFO_NTF with a 32-bit sequence number and a status per measurement, such as 0x21 (RX timeout). Android’s UWB service gives 0 as the UCI default for MAX_RR_RETRY: “Termination is disabled and ranging round attempt is infinite”. So a lost peer shows a growing sequence number with failed measurements, while a silent stall shows a frozen sequence number, no SESSION_STATUS_NTF and a state still reading ACTIVE. A host with UCI access can probe a quiet session, if the firmware implements these commands:
Host -> UWBS SESSION_GET_STATE_CMD GID 0x1, OID 0x06, session ID
UWBS -> Host SESSION_GET_STATE_RSP status, session_state
Host -> UWBS SESSION_GET_RANGING_COUNT_CMD GID 0x2, OID 0x03, session ID
UWBS -> Host SESSION_GET_RANGING_COUNT_RSP status, count (32 bits)
session_state 0x02 (ACTIVE) and a count that stops growing = silent stallWhy would the host be late?
- Interrupt contention with Bluetooth LE. Nordic’s SoftDevice reserves interrupt priority 0 for “timing critical processing”, and “the priorities of the interrupts reserved by the SoftDevice cannot be changed”. UWB handling therefore always runs below the radio work of Bluetooth LE.
- Bursts of radio events. Nordic’s figures for a three-packet advertising event add up to about 257 µs of processor time. Nordic also warns that “the application developer must add the latency of the first and last interrupt for all combinations of roles that are used”.
- Other threads and interrupts. LEAPS, a Qorvo partner, explained a similar case on the forum: “dwt_starttx may return error if another thread or interrupt happens, and cpu has to spend time for that.”
- Task context. The July snapshot lists the stack’s FreeRTOS tasks (llhw_mcps, qworkqueue), and any interrupt can delay them, including the SoftDevice’s levels 0, 1 and 4.
- Flash operations. On the nRF52833, “the CPU is halted if the CPU executes code from the flash while the NVMC is writing to the flash”, and a page erase can take up to 87.5 ms. The SoftDevice schedules flash access around its own radio events, not around UWB rounds.
- Too little lead time. A DW3000 erratum, quoted on Qorvo’s forum from the user manual, describes a case where “neither the HPDWARN event gets set nor does the packet get transmitted” unless the start time is at least the preamble length plus the SFD length plus 20 µs ahead. For a 64-symbol preamble and 8-symbol SFD at 64 MHz PRF, that is about 93 µs. The October report logged residual lead times of about 38.5 and 40.9 µs. That is a hypothesis to test, not a confirmed cause.
Memory is the other usual suspect. One community member traced a similar silent stop to a failed heap allocation at ranging start-up and moved some allocations to static variables; the same user calls the nRF52833 on the kit, which has 128 KB of RAM, “very memory constrained”. In the July snapshot, taken while wedged, the Control task showed 1992/2048 stack usage. Stack and heap margins deserve a check before anyone blames the radio.
Symptom, possible cause, test

| Symptom | Possible cause | Test |
|---|---|---|
| Rounds stop, no notification, tasks alive | The MAC stopped scheduling after a late transmission or an internal error | Read the DW3000 half-period warning counter; log driver return codes; capture the last frames with a sniffer |
| Stops come with Bluetooth LE activity | Interrupt or processor contention with the SoftDevice | Repeat with advertising off, at 1 s and at 200 ms; compare mean time between failures |
| HPDWARN before the stop | Lead time for delayed transmission too short | Log the margin between programmed and current time; try 2 ms slots instead of 1 ms; shorten work in the transmit path |
| Stop after hours, worse on one board | Heap exhaustion, stack overflow, crystal or temperature effects | Track minimum free heap and stack high-water marks; swap boards; check crystal trim |
| “Fira Report: err 0xFF”, only reset helps | Session state lost between phone and accessory | Log out-of-band messages and session IDs; compare session restart with full reset |
| HardFault when examples start | Build for the wrong target, or a library built for another floating-point ABI | Check the target board, compiler flags and linker map |
TX_FAILED right after start | Old flash content or calibration | Erase the whole chip, reload calibration, flash again |
| Session goes IDLE with a reason | Normal FiRa behaviour, such as in-band termination | Read the reason code and adjust the parameter |
Two Qorvo answers support the last rows. On slot timing, a Qorvo engineer wrote that “setting a slot to 1ms makes the scheduling very tight”, so you “may need to relax this setting”. On a custom board, a Qorvo account noted that a crystal trim value of 255 “suggests that your custom design isn’t calibrated/configured properly”.
Four failure patterns: confirm and fix
- Stop after a half-period warning. Likely cause: a late delayed start after which the MAC stops scheduling. Confirm: HPW rises in the last block; the lead time is below preamble plus SFD plus 20 µs. Fix: 2 ms slots (
SLOT_DURATION2400 RSTU, the UCI default) instead of 1 ms, and less interrupt and flash load near rounds. - Stops with advertising. Likely cause: processor contention. Confirm: Radio Notification markers next to the last delayed start; a rate difference between soak-test arms. Fix: stop advertising once connected, as stock QANI does, or advertise every second or slower.
- Thin memory margins. Likely cause: a failed allocation or stack overflow. Confirm:
configUSE_MALLOC_FAILED_HOOK, a non-zeroconfigCHECK_FOR_STACK_OVERFLOW, the largest free heap block, stack high-water marks. Fix: static allocation, larger stacks. - Console silence, ranging alive. Likely cause: the USB or console path. Confirm: the peer still reports or TXF still grows, as Qorvo staff asked in July. Fix: decouple logging from ranging.
A debugging method in eight steps

- Reproduce on a bench. Run the same firmware on several boards with a scripted peer or phone, log automatically and measure mean time between failures. “Sometimes” is not a measurement.
- Log three layers. Application callbacks (rounds per block), FiRa notifications such as
SESSION_STATUS_NTF, and driver return codes. On the DW3000, reading the system time latches it: “any subsequent read will return the same value” until an SPI write, so naive timing logs can lie. - Count events in hardware. The DW3000 event counters include an 8-bit count of half-period warnings, which “relate to late invocation of delayed transmission or reception functionality”. Enable them and log the count with every report.
- Capture the air interface. A UWB sniffer with FiRa decoders shows whether the controller still transmits, whether responders answer and which round was the last. A Bluetooth LE companion capture puts advertising events on the same timeline.
- Build the timing budget. Write down block length, slots per round, slot duration and the delayed-transmission lead time, then add the worst-case interrupt latency of every Bluetooth LE role you run.
- Isolate Bluetooth LE. Vary advertising and connection intervals one at a time. Nordic’s Radio Notification signals, which fire before and after each radio event, help you correlate stops with Bluetooth LE activity.
- Check memory. Record the minimum free heap and the stack high-water mark of every UWB task over long runs, and keep static analysis in the build.
- Compare versions and escalate. Test 1.0.2, 1.1.0 and 1.1.1 where possible; some bugs were fixed between releases. Because the FiRa MAC is closed, a fix must come from Qorvo, so send a complete package: SDK and library version, configuration, failure rate, logs from all three layers, sniffer captures, warning counts and a minimal reproducer.
Keep your own archive of SDK packages. In August 2026 a user reported that the old 1.0.2 download link served 1.1.1 instead, and in September Qorvo staff acknowledged “some issues with downloading this package”.
Instrumentation that does not disturb timing
Markers, RTT and a logic analyser
Instrumentation must cost far less than the 40 µs margins seen in October, so put GPIO markers, one register write each, on the DW3000 interrupt handler, the driver’s delayed-start call, the ranging callback and the SoftDevice’s Radio Notification handler. The DWM3001CDK gives “Access to all DWM3001C GPIOs and interfaces”, and its on-board J-Link reads RTT. Sample at 10 MS/s or more and trigger on a callback gap longer than two blocks. For text logs, SEGGER states that “an average line of text can be output in one microsecond or less” with RTT, which is non-blocking by default. Never use SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL in timing tests, because then “the application will wait when the buffer is full”. This sketch is illustrative; pin numbers are placeholders.
/* Illustrative: logic analyser markers on an nRF52833 running S113.
* Check that nothing else in your build uses SWI1. */
#include "nrf_gpio.h"
#include "nrf_soc.h"
#include "nrf_nvic.h"
#define PIN_DW_ISR NRF_GPIO_PIN_MAP(0, 2) /* high inside the DW3000 ISR */
#define PIN_DX_START NRF_GPIO_PIN_MAP(0, 3) /* pulse at the delayed start */
#define PIN_REPORT NRF_GPIO_PIN_MAP(0, 4) /* pulse per ranging report */
#define PIN_BLE NRF_GPIO_PIN_MAP(0, 5) /* toggles on ACTIVE/nACTIVE */
void RADIO_NOTIFICATION_IRQHandler(void) /* SWI1 on S113 */
{
nrf_gpio_pin_toggle(PIN_BLE);
}
void markers_init(void) /* call right after enabling the SoftDevice */
{
nrf_gpio_cfg_output(PIN_DW_ISR);
nrf_gpio_cfg_output(PIN_DX_START);
nrf_gpio_cfg_output(PIN_REPORT);
nrf_gpio_cfg_output(PIN_BLE);
sd_nvic_ClearPendingIRQ(RADIO_NOTIFICATION_IRQn);
sd_nvic_SetPriority(RADIO_NOTIFICATION_IRQn, 3); /* delayed only by 0, 1 */
sd_nvic_EnableIRQ(RADIO_NOTIFICATION_IRQn);
sd_radio_notification_cfg_set(NRF_RADIO_NOTIFICATION_TYPE_INT_ON_BOTH,
NRF_RADIO_NOTIFICATION_DISTANCE_800US);
}
/* In the driver and the application:
* nrf_gpio_pin_set(PIN_DW_ISR); ...ISR body... nrf_gpio_pin_clear(PIN_DW_ISR);
* nrf_gpio_pin_set(PIN_DX_START); dwt_starttx(...); nrf_gpio_pin_clear(PIN_DX_START);
*/Catching late transmissions in the driver
The driver is source code, so its delayed-start path can log its own margin, as the October reporter did. Qorvo’s guide gives the start-time resolution as “512/(499.2e6*128) seconds”, about 8 ns, because the lowest bit is ignored; one count is therefore about 4.006 ns, and 9,618 counts are 38.5 µs. A positive margin can still be late, because transmission begins at the programmed time “minus the times it needs to send preamble etc.” An illustrative sketch:
/* Illustrative: margin and abort counters in the delayed-TX path */
#include <stdint.h>
#include "deca_device_api.h"
static int32_t dx_min_margin = INT32_MAX; /* counts of about 4.006 ns */
static uint32_t dx_aborts;
int traced_delayed_tx(uint32_t dx_time, uint8_t mode)
{
uint32_t now = dwt_readsystimestamphi32(); /* latches SYS_TIME */
int32_t margin = (int32_t)(dx_time - now); /* valid within +/-8.6 s */
int ret;
dwt_setdelayedtrxtime(dx_time); /* SPI write unlatches it */
ret = dwt_starttx(mode | DWT_START_TX_DELAYED);
if (margin < dx_min_margin) {
dx_min_margin = margin;
}
if (ret == DWT_ERROR) {
dx_aborts++; /* late: TX was aborted */
}
return ret;
}Enable the chip’s counters with dwt_configeventcounters(1) and read them per block with dwt_readeventcounters(), from the driver’s context, because the stack owns the SPI bus. HPW counts half-period warnings in 8 bits and TXF sent frames in 12 bits; on a controller, a TXF delta of zero means it has stopped transmitting. An illustrative per-block reader:
/* Illustrative: per-block counter deltas, called from the driver context */
void diag_block(uint8_t *hpw_delta, uint16_t *txf_delta)
{
static uint8_t hpw_prev;
static uint16_t txf_prev;
dwt_deviceentcnts_t c;
dwt_readeventcounters(&c);
*hpw_delta = (uint8_t)(c.HPW - hpw_prev); /* 8-bit */
*txf_delta = (uint16_t)((c.TXF - txf_prev) & 0x0FFFu); /* 12-bit */
hpw_prev = c.HPW;
txf_prev = c.TXF;
}If HPW rises before every stall, late starts are the likely trigger. If it also rises in blocks that continue, the warning-to-stall ratio is useful evidence for Qorvo. If stalls come without HPW, look at memory.
Timing the Bluetooth LE interaction
Configure Radio Notification with sd_radio_notification_cfg_set() right after enabling the SoftDevice, with a distance between 800 and 5,500 µs. When radio events are closer together than that distance, the signals between them are skipped. Nordic’s timing figures:
| Bluetooth LE activity | Time |
|---|---|
| Connectable advertising, 3 channels | 2,750–5,500 µs |
| Non-connectable advertising, 3 channels | 2,150–2,950 µs |
| Preparation at priority 0 before an event | 167–1,542 µs |
| Longest advertiser interrupt | 128 µs |
| Connection event, LE 1M PHY | from 310 µs |
For each stall, compare the gap from the nearest ACTIVE marker to the last delayed start with healthy blocks. A 5.5 ms advertising event every 200 ms covers 2.75 % of the time, at 1 s only 0.55 %, which agrees in direction with the forum data.
Reading a frozen board
Capture the state before restarting. With a J-Link, the September reporter found the DW3000 IRQ pin low, nothing pending in GPIOTE or the NVIC and no MCU timer armed: in their words, it looks like “the next round was never programmed into the DW3000”. Add SYS_STATUS from dwt_readsysstatuslo() (HPDWARN is bit mask 0x08000000), the counters and memory data, and set the nRF52833 watchdog to pause while the debugger halts the CPU.
What to put in the escalation package
In July, Qorvo staff asked whether ranging had really stopped or only the console output, and for “an example command with run_fira_twr” that replicates the settings. Answer both first. The October report shows useful detail, down to the stack archive’s build hash (R12.7.0-00405-gb33c5c42726c).
| Item | Include |
|---|---|
| Versions | SDK, stack archive, dwt_version_string(), SoftDevice, compiler flags |
| Hardware | Board revision, dwt_getpartid(), dwt_getlotid(), crystal trim |
| Configuration | UWB and Bluetooth LE parameters, flash writes |
| Reproducer | run_fira_twr command or CLI sequence, plus the smallest triggering change |
| Statistics | Stall times and MTBF per board, one factor varied at a time |
| Evidence | Last notifications, return codes, HPW, TXF, margins, SYS_STATUS, memory |
| Captures | Sniffer capture of the stall, Bluetooth LE activity on the same timeline |
| Ruled out | Each exclusion with its experiment |
Qorvo’s one-to-many tutorial gives a baseline for both firmware types; -t -1 runs the scripts “forever until the return/enter key is pressed”:
# UCI firmware: controller first, then each controlee
run_fira_twr -t -1 --node onetomany --dest-mac '[0x1, 0x2]' --n_controlees 2
run_fira_twr -t -1 --node onetomany --mac 0x1 --controlee
run_fira_twr -t -1 --node onetomany --mac 0x2 --controlee
# CLI firmware: the same set-up
initf -multi -paddr=[1,2]
respf -multi -addr=1
respf -multi -addr=2A safety net while you wait for a fix
Two forum users describe the same workaround. Watch a ranging counter in the application; if it stops for a set time, stop every session and the MAC, then start again. One restarted after 15 seconds of silence and ranging resumed in under a second; the other used 2 seconds and saw recovery in about 200 ms.
Three details from those reports matter:
- The teardown calls “all return success on the wedged session — the stack does not know it is wedged”. Your watchdog must judge progress, not return codes.
- “Restarting only the frozen session does NOT recover it when two sessions exist – the whole MAC must be restarted.”
- Log every restart with context and count restarts in field telemetry. A watchdog keeps devices usable; it does not replace a root cause.
One QANI developer found that a MAC restart did not recover every case and that sometimes “only Watchdog can restore it”, so recover in levels: MAC restart first, chip reset if restarts bring no progress.
A progress watchdog in code
This illustrative sketch counts reports in the callback, which in the July set-up “fires on every block, including all-miss blocks”, so a lost peer does not trigger it.
/* Illustrative: progress watchdog for FiRa sessions on FreeRTOS + S113.
* uwb_restart_all() is your function that stops every session and the
* MAC and starts them again; diag_snapshot() saves the stall state. */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "nrf_nvic.h"
#define CHECK_MS 500u
#define STALL_MS 2000u /* 10 blocks at 200 ms */
#define MAX_RESTARTS 3u /* then reset the chip */
extern void uwb_restart_all(void);
extern void diag_snapshot(void);
static volatile uint32_t reports; /* +1 in every ranging report callback */
static volatile uint32_t restarts_in_row;
static TaskHandle_t recovery_task;
void on_ranging_report(void) { reports++; }
static void check_cb(TimerHandle_t t)
{
static uint32_t last, quiet_ms;
(void)t;
if (reports != last) {
last = reports;
quiet_ms = 0;
restarts_in_row = 0;
} else if ((quiet_ms += CHECK_MS) >= STALL_MS) {
quiet_ms = 0;
xTaskNotifyGive(recovery_task); /* restart outside the timer task */
}
}
static void recovery_fn(void *arg)
{
(void)arg;
for (;;) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
diag_snapshot(); /* capture first, then restart */
if (++restarts_in_row > MAX_RESTARTS) {
sd_nvic_SystemReset(); /* level 2: full reset */
}
uwb_restart_all(); /* level 1: MAC restart */
}
}
void progress_watchdog_start(void)
{
xTaskCreate(recovery_fn, "uwb_rec", 512, NULL, tskIDLE_PRIORITY + 2,
&recovery_task);
xTimerStart(xTimerCreate("uwb_wd", pdMS_TO_TICKS(CHECK_MS), pdTRUE,
NULL, check_cb), 0);
}Keep restart counts, the HPW total, the smallest margin, xPortGetMinimumEverFreeHeapSize(), the largest free block from vPortGetHeapStats() and uxTaskGetStackHighWaterMark() (in words) across resets. Behind it all, keep the nRF52833 hardware watchdog. Its timeout is (CRV + 1) / 32768 s, and even with its interrupt enabled the reset follows the TIMEOUT event after only two 32.768 kHz cycles, about 61 µs, so write telemetry continuously.
Prevent it before production
- Soak tests: run many boards for days with realistic Bluetooth LE traffic, because many timing faults appear after hours.
- Release gates: set a minimum mean time between failures for every firmware release and every SDK upgrade.
- Field telemetry: report watchdog restarts, warning counters and minimum free heap from devices in use.
- Architecture options: if Bluetooth LE load is heavy, move Bluetooth LE to its own core. Qorvo staff wrote in September 2026 that the “nRF5340 should be a good option using the M33 build”.
A soak-test harness
Qorvo staff call the CLI commands “meant for being human readable” and recommend the UCI build for scripting. A practical harness:
- Boards: four or more controllers; the July boards ran 5–27 minutes and 1–4 hours between failures on identical firmware.
- Load: the product’s real Bluetooth LE pattern and flash writes.
- Detection: a stall is ten blocks without a new SESSION_INFO_NTF sequence number; probe the console separately.
- Records per board: hours, stalls, restarts, HPW, smallest margin, heap and stack minima, temperature.
An illustrative test plan for comparing advertising settings:
{
"boards": ["A", "B", "C", "D"],
"firmware": "<SDK 1.1.1 build id>",
"block_ms": 200,
"stall_after_blocks": 10,
"arms": [
{"name": "adv_off", "adv_interval_ms": null},
{"name": "adv_1s", "adv_interval_ms": 1000},
{"name": "adv_200", "adv_interval_ms": 200}
],
"order": "interleaved per board",
"pass": {"target_mtbf_h": 24, "confidence": 0.95, "stalls_allowed": 0}
}How long to run and when to pass
For a constant failure rate, NIST’s reliability handbook gives the test time as the MTBF target times a factor: with no failures allowed, 2.30 at 90 % confidence and 3.00 at 95 %; with one failure, 3.89 and 4.74.
| Target MTBF | Confidence | Stalls allowed | Board-hours |
|---|---|---|---|
| 24 h | 90 % | 0 | 55 |
| 24 h | 95 % | 0 | 72 |
| 24 h | 90 % | 1 | 93 |
| 72 h | 95 % | 0 | 216 |
Report per board as well as in total, because pooling board-hours assumes identical boards. The same arithmetic limits the forum data: 92 freeze-free minutes show, at 90 % confidence, only an MTBF above about 40 minutes; showing more than 10 hours would take 23 freeze-free hours.
From our engineering work
Inside Qorvo’s UWB programme, needCode engineers developed firmware, drivers and protocol stacks, including the MAC layer built to the FiRa specification and multi-session scheduling. They also build Qorvo’s public QM35 SDK. Our Modular UWB Sniffer decodes FiRa traffic and adds Bluetooth LE capture of the out-of-band session setup.
How needCode helps
We debug and stabilise products built on the DWM3001C, QM33 and DW3000: bench reproduction with hardware-in-the-loop, logging and sniffer captures, timing and memory analysis, Bluetooth LE scheduling, and escalation packages for Qorvo. For products in the field we add watchdogs, telemetry and soak tests to the release pipeline, and we can take over sustaining engineering for the product.
Frequently asked questions
Why does my FiRa controller session stop ranging on the DWM3001CDK?
Qorvo has not published a root cause. Reports on Qorvo’s forum point to late delayed transmissions (HPDWARN), Bluetooth LE advertising during UWB sessions and memory pressure on the nRF52833. Measure which one applies with three-layer logs, the DW3000 warning counter and a sniffer capture.
What does HPDWARN mean on the DW3000?
It is the half-period warning. Qorvo’s API guide says the chip raises it when a delayed transmit or receive start time is “more than a half period (of the system clock) away”, which in practice means the time has already passed. A late dwt_starttx() is aborted and returns -1.
Why do DW3_QM33 SDK 1.1.1 examples crash with HardFault?
In a June 2026 thread the driver examples were built for a different target than the DWM3001CDK’s nRF52833. Check the target board, compiler flags and the floating-point ABI of the pre-compiled libraries; a mismatch often shows up as a HardFault rather than a link error.
Can I fix the FiRa MAC myself?
Not in the stack itself. Qorvo states: “We do not provide source code to the FiRa MAC.” You can change timing, Bluetooth LE scheduling, memory use and your application, add a MAC-level watchdog and escalate to Qorvo with evidence.
Does Bluetooth LE advertising affect UWB ranging on the DWM3001C?
It can. One developer measured one to five session freezes per hour with advertising every 200 ms, none in 92 minutes without advertising and one with advertising every second. Connection events alone did not cause freezes in that test.
How do I recover a stalled session in the field?
Monitor ranging progress in the application and, after a few seconds without new rounds, stop all sessions and the MAC and start again. Forum users report recovery in about 200 ms to under a second; restarting only the frozen session was not enough when two sessions existed.
Which DW3000 counters show late transmissions?
Enable them with dwt_configeventcounters(1) and read them with dwt_readeventcounters(). HPW counts half-period warnings and TXF sent frames. HPW rising before a stall supports the late-start hypothesis; TXF not growing on a controller shows that it has stopped transmitting.
How long should a soak test run?
For a constant failure rate and no failures allowed, NIST’s factors give the MTBF target times 2.30 at 90 % confidence or 3.00 at 95 %. A 24-hour target at 95 % needs 72 stall-free board-hours, spread over several boards and reported per board.
Sources
- Qorvo Tech Forum: “FiRa controller session stops producing ranging rounds silently” (July–September 2026)
- Qorvo Tech Forum: “FiRa Coordinator Scheduler Behavior Following Delayed-TX HPDWARN Abort” (October 2026)
- Qorvo Tech Forum: “UWB Ranging Failure with Recovery on Reset” (January 2026)
- Qorvo Tech Forum: “SDK v1.1.1 examples enter HardFault immediately on DWM3001CDK” (June 2026) and “FiRa applications: INITF in 1.1.0 and 1.1.1” (February 2026)
- Qorvo Tech Forum: in-band termination (staff, July 2025) and MCPS layer and 1 ms slots (staff, 2024)
- Qorvo Tech Forum: FiRa MAC source code (staff, August 2026)
- Qorvo DW3xxx/QM33xxx Device Driver API Guide (forum attachment, April 2025)
- Qorvo Tech Forum: “DW3000 HPDWARN errata: need clarification” (2022) and DW3000 datasheet v1.1 (distributor copy)
- Qorvo Tech Forum: “Delayed dwt_starttx randomly fails” (2025) and “DW3000 packet transmission aborted” (2024)
- Nordic S140 SoftDevice Specification: interrupt priority levels and advertiser processor usage
- Nordic S113 SoftDevice Specification: interrupt latency with multiple roles and Radio Notification signals
- Qorvo Tech Forum: nRF5340 with DWM3000 for Apple NI (staff, September 2026)
- Qorvo Tech Forum: crystal trim on a custom design (2025) and SDK 1.1.1 download issues (staff, September 2026)
- Qorvo Tech Forum: “Tutorial: How to Use DW3 QM33 SDK for One to Many FiRa Ranging” (staff, December 2024)
- Qorvo Tech Forum: format of the INITF/RESPF log message (staff reply, July 2025) and “Type2AB board calibration” (heap allocation report, September 2026)
- Android Open Source Project: UCI packet definitions (uci_packets.pdl) and FiraOpenSessionParams.java (UCI defaults)
- Nordic S113 SoftDevice headers: nrf_soc.h and nrf_nvic.h (copies in the nrf-softdevice repository)
- Nordic nRF52833 Product Specification: NVMC and WDT
- Nordic S113 SoftDevice Specification: Flash memory API
- Nordic nRF52833 product page, nrfx 2.5.0 GPIO HAL and nRF52 compatibility names
- FreeRTOS kernel: task.h, portable.h, timers.h, projdefs.h and heap_4.c
- SEGGER Knowledge Base: RTT
- NIST/SEMATECH e-Handbook of Statistical Methods, 8.3.1.1: Exponential life distribution (or HPP model) tests
- Qorvo DWM3001CDK product page
About needCode
needCode is an independent embedded engineering company from Kraków, Poland, and an official UWB business partner of Qorvo. Its engineers have worked inside Qorvo’s wireless programmes for more than eight years, including on the public QM35 SDK. needCode is certified to ISO 9001:2015 and ISO/IEC 27001:2022 and is a member of the UWB Alliance. This article does not represent Qorvo. All trademarks belong to their respective owners.

