Common Project Build Method

1. Background

In SDK versions before v2.1.5, under each example directory, different directories were created for each board to store corresponding project files. For instance, under $SDK_ROOT/hal_example/project, directories for eh-lb561, eh-lb563, and eh-lb523 boards were present, each corresponding to a project for the respective boards. Each directory contained similar SCons scripts and .config and rtconfig.h configuration files. To compile software for the eh-lb561 board, users would enter the eh-lb561 directory and execute scons to perform the compilation.

The problem with this approach was that every time a new board was added, a new project directory had to be created. As the number of examples increased, many new projects were added. If a common configuration needed modification for a certain example, it had to be updated in all the projects, leading to high maintenance overhead.

To address this issue, starting from v2.1.5, the SDK introduced a new project build method known as the “Common Project” approach. Under this method, only one project folder is required for each example, and it no longer stores the .config and rtconfig files. During compilation, the software for the selected board is generated, and .config and rtconfig.h are generated in the build directory. Multiple boards can be compiled simultaneously, and the generated files will not overwrite each other.

2. Compilation Method

In the common project directory, execute the following command to compile the image for a specified board. board_name is the name of the board, and it can still be followed by other scons parameters, such as -j8 to specify the use of 8 threads for compilation.

For dual-core chip boards, the board_name must specify which core is being used, for example, eh-lb523_hcpu, indicating the program that can run on the HCPU of the 523 HDK board.

To reduce repetitive file maintenance work, many files are generated during compilation, such as .config, rtconfig, and linker scripts, etc. The specific generation method is described in section 3.3.

    scons --board=board_name

The following command compiles a program that can run on the HCPU of the eh-lb523_v2 board.

    scons --board=eh-lb523_v2_hcpu -j8

The generated files will be stored in the build_eh-lb523_v2_hcpu directory, as shown below:

Build Output

3. How to Create a Common Project

The creation of a common project involves two parts: the board and the application. If creating a new application on an existing board, you can skip section 3.1 and directly create an application project.

3.1 Board

The directory structure for the board is shown below. The top-level directory stores the source files related to the board, including:

  • IO-related code, such as bsp_pinmux.c, bsp_power.c

  • Initialization code, bsp_init.c

  • ptab.json, memory layout

  • SConscript, build script

  • Kconfig.board, the board’s Kconfig configuration file

The second-level directories contain configuration files for each core, including:

  • _board.conf_, the minimal configuration file generated by Kconfig

  • _Kconfig.board_, the Kconfig configuration file for the core, which can source the top-level _Kconfig.board_

  • _link.sct_, optional, Keil’s linker script

  • _rtconfig.py_, which can specify JLINK_DEVICE, optimization level, and other compilation parameters (it is recommended to use the newly added Kconfig configuration for optimization)

  • _custom_mem_map.h_, used when CUSTOM_MEM_MAP is enabled

Sometimes, different chips may be used on the same model of HDK. To avoid duplicating IO setup code in different board directories, common code can be placed in a shared directory, which is then referenced by the individual board directories.

3.1.1 board.conf

Run menuconfig in the second-level directory to open the configuration window. This configuration interface loads all Kconfig files from the SDK except for the application-specific ones. After modifying the configuration, choose “[D] Save minimal config” to save the minimal differential configuration (the part that differs from the default Kconfig configuration), and name the file board.conf. Choosing “[S] Save” will generate .config and _rtconfig.h_, allowing the correct configuration to be displayed the next time it is opened. If .config is not generated, after closing menuconfig, the configuration will revert to the default configuration, and the settings in board.conf will not be loaded. It is recommended to delete the generated _rtconfig.h_ to avoid it being mistakenly referenced. Alternatively, you can run _gen_board_config.bat_ to generate .config and config.h based on board.conf.

It is recommended to configure a basic runtime environment in board.conf for general application development, such as ensuring the console (selecting the appropriate serial port) and file system (selecting the appropriate file system type) work. Application-specific configurations should be set in the application’s project configuration file.

3.1.2 rtconfig.py

The rtconfig.py file introduces two new variables: CORE and CHIP. CORE specifies the core type, which can be either “HCPU” or “LCPU,” and CHIP represents the chip series, such as “SF32LB56X” or “SF32LB52X.”

3.2 Application Project

For applications that use dual-core chips, the project directory is split into hcpu and lcpu subdirectories.

For the SF32LB52X, if only the HCPU application is needed, and no LCPU is used, or a precompiled LCPU image is used, the application project only needs to create a directory for the HCPU project files, as shown in the following example project.

The files in the directory include:

  • _Kconfig.proj_, the application’s Kconfig configuration file

  • _proj.conf_, the application’s minimal configuration file

  • _rtconfig.py_, custom compilation options for the application, which override any matching configurations in the board directory

  • Sconscript/Sconstruct, build scripts

  • Application-specific source code

3.2.1 SConstruct

Unlike the previous project setup, the SConstruct script must call PrepareEnv() at the beginning to prepare the board’s compilation environment.

Since sub-projects may run on different cores, parameters must be added in the SConstruct script to specify which core the sub-project will run on. If not specified, it defaults to the main project. For instance, the following shows how an LCPU sub-project is added.

3.2.2 proj.conf

Similar to generating board.conf, run menuconfig in the project directory to save the minimal configuration to proj.conf. If all configurations are saved, delete the generated _rtconfig.h_. You can also execute _gen_proj_config.bat_ to generate .config and config.h based on proj.conf. The generated files are equivalent to choosing “[S] Save” in menuconfig.

In the build directory, a Kconfig file will also be generated. Compared to the Kconfig file in the application project directory, it will additionally load the board’s Kconfig file to generate a complete configuration file.

source "$SIFLI_SDK/Kconfig.v2"
source "$SIFLI_SDK/customer/boards/eh-lb56xu_v2/hcpu/Kconfig.board"
source "D:/Users/xiaomingxi/code/bt7/example/multicore/data_service/common/hcpu/Kconfig.proj"

Below is an example of proj.conf. To disable a specific option, start with a # and write “is not set” after the option name (with the CONFIG_ prefix). The configuration below disables ULOG_USING_COLOR.

CONFIG_RT_MAIN_THREAD_STACK_SIZE=4096
CONFIG_RT_MAIN_THREAD_PRIORITY=15
CONFIG_RT_USING_ULOG=y
CONFIG_ULOG_USING_ISR_LOG=y
## CONFIG_ULOG_USING_COLOR is not set
CONFIG_ULOG_OUTPUT_THREAD_NAME=y
CONFIG_RT_TICK_PER_SECOND=1000
CONFIG_IDLE_THREAD_STACK_SIZE=512
CONFIG_RT_TIMER_THREAD_STACK_SIZE=1024
CONFIG_RT_CONSOLE_DEVICE_NAME="uart1"
CONFIG_BSP_USING_TOUCHD=y
CONFIG_BSP_USING_LCPU_PATCH=y
CONFIG_BSP_USING_LCD=y
CONFIG_BLUETOOTH=y
CONFIG_BSP_USING_FULL_ASSERT=y
## CONFIG_BSP_USING_LOOP_ASSERT is not set
## CONFIG_BSP_USING_EMPTY_ASSERT is not set

3.3 File Generation Rules

To reduce repetitive file maintenance, the following files are dynamically generated during compilation based on the selected board in the build directory:

  • _rtconfig.h (and .config)

  • _ptab.json/ptab.h_

  • _custom_mem_map.h_

  • _link.sct/link.lds_ (linker scripts)

The general rule for file generation is to select the highest-priority file from the relevant directories as the final used file or to override lower-priority configurations. The priority order from highest to lowest is:

  1. The board directory in the application project directory

  2. The chip directory in the application project directory (specified by rtconfig.CHIP for the chip series, e.g., sf32lb56x)

  3. The application project directory

  4. The board directory

  5. The chip series directory

3.3.1 custom_mem_map.h

For example, in the application project directory data_service/common/hcpu, there is a board directory eh-lb561_v2_hcpu that contains the _custom_mem_map.h_. Therefore, the _custom_mem_map.h_ in the build directory is copied from data_service/common/hcpu/eh-lb561_v2_hcpu/custom_mem_map.h. If the application’s board directory doesn’t have _custom_mem_map.h_ but the application project directory does, it will be copied from there. Only if the file is not present in both the application and the board directory will it be copied from _$SDK_ROOT/customer/boards/eh-lb561_v2/hcpu/custom_mem_map.h_.

3.3.2 ptab.json

The following order is used to select the _ptab.json_ file for compilation:

  1. The board directory in the application project directory

  2. The chip directory in the application project directory

  3. The application project directory

  4. The board directory

The ptab.h is generated from _ptab.json_ and stored in the build directory.

3.3.4 rtconfig.h

The _rtconfig.h_ is generated by merging the default values from Kconfig with _board.conf_ and _proj.conf_. _board.conf_ and _proj.conf_ record the modified configurations (changes compared to the default values). If the same configuration appears in both _board.conf_ and _proj.conf_, the configuration in _proj.conf_ takes precedence. You can also add a board directory to the application project to place a board-specific proj.conf. For instance, if most configurations are the same across boards but only a few parameters differ, you can define the shared configurations in the root proj.conf and place the specific ones in each board’s directory.

The order of parameter values in _rtconfig.h_ and .config follows the priority from highest to lowest, as follows:

  1. proj.conf in the application’s board directory

  2. proj.conf in the application’s chip directory

  3. proj.conf in the application project directory

  4. _board.conf_ in the board directory

  5. Default values from Kconfig

4. Modifying Existing Projects

Follow these steps to convert an existing project into a common project supporting compilation for any board:

  1. Create the board folder, extract board-related configurations from the original project’s .config, write them into board.conf (skip this step if the board already exists), and copy the _ptab.json_ file from the original project to the newly created board folder.

  2. Create the application project folder, extract common configurations from the original project’s .config, write them into the root proj.conf of the application project, and place board-specific configurations in the corresponding board directory under the application.

  3. Copy the Sconscript and SConstruct from the original project directory, and add the PrepareEnv() call to the SConstruct to support compiling for the specified board.