How To Compile Firmware for Alternative Cores (NXP)
Introduction
This article describes how to compile firmware for alternative cores using the MCUXpresso SDK.
This article complies with the Typographic Conventions for Toradex Documentation.
Prerequisites
The MCUXpresso SDK and all required tools must be configured before proceeding. Refer to the Setting Up the MCUXpresso SDK and Toolchain for HMP Development article for more information about the installation process.
Understand the NXP MCUXpresso SDK Structure
After the MCUXpresso SDK workspace is installed, the main SDK content is available in the mcuxsdk directory. The example applications provided by the NXP MCUXpresso SDK are available under the mcuxsdk/examples directory.
The following command shows the top-level structure of the mcuxsdk directory:
$ cd mcuxsdk
$ tree -L 1 --dirsfirst
.
├── arch/ # Architecture-specific code
├── cmake/ # CMake modules and toolchain helpers
├── components/ # Reusable software components
├── devices/ # Device-specific headers and startup files
├── docs/ # Documentation
├── drivers/ # Peripheral drivers
├── examples/ # Example applications
├── firmware/ # Prebuilt firmware binaries
├── middleware/ # Middleware stacks
├── rtos/ # RTOS support
├── scripts/ # Build and utility scripts
├── share/ # Shared resources and data files
├── tool_data/ # Tool configuration and metadata
├── cmake_format_config.yml # cmake-format style configuration
├── CMakeLists.txt # Top-level CMake build entry point
├── COPYING-BSD-3 # BSD-3-Clause license
├── Kconfig # Top-level Kconfig
├── Kconfig.mcuxpresso # MCUXpresso IDE-specific Kconfig options
├── mcux-env.cmd # Windows environment setup script
├── mcux-env.sh # Environment setup script
├── MCUX_VERSION # SDK version string
├── README.md # Project overview and quick-start guide
├── SBOM.spdx.json # Software Bill of Materials
├── SCR.txt # Software Content Register
├── tool.yml # West-compatible tool manifest
└── yamllint_config.yml # YAML linter configuration
14 directories, 13 files
After the MCUXpresso SDK workspace is installed, the example applications provided by the NXP MCUXpresso SDK are available under the SDK_2.x.x_<BOARD>/boards/<board_name>/demo_apps directory.
The SDK structure is organized as follows:
SDK_2.x.x_<BOARD>/
├── boards/ # Board-specific files
│ └── <board_name>/
│ ├── demo_apps/ # Demo applications
│ ├── driver_examples/ # Driver examples
│ └── project_template/ # Empty project template
├── CMSIS/ # ARM CMSIS headers
├── components/ # Reusable components
├── devices/ # Device-specific files
│ └── <device>/
│ ├── drivers/ # Peripheral drivers
│ └── gcc/ # GCC linker scripts
├── docs/ # Documentation
├── middleware/ # Selected middleware
├── rtos/ # RTOS support
└── tools/ # Utilities
Compile the Hello World Example
The following procedure compiles the Hello World example, available under the mcuxsdk/examples/demo_apps/hello_world directory.
-
Source the Python environment used during the MCUXpresso SDK installation, which contains the
westtool. -
Enter the
mcuxsdkdirectory:$ cd mcuxsdk -
Compile the example using
westfor the target processor:Alternative Core UART Function
MCUXpresso SDK examples uses the
LPUART3peripheral for the UART output on i.MX 95 modules. However, Toradex i.MX 95-based modules are connected to theLPUART2peripheral instead.To be able to view the output of the
hello_worldexample on i.MX 95-based modules, apply the changes shown in the diff below to use theLPUART2peripheral:board.hdiff --git a/_boards/imx95lp4xevk15/board.h b/_boards/imx95lp4xevk15/board.h
index 50747a266255..22f238c946ba 100644
--- a/_boards/imx95lp4xevk15/board.h
+++ b/_boards/imx95lp4xevk15/board.h
@@ -85,7 +85,7 @@
*/
/* boad type: imx95 emulator or imx95 lpddr5 19x19 evk */
-#define BOARD_DEBUG_UART_INSTANCE 3
+#define BOARD_DEBUG_UART_INSTANCE 2
#define BOARD_DEBUG_UART_INSTANCE_FOR_CM7_WITH_SM 3U
#define BOARD_DEBUG_UART_CLOCK_ROOT_FOR_CM7_WITH_SM hal_clock_lpuart3
@@ -99,7 +99,7 @@
#define BOARD_DEBUG_UART_CLOCK_ROOT_FOR_CM33_WITHOUT_SM hal_clock_lpuart2
#define BOARD_DEBUG_UART_CLK_FREQ_FOR_CM33_WITHOUT_SM HAL_ClockGetRate(BOARD_DEBUG_UART_CLOCK_ROOT_FOR_CM33_WITHOUT_SM)
-#define BOARD_DEBUG_UART_CLOCK_ROOT hal_clock_lpuart3
+#define BOARD_DEBUG_UART_CLOCK_ROOT hal_clock_lpuart2
#define BOARD_DEBUG_UART_CLK_FREQ HAL_ClockGetRate(BOARD_DEBUG_UART_CLOCK_ROOT)
#define BOARD_DEBUG_UART_BAUDRATE 115200Upin_mux.cdiff --git a/_boards/imx95lp4xevk15/demo_apps/hello_world/cm7/pin_mux.c b/_boards/imx95lp4xevk15/demo_apps/hello_world/cm7/pin_mux.c
index 7bab22dc933f..0be06a12ed3a 100644
--- a/_boards/imx95lp4xevk15/demo_apps/hello_world/cm7/pin_mux.c
+++ b/_boards/imx95lp4xevk15/demo_apps/hello_world/cm7/pin_mux.c
@@ -50,6 +50,7 @@ BOARD_InitPins:
*
* END ****************************************************************************************************************/
void BOARD_InitPins(void) { /*!< Function assigned for the core: Cortex-M7F[cm7] */
+#if 0
HAL_PinctrlSetPinMux(HAL_PINCTRL_PLATFORM_IOMUXC_PAD_GPIO_IO14__LPUART3_TX, 0U);
HAL_PinctrlSetPinCfg(HAL_PINCTRL_PLATFORM_IOMUXC_PAD_GPIO_IO14__LPUART3_TX,
HAL_PINCTRL_PLATFORM_IOMUXC_PAD_DSE(15U) |
@@ -60,6 +61,18 @@ void BOARD_InitPins(void) { /*!< Function assigne
HAL_PINCTRL_PLATFORM_IOMUXC_PAD_DSE(15U) |
HAL_PINCTRL_PLATFORM_IOMUXC_PAD_FSEL1(2U) |
HAL_PINCTRL_PLATFORM_IOMUXC_PAD_PD_MASK);
+#else
+ HAL_PinctrlSetPinMux(HAL_PINCTRL_PLATFORM_IOMUXC_PAD_UART2_TXD__LPUART2_TX, 0U);
+ HAL_PinctrlSetPinCfg(HAL_PINCTRL_PLATFORM_IOMUXC_PAD_UART2_TXD__LPUART2_TX,
+ HAL_PINCTRL_PLATFORM_IOMUXC_PAD_DSE(15U) |
+ HAL_PINCTRL_PLATFORM_IOMUXC_PAD_FSEL1(2U) |
+ HAL_PINCTRL_PLATFORM_IOMUXC_PAD_PD_MASK);
+ HAL_PinctrlSetPinMux(HAL_PINCTRL_PLATFORM_IOMUXC_PAD_UART2_RXD__LPUART2_RX, 0U);
+ HAL_PinctrlSetPinCfg(HAL_PINCTRL_PLATFORM_IOMUXC_PAD_UART2_RXD__LPUART2_RX,
+ HAL_PINCTRL_PLATFORM_IOMUXC_PAD_DSE(15U) |
+ HAL_PINCTRL_PLATFORM_IOMUXC_PAD_FSEL1(2U) |
+ HAL_PINCTRL_PLATFORM_IOMUXC_PAD_PD_MASK);
+#endif
}$ west build --pristine always examples/demo_apps/hello_world/ --config debug --board imx95lp4xevk15 -Dcore_id=cm7$ west build --pristine always examples/demo_apps/hello_world/ --config debug --board evkmimx8mp$ west build --pristine always examples/demo_apps/hello_world/ --config debug --board evkmimx8mmThe
--pristine alwaysflag performs a full rebuild, removing previous build outputs before generating new files.infoRun the following command to list the board configurations supported by the Hello World example:
$ west list_project -p examples/demo_apps/hello_world -
After the build process completes, the generated build artifacts are available in the
mcuxsdk/builddirectory.
The following procedure compiles the Hello World example, available under the SDK_2.x.x_<BOARD>/boards/<board_name>/demo_apps/hello_world directory.
-
Export the
ARMGCC_DIRenvironment variable, pointing to the root directory of the Arm GCC toolchain:$ export ARMGCC_DIR=/path/to/arm/gcc/toolchain/directory -
Enter the example directory:
infoThe Apalis iMX8 module has two Cortex-M cores, resulting in two separate example directories. Select the correct example according to the target core, for example, 'cm4_core0`.
$ cd SDK_2.x.x_<BOARD>/boards/<board_name>/demo_apps/hello_world -
Compile the example using the shell script provided in the
armgccdirectory:Alternative Core UART Function on Colibri iMX8X
For Colibri iMX8X, the SoC provides two pin pairs with the
M40_UARTfunction:ADC_IN2/ADC_IN3andSCU_GPIO0_00/SCU_GPIO0_01. However, only theSCU_GPIO0_00/SCU_GPIO0_01pair is available for this use case.The NXP
hello_worldexample uses the ADC pins by default. To be able to view the output of thehello_worldexample on Colibri iMX8X, apply the changes shown in the diff below to use theSCU_GPIO0_00/SCU_GPIO0_01pins:pin_mux.cdiff --git a/boards/mekmimx8qx/demo_apps/hello_world/pin_mux.c b/boards/mekmimx8qx/demo_apps/hello_world/pin_mux.c
index 3e390a3..1d84c50 100644
--- a/boards/mekmimx8qx/demo_apps/hello_world/pin_mux.c
+++ b/boards/mekmimx8qx/demo_apps/hello_world/pin_mux.c
@@ -57,12 +57,12 @@ void BOARD_InitPins(sc_ipc_t ipc) /*!< Function assigne
{
sc_err_t err = SC_ERR_NONE;
- err = sc_pad_set_all(ipc, BOARD_INITPINS_FTDI_M40_UART0_RX_PIN_FUNCTION_ID, 1U, SC_PAD_CONFIG_NORMAL, SC_PAD_ISO_OFF, 0x0 ,SC_PAD_WAKEUP_OFF);/* IOMUXD_ADC_IN2 register modification value */
+ err = sc_pad_set_all(ipc, BOARD_INITPINS_FTDI_M40_UART0_RX_PIN_FUNCTION_ID, 2U, SC_PAD_CONFIG_NORMAL, SC_PAD_ISO_OFF, 0x0 ,SC_PAD_WAKEUP_OFF);/* IOMUXD_ADC_IN2 register modification value */
if (SC_ERR_NONE != err)
{
assert(false);
}
- err = sc_pad_set_all(ipc, BOARD_INITPINS_FTDI_M40_UART0_TX_PIN_FUNCTION_ID, 1U, SC_PAD_CONFIG_NORMAL, SC_PAD_ISO_OFF, 0x0 ,SC_PAD_WAKEUP_OFF);/* IOMUXD_ADC_IN3 register modification value */
+ err = sc_pad_set_all(ipc, BOARD_INITPINS_FTDI_M40_UART0_TX_PIN_FUNCTION_ID, 2U, SC_PAD_CONFIG_NORMAL, SC_PAD_ISO_OFF, 0x0 ,SC_PAD_WAKEUP_OFF);/* IOMUXD_ADC_IN3 register modification value */
if (SC_ERR_NONE != err)
{
assert(false);pin_mux.hdiff --git a/boards/mekmimx8qx/demo_apps/hello_world/pin_mux.h b/boards/mekmimx8qx/demo_apps/hello_world/pin_mux.h
index 8bb2a79..b53e387 100644
--- a/boards/mekmimx8qx/demo_apps/hello_world/pin_mux.h
+++ b/boards/mekmimx8qx/demo_apps/hello_world/pin_mux.h
@@ -17,16 +17,16 @@
/* ADC_IN2 (coord V32), FTDI_M40_UART0_RX */
#define BOARD_INITPINS_FTDI_M40_UART0_RX_PERIPHERAL M40__UART0 /*!< Device name: M40__UART0 */
#define BOARD_INITPINS_FTDI_M40_UART0_RX_SIGNAL uart_rx /*!< M40__UART0 signal: uart_rx */
-#define BOARD_INITPINS_FTDI_M40_UART0_RX_PIN_NAME ADC_IN2 /*!< Pin name */
-#define BOARD_INITPINS_FTDI_M40_UART0_RX_PIN_FUNCTION_ID SC_P_ADC_IN2 /*!< Pin function id */
+#define BOARD_INITPINS_FTDI_M40_UART0_RX_PIN_NAME SCU_GPIO0_00 /*!< Pin name */
+#define BOARD_INITPINS_FTDI_M40_UART0_RX_PIN_FUNCTION_ID SC_P_SCU_GPIO0_00 /*!< Pin function id */
#define BOARD_INITPINS_FTDI_M40_UART0_RX_LABEL "FTDI_M40_UART0_RX" /*!< Label */
#define BOARD_INITPINS_FTDI_M40_UART0_RX_NAME "FTDI_M40_UART0_RX" /*!< Identifier name */
/* ADC_IN3 (coord V30), FTDI_M40_UART0_TX */
#define BOARD_INITPINS_FTDI_M40_UART0_TX_PERIPHERAL M40__UART0 /*!< Device name: M40__UART0 */
#define BOARD_INITPINS_FTDI_M40_UART0_TX_SIGNAL uart_tx /*!< M40__UART0 signal: uart_tx */
-#define BOARD_INITPINS_FTDI_M40_UART0_TX_PIN_NAME ADC_IN3 /*!< Pin name */
-#define BOARD_INITPINS_FTDI_M40_UART0_TX_PIN_FUNCTION_ID SC_P_ADC_IN3 /*!< Pin function id */
+#define BOARD_INITPINS_FTDI_M40_UART0_TX_PIN_NAME SCU_GPIO0_01 /*!< Pin name */
+#define BOARD_INITPINS_FTDI_M40_UART0_TX_PIN_FUNCTION_ID SC_P_SCU_GPIO0_01 /*!< Pin function id */
#define BOARD_INITPINS_FTDI_M40_UART0_TX_LABEL "FTDI_M40_UART0_TX" /*!< Label */
#define BOARD_INITPINS_FTDI_M40_UART0_TX_NAME "FTDI_M40_UART0_TX" /*!< Identifier name */After applying the changes above, apply the
colibri-imx8x_disable-cm40-uart_overlay.dtsoverlay on the target module to modify the device tree and enable the UART output from the alternative core.$ cd armgcc
$ ./clean.sh
$ ./build_debug.shThe
clean.shscript cleans the build directory, removing previous build outputs before generating new files. -
After the build process completes, the generated build artifacts are available in the
armgcc/debugdirectory.
Next Steps
Follow the How To Load and Run Firmware on Alternative Cores (NXP) article for instructions on deploying the firmware on the alternative cores.