Understanding Zephyr Build and Configuration System (Part 2)

Understanding Zephyr Build and Configuration System (Part 2)

Source: cnblogs.com | Author: Jayant Tang

Understanding Zephyr Build and Configuration System (Part 2)

The Zephyr Project is an Apache 2.0 open-source project launched by the Linux Foundation, with a very friendly copyright, suitable for commercial project development. It includes an RTOS, a build system, and various third-party libraries. Most examples in NCS run on the Zephyr RTOS.

For developers who have previously only been exposed to the IDE + peripheral driver library development approach, the configuration and build system of Zephyr may be somewhat confusing, but once you master it, you will find its convenience.

This article continues from the previous part and will further introduce the configuration and build tools in NCS, including Zephyr’s unique Sysbuild, Boards, and the Partition Manager for memory partitioning provided by Nordic.

【Nordic Blog Series】Understanding Zephyr Build and Configuration System (Part 1)

Sysbuild (System Build)

The previously introduced CMake, Kconfig, and DeviceTree are configuration tools widely used in other fields (such as the Linux kernel). However, Sysbuild is a newly introduced build mechanism in Zephyr; it is a high-level configuration tool that addresses the issue of multi-image compilation for MCUs.

The tools mentioned earlier are used for compiling a single image. When we need to compile firmware with multiple images, there may be some differences in configuration items between these different images.

For example, I want my serial port to be used for logging, but in the bootloader image, the same serial port is used for firmware upgrades.

Another example is that I have chosen an external QSPI Flash that differs from the Flash on the Nordic official development board, so I modified the overlay file in my project. However, I also need to modify the overlay file in the bootloader project somewhere so that the bootloader can recognize my Flash.

The above describes the configuration differences between different images running on the same CPU. In addition, there are identical configurations between different images running on different CPUs; for example, on a dual-core MCU, I want to configure both the App Core and Net Core to be in debug mode or release mode simultaneously, rather than tuning them separately.

1

Sysbuild Switch

You can decide whether to use Sysbuild during compilation

west build --sysbuild
west build --no-sysbuild

After NCS v2.7.0, the west build command defaults to enabling –sysbuild. In NCS v2.6.x and earlier, it is disabled by default.

2

Namespace

In the multi-image compilation scenario, when we use west build for command-line compilation, if we want to add some configuration items, we may need to specify which sub-project this configuration item belongs to or if it belongs to the overall (Sysbuild).

# Kconfig with Namespace-D<namespace>_CONFIG_<var>=<value>
# CMake options with Namespace-D<namespace>_<var>=<value>

For example:

west build -b reel_board --sysbuild samples/hello_world \ 
 -- \ 
 -DSB_CONFIG_BOOTLOADER_MCUBOOT=y \ 
 -DCONFIG_DEBUG_OPTIMIZATIONS=y \ 
 -Dmcuboot_CONFIG_DEBUG_OPTIMIZATIONS=y# Pass CONFIG_BOOTLOADER_MCUBOOT=y to Sysbuild (global), indicating to use bootloader as MCUBOOT, namespace is SB# Pass CONFIG_DEBUG_OPTIMIZATIONS=y to the current default Application project, namespace is empty# Pass CONFIG_DEBUG_OPTIMIZATIONS=y to the mcuboot project, namespace is mcuboot, which is the name of the sub-project

3

Sysbuild Configuration Files

In addition to the method of passing compilation options during compilation mentioned above, you can also save Sysbuild-level configuration files

application/
├── ...
├── CMakeLists.txt # CMake for the application
├── prj.conf       # Configuration items for the application
├── ...
├── Kconfig.sysbuild # Sysbuild global-level Kconfig menu definition. Can be omitted; if omitted, the default menu in the SDK is used
├── sysbuild.conf    # Sysbuild global configuration items
├── ...
├── sysbuild.cmake   # Sysbuild global-level CMake. Can be used to manage which project images participate in the overall image compilation
├── ...
└── sysbuild/         # Under the Sysbuild directory, you can configure each sub-project separately
    └── mcuboot                   
        ├── prj.conf        
        ├── app.overlay        
        └── boards            
            ├── <board_A>.conf            
            ├── <board_A>.overlay            
            ├── <board_B>.conf            
            └── <board_B>.overlay

For examples of sysbuild, refer to several examples under zephyr/samples/sysbuild/.

4

Sysbuild Configuration Files

Refer to zephyr/samples/sysbuild/hello_world; this project is used for dual-core MCU operation. The App Core runs a Hello World, and then another Hello World project is added for the other core. Finally, dual-image firmware is compiled.

To add a sub-project to the current project, it is essentially modifying sysbuild.cmake.

ExternalZephyrProject_Add(  APPLICATION my_sample                 # Name of the project to be added  SOURCE_DIR <path-to>/my_sample        # Path of the project to be added  BOARD mps2_an521_remote               # If necessary, specify the board used by the project to be added  BUILD_ONLY TRUE                       # If necessary, compile only without flashing)
# Compile my_sample first, then compile the current default application project
sysbuild_add_dependencies(CONFIGURE ${DEFAULT_IMAGE} my_sample)# Equivalent to the standard CMake function add_dependencies(${DEFAULT_IMAGE} my_sample)
# Flash my_sample first, then flash the current application project
sysbuild_add_dependencies(FLASH ${DEFAULT_IMAGE} my_sample)# If my_sample is configured as BUILD_ONLY=TRUE, an error will occur

Specifically, if the project to be added is MCUBOOT, you only need to add the following configuration in sysbuild.conf:

SB_CONFIG_BOOTLOADER_MCUBOOT=y

Because the SDK has already written the sysbuild related to MCUBOOT, you can enable it directly.

[Deprecated] Parent-child Image

In versions of NCS v2.6.x and earlier, multi-image management relied on the parent-child image. This tool is not from Zephyr, but from Nordic. It can also manage the configuration of sub-images separately in a sub-folder. However, its difference from Sysbuild is that it does not have a separate high-level global configuration. This leads to some configurations that should actually belong to the global being placed directly in the Application-level configuration (for example, selecting which bootloader), which can occasionally cause confusion.

If you are using an older version of NCS, it is recommended to refer to the documentation regarding this aspect: https://docs.nordicsemi.com/bundle/ncs-2.7.0/page/nrf/config_and_build/multi_image.html

Partition Manager Memory Partition File

Managing the memory partition of an MCU is a common need. It needs to be managed not only in multi-image and OTA scenarios but also when mounting file systems on internal and external flash, storing production information in separate partitions, and so on.

For memory partition files, especially those with external flash, you can refer to the Matter example, such as nrf/samples/matter/lock. You can see many 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: &amp;id001  - mcuboot_pad  - app  span: *id001  address: 0x7000  size: 0xf0000  region: flash_primary
mcuboot_primary_app:  orig_span: &amp;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

The detailed syntax does not need to be focused on; different projects are basically similar.

Note: When configuring the Partition Manager, be sure to align the Flash Page!!!

1

Static Partition File Description

MCUBoot Related

MCUBoot related can be copied directly, just modify the address and size.

  • mcuboot: This is the firmware size of MCUBoot. The Matter MCUBoot configuration is specially optimized in the SDK, so it only needs 0x7000 bytes. Generally, adding a space of 0xc000 is needed.

  • mcuboot_pad: During DFU, store some flags and verification information about firmware upgrades.

  • mcuboot_primary: This is the slot where the app is located, and it also has mcuboot_pad.

  • mcuboot_secondary: This is the slot where the new firmware is stored during upgrades. Usually, the app is responsible for receiving the new firmware, then jumping to MCUBoot, which performs partition firmware swapping, completing the upgrade. The secondary slot can also be placed in external flash.

App Related

App related can be copied directly, just modify the address and size.

  • app and mcuboot_primary_app: Both are app partitions.

Settings Storage

Settings_storage is a partition for storing configuration items in the Zephyr system, which is a simple file system. It can use “strings” (usually file paths, such as id/serial) as handles to access data (providing start address and length).

Many libraries in Zephyr rely on Settings to store persistent data, such as Bluetooth binding keys. Therefore, this partition is very common. Considering that many components use Settings, it is best not to place Settings in external flash; otherwise, if external flash goes to low power mode while some component needs Settings, an error will occur, which is very troublesome.

Since Settings is a file system, it does not store data at a single address but continuously writes backward until the partition flash is full, then erases all previous pages for garbage collection. Therefore, it is best to prepare at least 2 pages of flash space for settings_storage (the above example is 0x8000, which is for two 4kB pages). If in specific extreme peak conditions, flash read and write are very fast and numerous, then 3 pages or more may be needed. For example, during HomeKit certification with 16 tests of cyclic Bluetooth binding, 3 pages are required.

Other Partitions

There is nothing special about other partitions; just define a label to name a partition.

  • factory_data: In the Matter project, this partition is used to store certificates and other data.

  • external_flash: The remaining position in the external flash, named arbitrarily.

In fact, the Partition Manager is just a set of scripts, and it ultimately needs to be implemented in C code. In the code, you can access these partitions through labels. For example, in the Matter SDK, it will access authentication certificates and other data through factory_data.

You can also make full use of this unused partition. Use macros defined in nrf/include/flash_map_pm.h to convert these labels into Flash Device handles and partition handles that Zephyr can use. For example, use this external_flash partition to establish an NVS file system.

#include <zephyr/storage/flash_map.h>
#define NVS_PARTITION    external_storage
#define NVS_PARTITION_DEVICE  FIXED_PARTITION_DEVICE(NVS_PARTITION)
#define NVS_PARTITION_OFFSET  FIXED_PARTITION_OFFSET(NVS_PARTITION)
#include <zephyr/fs/nvs.h>
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;
    }
    ...}

It is worth mentioning that according to the definitions in nrf/include/flash_map_pm.h, when using the following three file systems, it is best to use that name as a label.

  • settings_storage

  • littlefs_storage

  • nvs_storage

2

External Flash Partition

When a partition is located in external Flash, this partition needs to be configured:

region: external_flash
device: MX25R64

Where device needs to be configured in the device tree to let the partition manager know which device the external flash is, for example, here is the mx25r64 node:

/ {  chosen {    nordic,pm-ext-flash = &mx25r64;  };};

If the Bootloader also needs to access the external flash, do not forget to add the above configuration in mcuboot as well.

In addition, it is important to note that if you have to place the file system in external flash, you must enable the corresponding configuration, such as:

  • CONFIG_PM_PARTITION_REGION_LITTLEFS_EXTERNAL

  • CONFIG_PM_PARTITION_REGION_SETTINGS_STORAGE_EXTERNAL

  • CONFIG_PM_PARTITION_REGION_NVS_STORAGE_EXTERNAL

And these configurations only take effect when you use Nordic’s QSPI Flash driver (compatible = “nordic,qspi-nor”).

For more details on using external flash, see the documentation. https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/app_dev/bootloaders_dfu/mcuboot_nsib/bootloader_partitioning.html#ug-bootloader-external-flash

3

Dynamic Partitioning

In fact, the Partition Manager also supports dynamic partitioning based on the size of different sub-projects during compilation. However, dynamic partitioning has no significance for actual projects, as actual projects must require static partitioning to ensure the correctness of firmware upgrades (DFU).

For more information, refer to the Partition Manager documentation.

https://docs.nordicsemi.com/bundle/ncs-2.9.0/page/nrf/scripts/partition_manager/partition_manager.html

4

Check if the Partition Manager is Enabled

To check whether you have enabled the Partition Manager, check the compiled .config for:

CONFIG_PARTITION_MANAGER_ENABLED=y

Do not actively set it; generally, after enabling multi-image compilation, it will automatically be enabled.

5

Specify Partition Files with CMake Variables

Generally, the pm_static_.yaml file in the project root directory will be automatically selected during compilation.

However, if your project is more complex and you want to specify the Partition Manager file using CMake variables, similar to specifying the CONF_FILE configuration file, you need to set it in the Sysbuild-level configuration sysbuild.cmake, with the variable being PM_STATIC_FILE.

sysbuild.cmake

set(PM_STATIC_YML_FILE ${CMAKE_CURRENT_LIST_DIR}/foo/bar/pm_static.yml CACHE INTERNAL "")

Boards in Zephyr

In Zephyr, Boards are a very important concept. Intuitively, it refers to the PCB board of your developed project. There are many selectable Boards in Zephyr, all from various manufacturers or submitted to Zephyr. One must choose a Board during compilation.

However, after reading the previous introduction, we can understand Boards more deeply: it is actually a collection of default Kconfig and DeviceTree configuration files.

1

Default Configuration Files for Boards

When we select nrf52840dk/nrf52840, it imports various configuration files under the directory ${NCS}/zephyr/boards/nordic/nrf52840dk/. Among them, nrf52840dk is the name of the board, and nrf52840 is the name of the SoC.

The Kconfig configuration file is nrf52840dk_nrf52840_defconfig; the DeviceTree file is nrf52840dk_nrf52840.dts. Other .dts or .dtsi files are included by it. For example, the pin assignment file nrf52840dk_nrf52840-pinctrl.dtsi.

When compiling, if you choose nrf52840dk/nrf52811, it simulates the resources of nrf52811 using the nrf52840 chip, allowing you to develop nRF52811 using the nRF52840DK development board.

2

Board Name

Boards serve the purpose of compiling firmware. Therefore, the board name must include the information required for the compilation target.

Examples:

  • nrf52840dk/nrf52840: Compiling firmware for the nRF52840 SoC chip on the nRF52840DK development board.

  • nrf5340dk/nrf5340/cpuapp: Compiling firmware for the App core of the nRF5340 dual-core chip on the nRF5340DK development board.

  • nrf54l15/cpuapp/ns: Compiling firmware for the App core of the nRF54L15 dual-core chip on the nRF554L15DK development board, selecting the non-secure address space for compilation.

Complete example:

Understanding Zephyr Build and Configuration System (Part 2)

[email protected]/nrf54l15/cpuapp/ns:

nrf54l15dk

Board Name

@1.0.0

Board Version

(common in engineering sample versions)

/nrf54l15

Board qualifier for SoC

/cpuapp

Board qualifier for CPU cluster

/ns

Board qualifier for variant

Old Version Board Names

The above introduction is for Zephyr’s Hardware Model v2. There is a hierarchical relationship between the board, SoC, and CPU.

In versions of NCS v2.6.x and earlier, the board names without hierarchical relationships were used. For example:

nrf52840dk_nrf52840 and nrf52840dk_nrf52811 were considered two different boards.

Of course, you can also simply understand that the Hardware Model v2 is just replacing the underscore _ with a slash /.

3

Using Boards Variables in CMake

You may need to configure different files in CMake based on the Board.

  • ${BOARDS}: Board name, e.g., nrf52840dk, nrf54l15dk

  • ${BOARD_QUALIFIERS}: Suffixes, e.g., /nrf52840, /nrf54l15/cpuapp/ns

For example, in sysbuild.cmake, use different Partition Manager configuration files based on different boards:

# Multi-image partition configuration# Configure in sysbuild.cmake; the following configuration will be appended to all sub-projects' 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()

Here ${BOARD}${BOARD_QUALIFIERS} is concatenated, corresponding to the configuration file directory hierarchy:

Understanding Zephyr Build and Configuration System (Part 2)

4

Custom Boards

If your project is relatively simple, you can choose not to customize a board. Directly select a Nordic development board as the base Board. Then use device tree overlay files and Kconfig configuration files to add, delete, or modify configurations.

However, defining your own board has many benefits, such as:

  • Allowing a project to support both its own Board and the development board simultaneously. During debugging, it is very useful to compare the performance of the development board with that of your own board when troubleshooting hardware issues or optimizing power consumption.

  • When developing different projects with the same board, it is very convenient to port.

  • If the chip package you choose is different from the one on the development board, and the number of pins differs, you need to customize the board.

Steps to Define a Custom Board

You can also refer to the official documentation https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/app_dev/board_support/defining_custom_board.html

Create Board

You can graphically operate in VS Code to define the board:

Understanding Zephyr Build and Configuration System (Part 2)

Enter the board name, which is a readable string and can contain spaces:

Understanding Zephyr Build and Configuration System (Part 2)

Enter the board name, which is the name used during compilation and cannot contain spaces:

Understanding Zephyr Build and Configuration System (Part 2)

Select the NCS version to be used:

Understanding Zephyr Build and Configuration System (Part 2)

Select the location to store the boards related files:

Understanding Zephyr Build and Configuration System (Part 2)

Enter the company name as the vendor field:

Understanding Zephyr Build and Configuration System (Part 2)

After creation, it will be stored in the current project’s boards directory:

Understanding Zephyr Build and Configuration System (Part 2)Understanding Zephyr Build and Configuration System (Part 2)

Add Default Kconfig

The default config is your <board_name>_defconfig:

Understanding Zephyr Build and Configuration System (Part 2)

You can copy the default configuration of the development board as needed, referring to ${NCS-2.8.0}/zephyr/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840_defconfig

Understanding Zephyr Build and Configuration System (Part 2)

The above is to add the default configuration values. If you want to add menu options for this board, you can add your menu items in Kconfig.

It is worth mentioning that if your board does not have a 32.768kHz crystal oscillator, you need to use the internal RC oscillator. You can write the related configurations for the internal oscillator into this defconfig.

CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y
CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=n
CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC_CALIBRATION=y

However, if cost allows, it is still highly recommended to use an external 32k crystal oscillator. Compared to the internal RC oscillator, the external crystal has better temperature stability. In addition, the internal RC oscillator needs to be calibrated frequently with a high-frequency clock, so the power consumption will also be higher.

Add Default Device Tree Configuration

In <board_name>.dts, add your default device tree configuration. You can also copy the corresponding development board file as needed. For example:

/ ${NCS-v2.8.0}/zephyr/boards/nordic/nrf52840dk/nrf52840dk_nrf52840.dts

Here are some important ones to introduce:

Special Pin Configuration (in UICR)

When your GPIOs are insufficient, you may need to use some special pins as GPIOs. These need to write to the UICR register of the chip (similar to a Flash area that stores user configurations).

&uicr {    // bool type attribute, true if present, false if not
        // Reset pin used as reset instead of GPIO
        gpio-as-nreset;
    // Deleting the attribute means setting the bool type to false
    // NFC pins not used as GPIO
    /delete-property/ nfct-pins-as-gpios;
};

In older versions of NCS, v2.4.x and earlier, it was not set in the DeviceTree but in Kconfig:

CONFIG_GPIO_AS_PINRESET=y
CONFIG_NFCT_PINS_AS_GPIOS=n

Power Regulator Configuration

The board powers the chip externally via the VDD pin, and Nordic chips have an internal power regulator to power the core. This regulator can be configured as DC/DC or LDO. If it is DC/DC, the board needs to add corresponding inductors and capacitors.

Understanding Zephyr Build and Configuration System (Part 2)

nRF52832 internal power – DC/DC mode

Understanding Zephyr Build and Configuration System (Part 2)

nRF52840 internal two-stage power – dual DC/DC mode

The nRF52840 has a high voltage mode, allowing a voltage input of 2.5 to 5.5V via the VDDH pin.

You can also choose not to use VDDH. Directly short VDDH and VDD, in which case Regulator0 will be skipped, and the power supply range will be 1.7~3.6V:

Understanding Zephyr Build and Configuration System (Part 2)

nRF52840 single-stage power – LDO mode

For most applications, single-stage power is sufficient. In addition, for packages like nRF52840-QFAA (QFN48), VDDH and VDD are internally shorted, and Regulator0 is masked. You can directly configure reg1.

// Use DC/DC
&reg1 {  regulator-initial-mode = <NRF5X_REG_MODE_DCDC>;};
// Use LDO
&reg1 {  regulator-initial-mode = <NRF5X_REG_MODE_LDO>;};

If you are using a package with VDDH power supply, use the following device tree to enable REG0’s DC/DC:

// reg0 is only defined in nrf52840-qiaa.dtsi
&reg0 {  status = "okay";};

In older versions of NCS, it was not set in the device tree but configured using Kconfig for DC/DC:

CONFIG_SOC_DCDC_NRF52X=y
CONFIG_SOC_DCDC_NRF52X_HV=y

GPIO Reserve

In the development board’s device tree, we may see some configurations under the gpio port node. We need to know what they mean.

&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";};

The gpio-reserved-ranges means: from the software level, restrict certain pins of gpio0 from being used as ordinary GPIOs because they are already connected to some components on the development board. This can prevent pin assignment issues.

<0 2> means P0.00 and the next 2 pins, which are P0.00 and P0.01, as they are used for the 32.768kHz low-frequency crystal oscillator; similarly, <17 7> means P0.17 and the next 7 pins cannot be used as ordinary GPIOs because they are the pins used by the external QSPI flash on the board, and P0.18 is the reset pin.

This only restricts the pins from being used as ordinary GPIOs; runtime errors will occur. However, it does not restrict these pins from being allocated to peripherals using pinctrl (after all, QSPI pins are allocated this way).

When copying the development board’s dts to our custom board, be careful not to copy this part entirely; it should be adjusted according to requirements.

Device Tree Nodes Dependent on Zephyr Software

There are many ready-made software modules in Zephyr that are related to hardware. For example, command line terminal shell, as well as drivers for LEDs and buttons. When you enable these software modules, they will look in the device tree for which hardware they should operate.

For example, many Zephyr Kernel functions use definitions under the /chosen node:

/{  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;  };};
// If using OpenThread or Zigbee protocol, you need to enable 802.15.4
&ieee802154 {  status = "okay";};

Other libraries and examples use definitions under the /aliases node:

/{  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;  };};

Many examples will use LEDs and Buttons. When you run examples on your own board, and your board does not have definitions for LEDs or buttons, remember to delete the LED and Button related code in the examples.

The CONFIG related to LED and button in examples is:

# Remove support for LEDs and buttons on Nordic development kits
CONFIG_DK_LIBRARY=n

External Flash

The default QSPI flash on the nRF52840DK development board is:

&qspi {  status = "okay";  pinctrl-0 = &lt;&qspi_default&gt;;  pinctrl-1 = &lt;&qspi_sleep&gt;;  pinctrl-names = "default", "sleep";  mx25r64: mx25r6435f@0 {    compatible = "nordic,qspi-nor";    reg = &lt;0&gt;;    /* MX25R64 supports only pp and pp4io */    writeoc = "pp4io";    /* MX25R64 supports all readoc options */    readoc = "read4io";    sck-frequency = &lt;8000000&gt;;    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 = &lt;67108864&gt;;    has-dpd;    t-enter-dpd = &lt;10000&gt;;    t-exit-dpd = &lt;35000&gt;;  };};

In the nRF7002DK, there is also an SPI Flash

&spi4 {  compatible = "nordic,nrf-spim";  status = "okay";  pinctrl-0 = &lt;&spi4_default&gt;;  pinctrl-1 = &lt;&spi4_sleep&gt;;  pinctrl-names = "default", "sleep";  cs-gpios = &lt;&gpio0 11 GPIO_ACTIVE_LOW&gt;;  mx25r64: mx25r6435f@0 {    compatible = "jedec,spi-nor";    reg = &lt;0&gt;;    spi-max-frequency = &lt;33000000&gt;;    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 = &lt;67108864&gt;;    has-dpd;    t-enter-dpd = &lt;10000&gt;;    t-exit-dpd = &lt;5000&gt;;  };};

The driver used for QSPI Flash is compatible = “nordic,qspi-nor”. The driver used for SPI Flash is compatible = “jedec,spi-nor”.

If the external flash you choose on the board is different from the one provided with the development board, you can refer to the ${NCS}/zephyr/samples/driversamples/drivers/jesd216 example. Regardless of whether you use QSPI or SPI Flash, first mount it to SPI, and then run according to the instructions of this example. The example will automatically read the Flash information and print the corresponding device tree configuration in the logs, which can be copied out. However, the Flash must support JEDEC.

JEDEC (Joint Electron Device Engineering Council) is an organization that sets standards for the semiconductor industry. For external Flash memory, JEDEC standards define the interface, performance, and functional characteristics of Flash memory. JEDEC standards ensure interoperability and compatibility of Flash memory produced by different manufacturers.

Partition Manager

When upgrading with MCUBoot, if you need to place the Second slot in external Flash, you need to add the following configuration to let the Partition Manager know that external Flash should also participate in memory partitioning:

chosen { nordic,pm-ext-flash = &mx25r64; // Assign to the label of your external flash};

Compiling with Custom Boards

In the VS Code Build interface, you can select the custom Board:

Understanding Zephyr Build and Configuration System (Part 2)

You can also compile from the command line using the current board as a parameter:

west build -d build -b my_board/nrf52840 --sysbuild

Compilation Process and Output Files

1

Compilation Process

Understanding Zephyr Build and Configuration System (Part 2)

2

Output Files

The following paths are based on enabling sysbuild:

  • Current application firmware: build/<your_application_name>/zephyr/zephyr.hex

  • Current multi-project compiled merged firmware: build/merged.hex; if there are multiple cores, each core will have its own merged_<core>.hex

  • DFU upgrade files: build/dfu_application.zip, used for upgrade packages during upgrades via Bluetooth, etc.

For more output files, please refer to the official documentation.

https://docs.nordicsemi.com/bundle/ncs-latest/page/nrf/app_dev/config_and_build/output_build_files.html

3

VS Code Interface

You can also view all source codes, configuration files, and output files involved in the compilation in the nRF Connect for VS Code plugin interface:

Understanding Zephyr Build and Configuration System (Part 2)Understanding Zephyr Build and Configuration System (Part 2)

[Contact Us]

Chinese Official Website: www.nordicsemi.cn

English Official Website: www.nordicsemi.com

WeChat Official Account: nordicsemi

[Nordic Developer Forum]

https://devzone.nordicsemi.com

[Sales Contact]

Beijing Branch: +86 010 8438 2767

Shanghai Branch: +86 21 6330 0620

Shenzhen Branch: +86 755 8322 0147

[email protected]

Understanding Zephyr Build and Configuration System (Part 2)Understanding Zephyr Build and Configuration System (Part 2)

Click “Read the Original” to Explore More Nordic Information

Leave a Comment