从 DW1000 升级到 DW3000

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 个部分的功率:

alt text

每个部分 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 方面的项目合作,可以联系我。