MCX Microcontrollers Knowledge Base

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MCX Microcontrollers Knowledge Base

Discussions

Sort by:
The MCX N microcontroller family includes an eIQ Neutron N1-16 NPU for accelerating neural network models. The FRDM-MCXN947 development board can be combined with a camera and LCD screen to showcase running TinyML vision models on a microcontroller.   MCX N Camera Hardware Setup: The following hardware is used: MCX N FRDM Development Board - FRDM-MCXN947 OV7670 camera (with optional wide-angle lens) NXP LCD-PAR-S035  There are three small modifications needed for the FRDM-MCXN947 board for camera support. Without this modification the camera colors will be incorrect and tinted red.   Change SJ16, SJ26, and SJ27 found on the back of the Rev B board to connect pin 3 (the dashed side) so that it looks like the following:          Then connect the camera and LCD to the FRDM-MCXN947: Plug in the OV7670 camera into J11. It should line up with the orange box.                                Connect the LCD-PAR-S035 LCD into J12. It should be flush with the bottom so that the top 2 rows of pins are left hanging off the edge. Also note that on some LCD-PAR-S035 boards those top two rows of pins are not installed.            It should look like the following when complete             Also as the camera and Ethernet pins are shared, if you need to use the Ethernet+Camera at the same time please see this NXP Community post. MCX N Vision ML Examples: The NXP Application Code Hub contains several vision AI/ML examples: Face Detect Face Detect with Zephyr Multiple Person Detection  CIFAR10 Fashion MNIST There are also Multimedia Processing Pipeline (MPP) examples inside the MCX N MCUXpresso SDK that demonstrate more examples of using vision AI/ML on MCX N. These examples are only available for VSCode/GCC in the Repository-Layout SDK package. Note: It is recommended to use MCUXpresso SDK 25.09 for these examples. The MPP issues in the 25.12 and 26.03 MCUXpresso SDK releases should be fixed in the upcoming MCUXpresso SDK 26.06.    MCX N ML Vision Lab: The attached eIQ Neutron NPU for MCX N Lab Guide - Face Detect.pdf lab document walks through the steps to download an example Face Detect ML project from the NXP Application Code Hub and use the eIQ Neutron Converter tool to convert a model. It also describes how to update the eIQ and Neutron software libraries in an older MCUXpresso SDK project to work with the latest eIQ Neutron SDK libraries. It is recommended to go through the general MCX N NPU Lab Guide first and then do the attached Face Detect lab second. 
View full article
These lab guides provide step-by-step instructions on how to take a quantized TensorFlow Lite model and use the Neutron Conversion Tool found in eIQ Neutron SDK to convert the model to run on the eIQ Neutron NPU found on NXP MCU devices.  The eIQ Neutron NPU for MCX N Lab Guide  documents focus on using the Neutron Converter tool found inside eIQ Neutron SDK to convert a model and then import that converted model into an eIQ MCUXpresso SDK example. There are labs for VSCode, GCC, and MCUXpresso IDE. The labs designed to run on the FRDM-MCXN947 but the same concepts can be applied to other MCX N boards as well. There is a similar NPU lab available for i.MX RT700 too.  Also be sure to also check out the Getting Started community post for more details on the eIQ Neutron NPU. You can also explore the TFLM Getting Started Guide for information on how to use your own model and data for inference.  --- Updated Late April 2026 for MCUXpresso SDK 26.03 and Neutron SDK 3.1.0
View full article
Part 1: Introduction The eIQ Neutron Neural Processing Unit (NPU) is a highly scalable accelerator core architecture that provides machine learning (ML) acceleration. Compared to traditional MCUs like the Kinetis series and LPC series, the MCX N series marks the first integration of NXP's eIQ® Neutron NPU for ML acceleration. The eIQ Neutron NPU offers up to 38 times faster machine learning inference performance compared to a standalone CPU core. Specifically, the MCX N94 can execute 4.8G (150MHz * 4 * 4 * 2) INT8 operations per second.   Hardware Environment: Development Board: FRDM-MCXN947 Display: 3.5" TFT LCD (PAR-LCD-S035) Camera: OV7670 Instructions for putting together demo   Software Environment: eIQ Neutron SDK MCUXpresso IDE Label CIFAR10 Image Demo on NXP App Code Hub   Part 2: Basic Model Classification Training and Deployment The main content is divided into three steps: model training, model converting, and model deployment. 1. Dataset Preparation A fruit dataset is prepared for a simple demonstration of binary classification between apples and bananas. The training set and test set are split in an 8:2 ratio.  2. Use a model generation tool like eIQ Model Creator or TensorFlow to train a model based on the image dataset.  3. Convert to TensorFlow Lite for Neutron (.tflite) Unzip the eIQ Neutron SDK and use the neutron-converter command line tool to convert the trained TensorFlow Lite model to an eIQ Neutron enabled TFLite model: neutron-converter --target mcxn94x --input fruit_model.tflite --output fruit_model_npu.tflite    4. Deploy the Model to the Label CIFAR10 Image Project This example is based on a machine learning algorithm supported by the MCXN947, which can label images captured from a camera and display the type of object at the bottom of the LCD. The model is trained on the CIFAR10 dataset, which supports 10 categories of images: "Airplane", "Automobile", "Bird", "Cat", "Deer", "Dog", "Frog", "Horse", "Ship", "Truck". a. Open MCUXpresso IDE and import the Label CIFAR10 Image project from the Application Code Hub, as follows:   b. Select the project, click on "GitHub link" -> "Next", as shown below:   c. Set the save path, click "Next" -> "Next" -> "Finish", as shown below:   d. After successful import, click on the "source" folder -> "model" folder, open "model_data.s", and copy the model file converted using eIQ Neutron SDK into the "model" folder. Modify the name of the imported model (the name of the converted model) in "model_data.s", as shown below:     e. Click on the "source" folder -> "model" folder -> open the "labels.h" file. Modify the "labels[]" array to match the order of labels model output as shown below:   f. The eIQ middleware in the project needs to be updated to be compatible with the version of the eIQ Neutron SDK used to convert the TFLite model. Update the eIQ middleware folder in the project, including the eIQ Neutron libraries, as described in this Community post or in this lab.   f. Compile the project and download it to the development board.   Part 3: Results     Part 4: Summary By efficiently utilizing the powerful performance of the eIQ Neutron NPU and the eIQ enablement tools like eIQ Neutron SDK, developers can significantly streamline the entire process from model training to deployment. This not only accelerates the development cycle of machine learning applications but also enhances their performance and reliability. Therefore, for developers looking to implement efficient machine learning applications on MCX N-series edge devices, mastering these technologies and tools is crucial.   We can also refer to the video for detailed steps using the deprecated eIQ Toolkit to generate a model. https://www.bilibili.com/video/BV1SS411N7Hv?t=12.9  For more vision examples on MCX N see this Community Post.
View full article
eIQ Time Series Studio includes a command line interface (CLI) that allows you to generate time series models via the command line just like you would in the GUI. Full documentation of this feature can be found in the eIQ TSS documentation A Quick Start with the basic key commands is also available.  In TSS version 1.5.5, there are a few command line interface issues to be aware of that will be addressed in the next TSS release. In the meantime, here are workarounds and clarifications: Library Compile Error Generating the TSS library with the library compile option may not work in all circumstances and may return a "Not Found" error.  Workaround: This will be fixed in the next TSS release.    Windows Workspace Permissions On Windows PCs, specify the workspace location when launching the TSS CLI server. The default workspace on Windows may not work properly due to a permissions issue, resulting in the following error: [PYI-12556:ERROR] Failed to execute script 'server' due to unhandled exception!   Workaround: Specify a workspace directory location where TSS has read/write access with the tss_cli engine launch --workspace <directory_location> argument   Do Not Run CLI and GUI Simultaneously The TSS CLI and TSS GUI should not be run at the same time. Also only one user should interact with the TSS CLI at a time to avoid race conditions in the TSS database if it is on a shared server.    Engine Launch Syntax Correction The TSS CLI documentation uses tss_cli engine launch –engine <path to tss_engine>, but the correct syntax is: tss_cli engine –exe_path <path to tss_engine>   Windows Command Prompt Delimiters When using Windows Command Prompt and importing sensor data with the signal import command, use double quotes (" ") to specify the delimiters (ie a space in this case) instead of the single quotes ('  ')    Terminology Clarification "Optimization" in the documentation refers to the process of training the time series model.   Finding the Optimization ID during training The my-opt-id value can be found by viewing the optimization list with tss_cli optimization list --project_name cli_test_project   Finding the Label Name The label-name value used for emulation commands can be found by viewing the name of the signals with tss_cli signal list --project_name cli_test_project   Boolean Arguments Arguments such as quick search during training are Boolean values, which are automatically enabled when included as part of the command line argument. For example, use -qs rather than -qs true. Below is an example using the command line interface with eIQ Time Series Studio: #Assumes the following items: #1) tss_cli is in the executable path (C:\Program Files\NXP\eIQ_TimeSeriesStudio-1.5.5) #2) The dataset is in C:\tss\dataset #3) A workspace will be setup in C:\tss\workspace #4) The license key has already been retrieved from the TSS GUI #5) The TSS GUI is not also concurrently running #Install license Key tss_cli.exe license activate --key <your_key> #Start TSS CLI tss_cli engine launch -e "C:\Program Files\NXP\eIQ_TimeSeriesStudio-1.5.5\tss_engine\tss_engine.exe" --port 18000 --workspace "C:\tss\workspace" #Install license key tss_cli license activate --key <your_key> #Create a classification project for a FRDM-MCXN947 tss_cli project create --project_name cli_fan_project --algo_type cls --device FRDM-MCXN947 --channels 3 --label_target_num 4 #List all projects in the workspace and see details for the newly generated cli_fan_project tss_cli project list tss_cli project query --project_name cli_fan_project #Add training data tss_cli signal list --project_name cli_fan_project tss_cli signal import --project_name cli_fan_project --signal_name ON --file_path C:\tss\data\fan_state_monitoring_3channel\train\train_on.csv --label_id 1 --delimiter " " tss_cli signal import --project_name cli_fan_project --signal_name OFF --file_path C:\tss\data\fan_state_monitoring_3channel\train\train_off.csv --label_id 2 --delimiter " " tss_cli signal import --project_name cli_fan_project --signal_name FRICTION --file_path C:\tss\data\fan_state_monitoring_3channel\train\train_friction.csv --label_id 3 --delimiter " " tss_cli signal import --project_name cli_fan_project --signal_name CLOG --file_path C:\tss\data\fan_state_monitoring_3channel\train\train_clog.csv --label_id 4 --delimiter " " #Check training data tss_cli signal query --project_name cli_fan_project --signal_id 1 #Start training the model. It will print out an opt_ID number, which the first time you run it will be "1". tss_cli optimization start --project_name cli_fan_project -qs --opt_name cli_fan_opt --signals 1 2 3 4 #Get opt_id number while training is running tss_cli optimization list --project_name cli_fan_project #Check how far along the training is and get ranking of models to choose a result_ids tss_cli optimization progress --project_name cli_fan_project --opt_id 1   #Can stop the training if feel like have enough results tss_cli optimization stop --project_name cli_fan_project --opt_id 1 #Get the result_ids of the best result. It will also be the top ID when checking the progress above. In this case will use 48 tss_cli optimization results --project_name cli_fan_project --opt_id 1 #Get Execution Time estimate for that model tss_cli library time_estimate --project_name cli_fan_project --opt_id 1 --result_id 48   #Get Label Names tss_cli signal list --project_name cli_fan_project   #Emulate the library on test data tss_cli emulation launch --project_name cli_fan_project --opt_id 1 --result_ids 48 --test_file_info "1" C:\tss\data\fan_state_monitoring_3channel\test\test_on.csv " " --test_file_info "2" C:\tss\data\fan_state_monitoring_3channel\test\test_off.csv " " --test_file_info "3" C:\tss\data\fan_state_monitoring_3channel\test\test_friction.csv " " --test_file_info "4" C:\tss\data\fan_state_monitoring_3channel\test\test_clog.csv " " #Create a TSS library tss_cli library compile --project_name cli_fan_project --opt_id 1 --result_id 48 --save_path "C:\tss\" --arch "cortex-m33" --toolchain "GCC" #Create a TSS example project tss_cli library sample_project --project_name cli_fan_project --opt_id 1 --result_id 48 --save_path "C:\tss" --arch "cortex-m33" --toolchain "GCC"  
View full article
The attached lab will describe how to add eIQ Time Series Studio generated libraries to an existing NXP embedded application.   It describes how to add the TSS library files to your application and configure the project settings in VS Code, MCUXpresso IDE, IAR, and Keil. It also covers how to call the TSS API from existing user code so that you can quickly and easily add time series ML analysis to  your embedded application.  For details on how to create a time series model with eIQ Time Series Studio, see the Getting Started with TSS Lab.
View full article
When deploying a custom built model to replace the default models in MCUXpresso SDK examples, there are several modifications that need to be made as described in the eIQ Neutron NPU hands-on labs. Here are some common issues and error messages that you might encounter when using a new custom model with the SDK examples and how to solve them. If there is an issue not covered here, then please make a new thread to discuss that issue.    “Didn't find op for builtin opcode ‘<operator_name>’” Need to add that operator to MODEL_GetOpsResolver function found in source\model\model_name_ops_npu.cpp A full list of operators used by a model that can be copy-and-pasted into that file is automatically generated by Neutron Converter Tool with the --dump-header-file-output option at the top of the resulting header file.  Make sure to also increase the size of the static array s_microOpResolver to match the number of operators   “resolver size is too small” Need to increase the size of the static array s_microOpResolver in MODEL_GetOpsResolver function found in source\model\model_name_ops_npu.cpp to match the number of operators     “Failed to resize buffer” The scratch memory buffer for the model is too small for the model and needs to be increased. The size of the memory buffer is set with the kTensorArenaSize variable found in the model data header file The size of this buffer can be estimated when running the Neutron Converter tool in the "Total data" field but this estimate is often slightly smaller than the actual amount used. The actual TensorArenaSize buffer required can be determined when running the model by calling s_interpreter->arena_used_bytes(); which is printed out to the serial terminal in the eIQ MCUXpresso SDK examples. The recommendation is to use the estimation but increase by ~10%, run the model, and then use the arena_used_bytes API to determine the true amount of scratch memory required.   “Internal Neutron NPU driver error 281b in model prepare!” or “Incompatible Neutron NPU microcode and driver versions!” Ensure the version of the eIQ Neutron Converter Tool used to convert the model is the correct one that is compatible with the NPU libraries used by the SDK project.  See this Community Post for how to update the eIQ Neutron libraries.     Camera colors are incorrect on FRDM-MCXN947 board See this Community post for more details on using a camera with the FRDM-MCXN947 Modify solder jumpers SJ16, SJ26, and SJ27 on the back of board to move them to the left (dashed line side) to connect camera signals properly.             This modification will disable Ethernet functionality on the board due to a signal conflict with EZH D0 and ENET_TXCLK. If your project needs both camera and Ethernet functionality, then only move SJ16 and SJ26 to the left (dashed line side) and then connect a wire from P1_4 (J9 pin 😎 to the left side of R58. Then in the pin_mux.c file in the project, instead of using PORT1_PCR4 for EZH_Camera_D0, use PORT3_PCR0.                           
View full article
Clone an Example Project from MCUXpresso IDE The following steps will guide you through the manipulation of the general-purpose outputs. The example sets up a CTimer to generate a PWM signal and change between two LEDs. Find the Quickstart Panel in the lower left-hand corner and click on Import SDK example(s) Click on the FRDM-MCXN947 board to select that you want to import an example that can run on that board, and then click on Next Use the arrow button to expand the  driver_examples  category, then expand the ctimer examples, click on the check box next to  ctimer_match_interrupt_example  to select it. To use the UART for printing (instead of the default semihosting), Select UART as the SDK Debug Console checkbox under the project options. Then, click on Finish Click on the  “frdmmcxn947_ctimer_match_interrupt_example”  project in the Project Explorer View and build, compile, and run the demo as described in the previous section You should see the BLUE and RED LED changing back and forth Terminate the debug session Use MCUXpresso IDE Pins Tools to Modify Example   Note: Previously, you had to clone an SDK project like in the previous step. Open the pins tool by selecting “ConfigTools” on the top right hand of the file explorer window and then select “ Open Pins”     The pins tool should now display the pin configuration for the ctimer project     In the Pins view deselect “Show dedicated pins” and “Show no routed pins” checkboxes to see only the routed pins. Routed pins have a check in a green box next to the pin name. The functions selected for each routed pin are highlighted in green   In the current configuration, PIO3_2 and PIO3_3 are routed as the outputs of the CTimer. Let’s add a third Ctimer Match output and enable the Green LED Select “Show no routed pins” to see the other options. To enable the third Ctimer Match Output, browse the column for Ctimer and select and output. In this example, we will select, Ctimer4 Match 2 on PIO3_6. Select the item in the Ctimer column to enable   Now, let’s route the Green LED. In the search box type “green” so that the routed pin for this LED is shown. Finally, click the box under the GPIO column. The box will highlight in green, and a check will appear next to the pin   Next configure the GPIO pin as an output in the “Routing Details” window   Now it’s time to implement these changes into the project by exporting the new updated pin_mux.c and pin_mux.h files that are generated by the Pins tool. Click on Update Project in the menu bar   The screen that pops up will show the files that are changing and you can click on “diff” to see the difference between the current file and the new file generated by the Pins tool. Click on “OK” to overwrite the new files into your project   Let’s add some additional code to the example. Open  simple_match_interrupt.c  file and add the following macros for the third ctimer output.   Add the Green LED functions as well.   Some additional code to be implemented will be the third ctimer’s callback, this can be copied from  ctimer_match1_callback  and modify the content to match2. To be able to visually identify the new ctimer, we will remove one of the previous ctimers as shown     The main function will need to include the initialization of both the Green LED and the Ctimer   Build and download the project as done in the previous section Run the application. You should now see the Green and Blue LED blinking back and forth Terminate the debug session
View full article
Clone an Example Project Using MCUXpresso Config Tool    The following steps will guide you through the manipulation of the general-purpose outputs. The example sets up a SCTimer to generate a PWM signal and change a LED brightness. Open the MCUXpresso Config Tool In the wizard that comes up, select the “Create a new configuration based on an SDK example or hello word project” radio button and click on Next On the next screen, select the location of the MCUXpresso SDK . The SDK package must be unzipped beforehand. Then select the IDE that is being used. Note that only IDEs that were selected in the online SDK builder when the SDK was built will be available and click on clone select example. Then select the project to clone. For this example, we want to use the gpio led output project. You can filter for this by typing “ctimer” in the filter box and then selecting the  “ctimer_match_interrupt_example”  example project. You can then also specify where to clone the project and the name. Then click on Finish After cloning go to the directory you selected and open the project for your IDE. Import, compile, and run the project as done in previous sections You should see the BLUE and RED LED changing back and forth Terminate the debug session Use MCUXpresso IDE Pins Tools to Modify Example   Note: Previously, you had to clone an SDK project like in the previous step. Open the pins tool by selecting “ConfigTools” on the top right hand of the file explorer window and then select “ Open Pins”   The pins tool should now display the pin configuration for the ctimer project   In the Pins view deselect “Show dedicated pins” and “Show no routed pins” checkboxes to see only the routed pins. Routed pins have a check in a green box next to the pin name. The functions selected for each routed pin are highlighted in green In the current configuration, PIO3_2 and PIO3_3 are routed as the outputs of the CTimer. Let’s add a third Ctimer Match output and enable the Green LED Select “Show no routed pins” to see the other options. To enable the third Ctimer Match Output, browse the column for Ctimer and select and output. In this example, we will select, Ctimer4 Match 2 on PIO3_6. Select the item in the Ctimer column to enable Now, let’s route the Green LED. In the search box type “green” so that the routed pin for this LED is shown. Finally, click the box under the GPIO column. The box will highlight in green, and a check will appear next to the pin Next configure the GPIO pin as an output in the “Routing Details” window Now it’s time to implement these changes into the project by exporting the new updated pin_mux.c and pin_mux.h files that are generated by the Pins tool. Click on Update Project in the menu bar The screen that pops up will show the files that are changing and you can click on “diff” to see the difference between the current file and the new file generated by the Pins tool. Click on “OK” to overwrite the new files into your project Let’s add some additional code to the example. Open  simple_match_interrupt.c  file and add the following macros for the third ctimer output. Add the Green LED functions as well. Some additional code to be implemented will be the third ctimer’s callback, this can be copied from  ctimer_match1_callback  and modify the content to match2. To be able to visually identify the new ctimer, we will remove one of the previous ctimers as shown   The main function will need to include the initialization of both the Green LED and the Ctimer Build and download the project as done in the previous section Run the application. You should now see the Green and Blue LED blinking back and forth Terminate the debug session  
View full article
The following steps will guide you through the hello_world demo application using MCUXpresso IDE for the Cortex-M33 application. The MCUXpresso IDE installation and the SDK for the MCXN-Series can be found at the section Get Software of this Getting Started guide. Find the Quickstart Panel in the lower left-hand corner.   Then click on Import SDK example(s). Click on the board you are using to select an example that can run on that board, and then click on Next.   Use the arrow button to expand the demo_apps category, and then click the checkbox next to hello_world to select that project. To use the UART for printing (instead of the default semihosting), select UART as the SDK Debug Console checkbox under the project options. Then, click on Finish Select the project and build it by either clicking on the “build icon” in the shortcuts provided above or by clicking “Build” in the Quickstart Panel   The project should build without presenting any errors or warnings in the console   Connect the board to your computer with the type-C USB cable to ‘MCU-LINK’ port. Check your board's user manual for instructions.   Download the application to your board by either clicking on the “debug” icon above or clicking on “Debug” in the Quickstart Panel   Select the MCU-Link CMSIS-DAP debug probe  Open up a serial terminal to be able to see the application’s output. Select the “Terminal” window and press the “new terminal” icon   Choose a “Serial Terminal” and then set the UART settings to 115200 baudrate, 8 bit data size, no parity and 1 stop bit. Press OK   Run the application by pressing the “run” icon. See the output printed on the terminal  
View full article
Install CMSIS Device Pack After the MDK tools are installed, Cortex® Microcontroller Software Interface Standard (CMSIS) device packs must be installed to fully support the device from a debug perspective. These packs include things such as memory map information, register definitions and flash programming algorithms. Follow these steps to install the appropriate CMSIS pack. Please use MDK-Arm Microcontroller Development Kit (Keil)® version 5.38.1 or above. Open the MDK IDE, which is called µVision. Inside the IDE, select the "Pack Installer" icon In the Pack Installer window, search for "MCXW" to bring up the MCXW71 family. Click on the MCXW7XX name, and then in the right-hand side you'll see the NXP:  MCXW71_DFP  pack. Click on the "Install" button next to the pack. This process requires an internet connection to successfully complete After the installation finishes, close the Pack Installer window and return to the µVision IDE Build the Example Application The following steps will guide you through opening the  hello_world  application. These steps may change slightly for other example applications as some of these applications may have additional layers of folders in their path. If not already done, open the desired demo application workspace in: <install_dir>/boards/<sdk_board_name>/<example_type>/<application_name>/mdk Select Debug configuration Do right-click on the project and select the project options: Now, go to the Debug option and select CMSIS-DAP ARMv8-M Debugger. Click on the OK button To build the demo project, select the "Rebuild" button, highlighted in red The build will complete without errors
View full article
The following steps will guide you through opening the  hello_world  application. The instructions for compiling and debugging the Cortex M33 core are covered in the instructions below. Build an Example Application Please use IAR Embedded Workbench for Arm version 9.50.1 or above. First, unzip the previously downloaded FRDM-MCXW71 SDK package Open the desired example application workspace. Most example application workspace files can be located using the following path: <install_dir>/boards/<sdk_board_name>/<example_type>/<application_name>/iar Select the desired build target from the drop-down. For this example, select the "hello_world - debug" target Open the project properties by doing a right-click on the project and selecting "Options" Now, go to the "Debugger" section and change the debugger driver to CMSIS DAP. Press the OK button To build the application, click the "Make" button, highlighted in red below The build will complete without errors   Note: In case of building errors, make sure that the correct board is selected, right-click in Project → Options → General Options → Target → Device. Select the NXP MCU you are using and is supported by the IAR version you have installed.   Run an Example Application Connect the development platform to your PC via USB cable to 'MCU-Link' port Click the "Download and Debug" button to download the application to the target The application is then downloaded to the target and automatically runs to the main() function Run the code by clicking the "Go" button to start the application The  hello_world  application is now running on the MCU.
View full article
The most recent versions of MCUXpresso IDE count with a terminal emulation application. This tool can be used to display information sent from your NXP development platform's virtual serial port 1. Open the MCUXpresso IDE   2. Launch the MCUXpresso IDE terminal by clicking on the "Open a Terminal" button on the top of the IDE or press "Ctrl + Alt + Shift + T" 3. Select Serial Terminal   4. Configure the serial port settings (using the LPC-Link2 COM port number) to 115200 baud rate, 8 data bits, no parity and 1 stop bit, then press the "OK" button     5. Verify that the connection is open. If connected, MCUXpresso IDE will look like the figure below at the Terminal view     6. You're ready to go  
View full article
Porting an ST Application   This section outlines the process of migrating an application developed in the STM32Cube IDE to the NXP MCUXpresso VSCode extension, using a compatible SDK for the target NXP MCU.   For users familiar with STM32Cube IDE, maintaining a similar development environment can ease the transition and reduce the learning curve. In this example, an I2C-based application originally developed for an STM32 device will be recreated and adapted for an NXP MCU.   The migration begins by creating a minimal project in MCUXpresso that includes the necessary I2C drivers. The original ST application utilizes two I2C instances for communication between components on the same board. To replicate this functionality, two sets of I2C pins must be initialized. Additionally, the application uses a push-button input and an LED output to demonstrate behavior changes, requiring the configuration of corresponding GPIOs using the MCUXpresso pin configuration tools.   MCUXpresso for Visual Studio Code MCUXpresso Installer In addition to the MCUXpresso extension, some extra tools and software are required for the full development flow within VS Code. All these dependencies are managed by the MCUXpresso Installer from QUICKSTART PANEL view. This launches the Installer UI, where an intuitive interface allows users to select from Software Kits, Debug Probes, Standalone Tools, or ARM components.   Using the MCUXpresso Installer, select MCUXpresso SDK Developer, LinkServer, SEGGGER J-Link, PEmicro, and MCUXpresso Configuration Tools then Click Install. Once all dependencies have finished installing, you can safely close the MCUXpresso Installer. Import Repository The first step in the MCUXpresso for VS Code development flow is to import an SDK software repository. Go to the MCUXpresso for VS Code extension Click Import Repository in the QUICKSTART PANEL Select MCUXpresso SDK, main revision, choose your SDK destination folder. When finished, click Import NOTE this import step takes a long time to clone. VS Code shows a progress bar pop-up with the status of the west tool as it clones all the repos. The repository should be added to the IMPORTED REPOSITORY view one the import is successful   Importing Example from Repository In the QUICKSTART PANEL click Import Example from Repository. Choose the following board settings to import a Freestanding application To select the board, type MCXA15 to find FRDM-MCXA156 Type hello to find the demo_apps/hello_world For application type, select Freestanding application Change the Name to frdmmcxa156_i2c Click Import and the example should be added to the PROJECTS view   In the PROJECTS window open Project Files --> prj.conf and add CONFIG_MCUX_COMPONENT_driver.lpi2c=y to add I2C driver support to your project.   To begin the migration, the main source file from the original ST project—as well as any custom source files not part of the standard ST driver set—should be incorporated into the new NXP project.   The following steps outline the initial project setup in MCUXpresso for VS Code: Upon creation, the project includes a basic "hello_world" example. This template can be used as a starting point. All content within the main source file—except for the initial macro definitions—can be replaced incrementally to integrate the application logic, allowing for a modular and controlled migration process.   Functions quick summary from ST project The next step involves transferring the main source file from the original ST project into the newly created MCUXpresso project. During this process, standard ST includes, and driver references are excluded, unless custom header files are required. In this case, no custom headers are used, so only the core application logic is migrated.   Many of the function calls within the ST source file rely on STM32-specific HAL APIs. These will be reviewed and systematically replaced with equivalent functions from the NXP SDK. The approach involves analyzing each function within the main() routine to understand its purpose and then substituting it with the corresponding implementation in the NXP environment.   Interrupt Priority Configuration Configures the microcontroller’s interrupt system to manage priority levels when multiple interrupts occur simultaneously. Power Peripheral Clock Enablement Activates the clock for the Power (PWR) peripheral, a prerequisite for configuring power management settings. Power Management Setup Initializes power management features of the STM32U5xx microcontroller to optimize energy efficiency and performance across internal components. System Clock Configuration Sets up the timing system of the microcontroller, configuring it to operate at a frequency of 160 MHz. Peripheral Initialization Establishes pin configurations and functional settings for peripherals. In this application, I2C1 is configured as the follower and I2C3 as the leader. LED Initialization Configures the LED to start in a low-active state, turning it on to indicate initial status or communication feedback. GPIO Polling for Button Press Continuously monitors the status of a GPIO input pin. If the button is not pressed, the LED blinks rapidly. Once pressed, the loop exits, and the LED remains on. I2C Communication Start Initiates the I2C communication process from the master side, triggering data transfer between the two I2C interfaces.   How is this handled in the NXP SDK? 1. Interrupt Priority Configuration This functionality is supported through CMSIS core NVIC functions and can be reused directly. It requires defining macros to establish the desired pre-emption priority levels. 2–4. Clock and Power Configuration These aspects are consolidated within the BOARD_InitBootClocks function, located in clock_config.c under the board folder. This function initializes both the system clock and power settings for the NXP MCU. 5. Peripheral and Pin Initialization Peripheral setup is divided across two functions: BOARD_InitBootPins (in pin_mux.c) handles pin configuration for I2C and GPIO. BOARD_InitBootPeripherals (in peripherals.c) manages I2C peripheral initialization and GPIO interrupt setup. 6. LED Initialization GPIO pins can be configured as output high or low depending on the desired initial state. The LED can be toggled or set using GPIO_PinWrite. 7. GPIO Polling for Button Press This behavior can be replicated using a custom polling function that utilizes GPIO_PinRead to monitor the button state. 8. I2C Communication Start The I2C master communication is initiated using LPI2C_MasterStart, which begins the data transfer process with the designated slave device.   Generate Initialization Code with MCUXpresso Config Tools Clocks VS Code extension works with Config Tools standalone. To access and use MCUXpresso Config Tools from the MCUXpresso extension in VS Code. In the PROJECTS view, right click on the project folder then select Open with MCUXpresso Config Tools   Config Tools will be open in a new window, because this is the first time the project is being open a config tools overview window will appear. Make sure the project has Pins, Clocks and Peripherals enabled; then click Close.   To configure the system clocks, open the Clocks tool through the menu Tools --> Clocks.   The clock diagram displays the supported configurations for the selected MCU. In this example, the device has a maximum core clock frequency of 96 MHz. As this meets the application's requirements, no modifications to the default clock settings are necessary.   To enable the peripheral clocks for the I2C instances, navigate to the clock configuration diagram within the MCUXpresso Config Tools. Scroll through the diagram to locate the available peripherals and activate the I2C modules by selecting the appropriate clock sources.   To configure the clock source for the I2C0 and I2C3 peripherals, double-click on the CLKSEL field associated with each instance in the clock configuration diagram. For this setup, select FRO_HF_DIV as the clock source for both I2C0 and I2C3.   Next, configure the clock divider by selecting the corresponding CLKDIV field in the clock configuration diagram. The details will appear in the top-right panel of the interface. To enable the clock path to the I2C peripheral, ensure the option divider /2 and Divider clock is running are selected.   At this stage, the I2C peripheral clocks have been successfully enabled.   Pins In the standalone MCUXpresso Config Tools go to Tools menu and choose Pins.   Using the filter functionality, search for available pins compatible with I2C instance 0. After reviewing the board schematic, pins P0_16 and P0_17 were selected, as they are accessible via a header. Assign the appropriate I2C functionality to these pins by selecting LPI2C0:SDA and LPI2C0:SCL from the configuration options.   Repeat the configuration process for I2C instance 3. Based on the board schematic, pins P3_27 and P3_28 are selected for this instance. Assign the appropriate functionality by selecting LPI2C3:SDA and LPI2C3:SCL within the pin configuration tool.   Once the pin selections are made, a configuration table is generated displaying the routing and settings for each pin. Within this table, use the routing details to configure the pins as required. For the I2C pins, enable internal pull-up resistors to ensure proper signal integrity during communication.   In addition to configuring the I2C pins, it is necessary to set up two GPIO pins—one for input and one for output. On this board, SW2 (P1_7) is designated for button input functionality, while P3_0 is assigned for LED output.   Within the routing details of the pin configuration table, define the behavior for both input and output GPIOs. Based on the application requirements, the output pin should be initialized to a logical low state (select Logical 0) to activate the LED. For the input pin, enable interrupt detection on a falling edge to register button presses accurately. Peripherals In the standalone MCUXpresso Config Tools go to Tools menu and choose Peripherals.   Select “Peripheral Drivers” to access the list of supported drivers available for the target device   GPIO1 Configuration To filter the available peripheral options, enter “GPIO” in the search field within the Peripheral Drivers view. Once the relevant options are displayed, click “OK” to proceed with the GPIO configuration.   To enable the interrupt functionality for P1_7, which is assigned to the button input, begin by selecting a new peripheral driver. Use the filter to search for GPIO, then choose the appropriate driver to activate the GPIO1 interrupt handler.   SYSTICK Select “Peripheral Drivers” to access the list of supported drivers available for the target device.   To filter the available peripheral options, enter “SYSTICK” in the search field within the Peripheral Drivers view. Once the relevant options are displayed, click “OK” to proceed with the 1ms periodic timer configuration.   Change the Clock source frequence to 24MHz and the interrupt period to 1ms   I2C Master and Slave Inside the peripheral configuration panel, look for Functional Group then click on Functional Group Properties In the Functional group properties window, look for Functional groups or Instances. Click Add a new functional group.   Change the new peripheral function group name to BOARD_InitLPI2Cs then click OK   Double check that BOARD_InitLPI2Cs function group is selected   I2C3 Leader/Master To configure the I2C peripheral, filter the available options by entering “I2C” in the search field within the Peripheral Drivers view. Once the relevant driver is displayed, select the appropriate one for your application and click “OK” to proceed.   Configure I2C3 as the master (leader) device and enable interrupt-driven data transfer. This setup allows the I2C3 instance to initiate communication and handle data transmission using interrupt mechanisms for improved responsiveness and efficiency.   Additionally, enable the interrupt handler for the I2C3 peripheral. Configure the appropriate priority level and activate the Transmit Data Ready flag to support interrupt-driven data transmission.   I2C0 Follower/Slave Configuration To configure the I2C0 follower peripheral, filter the available drivers by entering “I2C” in the search field within the Peripheral Drivers view. Once the relevant driver is displayed, select the appropriate one and click “OK” to proceed with the configuration.   Configure I2C0 as the slave (follower) device. Enable the interrupt-driven transfer method and specify the slave address to be used for communication. This setup allows the I2C0 instance to respond to master requests and handle data reception via interrupts.   Additionally, enable the interrupt handler for the I2C0 peripheral. Configure the appropriate priority level, validate the assigned follower address, and activate the Address valid, Receive data flag to support interrupt-driven data reception.   Apply Changes To apply and integrate the configuration changes into the project, click “Update Code.”   A new window will open to approve all the changes to the corresponding source files and ensure the new settings are reflected in the project structure. Click OK and go back to VS Code   File Structure The MCUXpresso configuration tools automatically generate source code based on the selected settings, streamlining integration into the main application. This generated code includes initialization routines for clocks, pins, and peripherals configured in previous steps. All generated files are under board directory within the project structure.   To add the all the source files under the board folder and make the directory path only visible to this target. Modify CMakeList.txt   1. peripherals.c This file includes initialization code for peripherals configured via the Config Tools. In this example, it contains setup routines for both I2C instances and the GPIO interrupt. While the BOARD_InitPeripherals function can be used, it is often more effective to selectively integrate the generated code into specific locations within the application to align with the required execution sequence.   2. board.c When creating a project using an NXP development board, the default configuration includes initialization of debug UART pins for serial terminal communication. In this case, the UART functionality is not required, and the corresponding function in board.c will not be used.   3. clock_config.c This file contains all system clock configurations. Use the BOARD_InitBootClocks function to initialize the clock frequency and power mode settings. For this application, the system is configured to operate at 96 MHz.   4. pin_mux.c This file defines all pin configurations selected for the application, including I2C and GPIO assignments. Although UART pins are included by default, they are not utilized in this project. Use the BOARD_InitBootPins function to apply the pin settings.   Additionally, the original ST application includes a cache initialization function (MX_ICACHE_Init). In the NXP SDK, cache configuration is handled within the startup code. This can be reviewed in the SystemInit function located in system_MCU.c under the device folder. Replace Initialization Functions   1. Clock and Pin Initialization In the main function of the NXP-based project, system clocks and pin configurations are initialized in the BOARD_InitHardware using the functions generated by the configuration tools: BOARD_InitBootClocks BOARD_InitBootPins   2. Peripheral Initialization Initialization code for peripherals is sourced from the peripherals.c file generated by the Config Tools. BOARD_InitBootPeripherals sets up the GPIO interrupt handler, including its priority level and NVIC configuration. And setups a 1ms SYSTICK periodic timer.   3. I2C Initialization Following this, the I2C master and slave instances are initialized along with their respective interrupt handlers and priority levels. At this stage, interrupt flags are not yet enabled; they will be activated later within the data transfer function to ensure proper sequencing and avoid premature interrupt triggering.   Source file peripherals.c includes a code snippet specifically for initializing the LPI2C0 peripheral for slave operations. This code can be selectively integrated into the main function or other appropriate locations within the application to align with the desired execution flow.   While the standalone configuration tools effectively generate the necessary initialization code, it remains the developer’s responsibility to determine the most appropriate placement of this code within the application. This decision should be guided by the operational sequence required by the specific protocol or peripheral being implemented.   For example, in I2C communication, data transfer is managed through interrupts. If the LPI2C0_Init function is used without consideration for timing, interrupts may trigger prematurely, resulting in incomplete or mismanaged transactions.   To ensure proper execution, the recommended sequence is: Initialize the peripheral and its associated interrupt handler. Start the I2C transaction. Enable interrupts for both master and slave operations.   In this application, the initialization is performed within the main() function, while the interrupt flags are selectively enabled later to maintain correct timing and control.   Initialize LPI2C To add LPI2C project settings like the slave address and data transfer length open the Kconfig file and add the following config menu   Add I2C prototypes and variables, that will be used in the I2C interrupt handlers and action functions   Replace Action Functions   4. SYSTICK Initialization The SYSTICK timer is configured to support delay operations within the application, such as controlling the LED blinking rate. Detailed instructions for initializing SYSTICK are provided in the following sections. 5. Button Polling and LED Control This functionality is implemented through a custom function that continuously polls the button input. While waiting for user interaction, the LED toggles to indicate readiness. Once the button is pressed, the LED remains steadily lit, signaling progression to the I2C data transfer phase. 6. I2C Master Handling The Handle_I2C_Master function is implemented using the driver APIs provided for the I2C peripheral in the NXP SDK. This function initiates the I2C transaction and manages the communication sequence. Interrupt handlers for both master and slave I2C instances are derived from the peripheral initialization code. At this stage, relevant interrupt flags are selectively enabled to support the specific behaviors required by the application.   WaitForUserButtonPress To begin customizing the GPIO interrupt handler, open the Peripherals Config Tool. From there, you can copy the auto-generated IRQ handler for GPIO, which serves as a reliable starting point. This code can then be modified to suit the specific requirements of your application.   In the VS Code development environment, paste the copied IRQ handler code into the main source file—ideally near the top—for easier access and organization.   Modifications were made to include a control variable within a while loop, allowing the application to pause execution until a button press is detected. This ensures that the program proceeds only after user interaction, aligning with the intended flow of the application.   The WaitForUserButtonPress function utilizes GPIO toggle and write operations to control the LED state, along with a delay mechanism to manage the blinking interval during the polling loop. To implement the delay, the SYSTICK timer is initialized and configured accordingly.   Additionally, a global counter variable is introduced, along with the corresponding SYSTICK interrupt handler, to support time-based operations within the application.     Within the BOARD_InitBootPeripherals() function, the SysTick_init() timer initialization was added prior to the button polling logic. This ensures that the delay mechanism is fully operational before entering the loop that waits for user input.   The finalized WaitForUserButtonPress function will include: GPIO operations to toggle and control the LED state. A while loop that continuously checks the button state and proceeds only upon detection of a press event.   The GPIO_* APIs are part of the NXP GPIO driver library and are used for various operations such as initialization, pin control, and interrupt handling. The macros highlighted in the code—typically shown in pink within the IDE—are generated by the Config Tools and defined in the pin_mux.h header file.   The delay functionality used in the application is implemented through a custom SYSTICK-based function, as previously described.   To explore the full set of available GPIO APIs, refer to the fsl_gpio.h header file. This file provides comprehensive support for GPIO operations, including port and pin-level control, configuration, and interrupt management.   Customizing the I2C Interrupt Handlers To customize the I2C interrupt handlers in a manner similar to the GPIO handler, begin by opening the Peripherals Config Tool in MCUXpresso IDE. From there, locate and copy the auto-generated IRQ handler for I2C0. This serves as a foundational template that can be modified to meet the specific requirements of the application.   Repeat the same process for I2C3 by copying its auto-generated interrupt handler from the Peripherals Config Tool. This handler can then be used as a base for customization, like the approach taken with I2C0.   Consolidating I2C Interrupt Handlers In the original ST-based project, each I2C instance utilized two separate interrupt handlers: one for standard operations and another for error handling. However, the NXP MCU used in this migration provides a single interrupt vector per I2C instance, which handles both standard and error conditions.   As a result, the functionality of the original four handlers must be consolidated into two—one for each I2C instance. This requires a careful review of the original interrupt logic to ensure that all relevant flags and behaviors are preserved in the merged implementation.   For example, the slave handler in the original project checks for an address match flag and, upon detection, verifies readiness to receive data. The equivalent behavior in the NXP environment is implemented by monitoring the appropriate status flags within the unified interrupt handler, ensuring that both address recognition and data reception are handled correctly.   Slave Handler   The I2C slave interrupt handler is triggered when the master device addresses the slave at 0x7E. Upon detecting this address match, the slave acknowledges the request and prepares to receive incoming data.   The second part of the handler manages the data reception process. It handles each byte transmitted by the master, monitors for a NACK (Not Acknowledge) condition to signal the end of transmission, and stores the received data into a designated buffer. This ensures that the slave processes the communication sequence correctly and terminates the transfer gracefully once all data has been received.   Master Handler   The I2C master interrupt handler monitors the Master Transfer Ready flag, which indicates that the peripheral is prepared to transmit the next byte of data. Upon detecting this condition, the handler checks the transmit buffer to determine if additional data remains to be sent. A counter is used to track the progress of the transmission.   Using the appropriate Master Send operation, the handler transmits the next byte and advances the buffer pointer. When the final byte is sent, the handler issues a STOP condition to signal the completion of the data transfer sequence.   Error Callback When something goes wrong during the I2C communication, the Error_Callback function serves as an error handler doing two main actions. First, it shuts down the communication system by disabling the interrupts for both I2C instances. Second, it provides a clear visual indication to the user that an error has occur.   Handle_I2C_Master Function   The Handle_I2C_Master function is responsible for initiating and managing the I2C communication process. It begins by issuing a MasterStart command to initiate communication with the slave device at the specified address. Upon successful acknowledgment from the slave, the data transfer is handled through the corresponding interrupt routines.   This function also initializes the interrupt handlers for both the master and slave I2C instances. As previously noted, it is essential to enable interrupts after the master initiates communication to prevent premature interrupt triggering, which could disrupt the transaction sequence.   Once the data transfer is complete and the slave has received all expected bytes, the function concludes by setting the LED to a steady state—indicating successful execution and the end of the application flow.   Conclusion Migrating an application from the STM32 development environment to the NXP MCX platform using MCUXpresso involves a structured and methodical approach. By leveraging the integrated configuration tools and understanding the functional equivalence between STM32 and NXP SDK components, developers can effectively transition their applications while maintaining performance and functionality.   This guide has outlined the key steps involved in replicating an I2C-based application, including project setup, peripheral configuration, pin and clock initialization, and interrupt handling. While the tools provide a strong foundation through auto-generated code, careful consideration must be given to the sequencing and integration of initialization and runtime logic to ensure reliable operation.   With a clear understanding of both environments and thoughtful adaptation of application logic, developers can streamline the migration process and take full advantage of the capabilities offered by the NXP MCX platform.
View full article
Porting an ST Application   This section outlines the process of migrating an application developed in the STM32Cube IDE to the NXP MCUXpresso IDE, using a compatible SDK for the target NXP MCU. For users familiar with STM32Cube IDE, maintaining a similar development environment can ease the transition and reduce the learning curve. In this example, an I2C-based application originally developed for an STM32 device will be recreated and adapted for an NXP MCU.   The migration begins by creating a minimal project in MCUXpresso IDE that includes the necessary I2C drivers. The original ST application utilizes two I2C instances for communication between components on the same board. To replicate this functionality, two sets of I2C pins must be initialized. Additionally, the application uses a push-button input and an LED output to demonstrate behavior changes, requiring the configuration of corresponding GPIOs using the MCUXpresso pin configuration tools.   To begin the migration, the main source file from the original ST project—as well as any custom source files not part of the standard ST driver set—should be incorporated into the new NXP project.   The following steps outline the initial project setup in MCUXpresso IDE: Select Create a new C/C++ project. Choose the target MCU (e.g., MCXA156). Click Next. Expand the Drivers section. Select I2C. Click Next. Click Finish.   Upon creation, the project includes a basic "Hello World" example. This template can be used as a starting point. All content within the main source file—except for the initial macro definitions—can be replaced incrementally to integrate the application logic, allowing for a modular and controlled migration process. The next step involves transferring the main source file from the original ST project into the newly created MCUXpresso project. During this process, standard ST includes, and driver references are excluded, unless custom header files are required. In this case, no custom headers are used, so only the core application logic is migrated.   Many of the function calls within the ST source file rely on STM32-specific HAL APIs. These will be reviewed and systematically replaced with equivalent functions from the NXP SDK. The approach involves analyzing each function within the main() routine to understand its purpose and then substituting it with the corresponding implementation in the NXP environment.   Functions quick summary from ST project: Interrupt Priority Configuration Configures the microcontroller’s interrupt system to manage priority levels when multiple interrupts occur simultaneously. Power Peripheral Clock Enablement Activates the clock for the Power (PWR) peripheral, a prerequisite for configuring power management settings. Power Management Setup Initializes power management features of the STM32U5xx microcontroller to optimize energy efficiency and performance across internal components. System Clock Configuration Sets up the timing system of the microcontroller, configuring it to operate at a frequency of 160 MHz. Peripheral Initialization Establishes pin configurations and functional settings for peripherals. In this application, I2C1 is configured as the follower and I2C3 as the leader. LED Initialization Configures the LED to start in a low-active state, turning it on to indicate initial status or communication feedback. GPIO Polling for Button Press Continuously monitors the status of a GPIO input pin. If the button is not pressed, the LED blinks rapidly. Once pressed, the loop exits, and the LED remains on. I2C Communication Start Initiates the I2C communication process from the master side, triggering data transfer between the two I2C interfaces.   How is this handled in the NXP SDK? Interrupt Priority Configuration This functionality is supported through CMSIS core NVIC functions and can be reused directly. It requires defining macros to establish the desired pre-emption priority levels. Clock and Power Configuration These aspects are consolidated within the BOARD_InitBootClocks function, located in clock_config.c under the board folder. This function initializes both the system clock and power settings for the NXP MCU. Peripheral and Pin Initialization Peripheral setup is divided across two functions: BOARD_InitBootPins (in pin_mux.c) handles pin configuration for I2C and GPIO. BOARD_InitBootPeripherals (in peripherals.c) manages I2C peripheral initialization and GPIO interrupt setup. LED Initialization GPIO pins can be configured as output high or low depending on the desired initial state. The LED can be toggled or set using GPIO_PinWrite. GPIO Polling for Button Press This behavior can be replicated using a custom polling function that utilizes GPIO_PinRead to monitor the button state. I2C Communication Start The I2C master communication is initiated using LPI2C_MasterStart, which begins the data transfer process with the designated slave device.     Tackling Clock Initialization using Clock Config Tool The MCUXpresso IDE includes integrated configuration tools, which can be accessed via the Project Explorer by selecting the appropriate option from the drop-down menu located in the upper-right corner of the interface. To configure the system clocks, open the Clocks tool within MCUXpresso IDE. The clock diagram displays the supported configurations for the selected MCU. In this example, the device has a maximum core clock frequency of 96 MHz. As this meets the application's requirements, no modifications to the default clock settings are necessary. To enable the peripheral clocks for the I2C instances, navigate to the clock configuration diagram within the MCUXpresso Config Tools. Scroll through the diagram to locate the available peripherals and activate the I2C modules by selecting the appropriate clock sources. To configure the clock source for the I2C0 and I2C3 peripherals, double-click on the CLKSEL field associated with each instance in the clock configuration diagram. For this setup, select FRO_HF_DIV as the clock source for both I2C0 and I2C3. Next, configure the clock divider by selecting the corresponding field in the clock configuration diagram. The details will appear in the top-right panel of the interface. To enable the clock path to the I2C peripheral, ensure the option “Divider clock is running” is selected. At this stage, the I2C peripheral clocks have been successfully enabled.     To apply and integrate the configuration changes into the project, click “Update Code.” This action will generate the corresponding source files and ensure the new settings are reflected in the project structure.   Tackling Pin Initialization using Pins Config Tool The MCUXpresso IDE includes integrated configuration tools, which can be accessed from the Project Explorer by selecting the appropriate option from the drop-down menu located in the upper-right corner of the interface. To begin configuring the I2C pins, select “Open Pins” from the configuration tool menu within MCUXpresso IDE. Using the filter functionality, search for available pins compatible with I2C instance 0. After reviewing the board schematic, pins P0_16 and P0_17 were selected, as they are accessible via a header. Assign the appropriate I2C functionality to these pins by selecting LPI2C0:SDA and LPI2C0:SCL from the configuration options. Repeat the configuration process for I2C instance 3. Based on the board schematic, pins P3_27 and P3_28 are selected for this instance. Assign the appropriate functionality by selecting LPI2C3:SDA and LPI2C3:SCL within the pin configuration tool. Once the pin selections are made, a configuration table is generated displaying the routing and settings for each pin. Within this table, use the routing details to configure the pins as required. For the I2C pins, enable internal pull-up resistors to ensure proper signal integrity during communication. In addition to configuring the I2C pins, it is necessary to set up two GPIO pins—one for input and one for output. On this board, SW2 (P1_7) is designated for button input functionality, while P3_0 is assigned for LED output. Within the routing details of the pin configuration table, define the behavior for both input and output GPIOs. Based on the application requirements, the output pin should be initialized to a logical low state (select Logical 0) to activate the LED. For the input pin, enable interrupt detection on a falling edge to register button presses accurately. To finalize the configuration and integrate the changes into your project, click “Update Code.” This will generate the necessary source files and apply the selected settings to the project structure. Tackling Peripheral Initialization using Peripheral Config Tool The MCUXpresso IDE features integrated configuration tools, accessible via the Project Explorer. To launch these tools, use the drop-down menu located in the upper-right corner of the interface.   To begin peripheral configuration, select “Open Peripherals” from the configuration tool menu within MCUXpresso IDE. In this view, focus on initializing the GPIO and I2C settings for each instance. To proceed, select “Peripheral Drivers” to access the list of supported drivers available for the target device   GPIO1 Configuration To filter the available peripheral options, enter “GPIO” in the search field within the Peripheral Drivers view. Once the relevant options are displayed, click “OK” to proceed with the GPIO configuration. To enable the interrupt functionality for P1_7, which is assigned to the button input, begin by selecting a new peripheral driver. Use the filter to search for GPIO, then choose the appropriate driver to activate the GPIO1 interrupt handler. I2C3 Leader/Master Configuration To configure the I2C peripheral, filter the available options by entering “I2C” in the search field within the Peripheral Drivers view. Once the relevant driver is displayed, select the appropriate one for your application and click “OK” to proceed. Configure I2C3 as the master (leader) device and enable interrupt-driven data transfer. This setup allows the I2C3 instance to initiate communication and handle data transmission using interrupt mechanisms for improved responsiveness and efficiency. Additionally, enable the interrupt handler for the I2C3 peripheral. Configure the appropriate priority level and activate the Transmit Data Ready flag to support interrupt-driven data transmission. I2C0 Follower/Slave Configuration To configure the I2C0 follower peripheral, filter the available drivers by entering “I2C” in the search field within the Peripheral Drivers view. Once the relevant driver is displayed, select the appropriate one and click “OK” to proceed with the configuration. Configure I2C0 as the slave (follower) device. Enable the interrupt-driven transfer method and specify the slave address to be used for communication. This setup allows the I2C0 instance to respond to master requests and handle data reception via interrupts. Additionally, enable the interrupt handler for the I2C0 peripheral. Configure the appropriate priority level, validate the assigned follower address, and activate the Receive Data Ready flag to support interrupt-driven data reception. To apply the configured settings and integrate them into the project, click “Update Code.” This action will generate the necessary source files and ensure that all peripheral and pin configurations are reflected in the project structure. Config Tools Generated Files The MCUXpresso configuration tools automatically generate source code based on the selected settings, streamlining integration into the main application. This generated code includes initialization routines for clocks, pins, and peripherals configured in previous steps. All generated files are organized under the board directory within the project structure. board.c When creating a project using an NXP development board, the default configuration includes initialization of debug UART pins for serial terminal communication. In this case, the UART functionality is not required, and the corresponding function in board.c will not be used. clock_config.c This file contains all system clock configurations. Use the BOARD_InitBootClocks function to initialize the clock frequency and power mode settings. For this application, the system is configured to operate at 96 MHz. peripherals.c This file includes initialization code for peripherals configured via the Config Tools. In this example, it contains setup routines for both I2C instances and the GPIO interrupt. While the BOARD_InitPeripherals function can be used, it is often more effective to selectively integrate the generated code into specific locations within the application to align with the required execution sequence. pin_mux.c This file defines all pin configurations selected for the application, including I2C and GPIO assignments. Although UART pins are included by default, they are not utilized in this project. Use the BOARD_InitBootPins function to apply the pin settings. Additionally, the original ST application includes a cache initialization function (MX_ICACHE_Init). In the NXP SDK, cache configuration is handled within the startup code. This can be reviewed in the SystemInit function located in system_MCU.c under the device folder. Replacing the Initialization Functions Clock and Pin Initialization In the main function of the NXP-based project, system clocks and pin configurations are initialized using the functions generated by the configuration tools: BOARD_InitBootClocks BOARD_InitBootPins Peripheral Initialization Initialization code for peripherals is sourced from the peripherals.c file generated by the Config Tools. The first block of code sets up the GPIO interrupt handler, including its priority level and NVIC configuration. Following this, the I2C master and slave instances are initialized along with their respective interrupt handlers and priority levels. At this stage, interrupt flags are not yet enabled; they will be activated later within the data transfer function to ensure proper sequencing and avoid premature interrupt triggering. The peripherals.c file includes a code snippet specifically for initializing the LPI2C0 peripheral for slave operations. This code can be selectively integrated into the main function or other appropriate locations within the application to align with the desired execution flow. While the configuration tools in MCUXpresso IDE effectively generate the necessary initialization code, it remains the developer’s responsibility to determine the most appropriate placement of this code within the application. This decision should be guided by the operational sequence required by the specific protocol or peripheral being implemented. For example, in I2C communication, data transfer is managed through interrupts. If the LPI2C0_Init function is used without consideration for timing, interrupts may trigger prematurely, resulting in incomplete or mismanaged transactions. To ensure proper execution, the recommended sequence is: Initialize the peripheral and its associated interrupt handler. Start the I2C transaction. Enable interrupts for both master and slave operations. In this application, the initialization is performed within the main() function, while the interrupt flags are selectively enabled later within the Handle_I2C_Master function to maintain correct timing and control. Replacing the Action Functions   SYSTICK Initialization The SYSTICK timer is configured to support delay operations within the application, such as controlling the LED blinking rate. Detailed instructions for initializing SYSTICK are provided in the following sections. Button Polling and LED Control This functionality is implemented through a custom function that continuously polls the button input. While waiting for user interaction, the LED toggles to indicate readiness. Once the button is pressed, the LED remains steadily lit, signaling progression to the I2C data transfer phase. I2C Master Handling The Handle_I2C_Master function is implemented using the driver APIs provided for the I2C peripheral in the NXP SDK. This function initiates the I2C transaction and manages the communication sequence. Interrupt handlers for both master and slave I2C instances are derived from the peripheral initialization code. At this stage, relevant interrupt flags are selectively enabled to support the specific behaviors required by the application. WaitForUserButtonPress Function To begin customizing the GPIO interrupt handler, open the Peripherals Config Tool within MCUXpresso IDE. From there, you can copy the auto-generated IRQ handler for GPIO, which serves as a reliable starting point. This code can then be modified to suit the specific requirements of your application. To return to the code editor after configuring peripherals, click the “Develop” button located in the upper-right corner of the MCUXpresso IDE. Once in the development environment, paste the copied IRQ handler code into the main source file—ideally near the top—for easier access and organization. Modifications were made to include a control variable within a while loop, allowing the application to pause execution until a button press is detected. This ensures that the program proceeds only after user interaction, aligning with the intended flow of the application. The WaitForUserButtonPress function utilizes GPIO toggle and write operations to control the LED state, along with a delay mechanism to manage the blinking interval during the polling loop. To implement the delay, the SYSTICK timer is initialized and configured accordingly. Additionally, a global counter variable is introduced, along with the corresponding SYSTICK interrupt handler, to support time-based operations within the application. Within the main() function, the SYSTICK timer initialization should be added prior to the button polling logic. This ensures that the delay mechanism is fully operational before entering the loop that waits for user input. The finalized WaitForUserButtonPress function will include: GPIO operations to toggle and control the LED state. A while loop that continuously checks the button state and proceeds only upon detection of a press event. The GPIO_* APIs are part of the NXP GPIO driver library and are used for various operations such as initialization, pin control, and interrupt handling. The macros highlighted in the code—typically shown in pink within the IDE—are generated by the Config Tools and defined in the pin_mux.h header file. The delay functionality used in the application is implemented through a custom SYSTICK-based function, as previously described. To explore the full set of available GPIO APIs, refer to the fsl_gpio.h header file. This file provides comprehensive support for GPIO operations, including port and pin-level control, configuration, and interrupt management. Customizing the I2C Interrupt Handlers To customize the I2C interrupt handlers in a manner similar to the GPIO handler, begin by opening the Peripherals Config Tool in MCUXpresso IDE. From there, locate and copy the auto-generated IRQ handler for I2C0. This serves as a foundational template that can be modified to meet the specific requirements of the application. To return to the code editor, click the “Develop” button located in the upper-right corner of the MCUXpresso IDE. Once in the development environment, paste the copied I2C interrupt handler code into the main source file—preferably near the top—for better organization and accessibility. Repeat the same process for I2C3 by copying its auto-generated interrupt handler from the Peripherals Config Tool. This handler can then be used as a base for customization, similar to the approach taken with I2C0. Consolidating I2C Interrupt Handlers In the original ST-based project, each I2C instance utilized two separate interrupt handlers: one for standard operations and another for error handling. However, the NXP MCU used in this migration provides a single interrupt vector per I2C instance, which handles both standard and error conditions. As a result, the functionality of the original four handlers must be consolidated into two—one for each I2C instance. This requires a careful review of the original interrupt logic to ensure that all relevant flags and behaviors are preserved in the merged implementation. For example, the slave handler in the original project checks for an address match flag and, upon detection, verifies readiness to receive data. The equivalent behavior in the NXP environment is implemented by monitoring the appropriate status flags within the unified interrupt handler, ensuring that both address recognition and data reception are handled correctly. Slave Handler The I2C slave interrupt handler is triggered when the master device addresses the slave at 0x7E. Upon detecting this address match, the slave acknowledges the request and prepares to receive incoming data. The second part of the handler manages the data reception process. It handles each byte transmitted by the master, monitors for a NACK (Not Acknowledge) condition to signal the end of transmission, and stores the received data into a designated buffer. This ensures that the slave processes the communication sequence correctly and terminates the transfer gracefully once all data has been received. Master Handler The I2C master interrupt handler monitors the Master Transfer Ready flag, which indicates that the peripheral is prepared to transmit the next byte of data. Upon detecting this condition, the handler checks the transmit buffer to determine if additional data remains to be sent. A counter is used to track the progress of the transmission. Using the appropriate Master Send operation, the handler transmits the next byte and advances the buffer pointer. When the final byte is sent, the handler issues a STOP condition to signal the completion of the data transfer sequence. Handle_I2C_Master Function The Handle_I2C_Master function is responsible for initiating and managing the I2C communication process. It begins by issuing a MasterStart command to initiate communication with the slave device at the specified address. Upon successful acknowledgment from the slave, the data transfer is handled through the corresponding interrupt routines. This function also initializes the interrupt handlers for both the master and slave I2C instances. As previously noted, it is essential to enable interrupts after the master initiates communication to prevent premature interrupt triggering, which could disrupt the transaction sequence. Once the data transfer is complete and the slave has received all expected bytes, the function concludes by setting the LED to a steady state—indicating successful execution and the end of the application flow. Conclusion Migrating an application from the STM32 development environment to the NXP MCX platform using MCUXpresso IDE involves a structured and methodical approach. By leveraging the integrated configuration tools and understanding the functional equivalence between STM32 and NXP SDK components, developers can effectively transition their applications while maintaining performance and functionality. This guide has outlined the key steps involved in replicating an I2C-based application, including project setup, peripheral configuration, pin and clock initialization, and interrupt handling. While the tools provide a strong foundation through auto-generated code, careful consideration must be given to the sequencing and integration of initialization and runtime logic to ensure reliable operation. With a clear understanding of both environments and thoughtful adaptation of application logic, developers can streamline the migration process and take full advantage of the capabilities offered by the NXP MCX platform.    
View full article
Introduction This article describes the method to update the Boot ROM patch on MCX N23x devices to patch version T1.0.7 Before beginning, note that this process can only be performed via ISP mode of the device and can only be performed using a command line method.  The NXP Secure Provisioning tool uses command line operations in its backend and does make these available to the user.  For directions on how to access the command line interface through the Secure Provisioning tool, consult your Secure Provisioning Tool documentation.    Note: If in development lifecycle, perform a mass erase prior to updating ROM. Mass erase can be done by nxpdebugmbox -i pyocd cmd -f mcxn236 erase command from SPSDK.  Command line blhost method ISP Pin Method 1) With the device powered off, assert the ISP pin (GPIO P0_6) by pulling this pin low. 2) With ISP pin still asserted, power on the device.   3) After the device has fully powered on (at least as long as the t_POR time quoted in the Power mode transition operating behaviors table of the MCX N23x datasheet), release the ISP pin.  4) Open a command prompt and set the working directory to your blhost installation. 5) Verify that the current version of ROM patch is not T1.0.7 using this command: blhost <interface> <parameters> -- get-property 24.  a) Where <interface> should be replaced with the code for the interface type and <parameters> should be replaced with the parameters of that interface.  For more information on this syntax, refer to the blhost User's Guide.   6) Execute this command:  blhost <interface> <parameters> receive-sb-file <path_to_file_location>/mcx_n11_a0_prov_fw_rp_v7.0.sb3.  7) Repeat steps 1 - 5 to verify that the ROM version is T1.0.7.  ISP Pin Unavailable - SWD Method 1) Connect to target via SWD 2) Open the secure provisioning tool 3) Select the serial interface window and select the command line button 4) Send the following command: nxpdebugmbox -i pyocd ispmode -m 0 5) Verify that the current version of ROM patch is not T1.0.7 using this command: blhost <interface> <parameters> -- get-property 24.  a) Where <interface> should be replaced with the code for the interface type and <parameters> should be replaced with the parameters of that interface.  For more information on this syntax, refer to the blhost User's Guide.   6) Execute this command:  blhost <interface> <parameters> receive-sb-file <path_to_file_location>/mcx_n11_a0_prov_fw_rp_v7.0.sb3 7) Repeat steps 1 - 5 to verify that the ROM version is T1.0.7. 
View full article
In order to recover your board, you need to accomplish the following: Ensure that your PC successfully enumerates the LinkServer debugger under the COM ports. Confirm that you can attach to the running code on the board. When attempting to program the board, the following error appears:   The device stops during initialization because the value of SIM_CHIPCTL is not set to its default after reset. This happens because SRAMU and SRAML are retained across resets, which causes a flash initialization error. To resolve this issue, modify the debug script to override the SIM_CHIPCTL register with its default value: 0x0030_0000. Locate the file MCXE24x_connect.scp. If you are using the default installation path, it should be located at: C:\NXP\LinkServer_YourVersion\binaries\Scripts   Open the file and add the line "Poke32 this 0x40048004 0x00300000" I recommend do it after the "Release NRESET" message.     Note: You need to add a number to each line of code    After making this change, you should be able to program your MCX E24x board as usual.
View full article
Overview NXP FRDM-MCXN947 board is a low-cost design and evaluation board based on the MCXN947 device. NXP provides tools and software support for the MCXN947 device, including hardware evaluation boards, software development integrated development environment (IDE), sample applications, and drivers. The board is equipped with Ethernet PHY, and also supports camera modules and NXP's low-cost LCD module PAR-LCD-S035.   In this article, we will explore how to simultaneously implement Ethernet connection transmission and image acquisition using a camera on the MCXN947 board. Hardware Environment Development Board: FRDM-MCXN947 Display: 3.5" TFT LCD (P/N PAR-LCD-S035) Camera: OV7670 Network Cable: RJ45 Software Environment IDE: MCUXpresso IDE v11.9.0 SDK: MCUXpresso SDK Builder (nxp.com) Pin Configuration and Multiplexing When designing circuits, attention must be paid to avoiding pin conflicts, that is, ensuring that the same pin is not configured to perform conflicting functions at different times. When configuring pin functions, it is necessary to consider whether their electrical characteristics (such as voltage range, current drive capability, etc.) meet the requirements of the peripherals. When writing software, it is necessary to consider the support for pin multiplexing in different versions of MCU firmware or library files to ensure software compatibility and stability. Import the " lwip_examples " -> " lwip_ping_bm " project from the FDRM-MCXN947 SDK, open the board -> pin_mux.c file, and you can see the pin configuration for Ethernet connection as shown in the table below: Pin Name Pinmux Assignment P1_4 ALT9 - ENET0_TX_CLK P1_5 ALT9 - ENET0_TXEN P1_6 ALT9 - ENET0_TXD0 P1_7 ALT9 - ENET0_TXD1 P1_8 ALT9 - ENET0_TXD2 P1_9 ALT9 - ENET0_TXD3 P1_13 ALT9 - ENET0_RXDV P1_14 ALT9 - ENET0_RXD0 P1_15 ALT9 - ENET0_RXD1 P1_20 ALT9 - ENET0_MDC P1_21 ALT9 - ENET0_MDIO   Download the schematic of the MCXN947 board from NXP's official website, and find the modules corresponding to Camera and FlexIO LCD, as shown below:   FlexIO is a flexible input/output (I/O) technology developed by NXP, used to provide high-speed, programmable communication capabilities between microcontrollers (MCU) and external devices. It allows developers to configure the FlexIO module inside the microcontroller to simulate various communication protocols and develop custom protocols. Note: This LCD only supports 3V I/O voltage, so when configuring all pins on this connector, you must ensure they are all set to 3V3 operation mode. The following diagram shows the working principle of the SDK example, where the camera collects images and transmits them to the LCD display: It can be seen that the LCD module does not have any pin conflicts with the pins required for Ethernet and Camera functions, while the pins required for configuring the Camera module are duplicated with Ethernet. The pin reuse can be found in the datasheet provided on the NXP official website as shown in the following table: Pin Name Pinmux Assignment P0_4 ALT0 - P0_4 P0_5 ALT0 - P0_5 P1_4 ALT7 - SmartDMA_PIO0 P1_5 ALT7 - SmartDMA_PIO1 P1_6 ALT7 - SmartDMA_PIO2 P1_7 ALT7 - SmartDMA_PIO3 P1_10 ALT7 - SmartDMA_PIO6 P1_11 ALT7 - SmartDMA_PIO7 P1_18 Default-PIO-Low P1_19 Default-PIO-High P2_2 ALT1 - CLKOUT P3_2 ALT2 - FC7_P0 P3_3 ALT2 - FC7_P1 P3_4 ALT7 - SmartDMA_PIO4 P3_5 ALT7 - SmartDMA_PIO5 As seen above, pins P1_4, P1_5, P1_6, and P1_7 conflict directly with Ethernet pins. Since Ethernet pins are fixed to the RJ45 PHY, the Camera interface must be reassigned to alternate pins. From the datasheet, P3_0, P3_1, P3_2, and P3_3 can serve as alternatives. However, P3_2 and P3_3 are already used for I²C. To resolve this, they are reassigned to P3_8 and P3_7 respectively (using kPORT_MuxAlt3). The updated pin mapping is shown below: Previous Pin Current Pin Pinmux Assignment P1_4 P3_0 ALT7 - SmartDMA_PIO0 P1_5 P3_1 ALT7 - SmartDMA_PIO1 P1_6 P3_2 ALT7 - SmartDMA_PIO2 P1_7 P3_3 ALT7 - SmartDMA_PIO3 P3_2 P3_8 ALT3 - FC7_P0 P3_3 P3_7 ALT3 - FC7_P1   Implementation The reassigned pins (P3_0, P3_1, P3_7, P3_8) are not exposed on the board’s headers, but the schematic shows that they are connected to test pads TP12, TP31, TP18, and TP16. The camera can be wired to these pads directly.   Pin Name Solder Pad P3_0 TP12 P3_1 TP31 P3_7 TP18 P3_8 TP16     Integrate the smartdma_camera_flexio_mculcd example from display_examples into the lwip_ping_bm project. Merge .c and .h files from board , drivers , component , and source folders. Add these folders to the include path under Project -> Properties -> C/C++ Build -> Settings -> Includes .   After integration, compile and flash the project to the board. The output is shown in the images.   Conclusion The Ethernet and Camera functions can be simultaneously implemented on the MCX N947 board. The lwip_ping_bm demo showcases ICMP-based Ping functionality using the lwIP TCP/IP stack. It periodically sends ICMP echo requests to a PC and processes the replies. The smartdma_camera_flexio_mculcd demo demonstrates how to use SmartDMA to capture image data frame-by-frame from the OV7670 camera and display it on the ST7796S LCD panel via FlexIO. By reconfiguring and multiplexing pins, simultaneous use of Ethernet and Camera on the MCX N947 is achievable.  
View full article
1. Introduction During recent customer technical support, we have find that power supply design issues frequently occur when using MCXN94X/MCXN54X products with HLQFP 100-pin packaging. To address this, we have developed this design guide specifically for 100-pin packaged chips, based on the power supply design diagrams provided in the MCX Nx4x Power Management User Guide (UG10101). Description of Package Types The MCXNx4x series currently includes three package types: VFBGA 184-pin HDQFP 172-pin HLQFP 100-pin The power supply design solutions in the User Guide(UG10101) primarily target the 172-pin and 184-pin packages. 2. Special Design Requirements for HLQFP 100-Pin Packages 2.1 Power Supply Design Solution for HLQFP 100-Pin Packages (LDO_CORE Mode) When using a 100-pin MCXNx4x chip and selecting the LDO_CORE mode (with DCDC_CORE disabled), the power supply design shall comply with the following specifications: Key Design Differences 1)Shared Power Pin Characteristics In the 100-pin package, VDD_DCDC and VDD_LDO_SYS share the same pin. When DCDC_CORE is turned off, DCDC_LX must be left floating, and the DCDC function must be disabled through software configuration. 2) Port Power Supply Design The power supply pin Vdd_p2 for PORT2 shares a single pin with VDD. The 100-pin packaged chip cannot provide independent power supply to PORT2; instead, it must be uniformly powered by VDD, consistent with the power supply configuration for PORT0/PORT1. 2.2 Power Supply Design Solution for 100-Pin Packages (DCDC_CORE Mode) If the DCDC_CORE mode is used (with LDO_CORE turned off), the 100-pin chip can directly refer to the MCX Nx4x Power Management User Guide (UG10101). However, special attention must be paid to the following: PORT2 still cannot be supplied with independent power and must adhere to the port power supply design requirements specified above. 3.Technical Support If you have any issues during the power supply design of MCXNx4x series chips, please feel free to leave a message for communication at any time.   Thanks for Yang Zhang's help with the review.  
View full article
  The MCX  N series are MCUs with an integrated flash memory like many traditional MCU series. Having an embedded flash memory is particularly useful, as facilitates board design, development, simplifies BOM, software development.  However, the size of the embedded flash might not meet applications required memory footprint. Some customers simply need more flash memory. For example, Graphical applications require store large image buffers in a non-volatile memory. Data logger devices that need to store large amounts of data. Or heavy inference models for object recognition.  Applications that need to store backup versions of their firmware or are way too complex and big. To solve this requirement the MCX N94x provides the capability to interface a great variety of wider and external memories. There are several traditional options to expand flash storage, but the one we are addressing is the use of external NOR  flash memories. To access an external memory the MCX N94x integrates modules that support external memory interfacing, those are  FlexIO and the FlexSPI. The FlexSPI module is capable of communicating with several kinds of memories. One of them is the Serial NOR flash which can be used as booting device. The goal of this article is to present the solution of a customer case scenario: How to run code from an external flash memory. Demonstrating the flexibility of the MCX N94x platform as well as introducing several tools, peripherals, and concepts that a developer will need to be familiar with while developing an application that runs from an external flash memory. The below figure illustrates the goal of this article, Run code from an external flash memory. The same hello world application can be run from the internal and external memory, for example, a NOR serial QuadSPI memory, without any functionality changes. The core simply will fetch and execute the instructions, using dedicated peripherals like FlexSPI.   Figure 1 Executing same code from internal memory vs external memory. The MCX N94x series integrates a FlexSPI module, which enables running code from an external NOR flash memory.   Figure 2 MCX N94x block diagram To follow this article, you will need the FRDM-MCXN947 Development board. Which is the evaluation board for the MCX N94x and N54x MCUs. The FRDM-MCXN947 integrates a W25Q64JVSSIQ QuadSPI flash memory. Therefore, this platform is perfect for creating an application that runs from an external flash memory. Figure 3 External NOR flash memory on FRDM-MCXN947   Boot, PFR, and SPSDK   With the boot ROM  that the MCX  N integrates you can erase, program, and read the on-chip or external flash memory, which means you can use the boot ROM to download a boot image into the on-chip or external flash memory via the ISP interfaces. This article shows how to load a customized led_blinky demo, from the SDK  to the external flash memory using the boot ROM. However, other application projects may be used as well. Also, the boot ROM takes responsibility for the boot flow. It selects whether to boot from on-chip flash memory, external flash memory, or ISP mode.  The figure below shows an extremely simplified boot flow, which gives an overall understanding of the chip boot flow.  For more details on the boot flow mechanism refer to the section Top-level boot flow of the MCX Nx4x Reference manual.   Figure 4 Simplified boot Flow After the reset handling routine, the boot ROM will take control of the chip’s boot flow. It will begin with pertinent chip’s initialization. Then will check the status of the ISP pin. If the ISP pin is currently asserted, the ISP boot handling routine will be executed. ISP or  In-system programming is an execution mode where the boot ROM will wait for commands from an external host, over protocols like UART or USB, to do actions like read and write the chip memory, burn fuses, and many more. If the ISP pin is not asserted, the boot ROM will continue to determine the boot mode. Boot mode can be controlled with the CMPA[BOOT_SOURCE] bit of the CMPA of the PFR or eFUSES. If  CMPA[BOOT_SOURCE]= 01b the boot ROM will run FlexSPI NOR boot handling routine. If CMPA[BOOT_SOURCE] is 00b or 11b internal flash memory handling routine is executed. After the boot mode selection, the image will be validated. If it is not valid, for example, is not present in memory, is corrupted, or does not have proper format,  the ISP boot handling routine is executed. If the image is valid, finally the boot ROM will perform the jump to the user´s application. The default boot flow is by internal flash, most of the SDK examples will be configured to boot from internal flash, as CMPA[BOOT_SOURCE] equals zero by default, or when CMPA area is erased. According to the Simplified bot Flow diagram, we need to make boot ROM go to FlexSPI NOR boot handling routine, to boot from the external flash. Therefore, we need to make   CMPA[BOOT_SOURCE] = 01b. The PFR holds critical boot and security settings that are monitored by the boot ROM after every reset. As just described earlier, the CMPA area can be used to control boot mode. Therefore, PFR areas need to be carefully configured, as they control boot flow and also security features of the chip. The below figure shows a very minimalistic representation of the PFR containing the CMPA, next to the internal flash.   Figure 5 PFR's CMPA area   For specific details of the PFR  please refer to the MCXNx4x_IFR.xlsx, attached to the MCX Nx4x Reference Manual. To facilitate writing into the CMPA and other areas of the  PFR, signing applications, burning fuses.  programming applications, NXP already developed several host command tools, APIs, and applications and integrated into a python tool called SPSDK. The below figure shows all the tools contained by the SPSDK. To get  details on the SPSDK and description of APIs, Applications, and tools  refer to SPSDK documentation at  https://spsdk.readthedocs.io/en/latest/spsdk.html#   Figure 6 SPSDK API modules, applications, and tools The above figure highlights 3 applications, provided by the SPSDK,  that is going to be used to configure the chip to boot from the external flash memory those are: nxpdebugmbox, PRF, and BLHOST. Detailed step-by-step usage of these applications will be described later on.  The nxpdebugmbox application sends interfaces with the chip’s debug mailbox over SWD. The purpose of this tool is set MCU into ISP mode, without having to set low ISP pin,  also to make a mass erase to the chip's memory and PFR. Once the MCU enters ISP mode the host PC will be able to communicate with the boot ROM over UART or USB protocols. This enables the use of PFR and BLHOST applications. The PFR application will be used to write the CMPA[BOOT_SOURCE] = 01b and enable FlexSPI, port to probe and let the chip communicate with the external flash, in the CMPA area of the PFR. The BLHOST application will be used to erase the chip and program application image, in this particular case,  a led_blinky demo.    External Serial NOR flash interfacing   The following terms are critical to understand how we can execute code in an external NOR flash memory with the MCX N94x. First of all, Execute-in-Place refers to the capability that the MCU core has to fetch and execute instructions directly from the external memory. It refers to the capability that an MCU has to execute code from the flash memory instead of an internal and traditional flash. To do XIP the MCX  N94x requires a capable peripheral with the ability to fetch instructions from the external memory. The FlexSPI module is capable of doing this. The FlexSPI does support several types of external memories. One of them is Serial NOR Flash. To interface the external memory with the FlexSPI supports SPI. SPI is an excellent serial protocol for short-distance and high-speed communications. The term QuadSPI could be simply understood as an implementation of the SPI protocol, where instead of having a single Data line, there are 4 data lines. SPI also supports two, and eight data lines. Flexible Serial Peripheral Interface (FlexSPI) memory controller supports connection to external serial NOR, NAND, and RAMs. It supports two SPI channels and up to four external devices. Each channel supports Single/Dual/Quad/Octal mode data transfer (1/2/4/8 bidirectional data lines). Flexible sequence engine (LUT table) to support various vendor devices (serial NOR, serial NAND, HyperBus, FPGA, etc). Memory-mapped read/write access by AHB Bus AHB RX Buffer implemented to reduce read latency. Total AHB RX Buffer size: 1024 Kbytes 8 flexible and configurable buffers in AHB RX Buffer Software triggered Flash read/write access by IP Bus IP RX FIFO implemented to buffer all read data from External device. FIFO size: 1024 Bytes IP TX FIFO implemented to buffer all Write data to External device. FIFO size: 1024 Bytes DMA support to fill IP TX FIFO DMA support to read IP RX FIFO   Figure 7 FlexSPI block diagram   FlexSPI system memory map regions are remapped to different addresses at the FlexSPI sub-module:   Figure 8 FlexSPI memory map FlexSPI can support serial devices compliant with JESD216. Pre-requisites You will need the following Hardware: FRDM-MCXN947 evaluation board. USB C cable. Windows or Linux PC. You will need to install the following Software. MCUXpresso IDE v11.9.0 or above.  FRDM-MCXN947 SDK v2.15.0 or above.  SPSDK and python.     SPSDK installation and virtual environment   We recommend to run the SPSDK on a python virtual environment, as this simplifies the installation of the SPSDK. Before proceeding with installation steps for the SPSDK we recommend to create a folder in your computer. This is where the virtual environment will be running, the SPSDK tools will be called,  and all the files generated by the SPSDK will be stored. Open a terminal, command, or Power Shell prompt  and navigate to your folder and follow the SPSDK installation  commands listed in this guide: Installation Guide — SPSDK documentation            To double check installation of the SPSDK run the following command in your virtual environment. spsdk --version         This figure shows the example of this command and the spsdk version used for this document.   Figure 9 SPSDK version.  Setup  This chapter describes all steps to generate and boot an image from the external memory.  To run the commands listed in this document you will need use your python’s virtual environment. Use the virtual environment you created during SPSDK installation.  PFR settings This section describes the settings that need to be done in the MCX N94x PFR and bootable image.        Create CMPA and CFPA yaml  templates   In the following steps, we are going to focus on editing CMPA area since it contains boot-related fields for external execution.  CFPA area is not required to be edited.            Note:The commands used to generate the templates are based on ‘pfr’ tool  For details on the capabilities of these commands, visit: User Guide - pfr — SPSDK documentation First we are going to use pfr to create our yml CMPA/CFPA templates. These templates contain only the default configurations specified for the CMPA and CFPA areas of  device. If the command run successful the templates will be generated. As shown in figure this figures   Figure 10 Yaml template created.   Edit the CMPA and CFPA yaml templates   Open CMPA   template in any text editor and follow the below steps. Set DEFAULT_BOOT_SOURCE to FLEXSPI_FLASH_XIP_0b01 Set FLEXSPI_AUTO_PROBE   to ENABLE Save the changes in the CMPA template.      Create and write the  CMPA and CFPA binaries         After editing the cmpa yaml, you will generate the CMPA/CFPA binaries from the yml templates.     Import and edit image   This section shows how to create an XIP bootable image from the  MCUXpresso SDK  led_blinky example.    Import the led_blinky demo from the SDK.  Click on “Import SDK example(s)…” (1), then search and select the FRDM-MCXN947 (2), and click “Next” (3). Inside the “SDK import wizard” search and select the “led_blinky  demo (4) and click on “Finish” (5)     Figure 11 Import the blinky example.      Once the demo project is imported open the project properties. Do a right-click in the project’s name (1), then click on “Properties” option (2) and open the project properties(3)   Figure 12 Project ´properties Navigate to the Properties> C/C++ Build > MCU settings section       Figure 13 MCU settings window Make sure that there are two  Flash areas for the external memory: QSPI_FLASH and             QSPI_FCB as shown in Figure 14. If the areas are missing add them as shown in the next step.     Figure 14 External flash areas in the linker.     Add the two flash areas for the  QSPI_FLASH and QSPI_FCB in the “Memory details” table, the move them to the Top.  Click in “Add Flash”  (1) twice, then click on “Move selected memory up in table” (2), the two newly created flash areas should be placed at the top.   Note: Moving a memory area to the top of the “Memory details” table indicates the linker that text and data should be placed preferably in that area. Update the newly created flash areas name and parameters with the ones from the below table.   Type Name Alias Location Size Driver Flash QSPI_FLASH Flash 0x80001000 0xFFFF000 MCXN9xx_SFDP_FlexSPI.cfx Flash QSPI_FCB Flash 2 0x80000400 0x400 MCXN9xx_SFDP_FlexSPI.cfx     Make sure that the flash areas match the ones shown in the Figure 15.     Figure 15 Configured flash areas    Click “Build” (1), once compilation is finished, should return 0 errors (2).   Figure 16 Successfully compiled image.                                      Note: You should see that the QSPI_FLASH section is being used and that the PROGRAM_FLASH section is not. Generate the binary. Navigate to the project’s debug folder and locate generated .axf (1). Then do a right-click in the .axf, and click on Binary utilities > Create Binary.   Figure 17 Create binary.   7 The binary should appear in the debug folder. Get  easily get the binary location by doing a right click on the binary and navigating to  “Show in>System Explorer”   Figure 18 Get created binary with ease. 8. Paste the binary into the workspace where you created the cmpa_bin.bin. This step is only to simplify the commands shown later on.   Erase and ISP mode entry        ISP (In system programming ) is a mode where a host is able to instruct the ROM bootloader to program a new image or the PFR. The which holds the CMPA field with our configuration to do XIP from the external flash memory. Basically, the Host computer sends commands to the ROM bootloader to program the PFR using NXP’s BLHOST. To enter into ISP mode there are two options: ISP pin entry and Debugger mailbox. ISP pin entry requires keeping ISP pin asserted during reset sequence and de-asserting this pin after reset has been completed. Debugger mailbox only requires to use of a SWD debugger to make the ROM entry ISP mode. To enter into ISP mode over ISP pins follow is necessary keep ISP pin asserted during reset sequence and de-assert this pin after reset has been completed. To use the debugger mailbox is only needed having a debugger. For simplicity, the communication protocol will be USB. However, UART can be used as well. Erase the flash memory and enter ISP mode using the nxpdebugmbox. Proceed to run each command nxpdebugmbox erase  nxpdebugmbox ispmode -m 0   This figure shows the expected output when running the two commands from above.   This operation will erase the contents on the internal and external flash memory. Also the PFR contents. Repeating this operation can be useful to get the chip to boot from internal flash memory. Note:  nxpdebugmbox commands need to be run using a SWD-JTAG debugger. For this example on-board debugger of the FRDM-MCXN947 is used. Ping rom Bootloader  Run the following command to ping the rom Bootloader, this way we can ensure that the device was set correctly in ISP mode. blhost  -t 2000 -p COMxxx,115200 -j -- get-property 1     Figure 19 Ping rom Bootloader From now on, an external debugger is not strictly required. The communication with the rom bootloader can be done over UART or USB. For simplicity, the UART protocol-based commands are used from now on in the rest of this document. Write  image and PFR and run demo   We are going to follow the steps to write image.  1 Write CMPA binary. pfr write -p COMxxx,115200 -t cmpa -f mcxn9xx -b cmpa_bin.bin   2 Write CFPA binary. pfr write -p COM140,115200 -t cfpa -f mcxn9xx -b cfpa_bin.bin   3 Provide FlexSPI flash memory configuration blhost  -t 2000 -p COMxxx,115200 -- fill-memory 0x20000000 0x04 0xc0000405   4 Configure and fill memory. blhost  -t 2000 -p COMxxx,115200 -- configure-memory 0x09 0x20000000 blhost  -t 2000 -p COMxxx,115200 -- fill-memory 0x20003000 0x04 0xf000000f   5 Erase flash blhost  -t 2000 -p COMxxx,115200 -- flash-erase-region 0x80000000 0x100000   6 Configure memory. blhost  -t 2000 -p COMxxx,115200 -- configure-memory 0x09 0x20003000    7 Write image. blhost  -t 2000 -p COMxxx,115200 write-memory 0x80001000 frdmmcxn947_led_blinky.bin   8 Reset. blhost  -t 2000 -p COMxxx,115200 reset You might use this command or directly press the reset button from the FRDM board. The below image shows the successful execution of each command. Your FRDM-MCXN947  should be blinking by now. Figure 20 Successful image write and reset. Once the board is reset you will notice that the loaded example will begin to execute.    Double-check execution from external flash    To double-check that the image is executing from the external flash you can use the disassembly view from MCUXpresso. 1  Attach the debugger to the running target and place a breakpoint at any part of the code.   Figure 21 Attach debugger to a running target. Once your debug probe is discovered, click “OK.”   Halt the processor execution. Use the debug button.   Figure 22 halt execution. Reset processor. Use the “Restart button”. The program should be stop at the first line of the main function.   Figure 23 Breakpoint at main. Find and open the disassembly view. Click on “Instruction Stepping Mode” button or search for disassembly. Any option will open the MCUXpresso “Disassembly” view.   Figure 24 Open "Disassembly" view Processor must be running at 0x8000_0000 address space. On the disassembly view you can check that the instructions are executed from address on the range of 0x8000_xxxx which is assigned for external flash.   Figure 25 Running code from external flash. If you want to return the device to run from internal memory, then you need to go back to default values. If there are no modifications, to the ones shown in this document,  to the CMPA and CMPA areas, the nxpdebugmbox command can be executed.      
View full article
1.Overview The NXP MCXN947 is a high-performance microcontroller that supports booting from either internal or external Flash memory. For most embedded applications, the on-chip Flash provides sufficient capacity to host both code and resources. However, in domains such as AI, image processing, or speech recognition—especially when deploying large neural network models with the eIQ toolchain—the size of the models can easily exceed the available internal Flash space. Although the MCXN947 supports executing directly from external Flash (XIP), the system typically boots from a fixed entry point in either internal or external Flash. This raises the question: can we combine the best of both worlds by booting from internal Flash while placing large resources or code segments in external Flash for direct execution? This article presents a demo implementation of exactly such a hybrid “internal boot + external XIP execution” scheme. The approach preserves fast and flexible system startup, while significantly expanding available storage capacity—ideal for hosting large AI models. Hardware Environment: Development Board: FRDM-MCXN947 Software Environment: IDE: MCUXpresso IDE v11.9.0 SDK: SDK Builder | MCUXpresso SDK Builder (nxp.com) Base Project: frdmmcxn947_tflm_cifar10 2. External Flash Hardware Configuration and Pin Assignment The FRDM-MCXN947 board integrates an external 8-line Octal Flash, connected to the MCU’s FlexSPI interface. The key pin assignments are as follows: Octal Flash Pin Function MCXN947 Connection HyperRAM Chip Pin Function Connected to MCXN947 CS SPI communication chip select signal P3_0 / FLEXSPI0_A_SS0_b SCK SPI communication clock signal P3_7 / FLEXSPI0_A_SCLK DQS SPI communication data strobe signal P3_6 / FLEXSPI0_A_DQS DQ0 OSPI data signal D0 P3_8 / FLEXSPI0_A_DATA0 DQ1 OSPI data signal D1 P3_9 / FLEXSPI0_A_DATA1 DQ2 OSPI data signal D2 P3_10 / FLEXSPI0_A_DATA2 DQ3 OSPI data signal D3 P3_11 / FLEXSPI0_A_DATA3 DQ4 OSPI data signal D4 P3_12 / FLEXSPI0_A_DATA4 DQ5 OSPI data signal D5 P3_13 / FLEXSPI0_A_DATA5 DQ6 OSPI data signal D6 P3_14 / FLEXSPI0_A_DATA6 DQ7 OSPI data signal D7 P3_15 / FLEXSPI0_A_DATA7 The configuration code begins with  /* Enables the clock for PORT3: Enables clock */ CLOCK_EnableClock(kCLOCK_Port3); const port_pin_config_t port3_0_pinB17_config = {/* Internal pull-up/down resistor is disabled */ kPORT_PullDisable, /* Low internal pull resistor value is selected. */ kPORT_LowPullResistor, /* Fast slew rate is configured */ kPORT_FastSlewRate, /* Passive input filter is disabled */ kPORT_PassiveFilterDisable, /* Open drain output is disabled */ kPORT_OpenDrainDisable, /* Low drive strength is configured */ kPORT_LowDriveStrength, /* Pin is configured as FLEXSPI0_A_SS0_b */ kPORT_MuxAlt8, /* Digital input enabled */ kPORT_InputBufferEnable, /* Digital input is not inverted */ kPORT_InputNormal, /* Pin Control Register fields [15:0] are not locked */ kPORT_UnlockRegister}; /* PORT3_0 (pin B17) is configured as FLEXSPI0_A_SS0_b */ PORT_SetPinConfig(PORT3, 0U, &port3_0_pinB17_config);   The same procedure is repeated for all FlexSPI pins. 3. FlexSPI Module Initialization To enable XIP from external Flash, the FlexSPI peripheral must be properly initialized.   3.1. Configure the FlexSPI clock /* Flexspi frequency 150MHz / 2 = 75MHz */ CLOCK_SetClkDiv(kCLOCK_DivFlexspiClk, 2U); CLOCK_AttachClk(kPLL0_to_FLEXSPI); /*!< Switch FLEXSPI to PLL0 */ 3.2 Initialize the FlexSPI driver Integrate the FlexSPI driver, which is provided in the SDK, into the project, /*Get FLEXSPI default settings and configure the flexspi. */ FLEXSPI_GetDefaultConfig(&config); /*Set AHB buffer size for reading data through AHB bus. */ config.ahbConfig.enableAHBPrefetch = true; config.rxSampleClock = EXAMPLE_FLEXSPI_RX_SAMPLE_CLOCK; config.ahbConfig.enableAHBBufferable = true; config.ahbConfig.enableAHBCachable = true; FLEXSPI_Init(base, &config); /* Configure flash settings according to serial flash feature. */ FLEXSPI_SetFlashConfig(base, &deviceconfig, FLASH_PORT); #if defined(EXAMPLE_FLASH_RESET_CONFIG) uint32_t TempFastReadSDRLUTCommandSeq[4]; memcpy(TempFastReadSDRLUTCommandSeq, FastReadSDRLUTCommandSeq, sizeof(FastReadSDRLUTCommandSeq)); #endif   4. Configure MCUXpresso Project to Support Octal Flash In MCUXpresso IDE, go to MCU Settings > Memory, and add a new memory region: Name: OSPI_FLASH (or OCTAL_FLASH) Start Address: Set according to the external flash address connected to your chip. According to the user manual, the FLEXSPI start address is 0x80000000. Size: For example, 128MB Next, select the corresponding external flash driver provided by NXP. The FRDM_MCXN947 board is connected to the mt35xu512aba flash, which supports SFDP, so we can choose MCXN9xx_SFDP_FlexSPI.cfx. After adding it, you will see the memory details displayed. 5. Add Linker Script and Migrate Model Data 5.1 Create Linker Script Fragments Add two files to the linkscripts/ folder in your project: text.ldt (for code sections) rodata.ldt (for model read-only data) Contents: <#if memory.name=="OSPI_FLASH"> KEEP (*(.model_data*)) KEEP (*(model.o*)) KEEP(*(.text.OSPI_FLASH*)) *(.text.QSPI_FLASH*) *(.text.${memory.alias}*) *(.text.${memory.name}*) </#if> This ensures that model data (e.g., the .model_data section) is properly retained and placed in the XIP (Execute In Place) region. 5.2 Place Model Data in XIP Region Use the following method to place the model into the .model_data section (in C code): __attribute__((section(".model_data"))) const unsigned char model_data[] = { #include "model_data.inc" }; 6. Build and Verify After building the project, the Image Memory Map Report in MCUXpresso IDE will show that parts of the .text and .rodata sections have been successfully placed into the Octal Flash (OSPI_FLASH) region. For example: OSPI_FLASH:      100144 B    262140 KB      0.04% After downloading and running the program, the system boots from internal Flash and successfully reads model data directly from external Flash, completing the AI inference task.   Conclusion Through the configuration steps introduced in this article, the MCXN947 successfully implements a hybrid storage solution combining internal boot with external XIP execution. This approach retains the advantage of fast boot speed while significantly expanding the available storage capacity for programs and models, providing strong support for deploying complex AI models. For resource-constrained MCU platforms, this architecture is not only a practical and feasible choice, but also represents an optimized strategy that is likely to be widely adopted in future embedded AI applications.
View full article