element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products & Partners
    Products & Partners
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
    About the element14 Community
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Japan
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      •  Vietnam
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Embedded and Microcontrollers
  • Technologies
  • More
Embedded and Microcontrollers
Blog EZ-MCXN: CMake script for NXP MCXN326 controller
  • Blog
  • Forum
  • Documents
  • Quiz
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Embedded and Microcontrollers to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Jan Cumps
  • Date Created: 31 Oct 2026 9:43 PM Date Created
  • Views 92 views
  • Likes 5 likes
  • Comments 5 comments
  • EZ-MCXN
  • nxp
  • FRDM-MCXN236
  • MCXN236
Related
Recommended

EZ-MCXN: CMake script for NXP MCXN326 controller

Jan Cumps
Jan Cumps
31 Oct 2026

In this post, I propose a CMake script for NXP MCXN326 controller. Not dependent on MCUXpresso's IDE or VS Code extension. Also independent of dev board definitions and SDK example code files.

Prerequisites: What do you need:

  • working CMake and ARM GCC toolchains
  • a downloaded and unzipped SDK (check if this link works - NXP account needed)
  • MCUXPresso Config tools (link, NXP account needed)
  • a .mex configuration file for your project. If you use shabaz' EZ-MCXN dev board, get it from his GitHub repo.
  • a main file (example below)
  • a CMake config file, the main focus of this post.

CMake file

I'll go start to end over the file. Check the inline comments

Initialisation
This step sets standards, and some definitions that are needed early on.

cmake_minimum_required(VERSION 3.29)

set(CMAKE_VERBOSE_MAKEFILE OF)

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 26)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# SDK_ROOT set externally
set(SDK_ROOT $ENV{SDK_ROOT})                                                        # set as a CMake Environment variable. Points to root of unzipped SDK
message(STATUS "SDK_ROOT: ${SDK_ROOT}")

set(CMAKE_SYSTEM_NAME Generic)                                                      # no OS
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --specs=nosys.specs")         # prevents CMake throws toolchain error when using embedded GCC

add_compile_definitions(
    MCXN236                                                                         # controller
    CPU_MCXN236VKL                                                                  # package
)

Fetch debug configuration, in case you want to use a hardware debugger later.
Only runs if needed. Either at first run, or if the cache is cleaned. First run needs an internet connection.
If you don't plan to use a hardware debugger, you can safely comment this section.

include(FetchContent)
set(FETCHCONTENT_QUIET FALSE CACHE BOOL "" FORCE)                                   # show download, because it takes a while
set(FETCHCONTENT_UPDATES_DISCONNECTED ON CACHE BOOL "" FORCE)                       # skip if we have it in cache. Also allows for offline builds
FetchContent_Declare(svd                                                            # get MCXN236 svd definition, so registers are available during debug
  GIT_REPOSITORY "https://github.com/nxp-mcuxpresso/mcux-soc-svd.git"
  GIT_TAG origin/main
  GIT_PROGRESS TRUE                                                                 # show download, because it takes a while
  # prevent makefile execution (if any)
  SOURCE_SUBDIR =
)
FetchContent_MakeAvailable(svd)
file(COPY "${svd_SOURCE_DIR}/MCXN236/MCXN236.xml"                                   # copy svd from download to build dir, where launch.json can find it
     DESTINATION "${CMAKE_BINARY_DIR}"
)

Generate CMUXpresso Config source files
This is called, during Build, only when needed. 
Either if the source files don't exist yet (first build, files removed), or if they are older than the .mex file.
It checks that for Pins, Clocks and Peripherals. The required jobs will run in parallel.
Because my project doesn't use the peripherals (the source files aren't added to the build target), CMake knows that it can skip the Peripherals .h and .c file generation. 

# MCUXpresso Config section
set(CONFIG_TOOL_PATH $ENV{CONFIG_TOOL_PATH})                                        # check if MCUXpresso Config path is set         
if(CONFIG_TOOL_PATH)                                                                # path set: generate sources
    message(STATUS "CONFIG_TOOL_PATH: ${CONFIG_TOOL_PATH}")
    set(MEX_FILE "${CMAKE_CURRENT_SOURCE_DIR}/EZ_MCXN.mex")
    set(OUTPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")

    message(STATUS "MCUXpresso Config Tools: source-export (Pins, Clocks, Peripherals)...")

    # Check if needs to run: Pins
    set(PINS_DEST_HEADER "${OUTPUT_DIR}/board/pin_mux.h")
    set(PINS_DEST_SOURCE "${OUTPUT_DIR}/board/pin_mux.c")
    add_custom_command(
        OUTPUT "${PINS_DEST_HEADER}" "${PINS_DEST_SOURCE}"
        COMMAND "${CONFIG_TOOL_PATH}" 
        "-noSplash" 
        "-consoleLog"
        "-HeadlessTool" "Pins" 
        "-Load" "${MEX_FILE}" 
        "-ExportSrc" "${OUTPUT_DIR}"
        RESULT_VARIABLE CONFIG_TOOL_RESULT
        ERROR_VARIABLE CONFIG_TOOL_ERROR
        DEPENDS "${MEX_FILE}"
        COMMENT "Generating Pins files because ${MEX_FILE} changed or board files are missing"
        VERBATIM
    )


    # Check if needs to run: Clocks
    set(CLOCKS_DEST_HEADER "${OUTPUT_DIR}/board/clock_config.h")
    set(CLOCKS_DEST_SOURCE "${OUTPUT_DIR}/board/clock_config.c")
    add_custom_command(
        OUTPUT "${CLOCKS_DEST_HEADER}" "${CLOCKS_DEST_SOURCE}"
        COMMAND "${CONFIG_TOOL_PATH}" 
        "-noSplash" 
        "-consoleLog"
        "-HeadlessTool" "Clocks" 
        "-Load" "${MEX_FILE}" 
        "-ExportSrc" "${OUTPUT_DIR}"                    
        RESULT_VARIABLE CONFIG_TOOL_RESULT
        ERROR_VARIABLE CONFIG_TOOL_ERROR
        COMMAND ${CMAKE_COMMAND} -E rename "${OUTPUT_DIR}/cm33_core0/board/clock_config.h" "${CLOCKS_DEST_HEADER}"
        COMMAND ${CMAKE_COMMAND} -E rename "${OUTPUT_DIR}/cm33_core0/board/clock_config.c" "${CLOCKS_DEST_SOURCE}"
        COMMAND ${CMAKE_COMMAND} -E remove_directory "${OUTPUT_DIR}/cm33_core0/board"
        COMMAND ${CMAKE_COMMAND} -E remove_directory "${OUTPUT_DIR}/cm33_core0"
        DEPENDS "${MEX_FILE}"
        COMMENT "Generating Clocks files because ${MEX_FILE} changed or board files are missing"
        VERBATIM
    )


    # Check if needs to run: Peripherals
    set(PERIPHERALS_DEST_FILE_1 "${OUTPUT_DIR}/board/peripherals.h")
    set(PERIPHERALS_DEST_FILE_2 "${OUTPUT_DIR}/board/peripherals.c")
    add_custom_command(
        OUTPUT "${PERIPHERALS_DEST_FILE_1}" "${PERIPHERALS_DEST_FILE_2}"
        COMMAND "${CONFIG_TOOL_PATH}" 
        "-noSplash" 
        "-consoleLog"
        "-HeadlessTool" "Peripherals" 
        "-Load" "${MEX_FILE}" 
        "-ExportSrc" "${OUTPUT_DIR}"
        RESULT_VARIABLE CONFIG_TOOL_RESULT
        ERROR_VARIABLE CONFIG_TOOL_ERROR
        DEPENDS "${MEX_FILE}"
        COMMENT "Generating Peripherals files because ${MEX_FILE} changed or board files are missing"
        VERBATIM
    )

else()                                                                              # path not set: developer should generate sources with GUI
    message(STATUS "CONFIG_TOOL_PATH not set. Skipping source generation.")
endif()

Project declaration and includes

project(ez_mcxn_minimal LANGUAGES C CXX ASM)

include_directories(
    ${SDK_ROOT}/mcxn236/mcuxsdk/arch/arm/CMSIS/Core/Include
    ${SDK_ROOT}/mcxn236/mcuxsdk/arch/arm/CMSIS/Core/Include/m-profile
    ${SDK_ROOT}/mcxn236/mcuxsdk/devices/MCX/MCXN/MCXN236
    ${SDK_ROOT}/mcxn236/mcuxsdk/devices/MCX/MCXN/MCXN236/drivers
    ${SDK_ROOT}/mcxn236/mcuxsdk/devices/MCX/MCXN/periph1                            # MCXN326 files are in periph1 (see config file in parent dir)
    ${SDK_ROOT}/mcxn236/mcuxsdk/drivers/common
    ${SDK_ROOT}/mcxn236/mcuxsdk/drivers/mcx_spc                                     # system power controller
    ${SDK_ROOT}/mcxn236/mcuxsdk/drivers/port
    ${SDK_ROOT}/mcxn236/mcuxsdk/drivers/gpio
    # project includes
    ${CMAKE_SOURCE_DIR}/board
)

Firmware

add_executable( ${CMAKE_PROJECT_NAME})

set(MCXN_FLAGS                                                                      # flags common to compiler and linker
    -mcpu=cortex-m33
    -mthumb
    -mfloat-abi=hard
    -mfpu=fpv5-sp-d16
    --specs=nano.specs
)

target_sources(${CMAKE_PROJECT_NAME}                                                # default source files
        PRIVATE
        ${SDK_ROOT}/mcxn236/mcuxsdk/devices/MCX/MCXN/MCXN236/gcc/startup_MCXN236.S
        ${SDK_ROOT}/mcxn236/mcuxsdk/devices/MCX/MCXN/MCXN236/system_MCXN236.c
        ${SDK_ROOT}/mcxn236/mcuxsdk/devices/MCX/MCXN/MCXN236/drivers/fsl_clock.c
        ${SDK_ROOT}/mcxn236/mcuxsdk/devices/MCX/MCXN/MCXN236/drivers/fsl_reset.c 
        ${SDK_ROOT}/mcxn236/mcuxsdk/components/misc_utilities/fsl_syscall_stub.c    # implements stubs for functions not implemented in nano
        ${SDK_ROOT}/mcxn236/mcuxsdk/components/misc_utilities/fsl_sbrk.c            # alternative for gcc implementation
        ${SDK_ROOT}/mcxn236/mcuxsdk/components/misc_utilities/fsl_memcpy.S          # alternative for gcc implementation
        ${SDK_ROOT}/mcxn236/mcuxsdk/components/misc_utilities/fsl_memset.S          # alternative for gcc implementation
        ${SDK_ROOT}/mcxn236/mcuxsdk/drivers/common/fsl_common.c
        ${SDK_ROOT}/mcxn236/mcuxsdk/drivers/mcx_spc/fsl_spc.c                       # system power controller
)

target_sources(${CMAKE_PROJECT_NAME}                                                # project source files (c, asm, cpp), except cpp modules
        PRIVATE
        ${SDK_ROOT}/mcxn236/mcuxsdk/drivers/gpio/fsl_gpio.c
        # project sources
        # MCUXpresso Cfg generated:
        ${CLOCKS_DEST_SOURCE}
        ${PINS_DEST_SOURCE}
        # application sources
        ${CMAKE_SOURCE_DIR}/main.c
)

target_sources(${CMAKE_PROJECT_NAME}                                                # cpp modules
        PRIVATE
        FILE_SET cxx_modules TYPE CXX_MODULES FILES
)


target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE
    $<$<COMPILE_LANGUAGE:CXX>:-fno-use-cxa-atexit>                                  # cpp flag
    $<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>                                      # cpp flag
    $<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>                                            # cpp flag
    $<$<COMPILE_LANGUAGE:CXX>:-fcommon>                                             # cpp flag
    $<$<COMPILE_LANGUAGE:CXX>:-fmodules-ts>                                         # cpp flag: support modules
    ${MCXN_FLAGS}                                                                   # flags shared with linker
    -Wall
    -ffunction-sections 
    -fdata-sections
)

target_link_options(${CMAKE_PROJECT_NAME} PRIVATE
    ${MCXN_FLAGS}                                                                   # flags shared with compiler
    --specs=nano.specs                                                              # small c library
    -Wl,--gc-sections
    -Wl,--no-warn-rwx-segments
    -T ${SDK_ROOT}/mcxn236/mcuxsdk/devices/MCX/MCXN/MCXN236/gcc/MCXN236_flash.ld    # linker command file
)

Optional mcux-fix-elf

# MCUXpresso FIXELF section
# Not really needed for a single core MCXN236, but included for completeness
set(MCUX_FIXELF_EXE $ENV{MCUX_FIXELF_EXE})                                          # check if MCUXpresso FIXELF path is set         
message(STATUS "mcux-fixelf set as: ${MCUX_FIXELF_EXE}")
if(NOT MCUX_FIXELF_EXE)
    find_program(MCUX_FIXELF_EXE mcux-fixelf)
    if(NOT MCUX_FIXELF_EXE)
        message(STATUS "Can't locate mcux-fixelf.exe in environment or on path. Skipping post-build fixelf step.")
    endif()
else()
    message(STATUS "using mcux-fixelf: ${MCUX_FIXELF_EXE}")
endif()
if(MCUX_FIXELF_EXE)      
message(STATUS "start mcux-fixelf")
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
    COMMAND ${MCUX_FIXELF_EXE} 
    $<TARGET_FILE:${CMAKE_PROJECT_NAME}>                                            # .elf file to fix
    COMMENT "Executing mcux-fixelf post-build steps voor NXP MCU..."
    VERBATIM
)
endif()

Flashable binary

add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD                          # create extra output: flashable binary
    COMMAND ${CMAKE_OBJCOPY} 
    -O binary 
    $<TARGET_FILE:${CMAKE_PROJECT_NAME}> ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.bin
    COMMENT "create  bin executable: ${CMAKE_PROJECT_NAME}.bin"
)

Full CMakeLists.txt source:

cmake_minimum_required(VERSION 3.29)

set(CMAKE_VERBOSE_MAKEFILE OF)

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 26)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# SDK_ROOT set externally
set(SDK_ROOT $ENV{SDK_ROOT})                                                        # set as a CMake Environment variable. Points to root of unzipped SDK
message(STATUS "SDK_ROOT: ${SDK_ROOT}")

set(CMAKE_SYSTEM_NAME Generic)                                                      # no OS
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --specs=nosys.specs")         # prevents CMake throws toolchain error when using embedded GCC

add_compile_definitions(
    MCXN236                                                                         # controller
    CPU_MCXN236VKL                                                                  # package
)

include(FetchContent)
set(FETCHCONTENT_QUIET FALSE CACHE BOOL "" FORCE)                                   # show download, because it takes a while
set(FETCHCONTENT_UPDATES_DISCONNECTED ON CACHE BOOL "" FORCE)                       # skip if we have it in cache. Also allows for offline builds
FetchContent_Declare(svd                                                            # get MCXN236 svd definition, so registers are available during debug
  GIT_REPOSITORY "https://github.com/nxp-mcuxpresso/mcux-soc-svd.git"
  GIT_TAG origin/main
  GIT_PROGRESS TRUE                                                                 # show download, because it takes a while
  # prevent makefile execution (if any)
  SOURCE_SUBDIR =
)
FetchContent_MakeAvailable(svd)
file(COPY "${svd_SOURCE_DIR}/MCXN236/MCXN236.xml"                                   # copy svd from download to build dir, where launch.json can find it
     DESTINATION "${CMAKE_BINARY_DIR}"
)

# MCUXpresso Config section
set(CONFIG_TOOL_PATH $ENV{CONFIG_TOOL_PATH})                                        # check if MCUXpresso Config path is set         
if(CONFIG_TOOL_PATH)                                                                # path set: generate sources
    message(STATUS "CONFIG_TOOL_PATH: ${CONFIG_TOOL_PATH}")
    set(MEX_FILE "${CMAKE_CURRENT_SOURCE_DIR}/EZ_MCXN.mex")
    set(OUTPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")

    # Check if needs to run: Pins
    set(PINS_DEST_HEADER "${OUTPUT_DIR}/board/pin_mux.h")
    set(PINS_DEST_SOURCE "${OUTPUT_DIR}/board/pin_mux.c")
    add_custom_command(
        OUTPUT "${PINS_DEST_HEADER}" "${PINS_DEST_SOURCE}"
        COMMAND "${CONFIG_TOOL_PATH}" 
        "-noSplash" 
        "-consoleLog"
        "-HeadlessTool" "Pins" 
        "-Load" "${MEX_FILE}" 
        "-ExportSrc" "${OUTPUT_DIR}"
        RESULT_VARIABLE CONFIG_TOOL_RESULT
        ERROR_VARIABLE CONFIG_TOOL_ERROR
        DEPENDS "${MEX_FILE}"
        COMMENT "Generating Pins files because ${MEX_FILE} changed or board files are missing"
        VERBATIM
    )


    # Check if needs to run: Clocks
    set(CLOCKS_DEST_HEADER "${OUTPUT_DIR}/board/clock_config.h")
    set(CLOCKS_DEST_SOURCE "${OUTPUT_DIR}/board/clock_config.c")
    add_custom_command(
        OUTPUT "${CLOCKS_DEST_HEADER}" "${CLOCKS_DEST_SOURCE}"
        COMMAND "${CONFIG_TOOL_PATH}" 
        "-noSplash" 
        "-consoleLog"
        "-HeadlessTool" "Clocks" 
        "-Load" "${MEX_FILE}" 
        "-ExportSrc" "${OUTPUT_DIR}"                    
        RESULT_VARIABLE CONFIG_TOOL_RESULT
        ERROR_VARIABLE CONFIG_TOOL_ERROR
        COMMAND ${CMAKE_COMMAND} -E rename "${OUTPUT_DIR}/cm33_core0/board/clock_config.h" "${CLOCKS_DEST_HEADER}"
        COMMAND ${CMAKE_COMMAND} -E rename "${OUTPUT_DIR}/cm33_core0/board/clock_config.c" "${CLOCKS_DEST_SOURCE}"
        COMMAND ${CMAKE_COMMAND} -E remove_directory "${OUTPUT_DIR}/cm33_core0/board"
        COMMAND ${CMAKE_COMMAND} -E remove_directory "${OUTPUT_DIR}/cm33_core0"
        DEPENDS "${MEX_FILE}"
        COMMENT "Generating Clocks files because ${MEX_FILE} changed or board files are missing"
        VERBATIM
    )


    # Check if needs to run: Peripherals
    set(PERIPHERALS_DEST_FILE_1 "${OUTPUT_DIR}/board/peripherals.h")
    set(PERIPHERALS_DEST_FILE_2 "${OUTPUT_DIR}/board/peripherals.c")
    add_custom_command(
        OUTPUT "${PERIPHERALS_DEST_FILE_1}" "${PERIPHERALS_DEST_FILE_2}"
        COMMAND "${CONFIG_TOOL_PATH}" 
        "-noSplash" 
        "-consoleLog"
        "-HeadlessTool" "Peripherals" 
        "-Load" "${MEX_FILE}" 
        "-ExportSrc" "${OUTPUT_DIR}"
        RESULT_VARIABLE CONFIG_TOOL_RESULT
        ERROR_VARIABLE CONFIG_TOOL_ERROR
        DEPENDS "${MEX_FILE}"
        COMMENT "Generating Peripherals files because ${MEX_FILE} changed or board files are missing"
        VERBATIM
    )

else()                                                                              # path not set: developer should generate sources with GUI
    message(STATUS "CONFIG_TOOL_PATH not set. Skipping source generation.")
endif()

project(ez_mcxn_minimal LANGUAGES C CXX ASM)

include_directories(
    ${SDK_ROOT}/mcxn236/mcuxsdk/arch/arm/CMSIS/Core/Include
    ${SDK_ROOT}/mcxn236/mcuxsdk/arch/arm/CMSIS/Core/Include/m-profile
    ${SDK_ROOT}/mcxn236/mcuxsdk/devices/MCX/MCXN/MCXN236
    ${SDK_ROOT}/mcxn236/mcuxsdk/devices/MCX/MCXN/MCXN236/drivers
    ${SDK_ROOT}/mcxn236/mcuxsdk/devices/MCX/MCXN/periph1                            # MCXN326 files are in periph1 (see config file in parent dir)
    ${SDK_ROOT}/mcxn236/mcuxsdk/drivers/common
    ${SDK_ROOT}/mcxn236/mcuxsdk/drivers/mcx_spc                                     # system power controller
    ${SDK_ROOT}/mcxn236/mcuxsdk/drivers/port
    ${SDK_ROOT}/mcxn236/mcuxsdk/drivers/gpio
    # project includes
    ${CMAKE_SOURCE_DIR}/board
)

add_executable( ${CMAKE_PROJECT_NAME})

set(MCXN_FLAGS                                                                      # flags common to compiler and linker
    -mcpu=cortex-m33
    -mthumb
    -mfloat-abi=hard
    -mfpu=fpv5-sp-d16
    --specs=nano.specs
)

target_sources(${CMAKE_PROJECT_NAME}                                                # default source files
        PRIVATE
        ${SDK_ROOT}/mcxn236/mcuxsdk/devices/MCX/MCXN/MCXN236/gcc/startup_MCXN236.S
        ${SDK_ROOT}/mcxn236/mcuxsdk/devices/MCX/MCXN/MCXN236/system_MCXN236.c
        ${SDK_ROOT}/mcxn236/mcuxsdk/devices/MCX/MCXN/MCXN236/drivers/fsl_clock.c
        ${SDK_ROOT}/mcxn236/mcuxsdk/devices/MCX/MCXN/MCXN236/drivers/fsl_reset.c 
        ${SDK_ROOT}/mcxn236/mcuxsdk/components/misc_utilities/fsl_syscall_stub.c    # implements stubs for functions not implemented in nano
        ${SDK_ROOT}/mcxn236/mcuxsdk/components/misc_utilities/fsl_sbrk.c            # alternative for gcc implementation
        ${SDK_ROOT}/mcxn236/mcuxsdk/components/misc_utilities/fsl_memcpy.S          # alternative for gcc implementation
        ${SDK_ROOT}/mcxn236/mcuxsdk/components/misc_utilities/fsl_memset.S          # alternative for gcc implementation
        ${SDK_ROOT}/mcxn236/mcuxsdk/drivers/common/fsl_common.c
        ${SDK_ROOT}/mcxn236/mcuxsdk/drivers/mcx_spc/fsl_spc.c                       # system power controller
)

target_sources(${CMAKE_PROJECT_NAME}                                                # project source files (c, asm, cpp), except cpp modules
        PRIVATE
        ${SDK_ROOT}/mcxn236/mcuxsdk/drivers/gpio/fsl_gpio.c
        # project sources
        # MCUXpresso Cfg generated:
        ${CLOCKS_DEST_SOURCE}
        ${PINS_DEST_SOURCE}
        # ${PERIPHERALS_DEST_SOURCE}                                                # this minimal project doesn't use the Peripherals
        # application sources
        ${CMAKE_SOURCE_DIR}/main.c
)

target_sources(${CMAKE_PROJECT_NAME}                                                # cpp modules
        PRIVATE
        FILE_SET cxx_modules TYPE CXX_MODULES FILES
)


target_compile_options(${CMAKE_PROJECT_NAME} PRIVATE
    $<$<COMPILE_LANGUAGE:CXX>:-fno-use-cxa-atexit>                                  # cpp flag
    $<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>                                      # cpp flag
    $<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>                                            # cpp flag
    $<$<COMPILE_LANGUAGE:CXX>:-fcommon>                                             # cpp flag
    $<$<COMPILE_LANGUAGE:CXX>:-fmodules-ts>                                         # cpp flag: support modules
    ${MCXN_FLAGS}                                                                   # flags shared with linker
    -Wall
    -ffunction-sections 
    -fdata-sections
)

target_link_options(${CMAKE_PROJECT_NAME} PRIVATE
    ${MCXN_FLAGS}                                                                   # flags shared with compiler
    --specs=nano.specs                                                              # small c library
    -Wl,--gc-sections
    -Wl,--no-warn-rwx-segments
    -T ${SDK_ROOT}/mcxn236/mcuxsdk/devices/MCX/MCXN/MCXN236/gcc/MCXN236_flash.ld    # linker command file
)

# MCUXpresso FIXELF section
# Not really needed for a single core MCXN236, but included for completeness
set(MCUX_FIXELF_EXE $ENV{MCUX_FIXELF_EXE})                                          # check if MCUXpresso FIXELF path is set         
message(STATUS "mcux-fixelf set as: ${MCUX_FIXELF_EXE}")
if(NOT MCUX_FIXELF_EXE)
    find_program(MCUX_FIXELF_EXE mcux-fixelf)
    if(NOT MCUX_FIXELF_EXE)
        message(STATUS "Can't locate mcux-fixelf.exe in environment or on path. Skipping post-build fixelf step.")
    endif()
else()
    message(STATUS "using mcux-fixelf: ${MCUX_FIXELF_EXE}")
endif()
if(MCUX_FIXELF_EXE)      
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
    COMMAND ${MCUX_FIXELF_EXE} 
    $<TARGET_FILE:${CMAKE_PROJECT_NAME}>                                            # .elf file to fix
    COMMENT "Executing mcux-fixelf post-build steps voor NXP MCU..."
    VERBATIM
)
endif()

add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD                          # create extra output: flashable binary
    COMMAND ${CMAKE_OBJCOPY} 
    -O binary 
    $<TARGET_FILE:${CMAKE_PROJECT_NAME}> $<TARGET_FILE:${CMAKE_PROJECT_NAME}>.bin
    COMMENT "create  bin executable: $<TARGET_FILE:${CMAKE_PROJECT_NAME}>.bin"
)

Example main source

main.c:

#include "fsl_common.h"
// #include "fsl_device_registers.h"
#include "pin_mux.h"
#include "clock_config.h"

int main(void)
{

    BOARD_InitPins();
    BOARD_BootClockRUN();

    while (1) {

        for (uint32_t i = 0; i < 1000000U; i++) {
            __NOP();
        }
    }
}

Project setup

  • create a folder
  • put the CMakeLists.txt, main.c and EZ_MCXN.mex in that folder
  • If you define an environment variable CONFIG_TOOL_PATH that points to the CMUXpresso Config executable, do nothing,
    else: 
    open the .mex file with CMUXpresso Config, and click Update Code. 

 

Calling CMake

Do this as you 'd do for other projects. 
Pass the SDK_ROOT and ARM toolchain. Optionally CONFIG_TOOL_PATH.
Here is a DOS command prompt example:

set SDK_ROOT=C:/Users/jancu/Documents/elektronica/nxp/sdk/mcxn236_noboard
set CONFIG_TOOL_PATH=C:/NXP/MCUX_CFG_26.09/bin/tools.exe
mkdir build

cd build
cmake .. -G "Ninja" -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -DCMAKE_C_COMPILER:FILEPATH=c:\\Users\\jancu\\Documents\\toolchains\\arm-gnu-toolchain-15.2.rel1-mingw-w64-i686-arm-none-eabi\\bin\\arm-none-eabi-gcc.exe -DCMAKE_CXX_COMPILER:FILEPATH=c:\\Users\\jancu\\Documents\\toolchains\\arm-gnu-toolchain-15.2.rel1-mingw-w64-i686-arm-none-eabi\\bin\\arm-none-eabi-g++.exe -DCMAKE_BUILD_TYPE=Debug
cmake --build .
cd ..

First time CMake configuration takes a while, because the script fetches debug scripts from NXP's GitHub repositories.
First time CMake build also takes a bit, if the sources have to be generated from the .mex file.
After that, these two steps are only executed if the generated files are outdated, and will finish in seconds.
See the Timing section near the bottom of the post.

C:\Users\jancu\workspace_vscode_nxp\ez-mcxn_hello_world\ez_mcxn_minimal\build>cmake .. -G "Ninja" -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -DCMAKE_C_COMPILER:FILEPATH=c:\\Users\\jancu\\Documents\\toolchains\\arm-gnu-toolchain-15.2.rel1-mingw-w64-i686-arm-none-eabi\\bin\\arm-none-eabi-gcc.exe -DCMAKE_CXX_COMPILER:FILEPATH=c:\\Users\\jancu\\Documents\\toolchains\\arm-gnu-toolchain-15.2.rel1-mingw-w64-i686-arm-none-eabi\\bin\\arm-none-eabi-g++.exe -DCMAKE_BUILD_TYPE=Debug
-- SDK_ROOT: C:/Users/jancu/Documents/elektronica/nxp/sdk/mcxn236_noboard
-- The C compiler identification is GNU 15.2.1
-- The CXX compiler identification is GNU 15.2.1
-- The ASM compiler identification is GNU
-- Found assembler: C:/Users/jancu/Documents/toolchains/arm-gnu-toolchain-15.2.rel1-mingw-w64-i686-arm-none-eabi/bin/arm-none-eabi-gcc.exe
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: c:/Users/jancu/Documents/toolchains/arm-gnu-toolchain-15.2.rel1-mingw-w64-i686-arm-none-eabi/bin/arm-none-eabi-gcc.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: c:/Users/jancu/Documents/toolchains/arm-gnu-toolchain-15.2.rel1-mingw-w64-i686-arm-none-eabi/bin/arm-none-eabi-g++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done (66.2s)
-- Generating done (0.1s)
-- Build files have been written to: C:/Users/jancu/workspace_vscode_nxp/ez-mcxn_hello_world/ez_mcxn_minimal/build

C:\Users\jancu\workspace_vscode_nxp\ez-mcxn_hello_world\ez_mcxn_minimal\build>cmake --build .
[15/15] Linking C executable ez_mcxn_minimal

When you use VS Code's CMake extension:

  • you can select the toolchain there, and it 'll be passed automatically.
  • The SDK_ROOT and CONFIG_TOOL_PATH, you can configure in Extensions - CMake - CMake:Environment
  • press Configure
  • press build

Timings

  • config: < 2.5s
  • build: seconds**
  • first config (or when cache cleared): 66s*.
  • first build (or when build cleared, or .mex file altered): 20s**

* If you don't plan to use a hardware debugger, you can comment the svd section, and also a new config is below 10s
** first build includes generating the source files with CMUXpresso Config. If you do this step by hand, during your design, it takes virtually all time off. A rebuild after you changed / added some sources takes a few seconds.

All times recorded on

  • Windows 11 Laptop, 11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz (2.30 GHz), 16.0 GB RAM.
  • Fast internet, but WiFi connected.
  • BD711 solid state drive

In the next post, I'll try to get Debug working in VS Code. Also without the MCXpresso extension.

Thank you for reading

Project attached: ez_mcxn_minimal.zip

  • Sign in to reply
Parents
  • Jan Cumps
    Jan Cumps 2 days ago

    The MCUXpresso toolchain has a program called mcux-fix-elf, that touches up GCC created .elf files. 
    For the MCXN236 this isn't neccessary.
    For multicore and security enabled development, it is required. I added it for completion.

    If you don't set MCUX_FIXELF_EXE, and don't have the executable on your path, this will be skipped.

    # MCUXpresso FIXELF section
    # Not really needed for a single core MCXN236, but included for completeness
    set(MCUX_FIXELF_EXE $ENV{MCUX_FIXELF_EXE})                                          # check if MCUXpresso FIXELF path is set         
    message(STATUS "mcux-fixelf set as: ${MCUX_FIXELF_EXE}")
    if(NOT MCUX_FIXELF_EXE)
        find_program(MCUX_FIXELF_EXE mcux-fixelf)
        if(NOT MCUX_FIXELF_EXE)
            message(STATUS "Can't locate mcux-fixelf.exe in environment or on path. Skipping post-build fixelf step.")
        endif()
    else()
        message(STATUS "using mcux-fixelf: ${MCUX_FIXELF_EXE}")
    endif()
    if(MCUX_FIXELF_EXE)      
    message(STATUS "start mcux-fixelf")
    add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
        COMMAND ${MCUX_FIXELF_EXE} 
        $<TARGET_FILE:${CMAKE_PROJECT_NAME}>                                            # .elf file to fix
        COMMENT "Executing mcux-fixelf post-build steps voor NXP MCU..."
        VERBATIM
    )
    endif()

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
Comment
  • Jan Cumps
    Jan Cumps 2 days ago

    The MCUXpresso toolchain has a program called mcux-fix-elf, that touches up GCC created .elf files. 
    For the MCXN236 this isn't neccessary.
    For multicore and security enabled development, it is required. I added it for completion.

    If you don't set MCUX_FIXELF_EXE, and don't have the executable on your path, this will be skipped.

    # MCUXpresso FIXELF section
    # Not really needed for a single core MCXN236, but included for completeness
    set(MCUX_FIXELF_EXE $ENV{MCUX_FIXELF_EXE})                                          # check if MCUXpresso FIXELF path is set         
    message(STATUS "mcux-fixelf set as: ${MCUX_FIXELF_EXE}")
    if(NOT MCUX_FIXELF_EXE)
        find_program(MCUX_FIXELF_EXE mcux-fixelf)
        if(NOT MCUX_FIXELF_EXE)
            message(STATUS "Can't locate mcux-fixelf.exe in environment or on path. Skipping post-build fixelf step.")
        endif()
    else()
        message(STATUS "using mcux-fixelf: ${MCUX_FIXELF_EXE}")
    endif()
    if(MCUX_FIXELF_EXE)      
    message(STATUS "start mcux-fixelf")
    add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
        COMMAND ${MCUX_FIXELF_EXE} 
        $<TARGET_FILE:${CMAKE_PROJECT_NAME}>                                            # .elf file to fix
        COMMENT "Executing mcux-fixelf post-build steps voor NXP MCU..."
        VERBATIM
    )
    endif()

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
Children
No Data
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2026 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube