NRF52832DK协议栈实验
目录
1 蓝牙协议简介
2 蓝牙协议实验
蓝牙协议实验部分,我们借由串口透传实验,一步一步拆分,给大家介绍蓝牙的协议方面。
2.1 低功耗实验
2.1.1 实验简介
低功耗实验1.0_ble_central_pm与2.0_ble_peripheral_pm,这两个实验给大家带来的是最精简的主机以及从机例程,精简到什么程度呢,只保留了协议栈初始化以及电源管理部分。利用此实验,大家可以测试一下我们的BLE工程进入低功耗模式下的功耗情况。
2.1.2 实验现象
我们将万用表串联到电路中,并且打到电流档,此时我们可以看到功耗如下。
2.1.3 工程及源码讲解
2.1.3.1 主机部分
2.1.3.1.1 main()函数
首先我们查看一下main.c文件,在此文件的mian()函数中,我们首先初始化了电源管理模块,然后初始化了BLE栈堆,最后在while大循环中我们调用空闲状态处理的函数。
接下来我们分别针对这三个部分进行介绍。
170 //******************************************************************
171 // fn : main
172 //
173 // brief : 主函数
174 //
175 // param : none
176 //
177 // return : none
178 int main(void)
179 {
180 // 初始化
181 power_management_init();// 初始化电源控制
182 ble_stack_init(); // 初始化BLE栈堆
183
184 // 进入主循环
185 for (;;)
186 {
187 idle_state_handle(); // 空闲状态处理
188 }
189 }
2.1.3.1.2 ble_stack_init()函数及ble_evt_handler()回调函数
我们查看一下BLE协议栈初始化,这个部分是一个格式化的东西。
首先调用nrf_sdh_enable_request()函数请求使能softdevice,原因在于ble协议、时钟、错误的回调以及中断的配置等,都需要这个sd(softdevice)支持。
接下来我们要配置默认的ble协议,主要包含了RAM起始地址、本工程的角色(根据设备支持连接的角色来判断)、MTU的大小及UUID和属性表大小。
RAM的起始地址在下面的位置可以看到,我们打开\ble_ghostyu\1.0_ble_central_pm\LaunchIOT\s132\iar下的ble_app_ghostyu_iar_nRF5x.icf文件(将此文件拖到IAR中就可以打开,可以看到__ICFEDIT_region_RAM_start__ = 0x200029e0)。
然后我们携带RAM起始地址,使能BLE协议栈。
在最后,我们注册了一个ble_evt_handler回调,在这个回调中我们处理BLE的事件返回。
102 //******************************************************************
103 // fn : ble_stack_init
104 //
105 // brief : 用于初始化BLE协议栈
106 // details : 初始化SoftDevice、BLE事件中断
107 //
108 // param : none
109 //
110 // return : none
111 static void ble_stack_init(void)
112 {
113 ret_code_t err_code;
114
115 // SD使能请求,配置时钟,配置错误回调,中断(中断优先级栈堆默认设置)
116 err_code = nrf_sdh_enable_request();
117 APP_ERROR_CHECK(err_code);
118
119 // SD默认配置(如下),SD RAM起始地址配置(0x200029e0)
120 // 作为从机时的最大连接数量0
121 // 作为主机时的最大连接数据1(本工程是主机)
122 // 初始化MTU大小23
123 // 供应商特定的UUID数量1
124 // 属性表大小248(必须是4的倍数,以字节为单位)
125 // 配置服务更改特性数量0
126 uint32_t ram_start = 0;
127 err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
128 APP_ERROR_CHECK(err_code);
129
130 // 使能BLE栈堆
131 err_code = nrf_sdh_ble_enable(&ram_start);
132 APP_ERROR_CHECK(err_code);
133
134 // 注册BLE事件的处理程序,所有BLE的事件都将分派ble_evt_handler回调
135 NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
136 }
ble_evt_handler回调函数,用于处理BLE的事件回调,包含了COMMON、GAP、GATT Client、GATT Server、L2CAP等多种事件类型。在这个例程中,我们只给大家保留了最基础的两个GAP状态,分别为连接状态和断开连接状态。
68 //******************************************************************
69 // fn : ble_evt_handler
70 //
71 // brief : BLE事件回调
72 // details : 包含以下几种事件类型:COMMON、GAP、GATT Client、GATT Server、L2CAP
73 //
74 // param : ble_evt_t 事件类型
75 // p_context 未使用
76 //
77 // return : none
78 static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
79 {
80 ble_gap_evt_t const * p_gap_evt = &p_ble_evt->evt.gap_evt;
81
82 switch (p_ble_evt->header.evt_id)
83 {
84 // 连接
85 case BLE_GAP_EVT_CONNECTED:
86 NRF_LOG_INFO("Connected. conn_handle: 0x%x",p_gap_evt->conn_handle);
87 break;
88
89 // 断开连接
90 case BLE_GAP_EVT_DISCONNECTED:
91
92 NRF_LOG_INFO("Disconnected. conn_handle: 0x%x, reason: 0x%x",
93 p_gap_evt->conn_handle,
94 p_gap_evt->params.disconnected.reason);
95 break;
96
97 default:
98 break;
99 }
100 }
2.1.3.1.3 power_management_init()及idle_state_handle()函数
power_management_init()函数调用底层的nrf_pwr_mgmt_init()函数去初始化电源管理的部分。
idle_state_handle()函数调用底层的nrf_pwr_mgmt_run()函数,用于处理空闲状态的功能(处理完所有的挂起事件,然后进入休眠,直到下一个事件发生)。
138 //******************************************************************
139 // fn : power_management_init
140 //
141 // brief : 初始化电源管理
142 //
143 // param : none
144 //
145 // return : none
146 static void power_management_init(void)
147 {
148 ret_code_t err_code;
149 err_code = nrf_pwr_mgmt_init();
150 APP_ERROR_CHECK(err_code);
151 }
152
153 //******************************************************************
154 // fn : idle_state_handle
155 //
156 // brief : 处理空闲状态的功能(用于主循环)
157 // details : 处理任何挂起的日志操作,然后休眠直到下一个事件发生
158 //
159 // param : none
160 //
161 // return : none
162 static void idle_state_handle(void)
163 {
164 if (NRF_LOG_PROCESS() == false)
165 {
166 nrf_pwr_mgmt_run();
167 }
168 }
2.1.3.2 从机部分
2.1.3.2.1 ble_stack_init()函数
从机部分大体上是和主机一样的,在nordic的协议栈例程中,(如果大家对BLE协议有一定的了解或者使用过其他厂家的BLE芯片)我们可以发现,nordic为了简化BLE的开发难度,可谓是不择手段,他减掉了很多的ble协议相关的内容(这里的减掉指的是放到底层处理,不需要开发者去配置),这其中就包含了GAP Role,也就是蓝牙的角色。
ble_satck_init()函数在主机与从机中,唯一不同的点在初始化参数配置。
99 //******************************************************************
100 // fn : ble_stack_init
101 //
102 // brief : 用于初始化BLE协议栈
103 // details : 初始化SoftDevice、BLE事件中断
104 //
105 // param : none
106 //
107 // return : none
108 static void ble_stack_init(void)
109 {
110 ret_code_t err_code;
111
112 // SD使能请求,配置时钟,配置错误回调,中断(中断优先级栈堆默认设置)
113 err_code = nrf_sdh_enable_request();
114 APP_ERROR_CHECK(err_code);
115
116 // SD默认配置(如下),SD RAM起始地址配置(0x20002a98)
117 // 作为从机时的最大连接数量1(本工程为从机)
118 // 作为主机时的最大连接数据0
119 // 初始化MTU大小23
120 // 供应商特定的UUID数量1
121 // 属性表大小248(必须是4的倍数,以字节为单位)
122 // 配置服务更改特性数量0
123 uint32_t ram_start = 0;
124 err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
125 APP_ERROR_CHECK(err_code);
126
127 // 使能BLE栈堆
128 err_code = nrf_sdh_ble_enable(&ram_start);
129 APP_ERROR_CHECK(err_code);
130
131 // 注册BLE事件的处理程序,所有BLE的事件都将分派ble_evt_handler回调
132 NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
133 }
主机初始化时设置的是作为主机时最大连接数量1,从机初始化时设置的是作为从机时最大连接数量1。这个配置的宏定义是在sdk_config.h文件中。我们go to define,进入nrf_sdh_ble_default_cfg_set()默认参数配置函数中查看,可以找到如下部分。
NRF_SDH_BLE_PERIPHERAL_LINK_COUNT与NRF_SDH_BLE_CENTRAL_LINK_COUNT,在定义最大连接设备数量的同时,也决定了它本身的角色属性。
BLE中我们称Central中心设备为主机(发起连接的设备)、Peripheral外部设备为从机(广播等待被连接的设备)。
103 ret_code_t nrf_sdh_ble_default_cfg_set(uint8_t conn_cfg_tag, uint32_t * p_ram_start)
104 {
105 uint32_t ret_code;
106
107 ...
108
109 // Configure the connection roles.
110 memset(&ble_cfg, 0, sizeof(ble_cfg));
111 ble_cfg.gap_cfg.role_count_cfg.periph_role_count = NRF_SDH_BLE_PERIPHERAL_LINK_COUNT;
112 #ifndef S112
113 ble_cfg.gap_cfg.role_count_cfg.central_role_count = NRF_SDH_BLE_CENTRAL_LINK_COUNT;
114 ble_cfg.gap_cfg.role_count_cfg.central_sec_count = MIN(NRF_SDH_BLE_CENTRAL_LINK_COUNT,
115 BLE_GAP_ROLE_COUNT_CENTRAL_SEC_DEFAULT);
116 #endif
117
118 ...
119
120 return NRF_SUCCESS;
121 }
2.1.4 实验总结
在低功耗主从机的学习中,我们可以了解到最精简的主从机工程。也就是只包含了softdevice与ble协议栈初始化、以及电源管理初始化。
重点问题:
1.了解如何定义一个BLE工程是主机还是从机,或者其他的属性(主从一体等等)。
2.了解如何进行低功耗处理(main()函数中while循环的idle_state_handle空闲任务处理函数)。
2.2 LOG打印实验
2.2.1 实验简介
LOG打印实验是在低功耗实验的基础上,新增了LOG打印部分。
那么为什么我们需要添加log功能,主要是因为在开发的过程中,我们几乎很难一次调通我们需求的功能,这个时候我们就需要一种好的方式去帮助我们调通,我们出现问题点在哪(查找bug),以及我们的流程进行到哪边了(流程监视)。说到这里,大家会说为什么不使用在线调试的方式解决问题呢,下面谈一谈我个人的使用感觉(仅针对BLE)。
何时使用在线调试:
1.针对细小的问题点,例如某个参数的数值是否正确
2.针对不影响程序整机蓝牙功能运行的问题点,例如外设功能异常
何时使用log:
1.不能使用在线调试功能的时候(例如蓝牙连接状态下的通信调试,由于连接参数的限制,如果在线打断点调试,会导致异常断开)
2.监测关键节点信息(有些问题会出现在一些特殊情况下,可能需要监测N多次,才会出现一次异常)
2.2.2 实验现象
2.2.3 工程及源码讲解
2.2.3.1 主机部分
log打印实验相对于前一章节的低功耗实验,新增的功能并不多,我们仅仅添加了LOG的RTT打印功能,这边