Decawave (现在属于 Qorvo)的 DW3000 芯片推出已经有好几年了,它是 DW1000 芯片的升级版。 市场上,DW1000 的价格已经下调,而 DW3000 的价格依然很高。显然,Qorvo 把 DW3000 当作主推产品,而 DW1000 作为存量市场维持。
根据工信部 2024 年发布的《超宽带(UWB)设备无线电管理暂行规定》(https://www.miit.gov.cn/zwgk/zcwj/wjfb/tz/art/2024/art_81f11897939a4a78ad4aad953e9ffc20.html),从 2025 年 8 月 1 日起,UWB 业务的使用频率为 7163-8812MHz,这意味着 DW1000 使用的频率全部都不在允许范围。而 DW3000 支持 Channel 5/9,其中的 Channel 9 中心频率 7987.2MHz, 带宽 499.2MHz,符合工信部要求。
过去的几年中,很多产品是基于 DW1000 开发的,现在是时候升级到 DW3000 了。
我也一样,在过去的几年中,我花费了大量的时候在 DW1000 上。我使用 DW1000 开发了 TDOA 技术的 UWB 定位系统。 最近,我做了 DW3000 的适配工作。从 DW1000 迁移到 DW3000 比我预想的要容易。
DW1000 vs DW3000
大体上来看,DW3000 是 DW1000 的升级版本。简单的看它们有些什么差异:
- 支持的频道不同。DW1000 支持 1/2/3/4/5/7 频道,DW3000 支持 5/9 频道。
- DW3000 支持 IEEE802.15.4-2015 和 IEEE802.15.4z 标准
- DW3000 支持 PDOA,通过相位差测方位角
- DW3000 有更低的功耗
- DW3000 支持硬件 AES 256
- DW3000 的 SPI 接口速度提高到 36MHz
- DW3000 不支持 110 Kbps 的通讯速率
以上是 Datasheet 上的差异。在实际的代码迁移过程中,还发现 DW3000 的一些特点:
- DW3000 的驱动接口从结构上与 DW1000 有很大的变更,它尝试支持多种类型的芯片,所以接口函数被二级抽象。
- DW3000 的接口函数名称与 DW1000 大致相同,但是参数可能会有些变化。
- 收发使用的 PRF,不再通过手工设置,而是根据使用的 Preamble Code 由芯片内部判定设置。
- Preamble Length 有一些变化,新增了 32/72 这两种长度。并且,虽然很多长度宏变量的名称没变,例如 DWT_PLEN_64/DWT_PLEN_128 等,但是对应的整数值变了。还有,DW1000 使用 1 字节保存 Preamble Length, DW3000 使用 2 字节保存 Preamble Length。
- DW3000 的寄存器布局发生了比较大的变化,DW1000 中的很多寄存器被归并,作为某个寄存器的子寄存器存在。
- PAC 新增了一个 PAC4, 对应 Preamble Length 小于 128 的情况。比较有趣的是,驱动代码中 DWT_PAC8 的注释还是
PAC 8 (recommended for RX of preamble length 128 and below), 而 DWT_PAC4 的注释是PAC 4 (recommended for RX of preamble length < 127)。 - 是否使用非标 SFD, 变为 SFD Type, 支持更多的 SFD 类型。
- PHR 可以使用 6.8M 非标速率,大概是为了提高 PHR 的发送速度
- DW3000 取消了智能发送功能
DW3000 新增的 STS 和 PDOA 相关功能,DW1000 是没有的。因为只是升级老代码,所以这部分就不涉及。
DW1000 API
DW1000 提供的驱动叫 DW1000 API, 最后的版本是 dw1000_api_rev2p14。
DW1000 API 主要针对 ST MCU,如果你使用的 MCU 不是 ST 家的,可能需要做一些接口方面的适配。
DW1000 API 在设计上,同一个板子(MCU)中操作一个 DW1000 芯片。
我之前写的程序中,考虑到有同时支持多片 DW1000 的需要,所以我对 DW1000 API 进行了一些改造。
我定义了一个结构,用来描述某一个 DW1000 芯片,例如这个芯片使用的管脚的定义,SPI 的定义等等。
这个新增的结构大致如下:
typedef struct __DW1000_MODULE__
{
uint16_t Module_SPI_Prescaler;
SPI_TypeDef* SPIn;
GPIO_TypeDef* Module_SPI_Port;
uint16_t Module_SPI_SCK_Pin;
uint16_t Module_SPI_MISO_Pin;
uint16_t Module_SPI_MOSI_Pin;
GPIO_TypeDef* Module_SPI_CS_Port;
uint16_t Module_SPI_CS_Pin;
GPIO_TypeDef* Module_WakeUp_Port;
uint16_t Module_WakeUp_Pin;
GPIO_TypeDef* Module_RSTn_Port;
uint16_t Module_RSTn_Pin;
GPIO_TypeDef* Module_RST_IRQ_Port;
uint16_t Module_RST_IRQ_Pin;
uint32_t Module_RST_IRQ_EXTI_Line;
uint8_t Module_RST_IRQ_EXTI_PortSource;
uint8_t Module_RST_IRQ_EXTI_PinSource;
IRQn_Type Module_RST_IRQ_EXTI_IRQn;
GPIO_TypeDef* Module_IRQ_Port;
uint16_t Module_IRQ_Pin;
uint32_t Module_IRQ_EXTI_Line;
uint8_t Module_IRQ_EXTI_PortSource;
uint8_t Module_IRQ_EXTI_PinSource;
IRQn_Type Module_IRQ_EXTI_IRQn;
uint8_t Module_IRQ_EXTI_USEIRQ;
uint8_t Module_RST_IRQ_EXTI_USEIRQ;
uint8_t crystal_oscillator_trim;
uint8_t rx_buffer[RX_BUF_LEN];
DW_EVENT DWEvents[MAX_EVENT_NUMBER];
uint8_t DWEventIdxIn, DWEventIdxOut;
DW_EVENT dw_event_g;
} DW1000_MODULE;
typedef DW1000_MODULE* PDW1000_MODULE;
在我开始 UWB 定位项目时,当时 ST 公司最流行的芯片是 STM32F103 系列,MCU 的接口方式是使用标准外设库 (STM32F10x_StdPeriph_Driver)。那时候,虽然 ST 已经推出了 STM32CubeMX,但还不够稳定。
在那期间,我有一个小项目尝试使用 STM32CubeMX, 但我发现问题还比较多(甚至,我还向 ST 报告了一个 Bug)。所以 UWB 定位项目中,我还是使用标准外设库(STM32F10x_StdPeriph_Driver)的方式来操作 MCU。
我为 DW1000 API 的接口函数增加一个参数–指向要操作的 DW1000 的实例的指针,这样就可以支持多个 DW1000 芯片了。
DW3000 SDK 的特点
DW3000 的驱动叫 DW3000 SDK, 并且从某个版本(DW3_QM33_SDK_1.0.2)之后,就没有提供源代码了,只提供编译过的库文件。
DW3000 SDK 与 DW1000 SDK 有很大的不同。它考虑了多个 DW3000 的支持。并且,这个 SDK 除了支持 DW3000 外,还支持其他 DW3000 类似的芯片。
芯片的差异
PRF
两个芯片都支持 16M 和 64M PRF。在 DW1000 中,你需要指定芯片工作 时的 PRF 是 16M 还是 64M。 而 DW3000 则不需要。
其实前导码 Preamble Code 中就已经包含了 PRF 的信息。Preamble Code 支持 124, 其中 18 使用 PRF 16M,9~24 使用 PRF 64M。
所以,DW3000 中只需要指定 Preamble Code 就可以了,不需要专门设置 PRF。
Channel
DW3000 只支持 Channel 5 和 Channel 9。其实上,寄存器 01:14 中,RF_CHAN 字段是 1 位,如果为 1 表示使用 Channel 9, 如果为 0 表示使用 Channel 5。
当然,使用不同的频道时,还有一些其他的参数需要做相应的调整。
DataRate
DW3000 只支持 850K 和 6.8M 两种通讯速率,取消了 DW1000 中的 110K 的速率。
实际上,110K 这个速率实在是太低了,并且在 DW1000 中,要使用 110K 这个速率,很多参数要做特殊处理。
在实践中,使用得比较多的是 850K 这个速率。它可以达到覆盖范围和通讯速度的平衡。在使用 850K 的速率时,我们的系统的覆盖范围可以达到 200 米以上;而在使用 6.8M 的时候,覆盖范围在 30 米以内。
当然,如果对覆盖范围要求不高,使用 6.8M 的通讯速率有 2 个好处:省电、容纳更多的标签。因为通讯速率高了,每个数据包占用空中的时间就短,标签可以有更多的时候休眠,消耗的电力会少得多;也因为每个数据包占用空中的时间短,所以单位时间内可以空中可以有更多的数据包,这也意味着可以有更多的标签。
PreambLength
DW3000 支持更多的 PreambLength,它把 PreambLength 划分更小的粒度。但是,要注意的是 DW1000 中 PreambLength 最大值是 1 字节,而 DW3000 中则是 2 字节。
#define DWT_PLEN_4096 (0x1FFU) //!< Standard preamble length 4096 symbols
#define DWT_PLEN_2048 (0xFFU ) //!< Non-standard preamble length 2048 symbols
#define DWT_PLEN_1536 (0xBFU ) //!< Non-standard preamble length 1536 symbols
#define DWT_PLEN_1024 (0x7FU ) //!< Standard preamble length 1024 symbols
#define DWT_PLEN_512 (0x3FU ) //!< Non-standard preamble length 512 symbols
#define DWT_PLEN_256 (0x1FU ) //!< Non-standard preamble length 256 symbols
#define DWT_PLEN_128 (0x0FU ) //!< Non-standard preamble length 128 symbols
#define DWT_PLEN_72 (0x08U ) //!< Non-standard length 72
#define DWT_PLEN_64 (0x07U ) //!< Standard preamble length 64 symbols
#define DWT_PLEN_32 (0x03U ) //!< Non-standard length 32
RxPAC
DW3000 新增了 DWT_PAC4。
//! enums for specifying Preamble Acquisition Chunk (PAC) Size in symbols
typedef enum
{
DWT_PAC8 = 0, //!< PAC 8 (recommended for RX of preamble length 128 and below)
DWT_PAC16 = 1, //!< PAC 16 (recommended for RX of preamble length 256)
DWT_PAC32 = 2, //!< PAC 32 (recommended for RX of preamble length 512)
DWT_PAC4 = 3, //!< PAC 4 (recommended for RX of preamble length < 127)
} dwt_pac_size_e;
SFD
在 DW1000 中,只 2 个选项:标准 SFD 或 非标 SFD。而在 DW3000 中,则有更多的 SFD 种类:
//! enums for specifying SFD Types and size
typedef enum
{
DWT_SFD_IEEE_4A = 0, //!< IEEE 8-bit ternary
DWT_SFD_DW_8 = 1, //!< DW 8-bit
DWT_SFD_DW_16 = 2, //!< DW 16-bit
DWT_SFD_IEEE_4Z = 3, //!< IEEE 8-bit binary (4z)
DWT_SFD_LEN8 = 8, //!< IEEE, and DW 8-bit are length 8
DWT_SFD_LEN16 = 16, //!< DW 16-bit is length 16
} dwt_sfd_type_e;
PHRRATE
在 DW1000 中,PHR 的速率不能选,只能使用标准 PHR 速率。在 DW3000 中,可以选择 PHR 的速率。如果使用 6.8M,应该可以大大缩短数据包占用空中的时间。
//! enums for selecting PHR rate
typedef enum
{
DWT_PHRRATE_STD = 0x0, // standard PHR rate
DWT_PHRRATE_DTA = 0x1, // PHR at data rate (6M81)
} dwt_phr_rate_e;
发射功率
DW3000 的发射功率控制也有了很大改变。
DW1000 中的功率控制只有一个总的控制,而 DW3000 中可以分别控制发射过程中 4 个部分的功率:

每个部分 1 个字节,低 2 位是 4 级粗略控制,高 6 位是 64 级精细控制。 粗略控制 0/1/2 都会有比较大的变化,但是 2/3 之间则差别较小,针对 Channel 5 和 Channel 9 的差别还不太一样。文档建议就不要用到粗略控制的第 3 级,虽然耗电增加了,但是功率没有增加多少。
实际上,如果覆盖范围是一个重要考量,有时即使多耗一点电,但是增加的功率能保证覆盖范围也是值的。当然,遵守无线电管理部门规定的功率限制是前提。
在 DW3110 芯片的实际使用中,与 DW1000 作对比,我发现 DW3110 的通讯距离比 DW1000 要小。应该是 DW3110 的发射功率减小了,这也是 DW3110 Datasheet 中发射电流减小的一个原因。
STS
STS 是 IEEE 802.15.4z 中新增的特性,DW1000 中没有这个特性,DW3000 支持这个新特性。
// Define DW3000 STS modes
typedef enum
{
DWT_STS_MODE_OFF = 0x0, // STS is off
DWT_STS_MODE_1 = 0x1, // STS mode 1
DWT_STS_MODE_2 = 0x2, // STS mode 2
DWT_STS_MODE_ND = 0x3, // STS with no data
DWT_STS_MODE_SDC = 0x8, // Enable Super Deterministic Codes
DWT_STS_CONFIG_MASK = 0xB,
DWT_STS_CONFIG_MASK_NO_SDC = 0x3,
} dwt_sts_mode_e;
STS 有 4 种模式:
- 模式 0, 关闭 STS
- 模式 1, STS 加在 PHR 前面
- 模式 2, STS 加在 Payload 后面
- 模式 3, 只有 STS,没有数据(没有 PHR 和 Payload)
如果要与 DW1000 兼容,要选择模式 0,也就是不加 STS。因为 DW1000 不认识 STS。
PDOA
PDOA 是 DW3000 新增的功能,根据双天线收到的信号的相位差计算方向角。这个等以后再专门写文章介绍。
与 DW1000 共存
有些存量系统中,可能已经部署了大量使用 DW1000 的设备,如果全部替换为 DW3000,是一笔不小的成本。 DW1000 和 DW3000 的共存就变得很重要。
我测试过,当 DW1000 和 DW3000 的配置中取它们共同配置时,是可以相互通讯的。 所谓共同配置,是指不使用另外一个芯片没有的配置参数。例如:
- DW1000 不能使用 110K 的通讯速率,只能使用 850K 或 6.8M
- DW3000 不能使用 STS
- 通讯信道使用 Channel 5/9
- …
因为 DW3000 的价格比 DW1000 贵,如果保证兼容性而不使用 DW3000 的新特性,感觉有点可惜。
这篇文章就写到里吧。
我正在销售使用 TDOA 技术的 UWB 定位方案(https://uwbhome.top), 购买我们的方案,你可以跳过高风险的基础研发阶段,直接进入到生产销售状态。 如果你有 UWB 方面的项目合作,可以联系我。