NRF51822蓝牙初学笔记1.1之协议栈简单分析

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);//系统广播事件
}

到这里,就看完了。

你可能感兴趣的:(技术,初学)