802.15.4 SDK
概述
基于IEEE 802.15.4(2006),Telink 802.15.4 SDK支持标准的PHY(physical)层和MAC(media access control)层功能。此外,作为参考,SDK中实现了部分应用层功能。
SDK整体结构如下:
-
PHY(physical)层在telink硬件平台及驱动的基础上,实现了标准的2.4G无线连接,例如调制方式、支持频率、发射功率等,具体可以参考相应芯片的数据手册;
-
MAC(media access control)层由软件实现,基于IEEE 802.15.4 specification,实现标准的数据格式和加密机制等。
-
APP(application)层,SDK提供了部分应用示例,例如加入PAN、OTA等。
为了和15.4 协议栈交互,SDK提供了三种接口(interface)给APP层:MLME、MCPS、ASP。
a) MAC子层包含管理实体(MAC Layer Management Entity,MLME):应用层可以通过MLME,发送802.15.4 MAC COMMAND。例如,应用层通过此接口(interface)可以发送MLME-ASSOCIATE.request原语(primitive),同时也通过这个接口(interface)收到MLME-ASSOCIATE.confirm原语(primitive)。
b) MCPS接口(interface):应用层可以通过MCPS,发送和接收802.15.4 MAC DATA。
c) ASP接口(interface):应用层可以通过ASP设置MAC层PIB参数。
以上接口(interface)的使用,后续章节会有详细的介绍。
设备类型
从包含的功能角度,15.4包含以下两种设备类型:
-
全功能设备(Full Function Device,FFD): 具有15.4的所有功能设备,可以是协调器(PAN coordinator OR coordinator),路由设备(router),或者具有全功能的终端节点(end device),全功能设备(FFD)一般不进入休眠。
-
非全功能设备(Reduced Function Device,RFD): 只能作为终端节点,一般情况下有低功耗要求。
网络类型
802.15.4的网络属于集中式(Central)网络,也叫星形网络。
- 集中式(Central)网络: 通常是由PAN Coordinator来组建和管理的网络。
基本概念
1) PAN ID: 个人局域网(Personal Area Network)ID
由PAN ID来标识所组建的网络。PAN ID由负责组建该网络的节点分配,可以直接指定,也可以随机生成,但需要通过active scan来避免PAN ID冲突。
2) Channel: 频点/信道
15.4允许的工作频点(2.4G):2405 + (N-11)*5 (mHz), (信道N = 11~26)。 接入一个网络后采用单一频点的工作模式,不会主动跳频。
3) Direct Data Transfer: 直接数据发送
一般用于向FFD设备发送数据,例如end device发数据给coordinator。
4) Indirect Data Transfer: 间接数据发送
一般用于FFD设备发送数据给进入低功耗的RFD,例如coordinator发数据给end device,coordinator会先将数据存储在本地,end device通过poll request的方式,获得数据包。
Telink 802.15.4 SDK开发概述
在Telink提供的软硬件基础之上,实现Telink 802.15.4 SDK开发。
Telink 802.15.4 SDK软件开发环境
1) 必备软件工具 (下载地址: http://wiki.telink-semi.cn/)
-
集成开发环境:
TLSR8 Chips: Telink IDE for TC32
TLSR9 Chips: Telink RDS IDE for RISC-V
-
下载调试工具: Telink Burning and Debugging Tools
-
OTA编码转换工具: tl_ota_tool,具体过程参考OTA章节6.2.2
2) 抓包分析辅助工具 (自行下载或购买)
-
TI Packet Sniffer
-
Ubiqua
3) 软件开发包 (下载地址: http://wiki.telink-semi.cn/)
- TLSR8_802_15_4_SDK.zip
Telink 802.15.4 SDK支持的硬件平台
-
B85m (TC32平台)
826x: 8267 EVK Board and 8267 USB Dongle
8269 EVK Board and 8269 USB Dongle
8258: 8258 EVK Board and 8258 USB Dongle
8278: 8278 EVK Board and 8278 USB Dongle
-
B91m (RISC-V平台)
9518: 9518 EVK Board and 9518 USB Dongle
泰凌802.15.4 SDK
在安装SDK前,请根据1.4章节安装相应的集成开发环境Telink IDE for TC32或Telink RDS IDE for RISC-V。
TLSR8 TC32 SDK安装
项目导入
1) 打开IDE,依次进入界面File -> Import -> Existing Projects into Workspace。
2) 选择tl_802154_sdk/build目录点击“确定”。
3) 点击“Finish”,完成工程导入。
Copy project into workspace框根据实际情况决定是否勾选,如工程已经在此目录下不必勾选,如在其他目录下,希望将工程在当前目录编辑开发,则可以勾选。
工程目录结构
-
/demo: 用户工程目录。
-
/app_common: 应用层公共代码目录,包含包含应用数据包处理函数(tl_specific_data.c tl_specific_data.h)、以及在此处理函数中的具体应用OTA,其他的应用也可在此基础上完善,或者导入自己的应用层代码。
-
/associate_coor: 协调器(PAN Coordinator)例程。
-
/associate_dev: 终端节点(end device)例程。
-
-
/platform: 运行平台目录。
-
/boot: 启动和链接文件。
-
/chip_xx: 芯片驱动文件。
-
/services: 中断服务函数文件。
-
-
/proj: 工程代码目录。
-
/common: 通用代码目录。
-
/drivers: 抽象层驱动文件。
-
/os: 任务事件、buffer管理函数文件。
-
-
/802154: 协议栈相关目录。
-
/tools: hci命令处理相关目录。
-
div_mod.S: 除法和取余相关的汇编函数。(TLSR8不支持硬件除法器)
编译选项
点击下拉图标 ,可以看到当前所有的编译选项,选择需要编译的示例工程,如下图,等待编译完成。
编译完成后,“Project Explorer”窗口会出现编译出来的文件夹,其中包含了编译出来的固件,如下图。
assoc_dev_82xx工程会产生两个bin文件,红色框的assoc_dev_82xx.bin为运行bin,用于直接烧录到目标板;蓝色下划线的ota_assoc_dev_82xx.bin为OTA文件。
添加新项目
在提供的SDK中,仅仅给出了一些简单的用例。用户可以根据需求,自行添加应用工程以及编译选项。
具体步骤如下:
1) 步骤1: Project Explorer -> tl_802154_sdk -> Properties -> Manage Configurations
2) 步骤2: 单击New,弹出如下界面
-
Name: 项目名称
-
Description: 项目简单描述
-
Copy settings from: 建议选用Existing configuration,可以减少一些配置过程。
选用Existing configuration的原则如下所示:
-
使用8278平台,选择associate_xxx_8278;使用8258平台,选择associate_xxx_8258。
-
项目用于coordinator的开发,选择associate_coor_8258;项目用于end device设备的开发,选择associate_dev_8258。
假设需要用8258开发一个具有休眠功能的传感器的项目,根据该原则,应选择项目" associate_dev_8258"的配置作为这个新项目的配置。
如果需要修改配置,可按下节(2.1.5 项目配置说明),进行相应调整。
项目配置说明
依次进入: Project Explorer -> tl_802154_sdk -> Properties -> Settings (以项目associate_dev_8258为例说明)
在Tool Settings下,可以看到当前项目的一些预定义配置:
1) 设备类型预定义
-END_DEVICE=1: 表示项目是个终端节点(end device)设备
对于coordinator和end device的设备设置分别为:
-COORDINATOR=1:表示项目是个Coordinator功能的设备
-END_DEVICE=1:表示项目是个end device功能的设备
2) 平台选择
-
8269平台: -DMCU_CORE_826x=1以及-DCHIP_8269=1
启动代码cstartup_826x.S位于tl_802154_sdk -> platform -> boot目录下。
-
8258平台: -DMCU_CORE_8258=1
启动代码cstartup_8258.S位于tl_802154_sdk -> platform -> boot目录下。
-
8278平台: -DMCU_CORE_8278=1
启动代码cstartup_8278.S位于tl_802154_sdk -> platform -> boot目录下。
3) lib文件的链接
当前SDK里包括2类库文件:15.4 stack库和平台驱动库。
-
15.4 stack库: libmac_device.a,libmac_coor.a
位于tl_802154_sdk -> 802154 -> lib目录下。
-
平台驱动库:libdrivers_826x.a,libdrivers_8258.a,libdrivers_8278.a
位于tl_802154_sdk -> platform -> lib目录下。
4) 链接文件
用户可以依据实际应用需求,根据所选用的不同平台以及内存要求,调整合适的link文件。
当前SDK给出了826x、8258和8278平台的默认link文件boot_826x.link、boot_8258.link和boot_8278.link,分别在tl_802154_sdk -> platform -> boot对应的文件。
如下图所示,通过预编译调用脚本tl_link_load.sh(tl_802154_sdk -> tools目录下)来选择使用的link文件。
5) .image文件校验
为了保证下载文件的可靠性,通过脚本tl_check_fw.sh(tl_802154_sdk -> tools目录下)在生成的image文件中加入校验字段以及非协调器设备执行ota_bin_tool,OTA过程中会通过检查校验字段是否匹配,来决定是否更新image。
TLSR9 RISC-V SDK安装
项目导入
1) 打开IDE,依次进入界面File -> Import -> Existing Projects into Workspace。
2) 选择tl_802154_sdk -> build目录下的tlsr_riscv点击“确定”。
3) 点击“Finish”,完成工程导入。
工程目录结构
-
/demo: 用户工程目录。
-
/app_common: 应用层公共代码目录,包含应用数据包处理函数(tl_specific_data.c tl_specific_data.h)、以及在此处理函数中的具体应用OTA,其他的应用也可在此基础上完善,或者导入自己的应用层代码。
-
/associate_coor: 协调器(PAN Coordinator)例程。
-
/associate_dev: 终端节点(end device)例程。
-
-
/platform: 运行平台目录。
-
/chip_xx: 芯片驱动文件。
-
/services: 中断服务函数文件。
-
-
/proj: 工程代码目录。
-
/common: 通用代码目录。
-
/drivers: 抽象层驱动文件。
-
/os: 任务事件、buffer管理函数文件。
-
-
/802154: 协议栈相关目录。
编译选项
点击下拉图标 “”,可以看到当前所有的编译选项,选择需要编译的示例工程,如下图,等待编译完成。
编译完成后,在“Project Explorer”窗口会出现编译出来的文件夹,其中包含了编译出来的固件,如下图。
添加新项目
在提供的SDK中,仅仅给出了一些简单的用例。用户可以根据需求,自行添加应用工程以及编译选项。
具体步骤如下:
1) 步骤1: Project Explorer -> tl_802154_sdk -> Properties -> Manage Configurations
2) 步骤2: 单击New,弹出如下界面
-
Name: 项目名称
-
Description: 项目简单描述
-
Copy settings from: 建议选用Existing configuration,可以减少一些配置过程。
选用Existing configuration的原则如下所示:
-
使用9518芯片,选择xxx_9518。
-
项目用于Gateway的开发,选择sampleGw_xxxx;项目用于Router设备的开发,选择sampleLight_xxxx;项目用于End Device设备的开发,选择sampleSwitch_xxxx。
假设需要用9518开发一个具有路由功能的灯的项目,根据该原则,应选择项目"sampleLight_9518"的配置作为这个新项目的配置。
如果需要修改配置,可按下节(2.2.5 项目配置说明),进行相应调整。
项目配置说明
依次进入:Project Explorer -> tl_802154_sdk -> Properties -> Settings(以项目associate_coordinator_9518为例说明)
在Tool Settings下,可以看到当前项目的一些预定义配置:
1) 设备类型预定义
对于coordinator和end device的设备设置分别为:
-DEND_DEVICE=1:表示项目是个end device功能的设备
-DCOORDINATOR=1:表示项目是个Coordinator功能的设备
2) 平台选择
-
b91平台:-DMCU_CORE_B91=1
启动代码cstartup_b91.S位于tl_802154_sdk -> platform -> boot -> b91目录下。
3) lib文件的链接
当前SDK里包括2类库文件:802154 stack库和平台驱动库。
-
802154 stack库: libmac_coor.a,libmac_device.a
位于tl_802154_sdk -> 802154 -> lib -> riscv目录下。
-
平台驱动库:libdrivers_b91.a
位于tl_802154_sdk -> platform -> lib目录下。
4) 链接文件
用户可以依据实际应用需求,根据所选用的不同平台以及内存要求,调整合适的link文件。
当前SDK给出了b91平台的默认link文件boot_b91.link,在tl_802154_sdk -> platform -> boot对应的目录下。
如下图所示,通过预编译调用脚本tl_link_load.sh(tl_802154_sdk -> tools目录下)来选择使用的link文件。
5) .image文件校验
为了保证下载文件的可靠性,通过脚本tl_check_fw.sh(tl_802154_sdk -> tools目录下)在生成的image文件中加入校验字段,下载或OTA过程中会通过检查校验字段是否匹配,来决定是否更新image。
App版本管理
每个demo目录下都对应有一个version_cfg.h文件用来管理app的版本,对App进行版本管理是非常有必要的,尤其是在OTA时可以有效的防止错误升级而导致变砖的风险。
App版本是由三个关键字段组成的,分别是制造商代码(Manufacturer Code)、固件类型(Image Type)和文件版本(File Version),会以小端形式存放在固件的固定位置,如下图:
绿色框:文件版本(file version)
红色框:制造商代码(MANUFACTURER_CODE)
蓝色框:固件类型(image type)
制造商代码
MANUFACTURER_CODE:制造商代码是Zigbee联盟为每个成员公司分配的一个2字节长度的标识符,比如0x1141是Telink的制造商代码。用户可以将其修改成自己的制造商代码。
固件类型
IMAGE_TYPE:固件类型是一个2字节长度的常量,高字节代表Chip类型,低字节代表Image类型。Chip类型和Image类型定义在version_comm.h文件中,用户可以根据需求自行修改或添加。
文件版本
FILE_VERSION:文件版本是反应固件发行和编译的版本号,是一个4字节长度的常量。文件版本必须以递增形式进行管理,例如当前的文件版本号必须大于之前发行的版本号,因为当OTA时,只有检查到新的版本号大于之前的版本号时才会进行升级。
运行模式
Telink 826x/8258/8278 硬件平台支持两种启动模式: 多地址启动模式(从0x0或0x40000地址启动)和BootLoader启动模式(从BootLoader启动后跳转到App)。
Telink 802154 SDK仅支持多地址启动模式,后续会增加boot loader启动方式。
多地址启动模式
优点:启动速度快;OTA结束后无需再次搬运image,校验正确后可以快速启动。
缺点:image只能位于地址0x0或0x40000,会造成flash空间分配的不连续性;另外image的大小(如果支持OTA的话)只能小于208KB。
多地址启动模式Flash分布
Flash分布说明
1) MAC_Addr
MAC地址信息存放在Flash的0x76000或0xFF000地址开始的8个bytes位置。系统启动后会检查MAC地址信息,如果发现是0xFFFFFFFFFFFFFFFF,将会随机产生一个MAC地址。芯片出厂时会预先写入MAC地址,请谨慎擦除。
2) F_Cfg_Info
出厂配置参数信息。芯片在出厂时会预先写入一些校准参数信息,比如射频频偏校准、ADC校准等,请谨慎擦除。
3) U_Cfg_Info
用户配置参数信息。
4) NV(NV_1, NV_2)
节点入网后会将网络信息保存在NV区。512k Flash网络信息分两部分保存,分别保存在NV_1的48kB空间和NV_2的24kB空间。1M Flash网络信息保存在NV的88kB空间。
所以,如果只是更新固件或断电重启的话,网络信息不会丢失。
5) Firmware和OTA_Image
TLSR8支持Flash多地址启动,既可以从0x0地址启动,也可以从0x40000地址启动。Telink 802154 SDK使用该特性,使用乒乓模式,利用Firmware和OTA_Image相互切换来实现OTA功能。
固件烧录
1) 通过mini USB线将Telink烧录EVK与PC相连,EVK板指示灯会闪烁一次,表示EVK与PC连接正常;再使用三根杜邦线将EVK的VCC、GND和SWM分别与待烧录目标板的VCC、GND和SWS相连。
2) 硬件连接好之后,打开Telink BDT.exe烧录工具,准备烧录固件。
a) 选择“8258”芯片型号(本文档以8258为例)。
b) 选择“File” -> “Open”,选择要烧录的固件。
c) 点击“Erase”擦除512K Flash。
d) 点击“Download”下载固件。
(烧录工具详细的使用方法请参考烧录工具使用文档。)
软件架构
Telink 802154 SDK的目录结构已在“2.1.2工程目录结构”章节中列出,本章节会对各个目录下的文件具体作下说明。
目录说明
硬件平台目录
当前SDK支持b85m(826x、8258、8278)和b91m(9518)多个平台(tl_802154_sdk -> platform),后续可以添加其他硬件平台。
-
\boot: 不同平台的.S启动代码和.link链接文件
-
\chip_826x: 826x平台硬件模块驱动头文件
-
\chip_8258: 8258平台硬件模块驱动头文件
-
\chip_8278: 8278平台硬件模块驱动头文件
-
\chip_b91: b91平台硬件模块驱动头文件
-
\lib: 不同平台的驱动库文件
-
\services: 不同平台中断处理文件
通用函数目录
-
\common: 一些通用的功能函数,如字符串、链表、打印等处理函数文件
-
\drivers: 抽象层驱动文件
-
\os: 任务事件、buffer管理函数文件
802154协议栈目录
大多以.lib文件的给出,其中PHY层以及与应用层密切相关的ZCL和zbhci以开源代码方式给出。
-
\common: 802154协议栈配置相关文件
-
\lib: 802154协议栈库文件
-
\mac: 媒介控制层(Media Access Control)相关文件,802154协议栈核心代码
应用层目录
-
\app_common: 应用层通用文件目录
-
\ota:协调器和终端节点的OTA应用代码
tl_specific_data.c:应用代码函数入口
tl_specific_data.h:应用代码配置文件
-
\associate_coor:协调器应用例程
-
\associate_dev: 终端节点应用例程
工程编译目录
-
build -> tlsr_riscv: risc-v平台导入和编译的工程目录,TLSR9系列芯片请选择使用该目录
-
build -> tlsr_tc32: tc32平台导入和编译的工程目录,TLSR8系列芯片请选择使用该目录
抽象层驱动
Telink 802154 sdk兼容多款Telink芯片,为了便于驱动的接口统一,添加了驱动抽象层,位于proj -> drvier下,各驱动具体使用方法可参见后续章节。
平台初始化
- 初始化
drv_platform_init(void)
完成芯片、系统clock的配置、gpio、射频(RF)、timer等802154应用开发中所需的一些模块的初始化。
射频 (RF)
- 初始化
ZB_RADIO_INIT()
- 模式切换
ZB_RADIO_TRX_SWITCH(mode, chn)
mode: RF_MODE_TX = 0, 发送模式
RF_MODE_RX = 1, 接收模式
RF_MODE_AUTO = 2, 802154未使用
RF_MODE_OFF, 关闭射频模块
Chn: 11-26 (对应802.15.4中的2.4G的16个channel值)
- 发射功率
ZB_RADIO_TX_POWER_SET(level)
设置RF模块发送功率,不同芯片对应的功率值稍有不同,具体指请参考RF_PowerIndexTypeDef的定义(platform/chip/rf_drv.h)。
- 数据发送
ZB_RADIO_TX_START(txBuf)
参数txBuf: 待发送数据的内存地址,数据格式 dma length(4Bytes:payload长度+1) + len(1Byte: payload长度+2) + payload
- 设置射频接收buffer
ZB_RADIO_RX_BUF_SET(addr)
在设置射频为Rx模式时,必须确保将Rx buffer设置为有效安全的内存地址。
- RSSI获取
ZB_RADIO_RSSI_GET()
调用该函数时,请确保射频此时处于Rx模式。
- Rssi转化为Lqi
ZB_RADIO_RSSI_TO_LQI(mode, rssi, lqi)
mode: 仅对8269有效
typedef enum{
RF_GAIN_MODE_AUTO,
RF_GAIN_MODE_MANU_MAX,
}rf_rxGainMode_t;
- 接收中断
rf_rx_irq_handler(void)
- 发送中断
rf_tx_irq_handler(void)
注意: 射频中断函数rf_rx_irq_handler / rf_tx_irq_handler仅能被802154 stack中使用,如果用户自行调用ZB_RADIO_TX_START所产生的中断,需用户自行注册新的中断回调函数,以避免影响802154 stack的运行状态。
GPIO
- 初始化以及配置
gpio_init()
此函数是通过将platform -> chip_xxxx -> gpio_default.h下的默认配置(应用层的board_xxxx.h可以修改该默认配置)写入gpio寄存器,实现gpio初始化。
- IO功能设置
void drv_gpio_func_set(u32 pin)
设置IO具体功能。
参数pin:参见GPIO_PinTypeDef的定义。
- GPIO读
void drv_gpio_read(u32 pin);
读取gpio的高低电平。
- GPIO写
void drv_gpio_write(u32 pin, bool value);
设置gpio的高低电平。
- 输出使能
void drv_gpio_output_en(u32 pin, bool enable);
- 输入使能
void drv_gpio_input_en(u32 pin, bool enable)
- GPIO中断操作
芯片最多可以同时支持3路外部GPIO中断,中断模式分别为:GPIO_IRQ_MODE、GPIO_IRQ_RISC0_MODE和GPIO_IRQ_RISC1_MODE。
1) 注册中断服务函数
int drv_gpio_irq_conf(drv_gpio_irq_mode_t mode,u32 pin,
drv_gpioPoll_e polarity, irq_callback gpio_irq_callback);
2) 使能中断管脚
int drv_gpio_irq_en(u32 pin);
int drv_gpio_irq_risc0_en(u32 pin);
int drv_gpio_irq_risc1_en(u32 pin);
UART
- 管脚设置
void drv_uart_pin_set(u32 txPin, u32 rxPin)
使用uart之前必须选择相应的IO作为uart的收发管脚。
- 初始化
void drv_uart_init(u32 baudrate, u8 *rxBuf, u16 rxBufLen, uart_irq_callback uart_recvCb)
Baudrate: 波特率
rxBuf: 接收buffer
rxBufLen: 接收数据最大长度
uart_recvCb: 接收中断时供应用层的回调函数
- 发送
u8 drv_uart_tx_start(u8 *data, u32 len)
- 接收中断函数
void drv_uart_rx_irq_handler(void)
- 发送中断函数
void drv_uart_tx_irq_handler(void)
- 异常处理函数
void drv_uart_exceptionProcess(void)
注意:当使用uart时,为避免通讯异常,main_loop必须轮询该异常处理函数。
ADC
- 初始化
bool drv_adc_init(void);
- 配置
void drv_adc_mode_pin_set(drv_adc_mode_t mode, GPIO_PinTypeDef pin)
参数mode: 参见drv_adc_mode_t定义
参数pin: 所使用的管脚号,参见GPIO_PinTypeDe定义
- 获取采样值
u16 drv_get_adc_data(void)
PWM
- 初始化
void drv_pwm_init(void)
- 配置
void drv_pwm_cfg(u8 pwmId, u16 cmp_tick, u16 cycle_tick)
参数pwmId: pwm通道
参数cmp_tick: PWM一个周期中处于高电平的tick数
参数cycle_tick: PWM一个周期包含的tick数
TIMER
- 初始化
void drv_hwTmr_init(u8 tmrIdx, u8 mode)
参数tmrIdx: TIMER_IDX_0,TIMER_IDX_1,TIMER_IDX_2TIMER_IDX_3
参数mode: TIMER_MODE_SYSCLK,TIMER_MODE_GPIO_TRIGGER,TIMER_MODE_GPIO_WIDTH,TIMER_MODE_TICK
- 设置
void drv_hwTmr_set(u8 tmrIdx, u32 t_us, timerCb_t func, void *arg)
参数tmrIdx: 需要使用的timer
参数t_us: 定时间隔,单位:us
参数func: 该定时中断应用层回调函数
参数arg: 应用层回调函数所需参数
- 注销
void drv_hwTmr_cancel(u8 tmrIdx)
- 中断函数
void drv_timer_irq0_handler(void)
void drv_timer_irq1_handler(void)
void drv_timer_irq3_handler(void)
其中TIMER_IDX_2默认作为watchdog使用,建议用户不要使用;
TIMER_IDX_3用作MAC-CSMA,建议用户不要使用。
Watchdog
- 初始化
void drv_wd_setInterval(u32 ms)
参数ms:超时时间
- 启动
void drv_wd_start(void)
- 喂狗
void drv_wd_clear(void)
System Tick
System Tick计数器,它是一个32bit长度、每一个时钟周期自动加一的可读计数器。
由于826x和其他系列IC的System Timer的时钟源不同,8269的System Timer是32M,8258、8278和9518的System Timer是16M,所以在最大计数时间上存在区别。
-
8269最大定时时间:(1/32)us*(2^32)约等于134秒,每过134秒System Timer Tick转一圈。
-
8258、8278、9518最大定时时间:(1/16)us*(2^32)约等于268秒,每过268秒System Timer Ticker转一圈。
用户可以使用clock_time()接口获取当前tick。
电压检测
为了防止低压系统运行异常,SDK提供了基于ADC驱动实现的电压检测函数,需要注意的是:
1) 需要使用支持ADC功能的I/O口,且用于ADC检测的I/O口不可以用做其他功能
2) 使用DRV_ADC_VBAT_MODE模式时,I/O口需要悬空
3) 使用DRV_ADC_BASE_MODE模式时,I/O口需要连接电压测试点
4) B91只能使用DRV_ADC_BASE_MODE模式,且I/O口需要做外部分压处理
- 初始化
void voltage_detect_init(void)
- 电压检测
voltage_detect(void)
睡眠和唤醒
Telink 802154 SDK提供了相关的低功耗管理函数。associate_dev_826x使用suspend模式;associate_dev_8258、associate_dev_8278和associate_dev_B91使用deep with retention模式,即休眠时RAM数据可以保持(8258和8278支持32k RAM保持,B91支持64k RAM保持,详细请查阅数据手册)。
- 唤醒源类型
支持按键以及timer定时唤醒。
- 配置唤醒引脚
如果需要按键唤醒功能,首先需要配置对应的唤醒管脚以及唤醒电平。
/**
* @brief Definition for wakeup source and level for PM
*/
drv_pm_pinCfg_t g_switchPmCfg[] =
{
{BUTTON1, PM_WAKEUP_LEVEL},
{BUTTON2, PM_WAKEUP_LEVEL},
};
drv_pm_wakeupPinConfig(g_switchPmCfg, sizeof(g_switchPmCfg)/sizeof(drv_pm_pinCfg_t));
- 休眠函数
drv_pm_lowPowerEnter(void);
如果使能了按键唤醒,调用此函数时,若相应管脚当前的电平与唤醒电平一致,则系统不能有效进入低功耗状态。
- 休眠函数说明
1)调用tl_stackBusy()和zb_isTaskDone()检查是否符合休眠条件;
2)遍历软件定时任务列表,检查是否存在定时任务,如果有执行3),如果没有执行4);
3)检索出临近任务的时间,以该时间作为休眠时间,进入Suspend或Deep Retention休眠模式,可以定时器唤醒和按键唤醒;
4)进入Deep休眠模式,可以按键唤醒。
存储管理
动态内存管理
Telink 802154 SDK提供了动态内存分配和释放的接口,默认最大支持142字节长度的内存申请,用户可以在开发中直接使用,接口如下。
1) 申请内存
u8 *ev_buf_allocate(u16 size);
2) 释放内存
buf_sts_t ev_buf_free(u8 *pBuf);
3) 资源配置
默认由4组不同个数、不同大小的内存池构成,用户可以根据产品需求以及当前内存使用情况自行修改其个数以及大小。
MEMPOOL_DECLARE(size_x_pool, size_x_mem, BUFFER_GROUP_x, BUFFER_NUM_IN_GROUPx);
NV管理
因为802154需要保存各层的网络信息参数,在异常断电后能够恢复网络,所以SDK从FLASH中划分了一块区域专门用来存储此类信息,这块FLASH区域我们称它为NV区,即第2.4章节的NV(NV_1, NV_2)区。
由于芯片FLASH仅支持sector(1 sector = 4k)擦除,所以NV区的信息存储模块的最小单位为1个sector。
SDK中使用了以下几个信息模块,其中NV_MODULE_USER_INFO1和NV_MODULE_USER_INFO2是供用户使用,如需添加新的信息模块,请在末尾添加,不能改变现有的模块序号。
typedef enum {
NV_MODULE_MAC_INFO = 0,
NV_MODULE_NWK_FRAME_COUNT = 1,
NV_MODULE_USER_INFO1 = 2,
NV_MODULE_USER_INFO2 = 3,
NV_MAX_MODULS
}nv_module_t;
信息模块又由多个条目信息组成,例如NV_MODULE_USER_INFO1由一系列的NV_ITEM_USER_INFO组成。条目定义如下,如需添加新的条目信息,请在末尾添加,不能改变现有的条目序号。
typedef enum {
NV_ITEM_ID_INVALID = 0,/* Item id 0 should not be used. */
NV_ITEM_MAC_INFO = 1,
NV_ITEM_USER_INFO1 = 0x10,
NV_ITEM_USER_INFO2 = 0x20,
NV_ITEM_ID_MAX = 0xFF,/* Item id 0xFF should not be used. */
}nv_item_t;
-
每个module 占用2个或(2*n )sectors,格式:
sector info + item 索引 + item 内容
其中sector info标识该块是否有效,长度为sizeof(nv_sect_info_t),之后紧跟待写入的item索引,item内容起始于该module首地址偏移512Byte或1024Byte的位置。
-
为了避免频繁进行擦除操作,NV采用单module追加写入的方法,直到1个Sector写满后,将有效信息搬到另一个sector,再将之前的sector内容清除。
-
NV区读写操作接口如下:
nv_sts_t nv_flashWriteNew(u8 single, u16 id, u8 itemId, u16 len, u8 *buf);
nv_sts_t nv_flashReadNew(u8 single, u8 id, u8 itemId, u16 len, u8 *buf);
注意: 对于某个item,如果只存在一个有效值的话,则single为1,那么当再次写这个item时,会将之前有效的item清除; 否则的话,需要根据内容检索相同的item,将其置为无效,再写入新的item。
任务管理
单次任务队列
- 接口函数
TL_SCHEDULE_TASK(tl_zb_callback_t func, void *arg)
参数func: 任务回调函数
参数arg: 任务所需参数
-
只执行一次,没有按优先级,顺序依次处理
-
建议使用场合:
1) 需要避免函数深度嵌套引起的堆栈溢出问题;
2) 中断函数中,通过将数据、事件压入队列,避免在中断函数里消耗过多时间。
-
大小: 32个(使用时避免一次性压入过多任务)
常驻任务队列
- 任务注册 (任务注册后默认启动)
ev_on_poll(ev_poll_e e, ev_poll_callback_t cb)
- 任务暂停
ev_disable_poll(ev_poll_e e, ev_poll_callback_t cb)
- 任务重启
ev_enable_poll(ev_poll_e e, ev_poll_callback_t cb)
此任务注册后,会在主循环中一直执行。
软件定时任务
为了方便用户实现对时间精度需求不高的定时任务,Telink 802154 SDK提供了一个软件定时任务管理机制。
需要注意的是,从SDK V3.6.2版本开始,软件定时任务管理的时间单位从原来的ticker改为毫秒,这解决了长时间定时任务需求的问题。
(1) 接口函数
- 任务注册: TL_ZB_TIMER_SCHEDULE(cb, arg, timeout)
/**
* @param[in] func - the callback of the timer event
*
* @param[in] arg - the parameter to the callback
*
* @param cycle - the timer interval
*
* @return the status
*/
- 任务取消: TL_ZB_TIMER_CANCEL(evt)
/**
@param[in] evt - the pointer to the timer event pointer
*
* @return the status
*/
(2) 注意事项
1) 定时任务回调函数返回值的三种用法:
-
返回值小于0,则该任务执行后被自动删除,任务不复存在。
-
返回值等于0,则一直使用之前启动时的t_ms来周期定时触发回调函数。
-
返回值大于0,则使用该返回值作为新的周期定时触发回调函数,单位ms。
注意: 在中断函数里避免使用TL_ZB_TIMER_CANCEL()
(3) 使用实例
当VK_SW1按键按下后,启动或取消一个10秒的定时任务,时间到达后执行一次广播On/Off Toggle的命令,执行结束后退出。代码如下:
ev_timer_event_t *brc_toggleEvt = NULL;
s32 brc_toggleCb(void *arg)
{
epInfo_t dstEpInfo;
TL_SETSTRUCTCONTENT(dstEpInfo, 0);
dstEpInfo.dstAddrMode = APS_SHORT_DSTADDR_WITHEP;
dstEpInfo.dstEp = SAMPLE_GW_ENDPOINT;
dstEpInfo.dstAddr.shortAddr = 0xffff;
dstEpInfo.profileId = HA_PROFILE_ID;
dstEpInfo.txOptions = 0;
dstEpInfo.radius = 0;
zcl_onOff_toggleCmd(SAMPLE_GW_ENDPOINT, &dstEpInfo, FALSE);
brc_toggleEvt = NULL;
return -1;
}
void buttonShortPressed(u8 btNum)
{
if(btNum == VK_SW1){
if(!brc_toggleEvt){
brc_toggleEvt = TL_ZB_TIMER_SCHEDULE(brc_toggleCb,
NULL,
10 * 1000);
}else{
TL_ZB_TIMER_CANCEL(&brc_toggleEvt);
}
}
}
MAC常用APIs
MAC提供了一系列APIs,供应用层(APP)和MAC层实现命令、数据、状态的交互:
a) 请求(Request)及确认(Confirm):应用层对MAC层发出命令请求(COMMAND-request)和数据请求(DATA-request),以及收到MAC层回复的状态确认(CONFIRM).
b) 接收(indication):应用层收到MAC层命令 (COMMAND-indication)和数据 (DATA-indication).
应用层通过MAC层管理实体(MAC Layer Management Entity,MLME)和MAC层数据传输服务(MAC CommonLayer Service Access Point,MCPS)来实现。
MAC层管理实体(MAC Layer Management Entity,MLME)
MLME-POLL
1) MLME-POLL.request
实现函数:
u8 tl_MacMlmePollRequestSend(mac_mlme_poll_req_t req)
- req为指向MLME-POLL.request原语(primitive)的结构体变量。
MLME-POLL.request原语数据结构:mac_mlme_poll_req_t。
函数声明文件:upper_layer.h (路径:tl_802154_sdk -> 802154 -> mac -> includes)。
2) MLME-POLL.confirm
注册回调函数:
UpperLayerCallbackSet(CALLBACK_POLL_CONFIRM, MyPollCnfCb);
-
CALLBACK_POLL_CONFIRM为MLME-POLL.confirm回调函数ID,为固定值。
-
void MyPollCnfCb(unsigned char *pData)为应用层声明的回调函数,pData为指向MLME-POLL.confirm原语(primitive)的指针。
MLME-POLL.confirm原语数据结构:mac_mlme_poll_conf_t。
函数声明文件:upper_layer.h (路径:tl_802154_sdk -> 802154 -> mac -> includes)。
3) MLME-POLL.indication
注册回调函数:
UpperLayerCallbackSet(CALLBACK_POLL_INDICATION, MyPullIndCb);
-
CALLBACK_POLL_INDICATION为MLME-POLL.confirm回调函数ID,为固定值。
-
void MyPullIndCb (unsigned char *pData)为应用层声明的回调函数,pData为指向MLME-POLL.indication原语(primitive)的指针。
MLME-POLL.indication原语数据结构:mac_mlme_poll_ind_t。
函数声明文件:upper_layer.h (路径:tl_802154_sdk -> 802154 -> mac -> includes)。
MLME-ASSOCIATE
1) MLME-ASSOCIATE.request
实现函数:
u8 tl_MacMlmeAssociateRequestSend(zb_mlme_associate_req_t req)
- req为指向MLME-ASSOCIATE.request原语(primitive)的结构体变量。
MLME-ASSOCIATE.request原语数据结构:zb_mlme_associate_req_t。
函数声明文件:upper_layer.h (路径:tl_802154_sdk -> 802154 -> mac -> includes)。
2) MLME_ASSOCIATE.confirm
注册回调函数:
UpperLayerCallbackSet(CALLBACK_ASSOCIATE_CONFIRM, MyAssocCnfCb);
-
CALLBACK_ASSOCIATE_CONFIRM为MLME-ASSOCIATE.confirm回调函数ID,为固定值。
-
void MyAssocCnfCb (unsigned char *pData)为应用层声明的回调函数,pData为指向MLME-ASSOCIATE.confirm原语(primitive)的指针。
MLME-ASSOCIATE.confirm原语数据结构:zb_mlme_associate_conf_t。
函数声明文件:upper_layer.h (路径:tl_802154_sdk -> 802154 -> mac -> includes)。
3) MLME_ASSOCIATE.indication
注册回调函数:
UpperLayerCallbackSet(CALLBACK_ASSOCIATE_INDICATION, MyAssociateIndCb);
-
CALLBACK_ASSOCIATE_INDICATION为MLME-ASSOCIATE.indication回调函数ID,为固定值。
-
void MyAssociateIndCb (unsigned char *pData)为应用层声明的回调函数,pData为指向MLME-ASSOCIATE.indication原语(primitive)的指针。
MLME- ASSOCIATE.indication原语数据结构:zb_mlme_associate_ind_t。
函数声明文件:upper_layer.h (路径:tl_802154_sdk -> 802154 -> mac -> includes)。
4) MLME_ASSOCIATE.response
实现函数:
u8 tl_MacMlmeAssociateResponseSend(zb_mlme_associate_resp_t req)
- req为指向MLME-ASSOCIATE.response原语(primitive)的结构体变量。
MLME-ASSOCIATE.response原语数据结构:zb_mlme_associate_resp_t。
函数声明文件:upper_layer.h (路径:tl_802154_sdk -> 802154 -> mac -> includes)。
MLME-SCAN
1) MLME_SCAN.request
实现函数:
u8 tl_MacMlmeScanRequest(zb_mac_mlme_scan_req_t req)
- req为指向MLME-SCAN.request原语(primitive)的结构体变量。
MLME-SCAN.request原语数据结构:zb_mac_mlme_scan_req_t。
函数声明文件:upper_layer.h (路径:tl_802154_sdk -> 802154 -> mac -> includes)。
2) MLME_SCAN.confirm
注册回调函数:
UpperLayerCallbackSet(CALLBACK_SCAN_CONFIRM, MyScanCnfCb);
-
CALLBACK_SCAN_CONFIRM为MLME-SCAN.confirm回调函数ID,为固定值。
-
void MyScanCnfCb (unsigned char *pData)为应用层声明的回调函数,pData为指向MLME-SCAN.confirm原语(primitive)的指针。
MLME-SCAN.confirm原语数据结构:zb_mac_mlme_scan_conf_t。
函数声明文件:upper_layer.h (路径:tl_802154_sdk -> 802154 -> mac -> includes)。
MLME-START
1) MLME_START.request
实现函数:
u8 tl_MacMlmeStartRequest(zb_mac_mlme_start_req_t req)
- req为指向MLME-ASSOCIATE.request原语(primitive)的结构体变量。
MLME-ASSOCIATE.request原语数据结构:zb_mlme_associate_req_t。
函数声明文件:upper_layer.h (路径:tl_802154_sdk -> 802154 -> mac -> includes)。
2) MLME_START.confirm
注册回调函数:
UpperLayerCallbackSet(CALLBACK_START_CONFIRM, MyStartCnfCb);
-
CALLBACK_START_CONFIRM为MLME-START.confirm回调函数ID,为固定值。
-
void MyStartCnfCb (unsigned char *pData)为应用层声明的回调函数,pData为指向MLME- START.confirm原语(primitive)的指针。
MLME- START.confirm原语数据结构:mac_mlme_startCnf_t。
函数声明文件:upper_layer.h (路径:tl_802154_sdk -> 802154 -> mac -> includes)。
MLME-DISASSOCIATE
1) MLME_DISASSOCIATE.request
实现函数:
u8 tl_MacMlmeDisassociateRequestSend(zb_mlme_disassociate_req_t req)
- req为指向MLME-DISASSOCIATE.request原语(primitive)的结构体变量。
MLME- DISASSOCIATE.request原语数据结构:zb_mlme_disassociate_req_t。
函数声明文件:upper_layer.h (路径:tl_802154_sdk -> 802154 -> mac -> includes)。
2) MLME_DISASSOCIATE.confirm
注册回调函数:
UpperLayerCallbackSet(CALLBACK_DISASSOCIATE_CONFIRM, MyDisassocCnfCb);
-
CALLBACK_ASSOCIATE_CONFIRM为MLME-ASSOCIATE.confirm回调函数ID,为固定值。
-
void MyDisassocCnfCb (unsigned char *pData)为应用层声明的回调函数,pData为指向MLME-DISASSOCIATE.confirm原语(primitive)的指针。
MLME- DISASSOCIATE.confirm原语数据结构:zb_mlme_disassociate_conf_t。
函数声明文件:upper_layer.h (路径:tl_802154_sdk -> 802154 -> mac -> includes)。
3) MLME_DISASSOCIATE.indication
注册回调函数:
UpperLayerCallbackSet(CALLBACK_DISASSOCIATE_INDICATION, MyDisassociateIndCb);
-
CALLBACK_DISASSOCIATE_INDICATION为MLME-DISASSOCIATE.indication回调函数ID,为固定值。
-
void MyDisassociateIndCb (unsigned char *pData)为应用层声明的回调函数,pData为指向MLME-DISASSOCIATE.indication原语(primitive)的指针。
MLME-DISASSOCIATE.indication原语数据结构:zb_mlme_disassociate_ind_t。
函数声明文件:upper_layer.h (路径:tl_802154_sdk -> 802154 -> mac -> includes)。
MLME-BEACON-NOTIFY
1) MLME-BEACON-NOTIFY.indication
注册回调函数:
UpperLayerCallbackSet(CALLBACK_BEACON_NOTIFY_INDICATION, MyDisassociateIndCb);
-
CALLBACK_BEACON_NOTIFY_INDICATION为MLME-BEACON-NOTIFY.indication回调函数ID,为固定值。
-
void MyDisassociateIndCb (unsigned char *pData)为应用层声明的回调函数,pData为指向MLME-BEACON-NOTIFY.indication原语(primitive)的指针。
MLME-BEACON-NOTIFY.indication原语数据结构:zb_mlme_beacon_notify_ind_t。
函数声明文件:upper_layer.h (路径:tl_802154_sdk -> 802154 -> mac -> includes)。
MLME-COMM-STATUS
1) MLME-COMM-STATUS.indication
注册回调函数:
UpperLayerCallbackSet(CALLBACK_COMM_STATUS_INDICATION, MyStateIndCb);
-
CALLBACK_COMM_STATUS_INDICATION为MLME-COMM-STATUS.indication回调函数ID,为固定值。
-
void MyStateIndCb (unsigned char *pData)为应用层声明的回调函数,pData为指向MLME-COMM-STATUS.indication原语(primitive)的指针。
MLME-COMM-STATUS.indication原语数据结构:zb_mlme_comm_status_ind_t。
函数声明文件:upper_layer.h (路径:tl_802154_sdk -> 802154 -> mac -> tl_zb_mac.h)。
MAC层数据传输服务(MAC Common Layer Service Access Point,MCPS)
MCPS-DATA
1) MCPS-DATA.request
实现函数:
u8 tl_MacMcpsDataRequestSend(zb_mscp_data_req_t req,u8 *payload,u8 pay_len)
-
req为指向MCPS-DATA.request原语(primitive)的结构体变量。
-
payload为指向需要发送数据的指针。
-
pay_len为需要发送数据的长度。
MCPS-DATA.request原语数据结构:zb_mscp_data_req_t。
函数声明文件:upper_layer.h (路径:tl_802154_sdk -> 802154 -> mac -> includes)。
2) MCPS-DATA.confirm
注册回调函数:
UpperLayerCallbackSet(CALLBACK_MCPS_DATA_CONFIRM, MyDataCnfCb);
-
CALLBACK_MCPS_DATA_CONFIRM为MCPS-DATA.confirm回调函数ID,为固定值。
-
void MyDataCnfCb (unsigned char *pData)为应用层声明的回调函数,pData为指向MCPS-DATA.confirm原语(primitive)的指针。
MCPS-DATA.confirm原语数据结构:zb_mscp_data_conf_t。
函数声明文件:upper_layer.h (路径:tl_802154_sdk -> 802154 -> mac -> includes)。
3) MCPS-DATA.indication
注册回调函数:
UpperLayerCallbackSet(CALLBACK_DATA_INDICATION, MyDataIndCb);
-
CALLBACK_DATA_INDICATION为MCPS-DATA.indication回调函数ID,为固定值。
-
void MyDataIndCb (unsigned char *pData)为应用层声明的回调函数,pData为指向MCPS-DATA.indication原语(primitive)的指针。
MCPS-DATA.indication原语数据结构:zb_mscp_data_ind_t。
函数声明文件:upper_layer.h (路径:tl_802154_sdk -> 802154 -> mac -> includes)。
ASP (ATTRIBUTE SETTING)
MAC PIB属性(attribute)通过ASP来设置,这部分代码是开源的。
文件路径:tl_802154_sdk -> 802154 -> mac -> mac_pib.c
写MAC PIB属性函数(write MAC PIB attribute)
u8 tl_zbMacAttrSet(u8 attribute, u8 *value, u8 index)
-
attribute:MAC PIB 属性(attribute) 号(id)。
-
value:写入对应MAC PIB 属性(attribute) 值的指针。
-
index:如attribute写为加密相关的属性(attribute)号(id),例如MAC_KEY_TABLE、MAC_DEVICE_TABLE、MAC_SECURITY_LEVEL_TABLE,这几个属性(attribute)号(id)对应的MAC PIB属性均为有限个数的数组,则index表示为需要写入的对应入口号;如attribute其他值,index为对应MAC PIB 属性(attribute) 值的长度。
-
返回值:如果写成功返回MAC_SUCCESS,否则返回MAC_INVALID_PARAMETER。
读MAC PIB属性函数(read MAC PIB attribute)
u8 tl_zbMacAttrGet(u8 attribute, u8* value, u8* index)
-
attribute :MAC PIB 属性(attribute) 号id。
-
value:读对应MAC PIB 属性(attribute) 值的指针。
-
index:如attribute写为加密相关的属性(attribute)号(id),例如MAC_KEY_TABLE、MAC_DEVICE_TABLE、MAC_SECURITY_LEVEL_TABLE,这几个属性(attribute)号(id)对应的MAC PIB属性均为有限个数的数组,则index表示为要读的对应入口号;如attribute其他值,index为对应MAC PIB 属性(attribute) 值的长度。
-
返回值:如果读成功返回MAC_SUCCESS,否则返回MAC_INVALID_PARAMETER。
初次上电,SDK定义了MAC PIB默认值。
文件路径:tl_802154_sdk -> 802154 -> common -> zb_config.c
默认值变量:const tl_zb_mac_pib_t macPibDefault
读写MAC PIB属性(attribute)示例
1) associate device设置PAN ID
u8 len = 2;//pan id 长度为2字节
u16 panid = 0xbeef;
tl_zbMacAttrSet(MAC_ATTR_PAN_ID, &panid ,len);
-
MAC PIB 属性(attribute)ID attribute = MAC_ATTR_PAN_ID
-
写入值指针 value = &panid
-
写入长度 len = 2
2) associate device读associate coordinator长地址()
u8 coor_ext_short[8] = {0};
u8 len=0;
tl_zbMacAttrGet(MAC_ATTR_COORDINATOR_EXTENDED_ADDRESS,(u8*)coor_ext_short,
&len);
- MAC PIB 属性(attribute) ID
attribute = MAC_ATTR_COORDINATOR_EXTENDED_ADDRESS -
读出值指针 value = &panid
-
读出长度指针 index = &len
802.15.4 SDK应用开发
硬件选择
Telink 802154 SDK demo可以运行在不同系列芯片、不同硬件板子上,用户需要针对不同的硬件条件,做相应的配置。
芯片型号确认
Telink 802154 SDK在comm_cfg.h中列举了以下几种芯片类型,用户在编译工程实例前,请确认相应工程下version_cfg.h中选择的芯片类型是否与实际使用的芯片类型一致。
(1) comm_cfg.h芯片类型定义
/* Chip IDs */
#define TLSR_8267 0x00
#define TLSR_8269 0x01
#define TLSR_8258_512K 0x02
#define TLSR_8258_1M 0x03
#define TLSR_8278 0x04
#define TLSR_9518 0x05
(2) version_cfg.h芯片类型选择
#if defined(MCU_CORE_826x)
#if (CHIP_8269)
#define CHIP_TYPE TLSR_8269
#else
#define CHIP_TYPE TLSR_8267
#endif
#elif defined(MCU_CORE_8258)
#define CHIP_TYPE TLSR_8258_512K//TLSR_8258_1M
#elif defined(MCU_CORE_8278)
#define CHIP_TYPE TLSR_8278
#elif defined(MCU_CORE_B91)
#define CHIP_TYPE TLSR_9518
#endif
目标板选择
Telink 802154 SDK提供的Demo可以运行在EVK板或USB Dongle上的,用户可以在相应Demo下的app_cfg.h文件中选择更改目标板。
/* Board ID */
#define BOARD_826x_EVK 0
#define BOARD_826x_DONGLE 1
#define BOARD_826x_DONGLE_PA 2
#define BOARD_8258_EVK 3
#defineBOARD_8258_EVK_V1P2 4//C1T139A30_V1.2
#define BOARD_8258_DONGLE 5
#define BOARD_8278_EVK 6
#define BOARD_8278_DONGLE 7
#define BOARD_9518_EVK 8
#define BOARD_9518_DONGLE 9
/* Board define */
#if defined(MCU_CORE_8258)
#if (CHIP_TYPE == TLSR_8258_1M)
#define FLASH_CAP_SIZE_1M 1
#endif
#define BOARD BOARD_8258_DONGLE
#define CLOCK_SYS_CLOCK_HZ 48000000
#elif defined(MCU_CORE_8278)
#define FLASH_CAP_SIZE_1M 1
#define BOARD BOARD_8278_DONGLE
#define CLOCK_SYS_CLOCK_HZ 48000000
#elif defined(MCU_CORE_B91)
#define FLASH_CAP_SIZE_1M 1
#define BOARD BOARD_9518_DONGLE
#define CLOCK_SYS_CLOCK_HZ 48000000
#else
#error "MCU is undefined!"
#endif
在预编译阶段会根据先前的芯片类型选择加载对应的板级配置,配置文件是各工程目录下的board_xx.h,同时需要注意一下目标板的FLASH容量是否与板级配置一致,以防加载数据出错。
#defineFLASH_CAP_SIZE_1M 1
打印调试配置
UART打印
为避免硬件UART资源的浪费,我们通过GPIO模拟UART TX实现了UART打印功能(printf()函数),用户可以任意更改合适的GPIO。配置方法如下:
1) 打印使能配置:
#define UART_PRINTF_MODE 1
2) 打印口配置:
#define DEBUG_INFO_TX_PIN GPIO_PC4//print
3) 波特率配置:
#define BAUDRATE 1000000//1M
注意:
1. 826x最大支持2M波特率,8258、8278和9518最大支持1M波特率;
2. 不要在中断处理函数中使用该打印,防止打印数据较多或函数嵌套过深导致中断栈溢出。
USB打印
可以配合Telink BDT工具使用USB打印。配置方法如下:
1) 打印使能配置:
#define USB_PRINTF_MODE 1
2) 使能USB端口:
#define HW_USB_CFG() do{ \
usb_set_pin_en();\
}while(0)
注意:
当使用ZBHCI_USB_CDC或ZBHCI_USB_HID功能时,USB打印功能失效。
802154开发流程
应用层初始化(user_init)
应用层初始化主要由802154 stack以及802154应用层初始化组成。
1) os_init(u8 isRetention)
对于isRetention为0的上电设备来说,os_init函数完成任务队列,以及用户内存等非协议栈相关的初始化工作。
2) user_init()
用户根据具体产品功能,初始化应用代码。
- 协议栈初始化:
zb_init();
初始化 mac层的初始化,对于not factory-new设备,会从NV中读取入网信息,恢复网络信息以及各层属性。
注意: 对于已经入网的设备,无法通过修改zb_config.c里的默认属性表配置达到改变属性的目的,如果想修改属性的话,必须通过u8 tl_zbMacAttrSet(u8 attribute, u8 *value, u8 index)函数和attribute来修改。
- 设置异常处理回调函数:
sys_exceptHandlerRegister(sys_exception_cb_t cb)
注册一个异常状态回调函数,SDK中默认为异常闪灯。
- 注册MAC回调函数:
UpperLayerCallbackSet(unsigned char Index, UpperLayerCb_Type Callback)
根据实际需要用到原语标号(primitive ID)注册对应的回调处理函数。
3) Ev_on_poll()
注册用户轮询事件。
参数配置
用户可以根据需求在802154 -> common -> zb_config.c中修改网络参数配置。
- macPibDefault
MAC层的基本参数信息。
数据安全
15.4 SDK提供802.15.4(2006)标准的加密方式,SDK中默认使能15.4加密功能,应用层只需要配置好MAC PIB加密模式,发送前设置和MAC PIB对应的加密模式即可。
-
MAC PIB加密模式: SDK提供的demo中已经添加了加密示例,详细请参考函数:void add_key_material(void)
-
发送前设置加密模式: 在发送前,设置好结构体mac_sec_t sec的值,15.4 SDK会做模式和密钥的校对,如果和MAC PIB中一致,则在对应confirm回调函数中返回MAC_SUCCES,否则返回其他值。 参考函数void mac_send_data_indirect(void *arg):
解密由MAC完成,应用层只要配置好MAC PIB 即可。
工作流程
入网流程
Associate流程:
1) 终端节点(end device)
i) 通过MLME_SCAN.request启动active scan,scan结束后通过MLME-SCAN.confirm的注册回调函数将结果返回到应用层
MLME_SCAN.request api: MacMlmeScanRequest()
MLME_SCAN.confirm api: UpperLayerCallbackSet(CALLBACK_SCAN_CONFIRM, MyScanCnfCb);
ii) 根据active scan 结果,通过MLME-ASSOCIATE.request向协调器发起association,等待来自协调器的associate response 数据包(或超时)
MLME-ASSOCIATE.request api: tl_zbMacAssociateRequest
iii) 通过 MLME-ASSOCIATE.confirm的注册回调函数将association结果返回给应用层
MLME-ASSOCIATE.confirm api: UpperLayerCallbackSet(CALLBACK_START_CONFIRM, MyStartCnfCb);
2) 协调器节点(coordinator)
i) 通过MLME_START.request启动energy scan/active scan, 建立PAN, 后处于监听状态
MLME_START.request api: tl_zbMacStartRequest()
ii) 当接收到来自终端节点的MLME-ASSOCIATE.request后发送associate response,再通过MLME-COMM-STATUS.indication告知应用层association结果
如成功,状态为MAC_SUCCESS,其他状态则为失败,如pending列表满MAC_STA_TRANSACTION_OVERFLOW等。
具体状态参考枚举变量 mac_sts_t:tl_802154_sdk->802154->mac->includes->tl_zb_mac.h
MLME-COMM-STATUS.indication api: UpperLayerCallbackSet(CALLBACK_COMM_STATUS_INDICATION, MyStateIndCb);
数据交互
(a) There is No Frame Pending (FP=0)
(b) There is a Frame Pending (FP=1)
入网后,对于需要低功耗功能的终端节点,是通过周期性的MLME-POLL.request来实现查询和读取coordinator端的数据,应用层的代码都是基于这个流程来实现,例如OTA,终端节点作为开关控制灯等等应用。
系统异常处理
调用sys_exceptHandlerRegister()注册异常回调函数, 当stack发生buffer泄露、状态异常时会触发该函数,在此函数里用户可以添加相应异常处理。
建议:开发阶段,回调函数直接while(1),以便定位问题,通过变量T_evtExcept[1]可以定位到发生了何种异常;产品阶段,最好做复位处理。
例如:
Volatileu16 T_debug_except_code = 0;
static void sampleLightSysException(void){
T_debug_except_code = T_evtExcept[1];
while(1)//or SYSTEM_RESET();
}
/* Register except handler for test */
sys_exceptHandlerRegister(sampleLightSysException);
OTA
TLSR8和TLSR9系列芯片支持Flash多地址启动:除了Flash地址0x00000,还支持从0x40000读取固件运行。Telink 802154 SDK使用了该特性来实现OTA的功能。
从2.3节可知,我们分配了两块固件区域Firmware和OTA-Image,固件大小应不大于208K。
假设当前正在运行Firmware的固件,当设备执行OTA升级时,新的固件数据将被存储到OTA-Image,在OTA结束并且验证通过后,将重启并运行OTA-Image的固件。后续OTA,将交替执行。
OTA查询功能
ota_queryStart()
启动OTA查询功能,由终端节点 (end device)调用,周期性的查询coordinator端是否由固件需要更新。
- 原型
void ota_queryStart(u16 seconds)
- 返回值 None
Name | Type | Description |
---|---|---|
seconds | u8 | Query cycle, in second |
OTA设备类型
OTA设备分为服务设备(Server)和终端设备(Client)。因此,在OTA初始化时需要注意OTA初始化的服务类型。
一般地,被升级设备为终端设备(Client),一般是指终端节点 (end device);为被升级设备提供新固件的设备为服务设备(Server),一般是指协调器(PAN coordinator)。
OTA Server
OTA服务端需要将被升级设备所需要的新固件写入OTA-Image区域供OTA使用。
例如:服务端自己运行的固件在Firmware区,那么可以将目标设备的OTA image(包含OTA Header的新固件)暂存到OTA-Image区域。
OTA Client
入网成功,将调用void ota_queryStart(u16 seconds)设置OTA终端设备的OTA查询周期,单位:秒,即在设置的seconds秒后开始OTA请求。
OTA Client端的 OTA image和正常bin同时生成,在正常bin前会加上ota_以示区别,只有CLIENT端会执行tl_ota_tool,生成OTA文件。
如2.4.2 flash分布图所示,OTA_Image和firmware是轮流交替的,例如当前firmware在0x0000地址,则OTA被存储到0x40000,如OTA成功,则0x0000地址的firmware会被手动置为失效,CLIENT每次从0x40000启动,下一次OTA文件则存储到0x0000,如此往复。
OTA流程
-
OTA START OTA CLIENT端周期性的发送ot_start_req数据包给OTA SERVER,具体周期通过函数ota_queryStart()设置,单位为秒,ot_start_req数据包内包含当前OTA CLIENT端bin文件信息(文件版本(file version)、 制造商代码(MANUFACTURER_CODE)、固件类型(image type));OTA SERVER端收到ot_start_req后,读取0x40000位置的OTA文件信息,然后将OTA文件信息通过sot_start_rsp数据包发给OTA CLIENT;
-
OTA DATA OTA CLIENT解析OTA SERVER端start response后,会得到OTA SERVER端OTA文件信息,与OTA CLIENT当前bin比较后,如果制造商代码(MANUFACTURER_CODE)、固件类型(image type)一样,且OTA SERVER端OTA文件版本(file version)大于OTA CLIENT当前bin文件版本(file version),则OTA CLIENT发出ota data request给OTA SERVER,接着SERVER端读取OTA文件,通过ota data response发送给OTA CLIENT,此过程一直持续到OTA文件发送完。
-
OTA STOP OTA CLIENT端获取的数据长度大于等于OTA大小时,CLIENT会发送OTA STOP request给SERVER,结束整个OTA过程,接着CLIENT端会把本地计算的CRC值和OTA文件最后四个字节的CRC值做对比,如果一致则重启,否则忽略本次OTA。