Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5014412
  • 博文数量: 1198
  • 博客积分: 12961
  • 博客等级: 上将
  • 技术积分: 14416
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-09 11:25
  • 认证徽章:
个人简介

偷得浮生半桶水(半日闲), 好记性不如抄下来(烂笔头). 信息爆炸的时代, 学习是一项持续的工作.

文章分类

全部博文(1198)

文章存档

2019年(175)

2018年(81)

2017年(80)

2016年(70)

2015年(52)

2014年(41)

2013年(51)

2012年(85)

2011年(45)

2010年(231)

2009年(287)

分类: 其他平台

2019-09-10 19:16:41

DWM1001 module API 使用 TLV. (SPI / UART)

固件代码中, 包含很多 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的信息.
错误码:

点击(此处)折叠或打开

  1. err_code : 8-bit integer, valid values:
  2. 0 : OK
  3. 1 : unknown command or broken TLV frame
  4. 2 : internal error
  5. 3 : invalid parameter
  6. 4 : busy
  7. 5 : operation not permitted
位置 共 13 字节.

点击(此处)折叠或打开

  1. position = x, y, z, pqf : bytes 0-12, position coordinates and quality factor
  2. x : bytes 0-3, 32-bit integer, in millimeters
  3. y : bytes 4-7, 32-bit integer, in millimeters
  4. z : bytes 8-11, 32-bit integer, in millimeters
  5. pqf : bytes 12, 8-bit integer, position quality factor in percent
可用的GPIO变量 gpio_x:  

点击(此处)折叠或打开

  1. gpio_idx : 8-bit integer, valid values: 2, 8, 9, 10, 12, 13, 14, 15, 22, 23, 27, 30, 31.
在Tag的BLE使能时 GPIO2被占用.
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字节 

点击(此处)折叠或打开

  1. fw_version = maj, min, patch, ver: bytes 0-3, firmware version
  2. maj : byte 0, 8-bit number, MAJOR
  3. min : byte 1, 8-bit number, MINOR
  4. patch : byte 2, 8-bit number, PATCH
  5. ver : byte 3, 8-bit number, res and var
  6. res : byte 3, bits 4-7, 4-bit number, RESERVED
  7. var : byte 3, bits 0-3, 4-bit number, VARIANT
cfg_tag : 2 字节. tag的配置信息, 每个bit位的信息.

点击(此处)折叠或打开

  1. cfg_tag = stnry_en, low_power_en, meas_mode, loc_engine_en, led_en, ble_en, uwb_mode,fw_update_en, enc_en
  2. stnry _en: Stationary detection enabled, if enabled, the stationary update rate is used instead of normal
  3. update rate if node is not moving.
  4. meas_mode: measurement mode. 0 - TWR; 1, 2, 3 - reserved.
  5. low_power_en: low-power mode enable.
  6. loc_engine_en: internal Location Engine enable. 0 means do not use internal Location Engine, 1
  7. means internal Location Engine.
  8. enc_en : encryption enable
  9. led_en : general purpose LEDs enable
  10. ble_en: Bluetooth enable.
  11. uwb_mode: UWB operation mode: 0 - offline, 1 – passive, 2 – active.
  12. fw_upd_en: firmware update enable.
cfg_anchor: 2 bytes.

点击(此处)折叠或打开

  1. cfg_anchor = initiator, bridge, led_en, ble_en, uwb_mode, fw_update_en, enc_en,
  2. initiator : Initiator role enable.
  3. bridge : Bridge role enable.
  4. enc_en : encryption enable
  5. led_en : general purpose LEDs enable
  6. ble_en : Bluetooth enable.
  7. uwb_mode: UWB operation mode: 0 - offline, 1 – passive, 2 – active.
  8. fw_upd_en : Firmware update enable.
int_cfg: 16 bits (2 bytes), 中断的使能配置. 0=disabled, 1=enabled

点击(此处)折叠或打开

  1. int_cfg = spi_data_ready, loc_ready, bh_status_changed, bh_data_ready, bh_initialized_changed,
  2. uwb_scan_ready, usr_data_ready, uwbmac_joined_changed, usr_data_sent
  3. bit 0: loc_ready: interrupt is generated when location data are ready
  4. bit 1: spi_data_ready: new SPI data generates interrupt on dedicated GPIO pin
  5. bit 2: bh_status_changed: UWBMAC status changed
  6. bit 3: bh_data_ready: UWBMAC backhaul data ready
  7. bit 4: bh_initialized_changed: UWBMAC route configured
  8. bit 5: uwb_scan_ready: UWB scan result is available
  9. bit 6: usr_data_ready: user data received over UWBMAC
  10. bit 7: uwbmac_joined_changed: UWBMAC joined
  11. bit 8: usr_data_sent: user data TX completed over UWBMAC
  12. bit 9-15: reserved
stnry_sensitivity: 1字节. 配置加速计的门限值. 用于确定是否处于静止模式.

点击(此处)折叠或打开

  1. stnry_sensitivity = 8-bit integer, valid values:
  2. 0: low [512 mg]
  3. 1: normal [2048 mg]
  4. 2: high [4064 mg]
evt_id_map 32位的事件的 ID map.

点击(此处)折叠或打开

  1. evt_id_map = 32-bit integer, flags representing:
  2. bit 0: DWM_EVT_LOC_READY
  3. bit 1: DWM_EVT_UWBMAC_JOINED_CHANGED
  4. bit 4: DWM_EVT_UWB_SCAN_READY
  5. bit 5: DWM_EVT_USR_DATA_READY
  6. bit 6: DWM_EVT_USR_DATA_SENT
  7. 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");
}

 


























阅读(24) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册