转载自:cnblogs.com |作者:Jayant Tang
Zephyr Project是Linux基金会推出的一个Apache2.0开源项目,版权非常友好,适合用于商业项目开发。包含RTOS、编译系统、各类第三方库。NCS中的例程基本都跑在Zephyr RTOS上。
对于之前只接触过IDE+外设驱动库这种开发方式的开发者来说,Zephyr的配置和编译系统可能比较令人费解,但是一旦你能掌握,就会发现它的方便之处。
本文接上篇内容,将继续介绍NCS中的配置和编译工具,包含Zephyr中特有的Sysbuild、Boards,以及Nordic提供的Partition Manager存储器分区等介绍。
Sysbuild (System build)
前面介绍的CMake, Kconfig, DeviceTree都是其他领域(如Linux内核)已经在广泛使用的配置工具。但是Sysbuild是Zephyr的新引入的构建机制,它是一个High-Level的配置工具,解决的是MCU多镜像编译的问题。
前面介绍的那些工具,都是为了1个镜像编译时用的。当我们要编译一个多镜像的固件时,这些不同的镜像之间可能会有一些配置项的差别。
例如,我希望我的串口用于打印日志,但是在bootloader镜像中,同一个串口用于固件升级。
又比如,我选型了一款QSPI外挂Flash,与Nordic官方开发板上的Flash不同,于时我修改了我的工程中的overlay文件。但是,我也需要在某个地方修改bootloader工程的overlay文件,从而让bootloader也识别我的flash。
以上说的是运行在同一个CPU上,不同镜像之间的差异配置。除此之外,还有运行在不同CPU上,不同镜像之间的相同配置,例如双核MCU上的App Core和Net Core,我希望同时配置为debug模式或release模式,而不是单独去调。
Sysbuild的开关
编译时可以决定是否使用Sysbuild
west build --sysbuild
west build --no-sysbuild
在NCS v2.7.0之后,west build命令默认就是开启--sysbuild的。在NCS v2.6.x之前,则默认不开启。
命名空间(Namespace)
在多镜像编译的场景下,我们用west build进行命令行编译时,如果要添加一些配置项,则可能需要指定,这个配置项是属于哪个子工程的,或者是属于整体的(Sysbuild)。
# 带有Namespace的Kconfig
-D<namespace>_CONFIG_=
# 带有Namespace的CMake选项
-D<namespace>_=
例如:
west build -b reel_board --sysbuild samples/hello_world \
-- \
-DSB_CONFIG_BOOTLOADER_MCUBOOT=y \
-DCONFIG_DEBUG_OPTIMIZATIONS=y \
-Dmcuboot_CONFIG_DEBUG_OPTIMIZATIONS=y
# 给Sysbuild(全局)传递CONFIG_BOOTLOADER_MCUBOOT=y,表示使用bootloader作为MCUBOOT,命名空间为SB
# 给当前默认Application工程传递CONFIG_DEBUG_OPTIMIZATIONS=y,命名空间为空
# 给mcuboot工程传递CONFIG_DEBUG_OPTIMIZATIONS=y,命名空间为mcuboot,也就是子工程的名称
Sysbuild配置文件
除了上述在编译时传递编译选项的方法,也可以保存Sysbuild级别的配置文件
application/
├── ...
├── CMakeLists.txt
├── prj.conf
├── ...
├── Kconfig.sysbuild # Sysbuild全局级别的Kconfig菜单定义。可以不定义,不定义时使用SDK内的默认菜单
├── sysbuild.conf # Sysbuild全局配置项
├── ...
├── sysbuild.cmake # Sysbuild全局级别的CMake。可以用来管理有哪些工程镜像参与总镜像的编译
├── ...
└── sysbuild/ # Sysbuild目录下,可以分别给每个子工程单独进行配置
└── mcuboot
├── prj.conf
├── app.overlay
└── boards
├──
.conf ├──
.overlay ├──
.conf └──
.overlay
关于sysbuild的例程,可以参考zephyr/samples/sysbuild/下的几个例程。
Sysbuild配置文件
参考zephyr/samples/sysbuild/hello_world,这个工程是给双核MCU运行使用的。App核运行一个Hello World,然后同时再添加一个Hello World工程给另一个核使用。最后编译出双镜像固件。
要给当前工程添加子工程,其实就是修改sysbuild.cmake。
ExternalZephyrProject_Add(
APPLICATION my_sample # 要添加的工程名
SOURCE_DIR
/my_sample # 要添加的工程路径 BOARD mps2_an521_remote # 如有必要,单独指定要添加的工程使用的board
BUILD_ONLY TRUE # 如有必要,可以只编译不烧录
)
# 要先编译my_sample,再编译当前默认application工程
sysbuild_add_dependencies(CONFIGURE ${DEFAULT_IMAGE} my_sample)
# 等价于以下CMake标准函数
add_dependencies(${DEFAULT_IMAGE} my_sample)
# 要先烧录my_sample,再烧录当前application工程
sysbuild_add_dependencies(FLASH ${DEFAULT_IMAGE} my_sample)
# 如果my_sample配置为BUILD_ONLY=TRUE,则会报错
特别地,如果要添加的工程就是MCUBOOT,则只需在sysbuid.conf中添加下列配置即可:
SB_CONFIG_BOOTLOADER_MCUBOOT=y
因为SDK中已经把MCUBOOT相关的sysbuild写好了,这里直接使能即可。
【已抛弃】parent-child image
在NCS v2.6.x及之前的版本中,多镜像的管理靠的是parent-child image。这个工具不是Zephyr的,而是Nordic的。它也能在一个子文件夹里分别管理子镜像的配置。但它和Sysbuild的区别在于:它没有单独的High-Level的全局配置。这导致一些实际上应该属于全局的配置,直接放在了Application层的配置中(例如选择哪个Bootloader),因此偶尔会产生混淆。
如使用老版本的NCS,建议参考老版本NCS关于这方面的文档:https://docs.nordicsemi.com/bundle/ncs-2.7.0/page/nrf/config_and_build/multi_image.html
存储器分区文件
Partition Manager
管理一个MCU的存储器分区是很常见的需求。不仅在多镜像、OTA的场景下要管理,在内部和外部flash上挂载文件系统、用单独的分区存储生产信息等等场景下都要管理。
存储器分区文件,尤其是带有外部flash的,可以参考Matter例程,例如nrf/samples/matter/lock。你可以看到很多pm_static_xxx.yml:
mcuboot:
address: 0x0
size: 0x7000
region: flash_primary
mcuboot_pad:
address: 0x7000
size: 0x200
app:
address: 0x7200
size: 0xefe00
mcuboot_primary:
orig_span: &id001
- mcuboot_pad
- app
span: *id001
address: 0x7000
size: 0xf0000
region: flash_primary
mcuboot_primary_app:
orig_span: &id002
- app
span: *id002
address: 0x7200
size: 0xefe00
factory_data:
address: 0xf7000
size: 0x1000
region: flash_primary
settings_storage:
address: 0xf8000
size: 0x8000
region: flash_primary
mcuboot_secondary:
address: 0x0
size: 0xf0000
device: MX25R64
region: external_flash
external_flash:
address: 0xf0000
size: 0x710000
device: MX25R64
region: external_flash
详细的语法无需在意,不同工程基本都是大同小异的。
注意:配置Partition Manager时,一定要注意对齐Flash的Page!!!
静态分区文件说明
mcuboot相关
mcuboot相关照抄即可,只需修改地址和大小。
mcuboot:也就是mcuboot的固件大小。Matter的MCUBOOT配置是SDK中专门优化过的,因此只需要0x7000字节。一般来说自己添加一个需要0xc000的空间
mcuboot_pad:DFU期间,存储一些固件升级情况的标志位和校验信息
mcuboot_primary:也就是app所在的slot,同时也有mcuboot_pad。
mcuboot_secondary:也就是升级时新固件存放的slot。通常app负责接收新固件,然后跳转到mcuboot,mcuboot进行分区固件交换后,升级完成。secondary slot也可以放到外部flash
app相关
app相关照抄即可,只需修改地址和大小。
app与mcuboot_primary_app:都是app分区
settings_storage
settings_storage是Zephyr系统中一个存储配置项的分区,是一个简易的文件系统。可以用“字符串”(通常是文件路径,例如id/serial)作为句柄来存取数据(提供首地址、长度)。
Zephyr中许多的Librarys都依赖Settings来存储持久化数据,例如蓝牙的绑定密钥。因此这个分区非常常见。考虑到用到Settings的组件非常多,最好不要把Settings放到外部flash,不然做外部flash低功耗时,如果外部flash休眠了,而某个组件要用到Settings,就会报错,非常麻烦。
由于Settings是文件系统,因此它不是把数据单一的存在一个地址,而是像硬盘一样一直向后写,直到分区flash写满了,才把前面的page全部擦掉做垃圾回收。因此最好给settings_storage准备至少2个page的flash空间(上面的例子是0x8000,为两个4kB的page)。如果在特定极端峰值情况下,flash读写非常快且数量多,则需要3个page或以上。例如HomeKit认证时的循环蓝牙绑定16次测试,需要3个page。
其他分区
其他分区没有什么特别的,就是用一个label定义一个分区名称。
factory_data:在Matter工程中,用于存储证书等数据的分区。
external_flash:外部flash空余的位置,随意进行了一个命名。
其实Partition Manager只是一套脚本,最终还是要落实到C代码。在代码中,可以通过label来访问这些分区。例如Matter的SDK中就会通过factory_data来访问认证证书等数据。
你也可以充分利用这个未使用的分区。用nrf/include/flash_map_pm.h中定义的宏函数,来吧这些label转化成Zephyr可以使用的Flash Device句柄和分区句柄。例如把这个external_flash分区拿来建立NVS文件系统。
static struct nvs_fs fs;
int app_nvs_entry(void)
{
int rc = 0;
char buf[16];
uint8_t key[8], longarray[128];
uint32_t reboot_counter = 0U;
struct flash_pages_info info;
/* define the nvs file system by settings with:
* sector_size equal to the pagesize,
* 3 sectors
* starting at NVS_PARTITION_OFFSET
*/
fs.flash_device = NVS_PARTITION_DEVICE;
if (!device_is_ready(fs.flash_device)) {
LOG_ERR("Flash device %s is not ready", fs.flash_device->name);
return 0;
}
fs.offset = NVS_PARTITION_OFFSET;
rc = flash_get_page_info_by_offs(fs.flash_device, fs.offset, &info);
if (rc) {
LOG_ERR("Unable to get page info");
return 0;
}
fs.sector_size = info.size;
fs.sector_count = PAGE_COUNT;
LOG_INF("NVS sector size: %d, sector count: %d", fs.sector_size, fs.sector_count);
rc = nvs_mount(&fs);
if (rc) {
LOG_ERR("Flash Init failed");
return 0;
}
...
}
值的一提的是,根据nrf/include/flash_map_pm.h中的定义,当使用以下三种文件系统时,最好就使用那个名字作为label
settings_storage
littlefs_storage
nvs_storage
外部Flash分区
当某个分区位于外部Flash时,这个分区需要配置:
region: external_flash
device: MX25R64
其中device是需要在设备树中配置的,要让partition manager知道外部flash是哪个设备,比如这里是mx25r64这个节点:
/ {
chosen {
nordic,pm-ext-flash = &mx25r64;
};
};
如果Bootloader也需要访问外部flash,不要忘记在mcuboot中也添加以上配置。
除此之外,还要注意。如果不得已要把文件系统放在外部flash,一定要使能对应的配置,例如:
CONFIG_PM_PARTITION_REGION_LITTLEFS_EXTERNAL
CONFIG_PM_PARTITION_REGION_SETTINGS_STORAGE_EXTERNAL
CONFIG_PM_PARTITION_REGION_NVS_STORAGE_EXTERNAL
并且这些配置是,只有当你用Nordic的QSPI Flash驱动时(compatible = "nordic,qspi-nor")才有作用的。
更多使用外部flash的细节,见文档。
https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/app_dev/bootloaders_dfu/mcuboot_nsib/bootloader_partitioning.html#ug-bootloader-external-flash
动态分区
实际上Partition Manager还支持根据不同子工程编译的大小动态分区。但是动态分区对于实际的项目来说没有任何意义,实际项目一定都需要静态分区,才能确保固件升级(DFU)的正确性。
如需了解更多,参考Partition Manager文档。
https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/scripts/partition_manager/partition_manager.html
检查Partition Manager是否开启
要检查自己是否开启了Partition Manager,检查编译后的.config中有无:
CONFIG_PARTITION_MANAGER_ENABLED=y
不要主动去设置它,一般来说开启多镜像编译后,它就会自动使能。
用CMake变量指定分区文件
通常来说,编译时会自动选择项目根目录下的pm_static_.yaml文件。
但是如果你的项目比较复杂,希望用CMake变量来指定Partition Manager文件,类似于指定CONF_FILE配置文件那种方式,则需要在Sysbuild级别的配置sysbuild.cmake中进行设置,变量为PM_STATIC_FILE。
sysbuild.cmake
set(PM_STATIC_YML_FILE ${CMAKE_CURRENT_LIST_DIR}/foo/bar/pm_static.yml CACHE INTERNAL "")
Zephyr中的“Boards”
在Zephyr中,Boards是非常重要的一个概念。直观地理解,它指的就是你开发的项目的PCB板子。Zephyr中有很多可选择的Boards,都是各个厂商或提交给Zephyr的。在编译时必须选择一个Boards。
但看完前面的介绍,我们就可以更深入地理解Boards:它其实就是一堆默认的Kconfig,DeviceTree配置文件的集合。
Boards默认配置文件
当我们选择nrf52840dk/nrf52840时,就会导入SDK中${NCS}/zephyr/boards/nordic/nrf52840dk/目录下的各种配置文件。这其中,nrf52840dk是板子的名称,nrf52840是SoC的名称。
其中,Kconfig配置文件是nrf52840dk_nrf52840_defconfig;DeviceTree文件是nrf52840dk_nrf52840.dts。其余.dts或.dtsi文件是被它include的。例如,引脚分配文件nrf52840dk_nrf52840-pinctrl.dtsi。
当编译时,选择nrf52840dk/nrf52811时,它是用nrf52840这颗芯片来模拟nrf52811的资源,让你也可以用nRF52840DK这个开发板来进行nRF52811的开发。
Board Name
Boards是为了编译固件而服务的。因此board name中一定包含编译目标所需要的信息。
示例:
nrf52840dk/nrf52840:为nRF52840DK开发板上的nRF52840这颗SoC芯片编译固件
nrf5340dk/nrf5340/cpuapp:为nRF5340DK开发板上的nRF5340这颗双核芯片的App核编译固件
nrf54l15/cpuapp/ns:为nRF554L15DK开发板上的nRF54L15这颗双核芯片的App核编译固件,并且选择非安全(non-secure)地址空间进行编译。
完整示例:
nrf54l15dk@1.0.0/nrf54l15/cpuapp/ns:
nrf54l15dk
板子名称
@1.0.0
板子版本
(常见于工程样片版本)
/nrf54l15
Board qualifier
for SoC
/cpuapp
Board qualifier
for CPU cluster
/ns
Board qualifier
for variant
老版本板子名称
前面介绍的都是Zephyr的Hardware Model v2。在板子、SoC、CPU之间有层级关系。
在NCS v2.6.x之前,用的是没有层级关系的板子名称。例如:
nrf52840dk_nrf52840和nrf52840dk_nrf52811被认为是两块不同的板子。
当然你也可以简单理解为,Hardware Model v2就是简单把下划线_换成了斜杠/。
CMake中使用Boards变量
可能你需要在CMake中根据Board来配置不同的文件。
${BOARDS}:板子名,例如:
nrf52840dk,`nrf54l15dk``
${BOARD_QUALIFIERS}:后缀,例如:
/nrf52840,/nrf54l15/cpuapp/ns
比如,在sysbuild.cmake中,根据不同的board来使用不同的Partition Manager配置文件:
# 多镜像分区配置
# 在sysbuild.cmake中配置,以下配置会追加到所有子工程的CMakeLists.txt中
## Partition manager
if (EXISTS "${CMAKE_CURRENT_LIST_DIR}/configurations/${BOARD}${BOARD_QUALIFIERS}/pm_static.yml")
message(STATUS "Using Partition Manager file: ${CMAKE_CURRENT_LIST_DIR}/configurations/${BOARD}${BOARD_QUALIFIERS}/pm_static.yml")
set(PM_STATIC_YML_FILE ${CMAKE_CURRENT_LIST_DIR}/configurations/${BOARD}${BOARD_QUALIFIERS}/pm_static.yml CACHE INTERNAL "")
else()
message(FATAL_ERROR "Can't find Partition Manager configurations (${CMAKE_CURRENT_LIST_DIR}/configurations/${BOARD}${BOARD_QUALIFIERS}/pm_static.yml)")
endif()
这里${BOARD}${BOARD_QUALIFIERS}拼接起来,对应的就是配置文件目录层级:
自定义板子
如果你的项目比较简单,可以不用自定义板子。直接选择Nordic开发板作为基础的Board。然后用device tree overlay文件和Kconfig配置文件,来增、删、改配置。
但是定义自己的板子会有许多好处,比如:
让一个工程同时支持自己的Borad和开发板。debug时,可以对比开发板和自己的板子的表现。在排查硬件问题,进行功耗优化时非常有用。
用同一块板子开发不同工程时,移植非常方便。
你选择的芯片封装和开发板上的封装并不相同,引脚数量有区别,需要自定义board。
自定义板子的步骤
也可以参考官方文档
https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/app_dev/board_support/defining_custom_board.html
创建Board
可以在VS Code中图形化操作,定义板子:
输入板子名称,是给人阅读的字符串,可以带空格:
输入板子名称,是编译时使用的名称,不能带空格:
选择使用的NCS版本:
选择SoC芯片:
选择自己的boards相关文件存放的位置,通常就是当前project根目录即可。
输入公司名称,作为vendor字段:
创建完毕后,就存放在当前工程的boards目录下:
添加默认Kconfig
默认的config就是你的
可以按需求拷贝开发板的默认配置,参考${NCS-2.8.0}/zephyr/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840_defconfig
以上是添加默认的配置值。如果你想增加这个板子的菜单可选项,可以在Konfig.中添加你的菜单项。
值得一提的是,如果你的板子上没有32.768kHz晶振,则需要使用内部RC震荡器。可以把内部晶振相关配置写到这个defconfg中
CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y
CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=n
CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC_CALIBRATION=y
但是,在成本允许的情况下,还是非常推荐使用外部32k晶振的。外部晶体相比于内部RC震荡器具有更高的温度稳定性。此外,内部RC震荡器需要经常用高频时钟进行校准,因此功耗也会更高。
添加默认设备树配置
在
/${NCS-v2.8.0}/zephyr/boards/nordic/nrf52840dk/nrf52840dk_nrf52840.dts
这里着重介绍一些要用到的:
特殊引脚配置(in UICR)
当你的GPIO不够用时,可能需要把一些特殊引脚当作GPIO使用。这些需要写芯片的UICR寄存器(类似于Flash的一个区域,存储用户配置)。
&uicr {
// bool类型属性,有则为true,没有则为false
// Reset pin 当作 reset 而不是GPIO使用
gpio-as-nreset;
// 删除属性,就是把bool类型设为false
// NFC引脚不当作GPIO使用
/delete-property/ nfct-pins-as-gpios;
};
在较老的NCS版本,v2.4.x及之前,不是在DeviceTree中设置,而是在Kconfig中设置:
CONFIG_GPIO_AS_PINRESET=y
CONFIG_NFCT_PINS_AS_GPIOS=n
电源regulator配置
板子外部通过VDD引脚对芯片进行供电,Nordic芯片内部还有一级电源Regulator给内核供电。这个Regulator可以配置成DC/DC或者LDO。如果是DC/DC的话,板子外部需要添加对应的电感电容。
nRF52832内部供电-DCDC模式
nRF52840内部两级供电-双DC/DC模式
nRF52840有高电压模式,可以用VDDH引脚输入2.5~5.5V电压。
你也可以不使用VDDH。直接把VDDH和VDD短路,这种情况下会跳过Regulator0,供电范围是1.7~3.6V:
nRF52840一级供电 - LDO模式
大多数应用,采用一级供电即可。此外,像是nRF52840-QFAA这种封装(QFN48)内部已经把VDDH和VDD进行了短路操作,这时regulator0已经被屏蔽。直接配置reg1即可
// 使用DC/DC
®1 {
regulator-initial-mode =
; };
// 使用LDO
®1 {
regulator-initial-mode =
; };
如果你用的是带有VDDH供电的封装,则用以下设备树开启REG0的DC/DC
// reg0 只在nrf52840-qiaa.dtsi中有定义
®0 {
status = "okay";
};
在较老的NCS版本中,不是在设备树中配置,而是用Kconfig配置DC/DC
CONFIG_SOC_DCDC_NRF52X=y
CONFIG_SOC_DCDC_NRF52X_HV=y
gpio reserve
在开发板的设备树中,我们可能会看到gpio port的节点下有一些配置。我们需要知道它的意思。
&gpio0 {
status = "okay";
gpio-reserved-ranges = <0 2>, <6 1>, <8 3>, <17 7>;
gpio-line-names = "XL1", "XL2", "AREF", "A0", "A1", "RTS", "TXD",
"CTS", "RXD", "NFC1", "NFC2", "BUTTON1", "BUTTON2", "LED1",
"LED2", "LED3", "LED4", "QSPI CS", "RESET", "QSPI CLK",
"QSPI DIO0", "QSPI DIO1", "QSPI DIO2", "QSPI DIO3","BUTTON3",
"BUTTON4", "SDA", "SCL", "A2", "A3", "A4", "A5";
};
这里gpio-reserved-ranges的意思是:从软件层面上限制gpio0的某些引脚不能当作普通GPIO使用,因为它们在开发板上已经接了一些元器件。这可以防止出一些引脚分配问题。
<0 2>的意思是P0.00及其之后一共2个引脚,也就是P0.00和P0.01,因为它们是32.768kHz低频晶振所使用的引脚;同理,<17 7>的意思是P0.17及其之后一共7个引脚不能当普通GPIO使用,因为它们是板子上外部QSPI flash采用的引脚,还有P0.18是 reset引脚。
这个只是限制引脚不能当作普通GPIO使用,运行时会报错。但是并不限制这些引脚用pinctrl来分配给外设(毕竟QSPI引脚就是这么分配的)。
我们在拷贝开发板的dts到我们自定义的board时,注意不要完全拷贝这部分,要根据需求来。
Zephyr软件依赖的设备树节点
Zephyr中有许多现成的软件模块,它们与硬件有关。比如命令行终端shell,又比如LED和button的驱动。当你使能这些软件模块时,它们会去device tree中寻找自己应该操作哪些硬件。
比如,许多Zephyr Kernel功能用的是/chosen节点下的定义:
/{
chosen {
zephyr,console = &uart0;
zephyr,shell-uart = &uart0;
zephyr,uart-mcumgr = &uart0;
zephyr,bt-mon-uart = &uart0;
zephyr,bt-c2h-uart = &uart0;
zephyr,ieee802154 = &ieee802154;
};
};
// 如果用到OpenThread, Zigbee协议,则需要开启802.15.4
&ieee802154 {
status = "okay";
};
而其他一些library和例程用的是/aliases节点下的定义:
/{
aliases {
led0 = &led0;
led1 = &led1;
led2 = &led2;
led3 = &led3;
pwm-led0 = &pwm_led0;
sw0 = &button0;
sw1 = &button1;
sw2 = &button2;
sw3 = &button3;
bootloader-led0 = &led0;
mcuboot-button0 = &button0;
mcuboot-led0 = &led0;
watchdog0 = &wdt0;
};
};
很多例程会用到LED和Button。当你在自己的板子上运行例程,而你的板子上又没有定义led或button时,记得删除例程中LED和Button相关代码。
例程led和button相关的CONFIG是:
# Remove support for LEDs and buttons on Nordic development kits
CONFIG_DK_LIBRARY=n
外部Flash
nRF52840DK开发板上默认的QSPI flash为:
&qspi {
status = "okay";
pinctrl-0 = <&qspi_default>;
pinctrl-1 = <&qspi_sleep>;
pinctrl-names = "default", "sleep";
mx25r64: mx25r6435f@0 {
compatible = "nordic,qspi-nor";
reg = <0>;
/* MX25R64 supports only pp and pp4io */
writeoc = "pp4io";
/* MX25R64 supports all readoc options */
readoc = "read4io";
sck-frequency = <8000000>;
jedec-id = [c2 28 17];
sfdp-bfp = [
e5 20 f1 ff ff ff ff 03 44 eb 08 6b 08 3b 04 bb
ee ff ff ff ff ff 00 ff ff ff 00 ff 0c 20 0f 52
10 d8 00 ff 23 72 f5 00 82 ed 04 cc 44 83 68 44
30 b0 30 b0 f7 c4 d5 5c 00 be 29 ff f0 d0 ff ff
];
size = <67108864>;
has-dpd;
t-enter-dpd = <10000>;
t-exit-dpd = <35000>;
};
};
在nRF7002DK中,也有SPI Flash
&spi4 {
compatible = "nordic,nrf-spim";
status = "okay";
pinctrl-0 = <&spi4_default>;
pinctrl-1 = <&spi4_sleep>;
pinctrl-names = "default", "sleep";
cs-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>;
mx25r64: mx25r6435f@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <33000000>;
jedec-id = [c2 28 17];
sfdp-bfp = [
e5 20 f1 ff ff ff ff 03 44 eb 08 6b 08 3b 04 bb
ee ff ff ff ff ff 00 ff ff ff 00 ff 0c 20 0f 52
10 d8 00 ff 23 72 f5 00 82 ed 04 cc 44 83 68 44
30 b0 30 b0 f7 c4 d5 5c 00 be 29 ff f0 d0 ff ff
];
size = <67108864>;
has-dpd;
t-enter-dpd = <10000>;
t-exit-dpd = <5000>;
};
};
QSPI Flash选用的驱动为compatible = "nordic,qspi-nor". SPI Flash选用的驱动为compatible = "jedec,spi-nor。
如果你选的板子上的外挂flash和开发板自带的不同,则可以参考
${NCS}/zephyr/samples/driversamples/drivers/jesd216例程。不论你用的是QSPI还是SPI Flash,都把它先挂到SPI上,然后根据此例程的说明运行。例程会自动读取Flash信息,并把对应的设备树配置打印到日志中,复制出来即可。但是Flash一定是需要支持JEDEC的。
JEDEC (Joint Electron Device Engineering Council) 是一个制定半导体行业标准的组织。对于外挂Flash存储器来说,JEDEC标准定义了Flash存储器的接口、性能和功能特性。JEDEC标准确保了不同厂商生产的Flash存储器具有互操作性和兼容性。
Partition Manager
用MCUBoot进行升级时,如果需要把Second slot放到外部Flash,则需要增加以下配置,让Partition Manager知道外部Flash也要参与存储器分区:
chosen { nordic,pm-ext-flash = &mx25r64; // 赋值为你的外部flash的label};
用自定义板子编译
VS Code Build界面中出现自定义Board可以选择:
也可以在命令行编译时以当前板子为参数
west build -d build -b my_board/nrf52840 --sysbuild
编译流程与输出文件
编译流程
输出文件
以下均按照开启sysbuild的情况下来看路径:
当前application工程固件:build/
当前多工程编译合并固件:build/merged.hex,如果有多个核,每个核会有自己的merged_
DFU升级文件:build/dfu_application.zip,通过蓝牙等方式升级时使用的升级包
更多输出文件请参考官方文档.
https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/app_dev/config_and_build/output_build_files.html
VS Code界面
也可以在nRF Connect for VS Code插件界面中查看自己的所有参与编译的源码、配置文件、输出文件:
中文官网:www.nordicsemi.cn
英文官网:www.nordicsemi.com
微信公众号:nordicsemi
https://devzone.nordicsemi.com
北京分公司: +86 010 8438 2767
上海分公司: +86 21 6330 0620
深圳分公司: +86 755 8322 0147
sales.cn@nordicsemi.no
点击“阅读原文” 探索更多Nordic资讯