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

nrf52832 学习笔记(二)SDK框架分析,第1张

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中蓝牙各个部分之间的耦合度非常小,每个部分都有自己的观察者回调函数。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/732776.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-27
下一篇 2022-04-27

发表评论

登录后才能评论

评论列表(0条)

保存