Skip to content

Instantly share code, notes, and snippets.

@egnor
Last active May 13, 2024 09:53
Show Gist options
  • Save egnor/455d510e11c22deafdec14b09da5bf54 to your computer and use it in GitHub Desktop.
Save egnor/455d510e11c22deafdec14b09da5bf54 to your computer and use it in GitHub Desktop.

DW3000 "missing manual" notes

Overall

The DW3000 is an exciting part, available as a convenient Arduino-shield eval board with good distribution. HOWEVER, this is NOT a "maker friendly" part with SparkFun or Adafruit type tutorials and examples! It is a sophisticated radio that can be the heart of a positioning system, but you have to do quite a lot of heavy lifting to get there.

For basic use, the older-but-still-good DW1000 may be a better choice; interface libraries are available for Arduino and Raspberry Pi. Or look into packaged location-system vendors, like Estimote, Pozyx, Ubitrack and many others.

Documentation and APIs

The DW3000 user manual is actually pretty decent. Expect to cuddle up with this tome. However, it IS incomplete; some important notes are missing, and other parts refer you to the reference driver implementation for details (e.g. accessing OTP memory).

Qorvo would very much like you to use that reference driver library ("API Software and API Guide" here) to access the part. This reference implementation encapsulates lots of undocumented wisdom. HOWEVER, the current version (v1.2) is only available as a binary blob, packaged for the ST NUCLEO-F429ZI or Nordic nRF52840-DK dev boards. You MIGHT be able to use these blobs on another Cortex-M4 or Cortex-M33 based system, writing your own hardware access layer (for SPI and interrupts).

For the moment, source code for an older Qorvo driver version (v1.1) is still available for download; look for the nested DW3000_API_C0_rev4p0.zip. You can compile this for your platform, or just use it as reference. There is even some Raspberry Pi support! Of course, it will be buggier and less polished than newer versions. (I have confirmed with Qorvo's distributor Symmetry Electronics that source code for the current version of the dwt_uwb_driver core is not available to customers, even under NDA. However, support for more micros is in the works.)

As an alternative, you can use the Makerfabs driver for the ESP32 or Emin Eminof's driver for the Arduino, both of which seem to be based on Qorvo's source code.

If you want to write your own driver (or debug an existing one), you'll be running into hidden gotchas. This document is intended to help.

Known undocumented magic

(This is a very incomplete work in progress!)

Accessing OTP memory

The user manual describes the layout of OTP (One Time Programmable) memory but refers to driver functions for reading and writing those values. The Qorvo driver uses these steps to read an OTP register:

  1. set OTP_MAN (bit 0) in OTP_CFG
  2. write the OTP register address (7 bits) to OTP_ADDR
  3. clear OTP_MAN (bit 0) and set OTP_READ (bit 1) in OTP_CFG
  4. Read the value (32 bits) from OTP_RDATA
  5. clear OTP_READ (bit 1) in OTP_CFG

Writing OTP memory is more involved (and more dangerous!) but not typically necessary.

Register initialization from OTP

The OTP memory contains calibration/tuning values which should be loaded into operating registers on startup (and possibly wake from sleep?). There are "KICK" bits in the OTP_SF register to do this, but apparently they don't do a complete job.

From dwt_initialise() in deca_device.c (before PLL setup)

  • set LDO_KICK in OTP_CFG
  • set BIAS_KICK (undocumented bit 8!) in OTP_CFG
  • copy bits 16-20 (5 bits) from OTP BIASTUNE_CAL into bits 0-5 of BIAS_CTRL
  • copy bits 0-5 (6 bits) from OTP XTAL_Trim into XTAL

From dwt_configure() in deca_device.c

  • set DGC_KICK and (if ch9) DGC_SEL in OTP_CFG
  • set OPS_KICK and appropriate OPS_SEL bits in OTP_CFG

The Qorvo driver checks if the OTP values are 0, and uses hardcoded values instead of setting KICK bits if so. On DWM (Arduino-shield) boards, these OTP values should all be programmed.

Receiver calibration

Receiver calibration (aka "PGF calibration") must run successfully at startup (and after wakeup or 20°C temperature change) for decent performance. The manual describes how to start calibration with RX_CAL and check results in RX_CAL_RESI and RX_CAL_RESQ but misses some details:

  • Before running calibration, bits 0 (VDDMS1), 2 (VDDMS3), and 8 (VDDIF2) must be set in LDO_CTRL
  • Before reading RX_CAL_RESI/RESQ, bit 16 in RX_CAL_CFG (the low bit of COMP_DLY) must be set
  • (After calibration, the previous value of LDO_CTRL should be restored to save power.)

Without these steps, calibration will fail (missing LDOs) and the failure won't be noticed (result values not being read properly), but the radio will perform very badly.

DTUNE3

The manual says to always change the default 0xAF5F584C to 0xAF5F35CC. However, the Qorvo driver keeps the default (...584C) in most cases, only using the replacement (...35CC) when sending packets with no data.

RX_CTRL_HI

The Qorvo driver sets this undocumented register at 07:10 to 0x08B5A833 for ch9 (it is left alone for ch5), but this value is the default anyway so you don't have to worry about it.

Delayed TX and HPDWARN

The User Manual says this about detecting too-late submission of a delayed TX request (section 9.4.1):

Due to an errata in the DW3000, there is a case when neither the HPDWARN event gets set nor does the packet get transmitted. ... The host can check for this issue by reading the PMSC_STATE. When this bug occurs, the PMSC_STATE will be “TX” but TX_STATE will be “IDLE”, the TXFRS event will never be set, see state descriptions in 8.2.14.19 Sub-register 0x0F:30 – System state. The host should abort the transmission in this case. This check and recovery is implemented in the published DW3000 dwt-starttx() [sic] API.

However, the PMSC_STATE (aka TSE_STATE) bitfield is inconsistently described, and there are several "TX" states. The Qorvo driver reports an error if SYS_STATE == 0x000D0000 (which looks for a specific "TX" substate).

"SCP" mode

According to the API documentation, preamble codes 25-29 are associated with "SCP", as distinct from 16MHz or 64MHz PRF codes. A header comment describes SCP as "UWB PRF ~100MHz", and the Qorvo driver uses different parameter sets when SCP mode is selected. The chip user manual doesn't mention any of this.

The significance and purpose of "SCP" mode remains a mystery.

List of undocumented registers

These registers are named in deca_regs.h but not in the user manual:

  • 02:34 LCSS_MARGIN - unused in Qorvo driver
  • 03:1C DGC_CFG(0, 1) - hardcoded if OTP DGC data is missing
  • 03:38 DGC_LUT_(0-6)_CFG - hardcoded if OTP DGC data is missing
  • 07:10 RF_RX_CTRL_HI - loaded with magic value 0x08B5A833 for ch9
  • 0E:1E PGF_DELAY_COMP_(LO, HI) - unused in Qorvo driver
  • 11:10 PWR_UP_TIMES_LO - TXFSEQ, but at 11:10 instead of 11:12 (??)

There are also numerous undocumented fields in otherwise-documented registers (e.g. BIAS_KICK in OTP_CFG).

Things which are actually documented but easy to miss

  • If using a 16MHz PRF (PCODE 3 or 4), set RX_TUNE_EN in DGC_CFG
  • Always change THR_64 in DGC_CFG to 0x32
  • Always clear DT0B4 in DTUNE0
  • Always change COMP_DLY in RX_CAL to 0x2
  • Always change LDO_RLOAD to 0x14
  • Always change RF_TX_CTRL_1 to 0x0E
  • Always change RF_TX_CTRL_2 to 0x1C071134 (ch5) or 0x1C010034 (ch9)
  • Always change PLL_CFG to 0x1F3C (ch5) or 0x0F3C (ch9)
  • Always change PLL_CFG_LD in PLL_CAL to 0x8 (documented as 0x81 but that's the whole register)
  • For accurate ranging you need to calibrate antenna delay (see APS014)

References

Qorvo official

Community projects

Notable forum discussions

@egnor
Copy link
Author

egnor commented Feb 16, 2023

4 bits, actually. Here's the manual section I was working from
image
I interpreted the 0x31 and 0x81 as (incorrectly and misleadingly) referring to the value of the entire PLL_CAL register, not just the PLL_CFG_LD nybble. This seems likely because the default value of the entire PLL_CAL register is in fact 0x31, and because as you point out those 8-bit values can't fit in a 4-bit subfield. I'll update the gist to clarify. (Still need to see if I can work in @indietyp's notes!)

@cl0rm
Copy link

cl0rm commented Mar 23, 2023

A huge thanks to @indietyp and @egnor for this. Currently, CH9 is not working very well for me (seems like PLL is not calibrated very well), maybe I will get it working using this.

@cl0rm
Copy link

cl0rm commented Mar 23, 2023

Also, another bit of information I got from Qorvo via Email:
SCP stands for Short Compressed Packet. It allows TXing at 27 MBit/s but is a proprietary mode.
They couldn't say much more about it to me, however they stated that is unsupported.
I'm pretty sure that it uses a PRF of 124,8 MHz, which should also be the "~120MHz" PLL clock frequency. It is exactly double the 62,4 MHz 15.4z PRF. I'm guessing it's similar to the 15.4z High Pulse Rate ERDEV (which supports 124,8 MHz and 249,6 MHz PRF)

@egnor
Copy link
Author

egnor commented Mar 23, 2023

I really need to work all these comments into the original doc for clarity! (Or if one of you wants to fork it and make those edits, I can copy them back. I don't think there's such a thing as a PR for gists? Maybe this should live in a proper repo.)

@gabeart10
Copy link

gabeart10 commented Nov 1, 2023

Thank you for creating these notes! Would anyone happen to have a copy of the DW3000_API_C0_rev4p0.zip? The links to the old v1.1 API seem to only have the newer API (DW3XXX_API_rev9p3.zip) now and I haven't been able to find a copy on the web.

@nickd4
Copy link

nickd4 commented Mar 9, 2024

You can get it from:
https://download.csdn.net/download/weixin_44845841/86263459
However, foreigners can't join CSDN. The way I did it was to buy the product from:
https://duyhieu.com/product/download-form-csdn/
This cost me USD2. And once you complete the purchase you get access to a downloader menu which downloads the file from CSDN on your behalf, you have 3 uses of the downloader menu and no refunds. Hmm. Anyway, it worked for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment