TOF方案在DW1000上的实现(一):时间戳和延时收发
说明
我在之前的一篇博客《基于飞行时间的测距理论介绍》中介绍了基本的方案原理,现在再研究一下DW1000芯片内部跟TOF相关的功能。
系统时钟
DW1000内部有一个40bit长的系统时钟计数寄存器组Register file: 0x06 – System Time Counter,
DW1000芯片使用38.4Mhz晶振作为外部时钟源,通过PLL进行13倍频到499.2Mhz后再进行四分频到124.8Mhz信号作为内部系统总时钟。
在UWB系统中一般以一个tick为基本的时间单位,一个tick为15.65皮秒。因此一个124.8Mhz的时钟周期(1/124.8Mhz ≈ 8012.82ps)约等于512个tick的时间(512 * 15.65ps = 8012.8ps)。
对于这个40bit的寄存器来讲,他的单位为1个tick,但又由于他以124.8Mhz为时钟进行累加,所以它每次累加都要累加512(2^9)个tick,因此它的低9bit总是为0。
该寄存器的溢出时间便为2^40 * 15.65ps(1个tick时间) ≈ 17s,溢出后重新归零。每次上电复位开始运行,休眠时暂停。
在官方的API库中给出了读取系统时间的api接口dwt_readsystime,该接口以一个5字节长度的数组来保存芯片内部40bit长度的寄存器,以下是将数组转为64bit int型变量的示例。
static uint64 get_sys_timestamp_u64(void)
{
uint8 ts_tab[5];
uint64 ts = 0;
int i;
dwt_readsystime(ts_tab);
for (i = 4; i >= 0; i--)
{
ts <<= 8;
ts |= ts_tab[i];
}
return ts;
}
由于单位不一致,需要将寄存器中的数据先乘以15.65ps,再除以1000才能换算为us,反之亦然。
收发时间戳
首先介绍RMARKER,在IEEE 802.15.4 UWB PHY标准规定,UWB传输帧中的PHR(也就是PHY的头部)的起始事件作为作为标定数据接收或者发送的关键时间点。
以接收为例,接收端通过天线接收空中的UWB信号,当接收机成功接收到前导码和SFD后,接收机继续接收到达天线上的UWB信号帧中PHR的第一个symbol时,就可以认为该帧被接收到了。因此便把这个时间点作为接收机接收到UWB数据的时间点。这个点便称之为RMARKER,ranging marker。
同样的,发送便是发射机发送的UWB信号帧中PHR的第一个symbol送到天线端即将发送到空中的时间。
可以看到,无论是SS_TWR还是DS_TWR测距算法,都离不开RMARKER来计算飞行时间。
在DW1000芯片中,芯片发送或者接收UWB帧时,能够把出现RMARKER事件时的系统事件作为时间戳保存到相关寄存器组中去。
对于发送,会记录到发送时间戳寄存器组Register file: 0x17 – Transmit Time Stamp。
对于接收,会保存到接收时间戳寄存器组Register file: 0x15 – Receive Time Stamp
以发送时间戳寄存器组为例,该寄存器组在手册中的说明如下:
可以看到,该寄存器组由3个32bit寄存器组合而成。主要分为TX_STAMP和TX_RAWST两部分。每部分占用40个bit。
TX_RAWST为芯片内部数字电路读到RMARK的原始时间,而TX_STAMP是经过天线延迟补偿后的修正值。我们知道信号从天线传输到内部数字寄存器实际上会存在一定的延迟,为了提高测距的准确度,芯片特意设计了这一个补偿机制在里面。关于这一部分的说明后面有空再细讲。
可以看到时间戳的长度为40个bit,格式和单位和系统定时器一样。当发送UWB到出现RMARKER事件时,芯片会将系统时钟寄存器值记录到该时间戳寄存器中。
接收数据时亦然。
和系统时间类似,收发时间戳也是有类似的获取接口,也是返回5字节长的数组来保存40bit的寄存器数据
static uint64 get_rx_timestamp_u64(void)
{
uint8 ts_tab[5];
uint64 ts = 0;
int i;
dwt_readrxtimestamp(ts_tab);
for (i = 4; i >= 0; i--)
{
ts <<= 8;
ts |= ts_tab[i];
}
return ts;
}
延时收发
延时收发功能也是用于测距的重要功能,该功能通过设置Register file: 0x0A – Delayed Send or Receive Time寄存器组进行延时时间设置
该延时寄存器和系统时间寄存器格式和单位一致,但由于你不能设置小于512个tick单位的时间,所以低九位无法设置,或者说设置无效。
并且要注意设置的值是一个具体的时间值。例如当你想在收到一个数据包后,想要延时100ms后回发一个数据包,那么延时时间应该是先把前面收到数据的时间戳读出来,再加上100ms写到延时收发寄存器里,而不是直接写100ms的值到寄存器中。
通过这种延迟收发功能,可以更方便的控制收发时序。例如在上面的SS-TWR中,就可以通过这种方式来实现设备B收到数据后延时回发的功能。
在API库中的相关接口如下:
dwt_setdelayedtrxtime(delay_tx_time);
.............
.......
dwt_starttx(DWT_START_TX_DELAYED);
通过dwt_setdelayedtrxtime接口设置延时寄存器的高32bit(寄存器长度40bit,但低9bit设置无意义,所以接口只设置高32bit)来设置延时时间
再通过同样发送接口启动发射
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现