说明一下 Nordic nRF5 SDK 软件 应用程序 和 协议栈分开烧录的理解
前言
上一篇文章我们了解了 Nordic nRF5 SDK 目录结构,在那之前我们也已经搭建好了开发环境,实际上我们就已经可以进入我们的开发之旅了,但是如果刚接触 Nordic 蓝牙开发的小伙伴总是会有一些
疑问:
1、Nordic 蓝牙开发应用程序和协议栈分开是什么意思?
2、分开了那工程开发,烧录岂不是相当复杂?
带着这些问题,本文我们就来了了解 nRF5 SDK 应用与协议栈分开烧录是怎么一回事。
Nordic nRF5 SDK 入门系列博文:
GCC + Vscode 搭建 nRF52xxx 开发环境
nRF5 SDK 入门(二、了解 nRF5 SDK 目录结构)
.
我是矜辰所致,全网同名,尽量用心写好每一系列文章,不浮夸,不将就,认真对待学知识的我们,矜辰所致,金石为开!
目录
- 前言
- 一、 ARM 内核启动过程
- 1.1 启动过程
- 1.2 程序存放位置
- 二、nRF5 SDK 程序存储方式
- 2.1 nRF5 SDK 的区分存储
- 2.2 分开处理的好处
- 三、 烧录说明
- 结语
一、 ARM 内核启动过程
我们的使用的 nRF52xxx 芯片是 M4 内核,在讨论本文标题的问题之前,我们得复习一下 M4 内核启动相关的知识点。
1.1 启动过程
CPU 复位后会从 0x00000000 处取得第一条指令开始运行 ,ARM Cortex-M/R 内核在复位后,也会从 0x0000 0000 处开始执行:它是从地址 0x0000_0000 处取出 MSP 的初始值;从地址 0x0000_0004 处取出 PC 的初始值,然后从这个值对应的地址处取指。事实上,地址 0x00000004 开始存放的就是默认中断向量表。
上图是 M3 内核,这一点和 M4 内核是一样的。所以我们想要程序正常运行,就得从 0x0000 0000 这个地址开始存放程序。
1.2 程序存放位置
STM32 的程序存放位置:
这里回忆一下熟悉的 STM32 ,我们一般而言,程序存放的位置为 0X0800 0000,那是因为 STM32 为了方便不同的方式启动,所以 把前面 0x0000 0000 开始的空间让出来了,为了实现存储重映射的功能。可以使得芯片从内部 Flash, 系统存储器,内部 SRAM 启动,不同的启动方式只需要把不同的地址重映射到 0x0000 0000 即可。
在 STM32 的工程中,在很多地方都能够直接体现程序存放的这个地址:
但是和大多数芯片一样的是 ,STM32 的程序也只需要烧录一次 。
Nordic 的芯片没有用到类似 STM32 的存储重映射的功能,所以因为 内核 需要从0x0000 0000 开始执行程序,所以它必然需要把程序从 0 地址开始存放。(官方的例程是这样,如果个人测试采用其他方式不算。)
到这里我们只是确定了 Nordic 的芯片的程序必须要从 0 开始存放 ,但是 Nordic 还做了另外的一种事情,就是把程序分成了两部分!
二、nRF5 SDK 程序存储方式
我们在上一篇文章说明了一个问题:
一个裸机程序,单独烧录至 0x26000 处程序不会运行,如果烧录至 0x0 位置处,可以正常运行,也正是说明 Nordic 的芯片是从 0x0 地址开始运行程序的,那么为什么官方的示例会把位置放在 0x26000 处,而不是 0x0 处,这就是 Nordic 与其他厂商处理不一样的地方。
2.1 nRF5 SDK 的区分存储
实际上,我们通常的思维会是:
反正都是程序,协议栈也是程序,都在一个工程里面,编译过后生成一个 hex ,直接放到 0x0 的地址上直接运行即可。
对于 nRF5 SDK 而言,它们是把 协议栈 和 应用程序 分开处理,对于这一点,有位 Nordic 中国区的 FAE 在某园上写过一篇文章:《 nRF5 SDK软件架构及softdevice工作原理 》(文章大家可以直接度娘搜索,因为涉及到外站竞争链接,所以这里就不放了)里面很好的说明了这个问题,以下说明取自这篇文章:
Nordic nRF5 SDK将芯片的存储器划分成如下格局:
上面推荐文章中,有详细的说明:
Flash存储器最下面放的是softdevice(softdevice就是蓝牙协议栈,图中的MBR也属于softdevice的一部分),
中间是application,
最上面是bootloader(可选,只有需要OTA的时候,才需要下载bootloader)。
这里需要特别指出的是,softdevice是以二进制形式提供给大家的,它占据了Flash的一块固定空间,起始地址为0,结束地址为APP_CODE_BASE。
softdevice同时占用了RAM的一块固定空间,起始地址为0x20000000,结束地址为APP_RAM_BASE。
Softdevice占用的Flash空间是固定不变的,运行时不可调节,也就是说APP_CODE_BASE是一个固定值,而softdevice占用的RAM空间是动态可调的,跟softdevice配置和蓝牙服务的多少有直接关联,所以APP_RAM_BASE一定要根据应用的实际情况进行调整。
在文中提到协议栈(softdevice) 是以二进制(hex)形式提供给大家的, 这一点我们通过 SDK 文件夹下的内容也能知道,如图:
所以我们开发中比较关心的问题,听起来分开处理感觉会变得麻烦很多,实际上协议栈我们并不需要编程,编译,直接有现成的,只需要知道如何烧录到对应位置即可。
2.2 分开处理的好处
Nordic 这样分开处理好处,在上面大佬的文章也有详细的说明:
- 首先二进制形式可以保证蓝牙BQB认证的版本和发布给客户的版本一模一样(因为库形式的版本每次编译都会产生少许差异!)。
- 其次softdevice不需要跟你的应用一起编译或者链接,大大节省调试时间。
- 更主要的是,Softdevice运行在固定的Flash空间中,使用固定的RAM空间,从而与你的应用完全隔离开,实现了真正的模块分离,从而出现问题时,可以迅速定位是协议栈的问题还是应用的问题。
- 再次二进制形式的 Softdevice开启了保护机制,应用代码是不能对其进行访问的,以保证Softdevice的安全性,防止应用代码误访问或者误擦除某些softdevice区域。
- 最后这种多bin形式使得OTA变得非常灵活,你可以只OTA应用,也可以OTA协议栈和bootloader,或者三者同时OTA。
对于具体的 协议栈与应用 的细节大家可以自己查看上面推荐的文章《 nRF5 SDK软件架构及softdevice工作原理 》,或者等到后期随着我们的开发到了那一步,我也会详细的分析一下,在上面文章的结尾,有下面一段话,可以让大家对使用 Nordic nRF5 SDK 不那么刚到害怕:
从上面nRF5 SDK软件架构的讲解过程中,我们可以看到,当我们开发Nordic平台的BLE应用时,主要需要做两件事:
.
第1件事:初始化。为了简化初始化工作,Nordic SDK所有模块初始化时,只需要将相应API输入结构体参数清0即可完成初始化工作,也就是说,只要你保证初始化参数为0,蓝牙协议栈就可以工作起来,这对很多Nordic初学者来说,大大减轻了开发工作量。
.
第2件事:写蓝牙事件回调处理函数。一般来说,你的应用逻辑都是放在蓝牙事件回调处理函数中,所以写好回调处理函数代码,你的开发工作就完成了大半了。
三、 烧录说明
到这里,大家应该都能够理解与接受 Nordic nRF5 SDK 对于应用于协议栈分开处理的方式了,那么回到文章最开头的两个问题:
1、Nordic 蓝牙开发应用程序和协议栈分开是什么意思?
2、分开了那工程开发,烧录岂不是相当复杂?
第一个问题,我们在上文已经得到了答案,第二个问题其实我们也已经解决了一半,并不会更加复杂,因为我们还是只需要注重我们的应用程序即可。
本小节来讲一下烧录问题,首先我们的示例编译过后会生成一个 hex 文件,加上协议栈的 hex 文件,一共是两个 hex 文件。
这里我再次再次再次复习一个知识点:对于 .hex 文件来说,他包含了存放地址信息,可以直接烧录会根据链接文件存放至对应的地址。
就用我们的 J-Flash 工具来说,我们已经知道,示例编译过后拖动至 J-Flash ,它自动会显示需要存放在 flash 中的位置,应用程序如下图:
那同样的,我们也可以把协议栈 hex 文件用同样的方式烧录,我们拖动至 J-Flash ,如下图:
他们两个 hex 的存放位置是不一样的,我们可以直接按照正常步骤连接然后烧录 :
这样就好了! 并没有什么特别需要你注意的,不会存在什么覆盖啊,搞错之类的问题。
同样的,即便我们不用 J-Flash ,我们在我们搭建好的开发环境下面,使用命令烧录,大家可以查看一下 Makefile 最后的伪指令:
也只是需要我们敲两下命令即可,并没有过多的工作。
当然,大家用官方的 nRFgo Studo ,原理也是一样的,只要搞清楚程序存放的形式,就没那么难了。
但是这里有一点,对于使用 Keil 开发来说, 他的 hex 存放位置也是可以设置的:
上面是外设的裸机测试,如果是带协议栈的,那么在 keil 中是需要把上面地址修修改的,如下图:
但是对于 Keil 开发来说,他协议栈的烧录直接通过 Keil 我倒是不知道如何操作,都是需要借助第三方工具 nRFgo Studo 或者直接使用 J-Flash 单独烧录一次协议栈。
结语
本文我们主要了解了一下 Nordic nRF5 SDK 应用与协议栈分开处理的方式,通过文章我们应该明白了分开处理的是什么意思,分开的好处,以及对我们实际应用开发的影响。
详细大家都能够感受到,这种方式不仅不会让我们开发变得更加复杂,反而能够让我们专心与自己的应用程序,同时也跟让我们更好的定位开发过程中遇到的问题,相应付出的代价只不过是我们需要多烧录一次 hex而已。
好了,本文就到这里,谢谢大家!