Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
蓝牙BLE
RTT平台 zephyr_polling软件包 Bluenrg2 蓝牙芯片启动流程
发布于 2023-09-26 16:50:31 浏览:117
订阅该版
[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 流程接口,可以根据实际芯片的需求实现启动配置。  **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
机器人操作系统 (ROS2) 和 RT-Thread 通信
4
五分钟玩转RT-Thread新社区
5
国产MCU移植系列教程汇总,欢迎查看!
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
串口
LWIP
Env
AT
SPI
Bootloader
FinSH
ART-Pi
CAN总线
Hardfault
USB
文件系统
RT-Thread
DMA
SCons
线程
MQTT
RT-Thread Nano
STM32
RTC
rt-smart
ESP8266
flash
ota在线升级
WIZnet_W5500
FAL
I2C
packages_软件包
UART
cubemx
freemodbus
潘多拉开发板_Pandora
定时器
BSP
PWM
ADC
socket
中断
rt_mq_消息队列_msg_queue
keil_MDK
SDIO
Debug
AB32VG1
MicroPython
编译报错
C++_cpp
msh
ulog
QEMU
本月问答贡献
出出啊
1501
个答案
338
次被采纳
小小李sunny
1390
个答案
276
次被采纳
张世争
715
个答案
157
次被采纳
crystal266
522
个答案
153
次被采纳
whj467467222
1216
个答案
146
次被采纳
本月文章贡献
出出啊
1
篇文章
12
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
2
篇文章
2
次点赞
crystal266
2
篇文章
5
次点赞
whj467467222
2
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部