The i.MX93 SOC platform includes a high efficiency Cortex-M33 processor with security considerations. The Cortex-M33 implements the Armv8-M architecture with Main Extensions, including a single-precision floating-point unit (FPU), a nested vectored interrupt controller (NVIC), flash patch breakpoint (FPB), the data watchpoint and trace (DWT) unit, and instrumentation trace macrocell.

Download the SDK and toolchain

Before building the Cortex-M33 firmware, you must download and install the SDK, which includes example applications and the toolchain to build your firmware application.

Download the SDK

NXP offers an SDK that facilitates firmware development for the Cortex-M33 core. The SDK provides examples demonstrating how to access the peripherals available on this subsystem.

  1. Go to https://mcuxpresso.nxp.com/en/builder.

    You may have to register with NXP.
  2. Click Boards > i.MX.

  3. Select MCIMX93-EVK.

  4. Click the Build MCUXpresso SDK button.

  5. Select your Toolchain/IDE and Host OS.

  6. Click Download SDK.

Download the toolchain

You must also download the toolchain to build your firmware application.

  1. Go to https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads.

  2. Select the latest available version for "GNU Arm Embedded Toolchain".

Install the SDK and toolchain

  1. Decompress and install the SDK in your Linux PC.

    $ tar -xvf <SDK_VER>_MEK-MCIMX93-EVK.tar.gz -C <SDK_VER>_MCIMX93-EVK
  2. Install the toolchain.

    $ tar -xvf gcc-arm-none-eabi-7-2018-q2-update-linux.tar.bz2 -C <toolchain_install_path>

Debug console UART

The Cortex-M33 uses UART2 as default debug console. By default the UART2 is in use on the wireless variant of the ConnectCore 93 by the Bluetooth UART. Therefore, for debug purposes, modify the application code to use a different console port. For instance, change the console port to UART4 (used for XBee, available on the J37 connector, pin2: RX, pin3: TX).

As reference, the changes needed to modify the debug port from UART2 to UART4 are:

<demo_apps>/hello_world/board.h
 /* The UART to use for debug messages. */
-#define BOARD_DEBUG_UART_INSTANCE   2U
+#define BOARD_DEBUG_UART_INSTANCE   4U
 #define BOARD_DEBUG_UART_BAUDRATE   115200U
 #define BOARD_DEBUG_UART_TYPE       kSerialPort_Uart
-#define BOARD_DEBUG_UART_CLOCK_ROOT kCLOCK_Root_Lpuart2
-#define BOARD_DEBUG_UART_CLOCK_GATE kCLOCK_Lpuart2
+#define BOARD_DEBUG_UART_CLOCK_ROOT kCLOCK_Root_Lpuart4
+#define BOARD_DEBUG_UART_CLOCK_GATE kCLOCK_Lpuart4
<demo_apps>/hello_world/pin_mux.c
-    IOMUXC_SetPinMux(IOMUXC_PAD_UART2_RXD__LPUART2_RX, 0U);
-    IOMUXC_SetPinMux(IOMUXC_PAD_UART2_TXD__LPUART2_TX, 0U);
+    IOMUXC_SetPinMux(IOMUXC_PAD_ENET2_RD0__LPUART4_RX, 0U);
+    IOMUXC_SetPinMux(IOMUXC_PAD_ENET2_TD0__LPUART4_TX, 0U);

-    IOMUXC_SetPinConfig(IOMUXC_PAD_UART2_RXD__LPUART2_RX,
+    IOMUXC_SetPinConfig(IOMUXC_PAD_ENET2_RD0__LPUART4_RX,
                         IOMUXC_PAD_PD_MASK);
-    IOMUXC_SetPinConfig(IOMUXC_PAD_UART2_TXD__LPUART2_TX,
+    IOMUXC_SetPinConfig(IOMUXC_PAD_ENET2_TD0__LPUART4_TX,
                         IOMUXC_PAD_DSE(15U));

Build a demo application

  1. To build the hello_world example, export the variable ARMGCC_DIR with the absolute path to the GCC ARM Embedded toolchain.

    $ export ARMGCC_DIR=<toolchain_install_path>/gcc-arm-none-eabi-7-2017-q4-major/
  2. Add the toolchain bin folder to the system $PATH

    $ export PATH=$PATH:$ARMGCC_DIR/bin
  3. Build the application.

    $ cd ${SDK_INSTALL_DIR}/<SDK_VER>_MCIMX93-EVK/boards/mcimx93evk/demo_apps/hello_world/armgcc
    $ ./build_release.sh

    You can find the artifacts from a successful build in the release directory.

For more information, see the Getting Started with MCUXpressoSDK guide from NXP.

Transfer and run the demo application

  1. Boot your device and stop in the U-Boot console.

  2. Transfer the application to RAM, for example via TFTP:

    => tftp $loadaddr hello_world.bin
    Using ethernet@428a0000 device
    TFTP from server 192.168.123.100; our IP address is 192.168.2.170
    Filename 'hello_world.bin'.
    Load address: 0x80400000
    Loading: #
             3 MiB/s
    done
    Bytes transferred = 6268 (187c hex)
  3. Transfer the firmware to the Cortex-M33 memory:

{pu}cp.b $loadaddr 0x201e0000 $filesize
  1. Use the bootaux command to run the application on the Cortex-M33:

    => bootaux 0x1ffe0000 0
    ## Starting auxiliary core addr = 0x1FFE0000...

Linux remoteproc framework

Modern SoCs typically have remote processing devices on the same chip silicon. The remoteproc framework allows different platforms/architectures to control (power on, load firmware, power off) those remote processors.

The firmware file must be in ELF format to be used with the remoteproc framework.

Enable the remoteproc framework

remoteproc support is enabled as built-in on the ConnectCore 93 Development Kit kernel configuration file.

  • Linux remoteproc framework (CONFIG_REMOTEPROC)

  • IMX remoteproc driver (CONFIG_IMX_REMOTEPROC)

Control remote processors with remoteproc framework

You can use the remoteproc framework to load firmware onto an SoC and power it off and on. The location of the remoteproc device is available in the file system at:

# /sys/class/remoteproc/remoteprocX

Where X is the index of the device node, by default 0.

Use the following commands to load, start, and stop the Cortex-M33 firmware:

# echo -n <firmware_name.elf> > /sys/class/remoteproc/remoteproc0/firmware
# echo start > /sys/class/remoteproc/remoteproc0/state
# echo stop > /sys/class/remoteproc/remoteproc0/state

You can monitor the state of the remoteproc firmware with:

# cat /sys/class/remoteproc/remoteproc0/state