Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
蓝牙BLE
RTT平台 zephyr_polling软件包 Bluenrg2 蓝牙芯片启动流程
发布于 2023-09-26 16:50:31 浏览:402
订阅该版
[tocm] # RTT zephyr_polling软件包 Bluenrg2 蓝牙芯片启动流程 >“开源之夏”“蓝牙HOST协议栈zephyr_polling完善” 项目个人记录 >菜鸡参与项目的个人记录 >项目软件包地址:[RTT_PACKAGE_zephyr_polling](https://github.com/bobwenstudy/RTT_PACKAGE_zephyr_polling) 前面已经完成了 SPI 接口的实现,要让 zephyr_polling 在 Bluenrg2 上运行起来,下一步是实现其特殊的芯片启动流程。 ## 蓝牙芯片启动流程 在用标准的 HCI 指令控制设备进行蓝牙操作之前,需要提前通过 VS Command 对设备进行配置,只有正确配置好的设备才能正常使用。 芯片产商只出售芯片,并不关注外围电路和具体的产品形态,这些是具体的ODM厂商来实现的。也就是芯片产商提供带HCI蓝牙功能的芯片,ODM设计电路并设计产品,之后通过HCI和芯片进行交互。实际各家ODM产商的需求各不相同,芯片产商为了满足不同客户的需要,并且为了减少和客户的对接,就必然在同一套代码的基础上,需要提供一系列的配置参数来满足不同 ODM 厂商的需要。 配置可以包括:固件烧录(部分没有带 FLASH 的蓝牙芯片每次上电都需要重新烧录最新的固件)、蓝牙地址配置、硬件接口配置(如RF接口,晶振类型等,部分蓝牙芯片需要)、波特率配置(HCI 一般是UART接口,默认是115200)以及芯片需要的由厂商要求的其他参数配置。 此外,对于一些有Flash的芯片,完全可以将配置参数等预烧录到了 Flash 中,使用时完全不需要配置任何参数,直接通过HCI接口操作使用即可。 zephyr_polling 协议栈提供了 Boot 流程接口和 Prepare 流程接口,可以根据实际芯片的需求实现启动配置。 ![2023-09-25-23-46-34.png](https://oss-club.rt-thread.org/uploads/20230926/e8f63fa638665dc739506abc4ac73003.png) **Boot流程**: 完成厂商的初始化流程,如固件下载,蓝牙地址配置等。在 chipset 注册好接口后,协议栈启动时会通过`boot_start()`回调启动 chipset(指协议栈 chipset 目录下的启动流程代码,下同) 的 Boot 流程,由于操作接口是 HCI,所以一般都是下发一个VS Command,然后根据 VS Event 来进行后续动作,协议栈会通过`event_process()`回调接口将收到的 event 上报给 chipset,当 chipset 认为操作结束时,通过调用`bt_hci_set_boot_ready()`接口通知协议栈boot流程结束。 **Prepare流程**: 部分厂商的参数要求在 HCI_Reset Command 之后进行(意思是它们的 HCI_Reset Command 会清空配置的参数)。为了兼容这类参数形态,HCI_Reset Command 之后还加入了 Prepare 流程。协议栈收到 HCI_Reset 的 Command Complete Event 后会通过`prepare_start()`回调启动 chipset 的 Prepare 流程,和 Boot 流程一样,协议栈会通过`event_process()`回调接口将收到的 event 上报给 chipset ,当chipset 认为操作结束时,通过调用 `bt_hci_set_prepare_ready()`接口通知协议栈prepare流程结束。 ## BlueNRG-2 启动流程 查阅 ST 官方提供的手册和例程资料,可以了解到 BlueNRG-2 的启动配置需求。 **对于 BlueNRG-2**: Boot 流程:无事务。 Prepare 流程:关闭Host功能;蓝牙地址配置;设置 TX power;GATT配置;GAP配置。 ## BlueNRG-2 启动流程实现 ### Boot 流程 BlueNRG-2 的 HCI_Reset Command 会清空配置的参数,所以实际的配置放在协议栈的 Prepare 流程中。Boot 流程的回调函数直接调用`bt_hci_set_boot_ready()`结束流程。 ```C void boot_start(void) { state = STATE_POLLING_BOOTING; // nothing to do bt_hci_set_boot_ready(); //finish boot } ``` ### Prepare 流程 - 关闭 Host 功能 开发使用的蓝牙模块 X-NUCLEO-BNRG2A1 中的 BLE 本身是一个 SOC,里面集成了 host 的协议栈。厂商 ST 提供了一套 ACI 指令来控制芯片行为,包括 host 的接口。也就是说默认的情况下,这个芯片的 ACL 交互都被接管了,所以需要通过 ACI 命令,关闭 host 行为。需要通过`aci_hal_write_config_data`里的`CONFIG_DATA_LL_WITHOUT_HOST`关闭 host。 Prepare 流程第一步,关闭 host: ```C void prepare_start(void) { state = STATE_POLLING_PREPARING; step = 1; // step 1 close host bluenrg2_config_without_host(); // It can be written only if aci_hal_write_config_data() is the first command after reset. } ``` 关闭 host 的指令的 ogf 为`0x3f`,ocf 为`0x00c`,参数为`2c11`。其中,`0x2C`是关闭 Host 在 CONFIG_DATA 中的 offset。 ```c #define CONFIG_DATA_LL_WITHOUT_HOST (0x2C) /**< Switch on/off Link Layer only mode. Set to 1 to disable Host. */ #define CONFIG_DATA_LL_WITHOUT_HOST_LEN (1) static int bluenrg2_config_without_host() { uint8_t cmd_buffer[CONFIG_DATA_LL_WITHOUT_HOST_LEN + 2]; struct net_buf *buf; cmd_buffer[0] = CONFIG_DATA_LL_WITHOUT_HOST; //offset cmd_buffer[1] = CONFIG_DATA_LL_WITHOUT_HOST_LEN; //config len cmd_buffer[2] = 1; //Set to 1 to disable Host uint16_t ogf = 0x3f, ocf = 0x00c; uint16_t opcode = (uint16_t)((ocf & 0x03ff)|(ogf << 10)); buf = bt_hci_cmd_create(opcode, sizeof(cmd_buffer)); if (!buf) { return -ENOBUFS; } net_buf_add_mem(buf, cmd_buffer, sizeof(cmd_buffer)); return bt_hci_cmd_send(opcode, buf); } ``` ### Prepare 流程 - 蓝牙地址设置 需要通过`aci_hal_write_config_data`里的`CONFIG_DATA_PUBADDR_OFFSET`配置蓝牙地址。 配置蓝牙地址的指令的 ogf 为`0x3f`,ocf 为`0x00c`。配置蓝牙地址指令在 CONFIG_DATA 中的 offset 为 `0x00`,后面跟上地址长度和设置的蓝牙地址。 ```C #define BLE_MAC_ADDR \ { \ { \ 0xf5, 0x00, 0x00, 0xE1, 0x80, 0x02 \ } \ } #define CONFIG_DATA_PUBADDR_OFFSET (0x00) /**< Bluetooth public address */ #define CONFIG_DATA_PUBADDR_LEN (6) static int bluenrg2_config_set_public_addr() { uint8_t cmd_buffer[CONFIG_DATA_PUBADDR_LEN + 2]; struct net_buf *buf; bt_addr_t addr = BLE_MAC_ADDR; cmd_buffer[0] = CONFIG_DATA_PUBADDR_OFFSET; //offset cmd_buffer[1] = CONFIG_DATA_PUBADDR_LEN; //config len memcpy(cmd_buffer + 2, addr.val, CONFIG_DATA_PUBADDR_LEN); // addr uint16_t ogf = 0x3f, ocf = 0x00c; uint16_t opcode = (uint16_t)((ocf & 0x03ff)|(ogf << 10)); buf = bt_hci_cmd_create(opcode, sizeof(cmd_buffer)); if (!buf) { return -ENOBUFS; } net_buf_add_mem(buf, cmd_buffer, sizeof(cmd_buffer)); return bt_hci_cmd_send(opcode, buf); } ``` ### Prepare 流程 - 设置发射功率 配置发射功率的指令的 ogf 为`0x3f`,ocf 为`0x00f`。命令参数为是否启用高功率模式(`0x00`启用普通功率,`0x01`启用高功率)和功率放大器输出电平(允许的PA电平取决于设备)。 >PA_Level 值对应功率 0: -14 dBm (High Power) 1: -11 dBm (High Power) 2: -8 dBm (High Power) 3: -5 dBm (High Power) 4: -2 dBm (High Power) 5: 2 dBm (High Power) 6: 4 dBm (High Power) 7: 8 dBm (High Power) ```c static int bluenrg2_set_tx_power_level(uint8_t En_High_Power, uint8_t PA_Level) { uint8_t cmd_buffer[2]; struct net_buf *buf; cmd_buffer[0] = En_High_Power; //En_High_Power cmd_buffer[1] = PA_Level; //config PA_Level uint16_t ogf = 0x3f, ocf = 0x00f; uint16_t opcode = (uint16_t)((ocf & 0x03ff)|(ogf << 10)); buf = bt_hci_cmd_create(opcode, sizeof(cmd_buffer)); if (!buf) { return -ENOBUFS; } net_buf_add_mem(buf, cmd_buffer, sizeof(cmd_buffer)); return bt_hci_cmd_send(opcode, buf); } ``` ### Prepare 流程 - GATT 配置 GATT 初始化的指令的 ogf 为`0x3f`,ocf 为`0x101`,没有其它参数。 ```C static int bluenrg2_gatt_init(void) { uint16_t ogf = 0x3f, ocf = 0x101; uint16_t opcode = (uint16_t)((ocf & 0x03ff)|(ogf << 10)); return bt_hci_cmd_send(opcode, NULL); } ``` ### Prepare 流程 - GAP 配置 初始化 GAP 层。注册GAP服务,并设置标准 GAP 服务特性:设备名称、Appearance、外围设备首选连接参数(仅限外围设备)。 GAP 配置的指令的 ogf 为`0x3f`,ocf 为`0x08a`。配置为外围设备,如果需要用做其他角色,需要修改此处;不启用隐私策略(为保护地址不被窃取,进行地址加密/解密,并周期更新);设置设备名字长度。 > privacy: 0x00: Privacy disabled 0x01: Privacy host enabled 0x02: Privacy controller enabled ```C #define GAP_PERIPHERAL_ROLE (0x01) #define GAP_BROADCASTER_ROLE (0x02) #define GAP_CENTRAL_ROLE (0x04) #define GAP_OBSERVER_ROLE (0x08) #define privacy_enabled (0x00) #define device_name_char_len (0x08) static int bluenrg2_gap_init() { uint8_t cmd_buffer[3]; struct net_buf *buf; cmd_buffer[0] = GAP_PERIPHERAL_ROLE; //role cmd_buffer[1] = privacy_enabled; //privacy cmd_buffer[2] = device_name_char_len; //device_name_char_len uint16_t ogf = 0x3f, ocf = 0x08a; uint16_t opcode = (uint16_t)((ocf & 0x03ff)|(ogf << 10)); buf = bt_hci_cmd_create(opcode, sizeof(cmd_buffer)); if (!buf) { return -ENOBUFS; } net_buf_add_mem(buf, cmd_buffer, sizeof(cmd_buffer)); return bt_hci_cmd_send(opcode, buf); } ``` ### 启动事件处理 对于启动流程的返回响应,需要由`event_process()`回调进行判断和推进。这里为了方便,只对`CMD_COMPLETE`事件进行判断处理,推进 Prepare 流程进行。 GAP 设置完成后调用`bt_hci_set_prepare_ready()`结束流程。 ```C void event_process(uint8_t event, struct net_buf *buf) { if(state == STATE_POLLING_PREPARING) // boot do nothing { if (event == BT_HCI_EVT_CMD_COMPLETE) //only complete { printk("prepare_event_process, step: %d\n", step); switch (step) { case 1: //close host just now bluenrg2_config_set_public_addr(); //step2 set_public_addr step = 2; break; case 2: bluenrg2_set_tx_power_level(1, 4); //step3 set_public_addr step = 3; break; case 3: bluenrg2_gatt_init(); //step4 gatt_ini step = 4; break; case 4: bluenrg2_gap_init(); //step5 gap_ini step = 5; break; case 5: bt_hci_set_prepare_ready(); //finish prepare step = 0; break; } } } } ``` ### 启动流程注册 将上述实现的启动流程的函数指针打包到`bt_hci_chipset_driver`结构体中,供协议栈调用注册。 ```c static const struct bt_hci_chipset_driver chipset_drv = { init_work, boot_start, prepare_start, event_process, }; // public drv API const struct bt_hci_chipset_driver *bt_hci_chipset_impl_local_instance(void) { return &chipset_drv; } ``` ## 验证 完成 HCI 接口的时候虽然成功运行了 Beacon 例程,但 Beacon 例程是不需要进行 chipset 启动配置流程的(运行时启用的是`common`空白回调)。运行外设的心率例程验证 Bluenrg2 蓝牙芯片启动流程。 ```shel \ | / - RT - Thread Operating System / | \ 5.0.1 build Sep 20 2023 22:16:27 2006 - 2022 Copyright by RT-Thread team do components initialization. initialize rti_board_end:0 done initialize stm32l4_hw_lptim_init:0 done initialize finsh_system_init:0 done msh >zephyr zephyr_polling_init bt_init_hci_driver SPI_init_process device_name: spi10, spi_name: spi1, rate: 1000000, databits: 8, LSB_MSB: 1, Master_Slave: 0, CPOL: 0, CPHA: 1 SPI_init_process cs_pin_num: 1, irq_pin_num: 0 hci_driver_open, SPI_config_finish I: (bt_hci_core)hci_init():3230: work start. msh >prepare_event_process, step: 1 prepare_event_process, step: 2 prepare_event_process, step: 3 prepare_event_process, step: 4 prepare_event_process, step: 5 I: (bt_hci_core)hci_init_end():3205: work end. E: (bt_smp)smp_self_test():5695: smp_self_test start I: (bt_hci_core)bt_dev_show_info():3008: Identity: 02:80:e1:00:00:f5 (public) I: (bt_hci_core)bt_dev_show_info():3042: HCI: version 5.2 (0x0b) revision 0x1222, manufacturer 0x0030 I: (bt_hci_core)bt_dev_show_info():3044: LMP: version 5.2 (0x0b) subver 0x0015 Bluetooth initialized Advertising successfully started Connected BAS Notifications enabled HRS notifications enabled ``` prepare_event_process 步骤的日志输出正常,设备连接、电池服务、心率服务正常。
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
paradox
这家伙很懒,什么也没写!
文章
7
回答
1
被采纳
0
关注TA
发私信
相关文章
1
rtthread小程序“WIFI配网助手”进行蓝牙连接失败
2
透传的BLE蓝牙模块解析
3
柿饼派能实现蓝牙配网吗
4
ab32的notify的内容如何修改?
5
RT-Thread对低功耗蓝牙的支持
6
请问蓝牙mesh开发中如何实现ble部分
7
未知的寄存器名“r3”
8
BSP/nrf52832已经具备BLE协议栈串口透传DEMO
9
nrf52832 softdevice添加出错
10
蓝牙sdk,与art-pi的板子来回数据;类似项目使用protobuf来传输数据,求助其他方式
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
812
个答案
177
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
2
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
1
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部