3.2 NimBLE设置

大部分NimBLE的初始化工作都由sysinit自动完成。本节将介绍一些必须手动完成的少量初始化工作。

3.2.1配置控制器时钟

NimBLE协议栈使用操作系统的cputime,用于调度控制器内部不同的事件。由于控制器的代码基于32768Hz的时钟优化,因此必须相应地配置OS cputime。

为了让整体变得简单,控制器包(net/nimble/controller)定义了新的系统配置设置BLE_LP_CLOCK设置为1,所以在必要时可以配置其他包。下一节描述控制器正常工作时所需要的配置。

系统配置

注意:所有基于nRF5x的BSP在设置BLE_LP_CLOCK的情况下,都将自动完成以下配置,所以在应用中不需要再进行配置。

以下设置需要配置,以保证NimBLE控制器正常工作:

  • OS cputime频率设置为32768
  • OS cputime定时器源需要设置为32768Hz时钟源
  • 如果没有在应用中使用,默认1MHz的时钟源将被禁止。
  • 32768Hz时钟源应该使能
  • 晶振设置时间为非零值

例如,在nRF52平台定时器5可以设置为32768Hz时钟。此外,定时器0由于默认为OS cputime时钟,将不再使用,因此定时器0可以禁止。配置如下:

  1. syscfg.vals:
  2. OS_CPUTIME_FREQ: 32768
  3. OS_CPUTIME_TIMER_NUM: 5
  4. TIMER_0: 0
  5. TIMER_5: 1
  6. BLE_XTAL_SETTLE_TIME: 1500

在nRF51上唯一的区别是需要使用定时器3替代定时器5。

在没有32768Hz晶振的平台上,通常使用XTAL_32768_SYNTH来生成时钟,已经在现有的BSP中配置好。

晶振启动时间设置

控制器使用配置变量BLE_XTAL_SETTLE_TIME用于打开无线电及相关外设的蓝牙事件时钟源。在nRF5x平台,HFXO需要在启用无线电之前打开,BLE_XTAL_SETTLE_TIME必须设置以适应这个时间。具体所需要的时间适平台而定,因此用户必须描述硬件,并相应设置BLE_XTAL_SETTLE_TIME。当前1500μs是一个相对长的时间,对于多数平台而言基本足够。

需要注意,改变这个时间将会影响电池寿命,以及应用不同影响也不同。HFXO在运行时需要较大的电流,所以保持尽可能小的值将会减少总电流损耗。

3.2.2配置设备地址

BLE设备无论做什么工作都需要一个地址。有关各种类型的蓝牙地址,可以查看NimBLE主机标识参考文档:<../ble_hs/ble_hs_id/ble_hs_id>。

有几种方法可以为灵活的设备分配地址。

方法1:使用公开地址配置nRF硬件

当Mynewt运行在Nordic nRF平台,NimBLE控制器将尝试从FICR或UICR寄存器中读取一个公开地址。控制器尝试从硬件中读取地址时按照以下逻辑:

  1. 如果DEVICEADDRTYPE FICR寄存器写了值,读取编写在DEVICEADDR[0]和DEVICEADDR[1] FICR寄存器中的地址;
  2. 如果CUSTOMER[1] UICR寄存器的高16bit为0,读取写在CUSTOMER[0]和CUSTOMER[1]寄存器中的地址;
  3. 否则无可用地址。

方法2:Mynewt目标中的硬编码公开地址

NimBLE控制器包导出一个叫BLE_PUBLIC_DEV_ADDR的syscfg设置。该设置可以在应用或目标等级的配置中覆盖,以配置一个公开的蓝牙地址。例如,一个目标可以设置公开地址11:22:33:44:55:66

  1. syscfg.vals:
  2. BLE_PUBLIC_DEV_ADDR: '(uint8_t[6]){0x66, 0x55, 0x44, 0x33, 0x22, 0x11}'
  3. #即写地址按照小端的格式写,优先写低字节

这个设置按照C表达式的形式。具体来说,该值是一个指定的初始化器,以一个6字节的数组表示。需要注意字节与地址是反序的,因为数组本质上是小端(little-endian),而地址通常为大端(bit-endian)表示。

注意:此方法优先于方法1,写入BLE_PUBLIC_DEV_ADDR设置的内容就是要使用的地址。

方法3:运行时配置一个随机地址

通过NimBLE主机可以配置一个随机地址。以下两个函数用于配置随机地址:

  • ble_hs_id_gen_rnd:生成一个新的随机地址
  • ble_hs_id_set_rnd:设置设备的随机地址

注意:一个NimBLE设备可以配置多种地址,但每种类型地址最多一个。

3.2.3同步与复位事件响应

sync-同步

当主机与控制器不同步时,NimBLE协议栈是不能操作的。在一个组合的host-controller应用中,sync在启动时立即发生。当主机和控制器分离时,同步通常在应用启动后不到一秒时间内发生。应用程序通过配置主机的同步回调(ble_hs_cfg.sync_cb)来获知何时实现同步。当同步获取时,主机调用同步回调函数。同步回调函数按照以下形式:

  1. typedef void ble_hs_sync_fn(void);

由于NimBLE协议栈初始为未同步状态,应用程序需要延时所有BLE操作,直到同步回调函数被调用。

reset-复位

主机指示的另一个事件是控制器复位。当发生一个灾难错误发生时(如host与controller之间通信丢失),NimBLE协议栈重启。在复位时,host将删除所有的BLE连接,并丢失与控制器的同步。复位后,应用程序应该避免使用主机,直到sync建立。

应用程序通过配置主机复位回调函数ble_hs_cfg.reset_cb来获悉主机复位信号,复位回调函数按照以下格式:

  1. typedef void ble_hs_reset_fn(int reason);

应用示例:

  1. #include "sysinit/sysinit.h"
  2. #include "console/console.h"
  3. #include "host/ble_hs.h"
  4. static void
  5. on_sync(void)
  6. {
  7. /* Begin advertising, scanning for peripherals, etc. */
  8. }
  9. static void
  10. on_reset(int reason)
  11. {
  12. console_printf("Resetting state; reason=%d\n", reason);
  13. }
  14. int
  15. main(void)
  16. {
  17. /* Initialize all packages. */
  18. sysinit();
  19. ble_hs_cfg.sync_cb = on_sync;
  20. ble_hs_cfg.reset_cb = on_reset;
  21. /* As the last thing, process events from default event queue. */
  22. while (1) {
  23. os_eventq_run(os_eventq_dflt_get());
  24. }
  25. }