nrf52832 学习笔记SDK框架分析

Posted 不咸不要钱

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了nrf52832 学习笔记SDK框架分析相关的知识,希望对你有一定的参考价值。

nrf52832 学习笔记(二)SDK框架分析

个人对SDK框架的一些理解,如有错误欢迎斧正。

flash 分区


在不包含DFU的情况下,nrf52832 flash划分为:

  • MBR

    0x00000000 - 0x00001000 为主引导程序(MBR),包括中断向量表和主引导程序两部分,其中中断向量表用于处理派发中断回调函数,主引导程序主要用于判断是否存在DFU,判断跳转地址。

  • SoftDevice

    0x00001000 - 0x00026000 为协议栈程序

  • APP

    用户程序

    RAM分配

    • 协议栈占用RAM

      一般情况下把MBR+SoftDevice 统称为协议栈,协议栈占用RAM大小可以从协议栈配套文档获得。如果协议栈RAM过小,log信息会给出相应提示。

    • 用户APP使用RAM


在包含DFU的情况下,nrf52832 flash划分为:

  • MBR

    0x00000000 - 0x00001000 为主引导程序(MBR),包括中断向量表和主引导程序两部分,其中中断向量表用于处理派发中断回调函数,主引导程序主要用于判断是否存在DFU,判断跳转地址。

  • SoftDevice

    0x00001000 - 0x00026000 为协议栈程序

  • APP

    用户程序

  • bootLoader

    DFU 蓝牙空中升级boot,地址根据DFU程序大小自行设置。

  • bootLoader Parameter

    0x0007E000 - 0x00080000 DFU 蓝牙空中升级boot参数区,用于记录升级信息(升级过程断电的话,下次可以接着升级,相当与有断点续传功能),APP版本,BOOT版本,APP校验,参数区校验等信息。如果没有此分区,程序将无法正常运行。

nrf52832 启动流程

nRF52832上电后从固定位置0x0000 0000开始执行程序,flash 0x0000 0000–0x0002 6000存放Nordic的协议栈s132,协议栈s132前面4KB(0x0000-0x1000)为主引导程序(MBR),MBR根据地址0xFF8或者0x1000 1014中是否存在DFU程序起始地址决定跳转地址,如果地址0xFF8或者0x1000 1014中存在DFU程序起始地址则会跳转至DFU,DFU运行结束后程序会跳转0x0000 1000,然后协议栈根据协议栈大小跳转至协议栈结束地址也就是APP起始地址0x26000,至此开始执行APP程序。

用户app如何调用协议栈

#define SVCALL(number, return_type, signature) return_type __svc(number) signature

用户APP通过触发SVC中断的方式调用协议栈相关操作,将协议栈和用户程序完全分开,互不干预。协议栈相关函数声明都在ble.h中,以sd开头。以 sd_ble_enable 函数为例,用户在调用 sd_ble_enable 时,会触发SVC中断,协议栈中SVC中断服务函数根据 SVC服务号(SD_BLE_ENABLE)调用协议栈相应的函数进行处理,然后返回处理结果。

//SVC中断的等效代码,具体不是这样的
unsigned long svc_handler(int svc_num, void * param)

	switch(svc_num)
	
		case SD_BLE_ENABLE:
		
			...//协议栈操作
			break;
		
		...
	

从上面代码可以看出SVC中断和其他中断服务函数不同,有参数和返回值,有参数是因为在进SVC中断前将参数入栈,中断服务函数从对应栈空间取参数。返回值则是在退出时将返回值存入R0寄存器中。具体可以看 《Cortex-M3权威指南》 第11章 使用异常系统

协议栈如何上报状态到用户观察者函数

当蓝牙事件产生时(比如扫描到广播包,连接主从机成功等),协议栈会通过软中断(SWI)将蓝牙事件分发给用户APP,用户在观察者回调函数中添加自己的处理代码。


nrf52832 flash中存在3个中断向量表,但是在APP仿真时发现SCB->VTOR为 0x00000000,因此只有MBR Vector才是真的中断向量表,发生中断时会进入MBR Vector,在MBR Vector 中调用 SoftDevice Vector 中的中断服务函数,然后在SoftDevice Vector 中的中断服务函数中再调用 app vector table。

由于中断服务函数多次跳转,相比其他单片机,nrf52832 用户中断服务函数的中断延时相对比较高。

#define NRF_SECTION_ITEM_REGISTER(section_name, section_var) \\
    section_var __attribute__ ((section(STRINGIFY(section_name)))) __attribute__((used))


#define NRF_SECTION_SET_ITEM_REGISTER(_name, _priority, _var)                                       \\
	NRF_SECTION_ITEM_REGISTER(CONCAT_2(_name, _priority), _var)

#define NRF_SDH_BLE_OBSERVER(_name, _prio, _handler, _context)                                      \\
STATIC_ASSERT(NRF_SDH_BLE_ENABLED, "NRF_SDH_BLE_ENABLED not set!");                                 \\
STATIC_ASSERT(_prio < NRF_SDH_BLE_OBSERVER_PRIO_LEVELS, "Priority level unavailable.");             \\
NRF_SECTION_SET_ITEM_REGISTER(sdh_ble_observers, _prio, static nrf_sdh_ble_evt_observer_t _name) =  \\
                                                                                                   \\
    .handler   = _handler,                                                                          \\
    .p_context = _context                                                                           \\


#define APP_BLE_OBSERVER_PRIO           3

//注册观察者函数
NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);

在用户app中注册观察者函数,在观察者函数中处理蓝牙事件。注册观察者函数使用了一堆宏定义,这一大堆宏定义最终变成如下

static nrf_sdh_ble_evt_observer_t m_ble_observer __attribute__ ((section(sdh_ble_observers3))) __attribute__((used)) = 

	.handler   =  ble_evt_handler,
	.p_context = NULL

其实就干了两件事:

  • 声明了一个静态变量
  • 将该静态变量存放在 sdh_ble_observers3 段中

    软件中断服务函数最终调用 app软件中断服务函数 SD_EVT_IRQHandler, 在 nrf_sdh_evts_poll 中遍历调用sdh_ble_observers0、sdh_ble_observers1等flash段中所有的观察者回调函数。

    因此nrf52832 sdk中蓝牙各个部分之间的耦合度非常小,每个部分都有自己的观察者回调函数。

以上是关于nrf52832 学习笔记SDK框架分析的主要内容,如果未能解决你的问题,请参考以下文章

nrf52832 学习笔记开发资料汇总

nrf52832 学习笔记蓝牙主从机连接和连接参数更新

nrf52832 学习笔记蓝牙主机发现服务

nrf52832 学习笔记蓝牙主从机连接和连接参数更新

nrf52832 学习笔记蓝牙主机发现服务

nrf52832 学习笔记蓝牙主机发现服务