1.0、关于 协议栈
协议栈在蓝牙里面占有重要地位,在实际项目开发中,协议栈最多是作为配置配置时钟来源的作用。我们现在简单分析一下。
先源码:
static void ble_stack_init(void)
{
uint32_t err_code;
nrf_clock_lf_cfg_t clock_lf_cfg = NRF_CLOCK_LFCLKSRC;
// Initialize the SoftDevice handler module.
SOFTDEVICE_HANDLER_INIT(&clock_lf_cfg, NULL);
ble_enable_params_t ble_enable_params;
err_code = softdevice_enable_get_default_config(CENTRAL_LINK_COUNT,
PERIPHERAL_LINK_COUNT,
&ble_enable_params);
APP_ERROR_CHECK(err_code);
// Check the ram settings against the used number of links
CHECK_RAM_START_ADDR(CENTRAL_LINK_COUNT, PERIPHERAL_LINK_COUNT);
// Enable BLE stack.
#if (NRF_SD_BLE_API_VERSION == 3)
ble_enable_params.gatt_enable_params.att_mtu = NRF_BLE_MAX_MTU_SIZE;
#endif
err_code = softdevice_enable(&ble_enable_params);
APP_ERROR_CHECK(err_code);
// Register with the SoftDevice handler module for BLE events.
err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch);
APP_ERROR_CHECK(err_code);
// Register with the SoftDevice handler module for BLE events.
err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch);
APP_ERROR_CHECK(err_code);
}
2.1、
我们现在先分析一下:
static void ble_stack_init(void)
{
uint32_t err_code;
nrf_clock_lf_cfg_t clock_lf_cfg = NRF_CLOCK_LFCLKSRC;//结构体
// Initialize the SoftDevice handler module.
SOFTDEVICE_HANDLER_INIT(&clock_lf_cfg, NULL);
NRF_CLOCK_LFCLKSRC是一个结构体,跳过去可以看到
#define NRF_CLOCK_LFCLKSRC {.source = NRF_CLOCK_LF_SRC_XTAL, \
.rc_ctiv = 0, \
.rc_temp_ctiv = 0, \
.xtal_accuracy = NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM}
分析:
(1)、.source :是同一个时钟源选择,时钟源有三个选择,可以看一下
#define NRF_CLOCK_LF_SRC_RC (0) /**< LFCLK RC oscillator. */ //内部RC时钟
#define NRF_CLOCK_LF_SRC_XTAL (1) /**< LFCLK crystal oscillator. */ //外部时钟
#define NRF_CLOCK_LF_SRC_SYNTH (2) /**< LFCLK Synthesized from HFCLK. */ //从高速时钟合成低速时钟
他们三个是有区别 的,
其中看一下外部时钟,也就是我们常说的32.768KHZ的时钟,选择外部时钟,相对的电流 降低,但是,需要外部 加时钟晶振,也就是成本高那么一点(现在晶振价格还是比较便宜的)
再看一下,内部RC时钟,如果需要使用内部RC时钟,进行校准的时候芯片的32MHZ高速时钟 必须运行,但是,电流也就会加大,相对使用外部晶振,使用内部RC时钟,成本省去晶振,但是电流将加大 7-8UA
然后是合成时钟,它相比RC时钟和外部时钟,电流增加更多,具体使用,还要根据产品的要求去设定。不过我询问了一下公司研发蓝牙的人员,他们说第三个合成时钟从来没用过,全都是前面两种。
(2)、
.rc_ctiv : 在1/4秒单位下的校准时间间隔,为了避免过度的时间漂移,在一个刻度时间间隔下, 最大的温度变化允许0.5度
.rc_temp_ctiv :温度变化下的校准时间间隔。
在《清风例程文档》里面说明使用RC时钟时,推荐
.rc_ctiv = 16
.rc_temp_ctiv = 2
这两个参数好像没有特别关注,问了专门蓝牙工程师(本人是使用STM32芯片研发产品的程序员),他们告诉我说:“不怎么关注这个两个参数,一般使用外部就全部0,使用内部,就用 .rc_ctiv = 8 .rc_temp_ctiv = 1。
(3)、
.xtal_accuracy :晶振精度
这个有许多宏定义:
#define NRF_CLOCK_LF_XTAL_ACCURACY_250_PPM (0) /**< Default: 250 ppm */
#define NRF_CLOCK_LF_XTAL_ACCURACY_500_PPM (1) /**< 500 ppm */
#define NRF_CLOCK_LF_XTAL_ACCURACY_150_PPM (2) /**< 150 ppm */
#define NRF_CLOCK_LF_XTAL_ACCURACY_100_PPM (3) /**< 100 ppm */
#define NRF_CLOCK_LF_XTAL_ACCURACY_75_PPM (4) /**< 75 ppm */
#define NRF_CLOCK_LF_XTAL_ACCURACY_50_PPM (5) /**< 50 ppm */
#define NRF_CLOCK_LF_XTAL_ACCURACY_30_PPM (6) /**< 30 ppm */
#define NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM (7) /**< 20 ppm */
ppm是百万分之一的意思,在晶振里面,由于晶振的震荡频率随温度的变化,会发生小的漂移,有的漂移的定义为:温度变化1摄氏度,震荡频率相对标准值的变化量,如果漂移了 百万分之一 ,就是1ppm。
这个参数,我也是看的云里雾里的,咨询了蓝牙工程师,他们说:“如果使用外部,就20ppm,内部RC时钟就500ppm”。
2.1、协议栈使能
ble_enable_params_t ble_enable_params;
err_code = softdevice_enable_get_default_config(CENTRAL_LINK_COUNT,
PERIPHERAL_LINK_COUNT,
&ble_enable_params);
APP_ERROR_CHECK(err_code);
// Check the ram settings against the used number of links
CHECK_RAM_START_ADDR(CENTRAL_LINK_COUNT, PERIPHERAL_LINK_COUNT);
// Enable BLE stack.
#if (NRF_SD_BLE_API_VERSION == 3)
ble_enable_params.gatt_enable_params.att_mtu = NRF_BLE_MAX_MTU_SIZE;
#endif
err_code = softdevice_enable(&ble_enable_params);
APP_ERROR_CHECK(err_code);
这里处理的实际上就是分配RAM 空间
函数softdevice_enable_get_default_config()定义了 CENTRAL_LINK_COUNT(主机设备数量)和PERIPHERAL_LINK_COUNT(从机设备数量),这个明确一点主从机的概念:
主机:主动连接其他设备的蓝牙
从机:被连接 的设备
实在不明确,一个简单的方法就是看谁广播,谁主动广播,谁就是从机,另外连接它的就是主机。当然,我们可以通过设置,设置成一个蓝牙既可以做主机,也可以做从机,比如
#define CENTRAL_LINK_COUNT 3
#define PERIPHERAL_LINK_COUNT 1
这个定义就是 作为主机,连接3个从机;作为从机,连接1个主机。
然后就是看到函数CHECK_RAM_START_ADDR(CENTRAL_LINK_COUNT, PERIPHERAL_LINK_COUNT),这个功能是配置RAM空间
2.3、回调派发函数
// Register with the SoftDevice handler module for BLE events.
err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch); //蓝牙事件派发
APP_ERROR_CHECK(err_code);
// Register with the SoftDevice handler module for BLE events.
err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch);//系统事件派发
APP_ERROR_CHECK(err_code);
先看一下蓝牙事件派发:
static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
{
/** The Connection state module has to be fed BLE events in order to function correctly
* Remember to call ble_conn_state_on_ble_evt before calling any ble_conns_state_* functions. */
ble_conn_state_on_ble_evt(p_ble_evt);//连接状态管理事件
pm_on_ble_evt(p_ble_evt);
ble_rscs_on_ble_evt(&m_rscs, p_ble_evt);
ble_bas_on_ble_evt(&m_bas, p_ble_evt);
ble_conn_params_on_ble_evt(p_ble_evt);//连接参数管理处理函数
bsp_btn_ble_on_ble_evt(p_ble_evt);
on_ble_evt(p_ble_evt);//通用处理事件函数
ble_advertising_on_ble_evt(p_ble_evt);//广播蓝牙事件处理函数
/*****************增加LED私有服务**********************/
ble_lbs_on_ble_evt(&led_library, p_ble_evt);
ble_nus_on_ble_evt(&USART_library, p_ble_evt);
/***********************************************/
}
私有服务是自己增加的,不用在意,其中有注释的处理事件函数是大家经常要用到的,RTT仿真打印出一些内部问题,都可以在里面查找。
然后,看一下系统事件派发,不做具体分析,,大家可以自己看一下,里面代码很容易理解。
static void sys_evt_dispatch(uint32_t sys_evt)
{
// Dispatch the system event to the fstorage module, where it will be
// dispatched to the Flash Data Storage (FDS) module.
fs_sys_event_handler(sys_evt); //系统内存事件
// Dispatch to the Advertising module last, since it will check if there are any
// pending flash operations in fstorage. Let fstorage process system events first,
// so that it can report correctly to the Advertising module.
ble_advertising_on_sys_evt(sys_evt);//系统广播事件
}
到这里,就看完了。