
固件代码中, 包含很多 threads, 包括了 SPI/BLE/UART/GenericAPI/UserApp/... 都解决一个特定的任务.
SPI/BLE/UART 负责控制数据交互(和外部系统), 他们不解析数据, 数据都交给 GenericAPI thread处理解析.
GenericAPI thread 确定请求是否有效, 然后准备相应数据.(执行 call_back)
UserApp Thread 为一个独立的用户空间线程. 在 dwm\examples\dwm-simple 目录中.
BLE 和 SPI/Uart同时用的时候, 可能造成调用不成功. 应当避免同时使用.
在DWM1001处于 low power模式是, 唤醒时, SPI需要CS后至少35毫秒, UART至少要发送了一个字节才能确保被唤醒.
在定位系统中, 有两个参数需要注意:
1. Accuracy: 准确度. 计算位置和实际位置的差别. 目前为 < 10cm 的准确度.
2. Precision: 精度. 目前精度为 mm 毫米. 根据目前的准确度, 应该使用为 cm.
*****************************************************************************
*****************************************************************************
*****************************************************************************
BLE API

*****************************************************************************
*****************************************************************************
*****************************************************************************
SPI: Host 发送使用 TLV格式.
DWM1001作为 Slave端. 最大 SPI clock frequency = 8MHz (因为内部使用nRF52 MCU, 最大SPI就是8MHz)
操作步骤:
1. SPI Host 发起 TLV request
2. DWM1001 准备响应数据.
3. SPI Host 读取 SIZE(每个相应的长度) 和 NUM(多少个传输). 0,0说明数据没有准备好. {还有一种方式通过 GPIO P0.26 为 DataReadyPin. 需要先设置SPI interrupt, 等待 P0.26 为 高电平}
4. SPI Host 读取响应数据.
因为SPI为全双工, SPI Host 在发送X字节的同时, 也会受到X字节dummy假数据. 同样的 SPI host在读取数据时, 发送Y字节的 dummy假数据, 然后才收到Y字节的有效数据. 在目前方案中, SPI dummy假数据使用 0xFF.

*****************************************************************************
*****************************************************************************
*****************************************************************************
使用 UART API: 交互数据都是 TLV格式.
115200 8N1.
两种模式, 默认 Generic mode, 可以相互切换.
1. Generic mode: 1秒内, 连续两次 Enter 或者(两个 0x0D) 即可切换到 shell mode [如果模块在sleep模式, 可能需要多一个Enter.]
2. shell mode: 输入 quit 即可进入 GenericMode
模块的UART接收数据时, 在 25 clocks (25/32768 second ≈ 763 ?s), 未有新数据达到, 则直接把已读数据给 GenericThread 处理. 然后等待响应数据或者错误信息.

*****************************************************************************
*****************************************************************************
*****************************************************************************
GPIO操作.
SPI/UART 在数据发送后,如果数据准备好, 模块会置 GPIO pin (P0.26) 为 HIGH level.
Host端可以通过dwm_status_get 获取 此电平状态.
*****************************************************************************
*****************************************************************************
*****************************************************************************
用户程序: C code
模块已经内置了预编译的固件, 用户可以添加自己的服务模块和已有的FW集成. 在FW2中有单独的一块 UserApp空间.
1. 用户程序基于 eCos ROTS 和 DWM 库.
2. 需要引用 dwm.h 和 libdwm.a(DWM staticLib) + extras.o/verctors.o/libtarget.a(eCos staticLib) + target_s132_fw2.ld(FW2链接脚本)
3. API 包括 线程/内存/接口访问SPI_GPIO_UART_BLE/同步(mutex,signal), 以及DWM通讯栈的初始化,配置,保持. 还有回调
局限:
1. 最大用户线程 <5,
2. RAM < 5KB
3. Flash < 40KB
场景:
1. 定位引擎的优化. 获取Tag/Anchor的距离, 根据自己的算法计算位置.
2. Sensor数据融合. 例如使用卡尔曼滤波等.
3. 加入一些Sensor, 例如温湿度等. 用于 IOT
4. IOT联网, 用户远程控制.
5. 数据网桥 ...
*****************************************************************************
*****************************************************************************
*****************************************************************************
红色代表该外设是被用了, 用户可以用的是 Access 被标记为 Open的项目.








*****************************************************************************
*****************************************************************************
*****************************************************************************
TLV的信息.
错误码:
点击(此处)折叠或打开
-
err_code : 8-bit integer, valid values:
-
0 : OK
-
1 : unknown command or broken TLV frame
-
2 : internal error
-
3 : invalid parameter
-
4 : busy
- 5 : operation not permitted
点击(此处)折叠或打开
-
position = x, y, z, pqf : bytes 0-12, position coordinates and quality factor
-
x : bytes 0-3, 32-bit integer, in millimeters
-
y : bytes 4-7, 32-bit integer, in millimeters
-
z : bytes 8-11, 32-bit integer, in millimeters
- pqf : bytes 12, 8-bit integer, position quality factor in percent
点击(此处)折叠或打开
- gpio_idx : 8-bit integer, valid values: 2, 8, 9, 10, 12, 13, 14, 15, 22, 23, 27, 30, 31.
LED使能时, GPIO 22/30/31被占用
模块重启时, bootloader会在GPIO 22/30/31闪烁. 所以在重启的1s内要慎重使用这几个GPIO.
gpio_value: 1字节 0:低电平 1:高电平
gpio_pull: 1字节 0: nopull 1:pulldown 3:pull up
fw_version: 4字节
点击(此处)折叠或打开
-
fw_version = maj, min, patch, ver: bytes 0-3, firmware version
-
maj : byte 0, 8-bit number, MAJOR
-
min : byte 1, 8-bit number, MINOR
-
patch : byte 2, 8-bit number, PATCH
-
ver : byte 3, 8-bit number, res and var
-
res : byte 3, bits 4-7, 4-bit number, RESERVED
- var : byte 3, bits 0-3, 4-bit number, VARIANT
点击(此处)折叠或打开
-
cfg_tag = stnry_en, low_power_en, meas_mode, loc_engine_en, led_en, ble_en, uwb_mode,fw_update_en, enc_en
-
stnry _en: Stationary detection enabled, if enabled, the stationary update rate is used instead of normal
-
update rate if node is not moving.
-
meas_mode: measurement mode. 0 - TWR; 1, 2, 3 - reserved.
-
low_power_en: low-power mode enable.
-
loc_engine_en: internal Location Engine enable. 0 means do not use internal Location Engine, 1
-
means internal Location Engine.
-
enc_en : encryption enable
-
led_en : general purpose LEDs enable
-
ble_en: Bluetooth enable.
-
uwb_mode: UWB operation mode: 0 - offline, 1 – passive, 2 – active.
- fw_upd_en: firmware update enable.
点击(此处)折叠或打开
-
cfg_anchor = initiator, bridge, led_en, ble_en, uwb_mode, fw_update_en, enc_en,
-
initiator : Initiator role enable.
-
bridge : Bridge role enable.
-
enc_en : encryption enable
-
led_en : general purpose LEDs enable
-
ble_en : Bluetooth enable.
-
uwb_mode: UWB operation mode: 0 - offline, 1 – passive, 2 – active.
- fw_upd_en : Firmware update enable.
点击(此处)折叠或打开
-
int_cfg = spi_data_ready, loc_ready, bh_status_changed, bh_data_ready, bh_initialized_changed,
-
uwb_scan_ready, usr_data_ready, uwbmac_joined_changed, usr_data_sent
-
bit 0: loc_ready: interrupt is generated when location data are ready
-
bit 1: spi_data_ready: new SPI data generates interrupt on dedicated GPIO pin
-
bit 2: bh_status_changed: UWBMAC status changed
-
bit 3: bh_data_ready: UWBMAC backhaul data ready
-
bit 4: bh_initialized_changed: UWBMAC route configured
-
bit 5: uwb_scan_ready: UWB scan result is available
-
bit 6: usr_data_ready: user data received over UWBMAC
-
bit 7: uwbmac_joined_changed: UWBMAC joined
-
bit 8: usr_data_sent: user data TX completed over UWBMAC
- bit 9-15: reserved
点击(此处)折叠或打开
-
stnry_sensitivity = 8-bit integer, valid values:
-
0: low [512 mg]
-
1: normal [2048 mg]
- 2: high [4064 mg]
点击(此处)折叠或打开
-
evt_id_map = 32-bit integer, flags representing:
-
bit 0: DWM_EVT_LOC_READY
-
bit 1: DWM_EVT_UWBMAC_JOINED_CHANGED
-
bit 4: DWM_EVT_UWB_SCAN_READY
-
bit 5: DWM_EVT_USR_DATA_READY
-
bit 6: DWM_EVT_USR_DATA_SENT
- other bits: reserved
*****************************************************************************
*****************************************************************************
API 列表



int dwm_pos_set(dwm_pos_t* p_pos); 设置node所在默认位置 |
Example: dwm_pos_t pos; pos.qf = 100; pos.x = 121; pos.y = 50; pos.z = 251; dwm_pos_set(&pos); |
![]() |
|
int dwm_pos_set(dwm_pos_t* p_pos); 获取自己node的位置 |
dwm_pos_t pos; dwm_pos_get(&pos) |
![]() |
|
int dwm_upd_rate_set(uint16_t ur, uint16 urs); 设置更新率和静止更新率. 单位: 100ms. 静止更新率 必须>=更新率 此操作需要些internal flash,尽量少调用 ur: 位置发布周期 urs:静止时的位置发布周期, 最大2分钟. |
dwm_upd_rate_set(10, 50); // update rate 1 second. 5 seconds stationary |
![]() |
|
int dwm_upd_rate_get(uint16_t* p_ur, uint16_t* p_urs); 获取更新率 |
uint16_t ur, urs; dwm_upd_rate_get(&ur, &urs); |
![]() |
|
int dwm_cfg_tag_set(dwm_cfg_tag_t* p_cfg); 把一个节点配置成 Tag. dwm_cfg_tag_t 16-bit integer. 各个bit的意义看上面的描述 |
dwm_cfg_tag_t cfg; cfg.stnry_en = 1; cfg.meas_mode = DWM_MEAS_MODE_TWR; cfg.low_power_en = 0; cfg.loc_engine_en = 1; cfg.common.enc_en = 1; cfg.common.led_en = 1; cfg.common.ble_en = 0; cfg.common.fw_update_en = 0; cfg.common.uwb_mode = DWM_UWB_MODE_ACTIVE; dwm_cfg_tag_set(&cfg); |
![]() |
|
int dwm_cfg_anchor_set(dwm_cfg_anchor_t* p_cfg) 把一个node 配置成 anchor dwm_cfg_anchor_t = 8-bit integer |
dwm_cfg_anchor_t cfg; int rv; cfg.initiator = 1; cfg.bridge = 0; cfg.common.enc_en = 1; cfg.common.led_en = 1; cfg.common.ble_en = 1; cfg.common.fw_update_en = 1; cfg.common.uwb_mode = DWM_UWB_MODE_OFF; rv = dwm_cfg_anchor_set(&cfg); if (rv == DWM_ERR_PERM) printf(“Error: either encryption or BLE can be enabled, encryption can be enabled only if encryption key is set\n”); dwm_reset(); |
![]() ![]() |
|
int dwm_cfg_get(dwm_cfg_t* p_cfg); 获取node的当前配置 dwm_cfg_t = 16 bit integer |
dwm_cfg_t cfg; dwm_cfg_get(&cfg); printf(“mode %u \n”, cfg.mode); printf(“initiator %u \n”, cfg.initiator); printf(“bridge %u \n”, cfg.bridge); printf(“motion detection enabled %u \n”, cfg.stnry_en); printf(“measurement mode %u \n”, cfg.meas_mode); printf(“low power enabled %u \n”, cfg.low_power_en); printf(“internal location engine enabled %u \n”, cfg.loc_engine_en); printf(“encryption enabled %u \n”, cfg.common.enc_en); printf(“LED enabled %u \n”, cfg.common.led_en); printf(“BLE enabled %u \n”, cfg.common.ble_en); printf(“firmware update enabled %u \n”, cfg.common.fw_update_en); printf(“UWB mode %u \n”, cfg.common.uwb_mode); |
![]() ![]() |
|
int dwm_sleep(void); 在LowPower使能的情况下, 让node进入sleep mode. |
/* THREAD 1: sleep and block*/ dwm_sleep(); /*do something*/ ... /*THREAD 2: wait until event */ dwm_evt_wait(&evt); /*unblock dwm_sleep()*/ dwm_wake_up(); |
![]() |
|
int dwm_anchor_list_get(dwm_anchor_list_t* p_list); 只能用于anchor节点. 得到周边anchors列表. 包括自己网络以及其他相邻网络. |
dwm_anchor_list_t list; int i; dwm_anchor_list_get(&list); for (i = 0; i < list.cnt; ++i) { printf("%d. id=0x%04X pos=[%ld,%ld,%ld] rssi=%d seat=%u neighbor=%d\n", i, list.v[i].node_id, list.v[i].x, list.v[i].y, list.v[i].z, list.v[i].rssi, list.v[i].seat, list.v[i].neighbor_network); } |
![]() ![]() |
|
int dwm_loc_get(dwm_loc_data_t* p_loc); 适用于 tag low-power 以及 responsive 节点(在auto-position时, 部署时不用手动测量). 获取最近一次的距离和计算的位置. 在所有的TWR完成并且定位引擎LocationEngnine计算结束后(如果定位引擎LocationEngnine被禁用, 那么只输出距离信息) ![]() |
dwm_loc_data_t loc; int rv, i; /* if pos_available is false, position data are not read and function returns without error */ rv = dwm_loc_get(&loc); if (0 == rv) { if (loc.pos_available) { printf("[%ld,%ld,%ld,%u] ", loc.pos.x, loc.pos.y, loc.pos.z, loc.pos.qf); } for (i = 0; i < loc.anchors.dist.cnt; ++i) { printf("%u)", i); printf("0x%04x", loc.anchors.dist.addr[i]); if (i < loc.anchors.an_pos.cnt) { printf("[%ld,%ld,%ld,%u]", loc.anchors.an_pos.pos[i].x, loc.anchors.an_pos.pos[i].y, loc.anchors.an_pos.pos[i].z, loc.anchors.an_pos.pos[i].qf); } printf("=%lu,%u ", loc.anchors.dist.dist[i], loc.anchors.dist.qf[i]); } printf("\n"); } else { printf("err code: %d\n", rv); } |
![]() ![]() |
|
int dwm_baddr_set(dwm_baddr_t* p_baddr); 设置Bluetooth的地址, 地址需要模块复位reset生效. |
dwm_baddr_t baddr; baddr.byte[0] = 1; baddr.byte[1] = 2; baddr.byte[2] = 3; baddr.byte[3] = 4; baddr.byte[4] = 5; baddr.byte[5] = 6; dwm_baddr_set(&baddr); |
![]() |
|
int dwm_baddr_get(dwm_baddr_t* p_baddr); 获取 bluetooth的地址. |
dwm_baddr_t baddr; int i; if (DWM_OK == dwm_baddr_get(&baddr)) { printf("addr="); for (i = DWM_BLE_ADDR_LEN - 1; i >= 0; --i) { printf("%02x%s", baddr.byte[i], (i > 0) ? ":" : ""); } printf("\n"); } else { printf("FAILED"); } |
![]() |
|
int dwm_stnry_cfg_set(dwm_stnry_sensitivity_t sensitivity); 适用于 Tag. 配置Tag静止模式 dwm_stnry_sensitivity_t 8-bit integer = 0, 1, 2 |
dwm_stnry_cfg_set(DWM_STNRY_SENSITIVITY_HIGH); |
![]() |
|
int dwm_stnry_cfg_get(dwm_stnry_sensitivity_t* p_sensitivity); |
dwm_stnry_sensitivity_t sensitivity; dwm_stnry_cfg_get(&sensitivity); |
![]() |
|
int dwm_factory_reset(void); 恢复出厂设置. |
dwm_factory_reset(); |
![]() |
|
int dwm_reset(void); 模块复位重启 |
dwm_reset(); |
![]() |
|
int dwm_ver_get(dwm_ver_t* p_ver); 获取版本信息 |
dwm_ver_t ver; dwm_ver_get(&ver); ![]() |
![]() |
|
int dwm_uwb_cfg_set(dwm_uwb_cfg_t *p_cfg); 设置UWB参数. ![]() |
dwm_uwb_cfg_t cfg; cfg.pg_delay = 197; cfg.tx_power = 0xD0252525; dwm_uwb_cfg_set(&cfg); |
![]() |
|
int dwm_uwb_cfg_get(dwm_uwb_cfg_t *p_cfg);![]() |
dwm_uwb_cfg_t uwb_cfg; dwm_uwb_cfg_get(&uwb_cfg); printf("delay=%x, power=%lx compensated(%x,%lx)\n", uwb_cfg.pg_delay, uwb_cfg.tx_power, uwb_cfg.compensated.pg_delay, uwb_cfg.compensated.tx_power); |
![]() |
|
int dwm_usr_data_read(uint8_t* p_data, uint8_t* p_len); 读取下行的用户数据 downlink user data. 数据需要设定状态标识并且通过 dwm_evt_listener_register 设置了事件. p_data 最大34 字节. |
uint8_t data[DWM_USR_DATA_LEN_MAX]; uint8_t len; len = DWM_USR_DATA_LEN_MAX; dwm_usr_data_read(data, &len); |
![]() |
|
int dwm_usr_data_write(uint8_t* p_data, uint8_t len, bool overwrite); 发送用户数据. overwrite 是否覆盖尚未发送完毕的数据. |
uint8_t len, data[DWM_USR_DATA_LEN_MAX]; len = DWM_USR_DATA_LEN_MAX; dwm_usr_data_write(data, len, false); |
![]() |
|
int dwm_label_read(uint8_t* p_label, uint8_t* p_len); 读取node的标签 p_label 最长 16字节. |
uint8_t label[DWM_LABEL_LEN_MAX]; uint8_t len; len = DWM_LABEL_LEN_MAX; dwm_label_read(label, &len); |
![]() |
|
int dwm_label_write(uint8_t* p_label, uint8_t len); |
uint8_t len, label[DWM_LABEL_LEN_MAX]; len = DWM_LABEL_LEN_MAX; rv = dwm_label_write(label, len); if ( len == rv ) printf(“ok\n”); else printf(“error, %d”, rv); |
![]() |
|
int dwm_gpio_cfg_output(dwm_gpio_idx_t idx, bool value); 把GPIO设置成 output, 并置高低电平 |
dwm_gpio_cfg_output(DWM_GPIO_IDX_13, 1); // set pin 13 as output and to 1 (high voltage) |
![]() |
|
int dwm_gpio_cfg_input(dwm_gpio_idx_t idx, dwm_gpio_pin_pull_t pull_mode); 把 GPIO 设置为input 模式, 并配置 PULL. |
dwm_gpio_cfg_input(DWM_GPIO_IDX_13, DWM_GPIO_PIN_PULLUP); dwm_gpio_cfg_input(DWM_GPIO_IDX_9, DWM_GPIO_PIN_NOPULL); dwm_gpio_cfg_input(DWM_GPIO_IDX_31, DWM_GPIO_PIN_PULLDOWN); |
![]() |
|
int dwm_gpio_value_set(dwm_gpio_idx_t idx, bool value); |
dwm_gpio_value_set(DWM_GPIO_IDX_13, 1); |
![]() |
|
int dwm_gpio_value_get(dwm_gpio_idx_t idx, bool* p_value); |
uint8_t value; dwm_gpio_value_get(DWM_GPIO_IDX_13, &value); printf(“DWM_GPIO_IDX_13 value = %u\n”, value); |
![]() |
|
int dwm_gpio_value_toggle(dwm_gpio_idx_t idx); |
dwm_gpio_value_toggle(DWM_GPIO_IDX_13); |
![]() |
|
int dwm_panid_set(uint16_t panid); |
dwm_panid_set(0xABCD); |
![]() |
|
int dwm_panid_get(uint16_t *p_panid); |
uint16_t panid; if (DWM_OK == dwm_panid_get(&panid)) { printf("panid=%u\n"); } else { printf("FAILED\n"); } |
![]() |
|