Software Componentization

This chapter illustrates the MCUXpresso SDK Componentization concept and composition supported by the build system.

Componentization

To improve software component integration and portability, all MCUXpresso SDK components including drivers, components, utilities and middlewares are recorded and used in a componentized way instead of fragment code lines.

In addition to the sources, one MCUXpresso SDK software component always contains CMakeLists.txt and Kconfig files. CMake part defines the sources, includes, static configurations, versions, etc while Kconfig part defines the dynamic configurations and dependencies.

The following shows a typical MCUXpresso SDK component composition:

  uart
    ├── fsl_uart.h
    ├── fsl_uart.c
    ├── CMakeLists.txt
    ├── Kconfig

All MCUXpresso SDK components have an ID across the CMakeLists.txt and Kconfig. The ID starts with MCUX_COMPONENT_ to indicate this component is a ready MCUXpresso SDK component. Briefly, in CMakeLists.txt the ID is like CONFIG_MCUX_COMPONENT_<component name> while in Kconfig it is like MCUX_COMPONENT_<component name>, you will see details in next chapters.

According to Introduce Component, Project Segment and Dependency Definition Symbols, all Kconfig symbols with naming prefix MCUX_ will be intentionally removed out of the generated config header file, so they won’t affect example build.

For external customers enabling a software functionality, it is not required to follow and use this componentization way to organize the sources and data. You can still use the traditional cmake and Kconfig syntax to work, but it is recommended that you could put your sources and data into a component instead of keeping them in a scattered way.

CMakeLists.txt

In CMakeLists.txt, component data is recorded inside a if-endif guard. The condition of the if statement is the combination of the CONFIG_MCUX_COMPONENT_ prefix and the component name which indicates everything insides the if-endif section belongs to a software component. The combination name is the component ID. The nested if-endif is not supported, and the if condition shall only contain one component name, combined condition with || or && is not supported either.

Here is the driver.uart CMakeLists.txt:

if (CONFIG_MCUX_COMPONENT_driver.uart) # component name is driver.uart

    # component version
    mcux_component_version(2.5.1)
  
    # component data
    mcux_add_source(
        SOURCES fsl_uart.h 
                fsl_uart.c
    )
    mcux_add_include(
        INCLUDES .
    )
endif()

If a component definition is split into several cmake files, the same if(CONFIG_MCUX_COMPONENT_<component name>)-endif guards should be used in all files data.

Kconfig

In Kconfig, the symbol for a component also starts with MCUX_COMPONENT_ to be identical with cmake component name. Component configuration and dependency are recorded in Kconfig following the below pattern:

config MCUX_HAS_COMPONENT_driver.uart
    bool
    default y if MCUX_HW_IP_DriverType_UART # such MCUX_HW_IP_DriverType_UART is defined in device Kconfig.chip

config MCUX_COMPONENT_driver.uart
    bool "Use driver uart"
    select MCUX_COMPONENT_driver.common
    depends on MCUX_HAS_COMPONENT_driver.uart # component dependency

# Configuration for driver.uart shall be put into the if-endif so that only driver.uart is selected, the configuration will be showed
    if MCUX_COMPONENT_driver.uart 
     # Configuration for driver.uart
    endif

About the dependency, please refer Complex Dependency chapter for details.

For multiple components belonging to one middleware set, menu is used to gather them together, like

menu "freertos-kernel(FreeRTOSConfig.h)"
    config MCUX_COMPONENT_middleware.freertos-kernel
        bool "middleware.freertos-kernel"
        select MCUX_COMPONENT_middleware.freertos-kernel.extension
  
    ......
  
    config MCUX_COMPONENT_middleware.freertos-kernel.cm33_non_trustzone
        bool "cm33 non trustzone port"
        default n
        depends on (MCUX_HW_CORE_CM33 || MCUX_HW_CORE_CM33F)
    config MCUX_COMPONENT_middleware.freertos-kernel.cm33_trustzone.non_secure
        bool "cm33 trustzone, non secure port"
        default n
        depends on (MCUX_HW_CORE_CM33 || MCUX_HW_CORE_CM33F)

    config MCUX_COMPONENT_middleware.freertos-kernel.tfm_ns
        bool "TF-M NS support"
        select MCUX_COMPONENT_middleware.freertos-kernel.cm33_non_trustzone
        select MCUX_COMPONENT_middleware.tfm.ns
        default n
        help
            OS wrapper for running inside TF-M non secure world

    config MCUX_COMPONENT_middleware.freertos-kernel.extension
        default n
        bool "Task Aware Debugger (TAD) support"
    ......
endmenu

Component macro definitions will be generated in header files. Please refer to Config Headers chapter for details.

Supported Components

There are following components which are already enabled in MCUXpresso SDK: drivers, components/utilities, middlewares and RTOS. They are located under mcuxsdk/drivers, mcuxsdk/components, mcuxsdk/middlewares and mcuxsdk/rtos.

Base device and board specific drivers and components are located in the target device and board folder.

All software components are involved into build tree through the root mcuxsdk/CMakeLists.txt and mcuxsdk/Kconfig.mcuxpresso. You can check them with Kconfig GUI and select needed components into your example.

Component Naming

As you can see, in our build system, all components naming is in format MCUX_COMPONENT_<name> . The MCUX_COMPONENT_ prefix indicates that the data section is a software component. About the specific component name, currently they are generally following the format <major type>.<minor types>.<name>. The dot is used to separate component type and name. The minor type(s) is optional and can be more than one like driver.uart , middleware.fatfs and middleware.fatfs.mmc. Most frequently used major types are:

Major Types

Explanation

Examples

driver

Base SDK drivers

driver.uart, driver.clock

component

SDK components

component.serial_manager, component.serial_manager_spi

utilities

SDK utility

utilities.gcov, utilities.unity

middleware

Middlewares and RTOSes

middleware.fatfs, middleware.freertos-kernel

The above naming convention applies to both cmakes and Kconfigs. For Kconfig, normally all Kconfig symbols will be generated into header files as macros, so there will be macros like CONFIG_MCUX_COMPONENT_component.serial_manager=1 in the generated header file which will cause build failure because C language identifiers cannot contain punctuation mark dot. To resolve this, our build system intentionally remove such component naming symbols from generated header file. Please check MCUXpresso SDK Customized Kconfig Rules for more rules and details.