MCX Microcontrollers Knowledge Base

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

MCX Microcontrollers Knowledge Base

Discussions

Sort by:
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
Using external PSRAM on the MCX N FlexSPI port can enable a large degree of application flexibility. In this paper we show how to add 8MB of Octal DDR PSRAM to the MCXN947 and execute baseline performance tests.
View full article
1. Introduction The MCX C series chips are entry-level microcontrollers of MCX launched by NXP, including the MCX C04x/14x/24x/44x. They feature 16KB of Boot ROM(Except for MCXC04x, which has 8 KB), with a Bootloader pre-programmed into the ROM at the factory. This facilitates customers in updating the application code in the MCU, reducing workload and saving Flash space. After entering the ROM bootloader, operations on the device can be performed via tools such as blhost or MCUXpresso Secure Provisioning (SEC). This article will focus on how to use blhost to operate MCX C, and take the ROM Bootloader of FRDM-MCXC444 as an example for detailed introduction. For MCXC04x, some of its features differ from those of the MCXC14x/24x/44x series. For example, the MCXC04x only comes with an 8KB BOOT ROM and does not support USB communication. Therefore, some of the content in Section "2. Overview of MCX C444 ROM Bootloader" of this document (such as ROM Bootloader Location and Bootloader Pinmux) does not apply to the MCXC04x. It is recommended to refer to the product's Reference Manual for a detailed comparison of the specific differences. However, testing has shown that the "3. Operation Steps" in this document are applicable to the FRDM-MCXC041 development board.   2. Overview of MCX C444 ROM Bootloader In the ROM Bootloader chapter of the MCX C Reference Manual, detailed descriptions are provided for the functional characteristics, parameter configuration, instruction set, and Bootloader communication protocol of the ROM Bootloader. Next, I will specifically elaborate on the ROM Bootloader of the FRDM-MCXC444.   2.1. Bootloader Startup Process 2.1.1. Power-on-Reset (POR) or Normal Reset: When the device starts up, the microcontroller decides whether to enter the ROM Bootloader or directly boot from the normal FLASH according to the configuration of relevant registers. 2.1.2. Check Configuration Options: The Bootloader reads the configuration area at a specific address and determines communication interfaces, clock settings, etc., based on the parameters in it. 2.1.3. Wait for External Device Connection: After entering the Bootloader mode, it waits for external devices to connect through the specified communication interface to receive firmware update data.   Here is the startup flow chart:     2.2. ROM Bootloader 2.2.1. ROM Bootloader Location The ROM Bootloader is located within the ROM, spanning from address 0x1c00_0000 to 0x1c00_4000, with a total size of 16KB. During operation, it utilizes a portion of the RAM, as shown in the figure below.   2.2.2. Boot Process Control Factors First, let’s look at the startup process flow chart. This chart is derived from the MCX C242 Reference Manual. Although the MCX C444 Reference Manual does not provide this chart, the startup processes of the two are identical.   The Boot process is controlled by factors such as FORCEROM, BOOTPIN_OPT, BOOTCFG0 pin, and BOOTSRC_SEL. The following is a detailed introduction to each factor. 1) FORCEROM:Two bits used to always enter the ROM bootloader. If these two bits are not all zero, the system will always enter the ROM bootloader. 2) BOOTPIN_OPT:A part of the FOPT register. If this bit is zero, it enables the check for the optional bootloader enable pin (for MCX Cx4x, it is the NMI pin): if the pin is pulled low, the system will enter the ROM bootloader. 3) BOOTCFG0 pin: This is the pin enabled by the BOOTPIN_OPT setting (for MCX C, it’s the NMI pin). 4) BOOTSRC_SEL:A part of the FOPT register. If set to 10 or 11, it will enter the ROM bootloader: Based on the above content, it can be concluded that the ROM bootloader can be entered if one of the following conditions is met: 1) FORCEROM is set to a non-zero value 2) The Bootloader pin (NMI) is configured via BOOTPIN_OPT, and the pin is pulled low 3) BOOTSRC_SEL is set to 10 or 11   2.2.3. NMI pin information Next, let's take a look at the NMI pin. On the FRDM-MCXC444, the NMI pin is connected to the SW3 button. The SW3 button can be seen in the figure below.   2.2.4. Bootloader Pinmux As mentioned above, the NMI pin can be used to enter the Bootloader. Which pins can it communicate through? As shown in the reference manual, the MCX C444 can communicate via UART, I²C, SPI, and USB interfaces. These pins are predefined by the ROM bootloader and cannot be modified by the user.   2.2.5. Bootloader Configuration Area(BCA) 1) Role of BCA: The BCA stores configuration information for the Bootloader, such as the enable status of communication interfaces, clock settings, device addresses, etc. 2) Structure and Content of BCA: It is a structure located at address 0x3C0 in the FLASH, containing multiple fields. Each field corresponds to different configuration parameters. For example, there is a tag field to identify the validity of the configuration and bit fields to enable communication interfaces.   3. Operation Steps Through the above description, I believe everyone has gained a certain understanding of the ROM bootloader. Next, taking the FRDM-MCXC444 as an example, I will demonstrate step-by-step how to use blhost to update the application image in the Flash via the ROM bootloader (UART communication serial port).   3.1. Introduction to blhost The blhost is a command-line tool developed by NXP for the PC host. It realizes operations such as reading, writing, and erasing devices by sending commands to the BOOT ROM or an MCU running Flashloader, without relying on an IDE. blhost is a cross-platform tool compatible with Windows, Linux (x86), Mac, and Linux (Arm) systems. The host can directly connect to the MCU device via USB or UART, providing convenience for industrial field applications of the MCU. 3.1.1. Download link:Bootloader Host Application (blhost) 3.1.2. Blhost path:path\to\blhost_2.6.7\bin\win 3.1.3. User Guide: blhost User's Guide.pdf, you can find it in path\to\blhost_2.6.7\docs.   3.2. Enter ROM Bootloader Next, we will demonstrate the operation using UART communication. As previously introduced in the bootloader pinmux table, the LPUART0_TX/LPUART0_RX pins correspond to PTA2/PTA1 respectively. By referring to the FRDM-MCXC444 schematic diagram, you can see that these two pins are connected to the MCU-LINK Debug interface. Below are two methods to enter the ROM bootloader: 3.2.1. Mass Erase If your development board has pre-programmed firmware, you may encounter failures when attempting to enter the ROM Bootloader in subsequent operations. This is because the default configuration in the flash firmware might not be set to boot from ROM. Therefore, for boards with existing firmware, it is recommended to perform a mass erase operation before proceeding. Since the default value after flash erasure is all 1, a blank chip will automatically boot to the ROM. You can use the GUI Flash Tool in MCUXpresso IDE to perform a "Mass Erase" or choose other erasure methods. After completing the mass erase operation, simply connect a USB cable to the MCU-Link port to establish an initial connection with the ROM Bootloader.   3.2.2. Modify the FOPT Register at the Code Level In addition to using Mass Erase to enter the ROM Bootloader, you can also configure specific entry conditions through code-level settings. The following describes how to modify the FOPT register from the code. For SDK projects, this code is located in startup/startup_mcxc444.c:   Modifying the two specific bits marked in the figure above allows you to configure BOOTPIN_OPT and BOOTSRC_SEL. The exact bit mappings can be determined by inspecting the register values in debug mode. For example: 1) To set BOOTPIN_OPT to 0: Modify the value to 0xFFFF3DFE. After compiling and flashing the generated binary to the board, you can enter the ROM Bootloader via the NMI pin without performing a Mass Erase. Specifically, first hold down the SW3 button without releasing it, then connect the USB cable to the MCU-Link port, and finally release the SW3 button to establish an initial connection with the ROM Bootloader. 2) To set BOOTSRC_SEL to 10/11: Modify the value to 0xFFFFBFFE (for BOOTSRC_SEL=10) or 0xFFFFFFFE (for BOOTSRC_SEL=11). After compiling and flashing the generated binary to the board, the MCU will automatically enter the ROM Bootloader upon power-up without requiring the NMI pin. Specifically, directly connect the USB cable to the MCU-Link port to establish an initial connection with the ROM Bootloader.   3.3. View the serial port number through the Device Manager   3.4. Execute the blhost command 3.4.1. blhost -p COMx -- get-property 1 This command is used to obtain the attributes and settings of the MCU, where parameter 1 returns the bootloader version of the MCU. We use this command to test whether the connection is successful. Note:  The first command after power-up may be lost. Try again, the second attempt usually succeeds. For MCXC041 uart-ISP mode, the baud rate must be equal to or below 19200.   3.4.2. blhost -p COMx -- flash-erase-all This command is used to format the entire Flash.   3.4.3. blhost -p COMx -- write-memory 0 xxx.bin Write the bin file to the specified address. Here, we program it to the FLASH with a starting address of 0x00000000. If using an Srec file, the "flash-image" command is required. blhost -p COMx -- flash-image xxx.srec   4. Summary This article introduces the ROM Bootloader of the MCX C series and how to use the blhost tool to program the MCX C444. Later, there will also be more content on how to use the MCUXpresso Secure Provisioning Tool to update the firmware and program the BCA. Stay tuned!
View full article
1. Overview The MCXN947 chip is a highly integrated microcontroller featuring robust processing capabilities, extensive peripheral support, and advanced security features. It is suitable for a wide range of complex applications. The NXP FRDM-MCXN947 board is a low-cost design and evaluation board based on the MCXN947 device. NXP provides a comprehensive set of tools and software support for the MCXN947, including hardware evaluation boards, an integrated development environment (IDE), example applications, and drivers. Micro-ROS is an embedded version of ROS 2 specifically designed to operate on embedded systems, enabling real-time control and communication for robotics and embedded devices. It extends the powerful features of ROS 2 to resource-constrained embedded platforms like microcontrollers and embedded systems. The introduction of Micro-ROS facilitates tighter integration between embedded systems and the ROS 2 ecosystem, enabling advanced robotic automation and control. This document explores the process of porting Micro-ROS to the MCXN947 board.‌   This document explores the process of porting Micro-ROS to the MCXN947 board. Hardware Environment:     FRDM-MCXN947 Software Environment:     Ubuntu 22.04     IDE:MCUXpresso IDE v11.9.0     SDK:SDK Builder | MCUXpresso SDK Builder (nxp.com) 2. ROS 2 Architecture Before delving into the Micro-ROS porting process, let us briefly introduce the new ROS 2 architecture. This is necessary because Micro-ROS heavily leverages ROS 2's abstraction layer source code in its design and implementation. Compared to its predecessor ROS 1, ROS 2 employs a distinct communication mechanism, most notably adopting the DDS (Data Distribution Service) protocol for communication and node discovery. ROS 1, by contrast, relies on the XML-RPC protocol and requires the master node to launch before other nodes can join. ROS 1's limited support for embedded devices stems from the XML-RPC mechanism, which introduces significant software dependencies in these environments. To address this issue, projects like rosserial developed lightweight communication protocols tailored for MCU-to-PC master node communication. ROS 2, on the other hand, integrates the industry-proven DDS protocol, which has demonstrated its stability in domains like military, aerospace, and financial systems. It is important to note that DDS is a standard protocol with various implementations, such as Cyclone DDS (Eclipse), Fast DDS, and Micro XRCE-DDS (eProsima). To ensure that upper-layer ROS 2 code remains unaffected by different DDS implementations, ROS 2 defines a series of abstract layer interfaces, such as RCL (ROS Client Library) and RMW (ROS Middleware). These DDS implementations provide a uniform RMW interface. On top of RMW is the RCL, implemented in C, which supports various programming languages, including C++, Python, and Java. Thus, successfully porting ROS 2 to a real-time operating system (RTOS) hinges on the RTOS supporting a specific DDS implementation and its corresponding RMW interface. Only then can upper-layer RCL and ROS application code run without modification. ROS 2 comprises RCL (ROS Client Library), RMW (ROS Middleware Interface), and DDS (Data Distribution Service). Porting ROS 2 to a new platform essentially involves creating a compatible RMW-DDS combination, leaving the RCL layer unaltered. Micro-ROS provides such an RMW-DDS combination. Specifically, Micro-ROS employs Micro XRCE-DDS (a DDS standard designed for extremely resource-constrained environments) with a corresponding RMW implementation. This enables Micro-ROS to be compatible with ROS 2's architecture while efficiently running on resource-limited embedded devices. Thus, porting Micro-ROS to different hardware platforms fundamentally involves interfacing communication protocols like UART (Universal Asynchronous Receiver-Transmitter) and UDP (User Datagram Protocol) with the Micro-ROS RMW-DDS combination. This process ensures effective communication between Micro-ROS and other nodes or external systems while maintaining the lightweight and efficient characteristics suitable for embedded devices. From the above introduction, we can see that MicroROS transplantation mainly has two parts: Connect UART/UDP communication and clock to implement the 5 functions in default_transport.cpp. Folder DDS+RMW+RCL generates libmicroros.a static library. 3. Micro-ROS Static Library Toolchain and Environment Configuration 3.1 Micro-ROS Static Library Toolchain and Environment Configuration First, install ROS 2 on Ubuntu 22.04 LTS and run the following commands: sudo apt update&&sudo apt install locales sudo locale-gen en_US en_US.UTF-8 sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 export LANG=en_US.UTF-8 sudo apt update && sudo apt install curl gnupg lsb-release sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg (1) sudo apt update: Updates the system’s package list to fetch the latest package information. (2) sudo apt install locales: Installs the locales package, which provides tools for managing and configuring localization. (3) sudo locale-gen en_US en_US.UTF-8: Generates the localization settings for US English, including UTF-8 encoding. (4) sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8: Updates the system’s localization settings to use UTF-8 encoding for US English. (5) export LANG=en_US.UTF-8: Sets the current terminal’s language encoding to US English UTF-8. (6) sudo apt install curl gnupg lsb-release: Installs additional tools (curl for network requests, gnupg for encryption, lsb-release for distribution information). (7) sudo curl: Downloads the ROS public key for verifying package integrity.   3.2 Installing ROS on Ubuntu Set up and build the Micro-ROS development environment with the following commands: sudo apt update && sudo apt upgrade && sudo apt install ros-humble-desktop source /opt/ros/humble/setup.bash && echo “source /opt/ros/humble/setup.bash” >>~/.bashrc source /opt/ros/$ROS_DISTRO/setup.bash mkdir uros_ws && cd uros_ws git clone -b iron https://github.com/micro-ROS/micro_ros_setup.git src/micro_ros_setup rosdep update && rosdep install --from-paths src --ignore-src -y colcon build source install/local_setup.bash ros2 run micro_ros_setup create_firmware_ws.sh generate_lib (1) Update the software and install ROS (Robot Operating System) (2) Set and save the configuration of the ROS environment. (3) These two commands create a new directory uros_ws (workspace), and then switch to this directory. (4) Clone the project named micro_ros_setup from the GitHub repository and place it in the src directory of the workspace. (5) These two commands are used to install the dependencies required by the project. (6) This command uses the colcon build system to compile and install the project. Colcon is a general-purpose build tool suitable for multiple programming languages and platforms. (7) create_firmware_ws.sh: This is the name of the executable file to be run. It might be a script that creates a firmware workspace. The purpose of this command is to run the create_firmware_ws.sh script in the micro_ros_setup package and pass the parameter generate_lib to generate a firmware workspace containing the Micro-ROS library. This step requires downloading a large amount of source code from github. After failure, the next generation will prompt that the firmware already exists and you need to rm this folder. If the following picture appears, it proves that the code download is successful. 4. Generating the Micro-ROS Static Library If the toolchain and environment setup are successful, you should have five folders in your workspace: build, firmware, install, log, and src. The firmware folder contains the Micro-ROS workspace. 4.1 Configure the toolchain.cmake file according to the target processor Enter the fireware directory. The colcon.meta and toolchain.cmake inside are the configuration files we need to specify to generate the static library. Colcon.meta describes the configuration of our micro-ros, and toolchain.cmake describes the microcontroller platform. We can open MCUXpresso to find MCXN947 related configuration. and create toolchain.cmake. set(CMAKE_SYSTEM_NAME Generic) set(CMAKE_CROSSCOMPILING 1) set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) # SET HERE THE PATH TO YOUR C99 AND C++ COMPILERS set(PIX /opt/gcc-arm-none-eabi-10.3-2021.10/bin) set(CMAKE_C_COMPILER ${PIX}/arm-none-eabi-gcc) set(CMAKE_CXX_COMPILER ${PIX}/arm-none-eabi-g++) set(CMAKE_C_COMPILER_WORKS 1 CACHE INTERNAL "") set(CMAKE_CXX_COMPILER_WORKS 1 CACHE INTERNAL "") # SET HERE YOUR BUILDING FLAGS set(FLAGS "-O2 -ffunction-sections -fdata-sections -fno-exceptions -mcpu=cortex-m7 -mfpu=fpv5-d16 -mfloat-abi=hard -nostdlib -mthumb --param max-inline-insns-single=500 -D'RCUTILS_LOG_MIN_SEVERITY=RCUTILS_LOG_MIN_SEVERITY_NONE'" CACHE STRING "" FORCE) set(CMAKE_C_FLAGS_INIT "-std=c11 ${FLAGS} -DCLOCK_MONOTONIC=0 -D'__attribute__(x)='" CACHE STRING "" FORCE) set(CMAKE_CXX_FLAGS_INIT "-std=c++11 ${FLAGS} -fno-rtti -DCLOCK_MONOTONIC=0 -D'__attribute__(x)='" CACHE STRING "" FORCE) set(__BIG_ENDIAN__ 0) The above is how cmake is written. Among them, "-mcpu=cortex-m7 -mfpu=fpv5-d16 -mfloat-abi=hard": These options specify the architecture and floating point unit characteristics of the target processor. We can view the architecture and floating point unit characteristics of the MCXN947's target processor. We can open MCUXpresso IDE, open a MCXN947 project, and check mcpu=cortex-m33 -mfpu=fpv5-sp-d16 mfloat-abi=hard in All options in settings->MCU Linker. Therefore, the MCXN947 series is an M33 core. We need to change -mcpu=cortex-m7 to -mcpu=cortex-m33, and basically no other changes are needed. From this we can also see that a series of static libraries produced should be universal! 4.2 Configure the colcon.meta file according to Micro-ROS requirements The other file created sets the Micro-ROS library configurations. To set the transport layer type, here we want a custom transport layer, the configuration “-DUCLIENT_PROFILE_CUSTOM_TRANSPORT=ON” is set to “ON” and the configuration “-DRMW_UXRCE_TRANSPORT=custom” is set to “custom”. The other interesting settings are under the “rmw_microxrcedds” section. Here we can set the maximum number of nodes (1), publisher (5), subscribers (5), services (1) and clients (1) that should be supported, as well as the maximum message history (4) used for a reliable QoC mode. A more detailed description of all settings under this section, can be found in the eProsima Micro XRCE-DDS GitHub. An example configuration, the one I used, is shown below: touch colcon.meta { "names": { "tracetools": { "cmake-args": [ "-DTRACETOOLS_DISABLED=ON", "-DTRACETOOLS_STATUS_CHECKING_TOOL=OFF" ] }, "rosidl_typesupport": { "cmake-args": [ "-DROSIDL_TYPESUPPORT_SINGLE_TYPESUPPORT=ON" ] }, "rcl": { "cmake-args": [ "-DBUILD_TESTING=OFF", "-DRCL_COMMAND_LINE_ENABLED=OFF", "-DRCL_LOGGING_ENABLED=OFF" ] }, "rcutils": { "cmake-args": [ "-DENABLE_TESTING=OFF", "-DRCUTILS_NO_FILESYSTEM=ON", "-DRCUTILS_NO_THREAD_SUPPORT=ON", "-DRCUTILS_NO_64_ATOMIC=ON", "-DRCUTILS_AVOID_DYNAMIC_ALLOCATION=ON" ] }, "microxrcedds_client": { "cmake-args": [ "-DUCLIENT_PIC=OFF", "-DUCLIENT_PROFILE_UDP=OFF", "-DUCLIENT_PROFILE_TCP=OFF", "-DUCLIENT_PROFILE_DISCOVERY=OFF", "-DUCLIENT_PROFILE_SERIAL=OFF", "-UCLIENT_PROFILE_STREAM_FRAMING=ON", "-DUCLIENT_PROFILE_CUSTOM_TRANSPORT=ON", "-DUCLIENT_PROFILE_SHARED_MEMORY=ON", "-DUCLIENT_SHARED_MEMORY_MAX_ENTITIES=20" ] }, "rmw_microxrcedds": { "cmake-args": [ "-DRMW_UXRCE_MAX_NODES=5", "-DRMW_UXRCE_MAX_PUBLISHERS=6", "-DRMW_UXRCE_MAX_SUBSCRIPTIONS=4", "-DRMW_UXRCE_MAX_SERVICES=6", "-DRMW_UXRCE_MAX_CLIENTS=1", "-DRMW_UXRCE_MAX_HISTORY=4", "-DRMW_UXRCE_TRANSPORT=custom" ] } } } 4.3 Building the Micro-ROS Static Library Run the following commands: source install/local_setup.bash ros2 run micro_ros_setup build_firmware.sh $(pwd)/firmware/toolchain.cmake $(pwd)/firmware/colcon.meta If the static library is successfully generated, you will see libmicroros.a in the firmware/build file. 5. Integrating and Testing the Static Library Locally 5.1 Adding the Generated Micro-ros Static Library to the Local Project   (1) Create a folder named bsp_include. (2) Add all files from the include directory into your project under bsp_include. (3) Add all paths in the include file to the include path. (4) Add the generated libmicroros.a static library to the project, for example, add it to bsp_include.   (5) Add the libmicrorots.a static library and name path to Libraries(-l) and Library search path(-L). 5.2  Implementing the Serial Communication Interface Functions To port Micro-ROS to an MCU, you must provide transport layer functionalities for reading and writing through the communication interface. The required transport functions are defined as follows: rmw_ret_t rmw_uros_set_custom_transport( bool framing, void * args, open_custom_func open_cb, close_custom_func close_cb, write_custom_func write_cb, read_custom_func read_cb); ​ Through this structure, we can see that the communication interface function group mainly includes open, close, write, and read. open: This function is responsible for initializing (opening) peripheral devices used by the transport layer. This function is empty if the peripheral is initialized elsewhere and before the Micro-ROS function is called. close: This function is responsible for deinitializing (turning off) peripherals used by the transport layer. Because there is no need to deinitialize the function. This function is also empty. write: This function is responsible for writing data (bytes) on the peripheral device. The number of bytes to be written and the bytes themselves are given as parameters "len" and "buf" respectively. read: This function is responsible for reading data (bytes) from the peripheral device. The number of bytes to read is specified in the function parameter "len" and bytes should be returned via the function parameter "buf". bool transport_close(struct uxrCustomTransport * transport) { return true; } bool transport_open(struct uxrCustomTransport * transport) { return true; } size_t transport_write(struct uxrCustomTransport* transport, const uint8_t * buf, size_t len, uint8_t * err) { LPUART_WriteBlocking(DEMO_LPUART, buf, len); return len; } size_t transport_read(struct uxrCustomTransport* transport, uint8_t* buf, size_t len, int timeout, uint8_t* err) { LPUART_ReadBlocking(DEMO_LPUART, buf, len); return len; } Additionally, you need to implement a function to provide the system’s clock time. This clock does not have to provide real-time or world time, but rather elapsed time since startup or similar. For example: int clock_gettime(clock_t unused, struct timespec *tp) { (void)unused; IRTC_GetDatetime(RTC, &datetimeGet); tp->tv_sec = datetimeGet.second; tp->tv_nsec = (long)(datetimeGet.second) * 1000000; return 0; } 5.3 Testing To run Micro-ROS in practice, the setup includes two components: 1. A client running on the MCU. 2. An agent running on the host PC. Basic Micro-ROS Client (MCU) Below are the minimal steps and code needed to create and run a Micro-ROS client. These instructions are based on the Micro-ROS documentation for node creation. //Required global variables rcl_allocator_t allocator; rclc_support_t support; rcl_node_t node; rclc_executor_t executor; rmw_ret_t error; //Set Communication functions rmw_uros_set_custom_transport( true, NULL, rtt_transport_open, rtt_transport_close, rtt_transport_write, rtt_transport_read ); //Set Allocation functions (Optional) rcl_allocator_t allocator = rcutils_get_zero_initialized_allocator(); allocator.allocate = rtt_allocate; allocator.deallocate = rtt_deallocate; allocator.reallocate = rtt_reallocate; allocator.zero_allocate = rtt_zero_allocate; (void)!rcutils_set_default_allocator(&allocator); //Get allocator allocator = rcl_get_default_allocator(); //Create init_options error = rclc_support_init(&support, 0, NULL, &allocator); //Create node error = rclc_node_init_default(&node, "uROS_Terminal", "", &support); //Create executor error = rclc_executor_init(&executor, &support.context, 1, &allocator); //Call the executor periodically e.g. in the while(1) loop or a thread: while(1) { error = rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100)); } ​ Setting up the Micro-ROS Agent (PC) The agent establishes an interface between the Micro-ROS client on the MCU and ROS 2 on the host PC. To set up the agent: # Go to the Micro-ROS workspace folder cd microros_ws # Source ROS 2 source /opt/ros/humble/setup.bash # Source local packages source install/local_setup.bash # Create Agent ros2 run micro_ros_setup create_agent_ws.sh # Build Agent ros2 run micro_ros_setup build_agent.sh # Possible ROS Update sudo rosdep init rosdep update  After successfully building the Micro ROS agent, the following bash command starts/runs the agent: # Go to the Micro-ROS workspace folder cd microros_ws # Source ROS 2 source /opt/ros/humble/setup.bash # Source local packages source install/local_setup.bash # Run Agent (serial connection) ros2 run micro_ros_agent micro_ros_agent serial --dev /dev/ttyACM0 Of these bash commands, the last one is the one that actually starts the Micro-ROS agent. It takes several parameters, the first is the type of connection to use, in this case a serial connection. Then there are two parameters that only apply to serial connections: "--dev/ttyACM0", which sets the serial interface to be used (to list all serial interfaces in linux, you can use the following bash command: "dmesg | grep tty".) After starting the Micro-ROS agent, the MCU can connect to the host PC via the serial interface and reset to establish a new connection. If the following Micro-ROS agent terminal output: This proves the success of transplanting Micro-Ros On Frdm-mcxm947.
View full article
NXP officially launched the MCX C series chips in July 2024. As a Cortex-M0+ MCU with high cost-effectiveness, energy efficiency, and security, it strongly supports the upgrade of traditional 8-bit and 16-bit designs. Since its release, the chip has gained rapid favor among customers, with many projects now entering mass production. In practical applications, more and more customers have inquired about how to enter the ISP mode of MCX C series chips and complete firmware updates. We have previously introduced the method using the blhost tool (see MCX C: How to Enter the ROM Bootloader to Update the Firmware - NXP Community). It is worth noting that the MCUXpresso Secure Provisioning (SEC) tool now supports MCX C series chips starting from version 25.03. The operation process is described in detail below. Refer to the attached PDF file for details.
View full article
Introduction This article describes the method to update the Boot ROM patch on MCX N94x / N54x devices to patch version T1.1.5.   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.  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 N94x / N54x 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.1.5 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_n10_a1_prov_fw_rp_v5.0.sb3.  7) Repeat steps 1 - 5 to verify that the ROM version is T1.1.5.  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.1.5 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_n10_a1_prov_fw_rp_v5.0.sb3 7) Repeat steps 1 - 5 to verify that the ROM version is T1.1.5.         
View full article
MCUXN947 Security Configuration (Secure Boot + Lifecycle)   1. Introduction This application note aims to guide developers on configuring Secure Boot and Lifecycle on the MCXN947 microcontroller. The goal is to ensure security during mass production, prevent code theft and tampering, and allow for secure firmware updates. By following this document, developers can better understand and implement best practices for secure boot and firmware updates. 2. Implementation Overview 2.1 Secure Boot (SB) Introduction The Secure Binary (SB) container brings secure and easy way to upload or update firmware in embedded device during either the manufacturing process or end-customer's device lifecycle. An SB file is a command-based firmware update image. The SB file can be considered a script (commands and data), with the ROM acting as the interpreter. The ROM supports version 3.1 of the SB image format. The SB container in version 3.1 (SB3.1) uses the latest cryptographic algorithms to ensure the authenticity and confidentiality of the carried firmware. The boot time and security level, which fit the best for the required use case, control the various available security configurations. The digital signature based on Elliptic Curve Cryptography (ECC) ensures the authenticity of the SB3.1 container. The use of the Advanced Encryption Standard (AES) in Cipher Block Chaining (CBC) mode ensures the confidentiality of the SB3.1 container. 2.2 Lifecycle Introduction The lifecycle state of a chip reflects its actual state and is used to guide how the chip protects its hosted assets at specific times. For example, when a project is completed, during mass production, or when the device is in use by the end customer, the chip's access permissions are much more restricted compared to the development stage. The MCXN947 microcontroller supports multiple secure lifecycle states. For detailed information, refer to the "Lifecycle States" chapter in the MCX Nx4x Security Reference Manual. Note that the lifecycle state is monotonic, meaning it can only increase, and access permissions become more restrictive. This document focuses on field configuration (In-field) to ensure security after deployment. 2.3 MCUXpresso Tool Introduction The MCUXpresso Security Configuration Tool is a GUI-based application that simplifies the generation and configuration of bootable executable files on NXP MCUs. This tool can be used to generate SB3.1 files and deploy MCU security configurations. 3. Implementation Steps 3.1 Preparation Software Two image files: frdmmcxn947_led_blinky_red.s19 and frdmmcxn947_led_blinky_green.s19 MCUXpresso Secure Provisioning Tool v9.0 (SPT Tool) Blhost Hardware FRDM-MCXN947 Development Board 2 USB Type-C Cables Computer 3.2 Steps 3.2.1 Restore MCU to Default Configuration Power on MCU with ISP Mode Hold the ISP key and power on the MCU (POR). This document uses the ISP-USB interface, so connect the USB cable to J11 (HS-USB) port. Configure CMPA and CFPA to Default State Open the SPT Tool, create a new workspace, and select the corresponding chip. Configure as follows:   Program CMPA and CFPA OK -> Build image, Write image, to burn the configured default CMPA and CFPA into the MCU. Erase Entire Flash Connect the board's debugging interface MCU-link via USB. Select the debug probe in the SPT Tool. After a successful connection, use Erase to erase the entire flash. The chip is restored to its default state with no enabled security configurations. 3.2.2 Configure Secure Boot and Lifecycle for Field Mode (In-field)  Generate Secure Boot Keys Select the PKI management interface -> Generate Keys... -> Generate   Configure Image File Open the "Build image" interface and configure as follows: Boot: Select Encrypted (PRINCE/IPED) and signed Source executable image: Select the application image file frdmmcxn947_led_blinky_green.s19 Start address: 0x00000000 Firmware version: 1 Authentication key: Choose any one of the 4 options CUST_MK_SK: Click Random to generate a random number OEM seed: Click Random to generate a random number   Configure CMPA and CFPA Open CMPA and CFPA, and configure to enable security: Generate Configuration Files and Image File After configuration, build the image to generate CMPA, CFPA configuration files, and the SB3-formatted image file.   3.2.3 Program Application Program Configuration Files and Image File Open the "Write image" window, click "Write image" to program the configuration files and the SB image file.   Verify Application Power on the board again, and you should see the green LED flashing, indicating that the application is running normally. Then, hold the ISP key and perform a software reset of the board (note that this must be a software reset for the CFPA lifecycle configuration to take effect; a power-on reset will not activate the CFPA configuration). If the development is complete and in the production stage, and OTP is used to manage the lifecycle, any reset will detect the OTP configuration. At this point, secure boot is enabled, and the lifecycle is configured for field mode. Therefore, the chip no longer supports SWD interface debugging or reading flash content via ISP. To update the flash program, only a valid SB3 file can be burned. 3.2.4 Update Application Create a New SB3 File Compile the SDK example frdmmcxn947_led_blinky to generate a .bin file or s19 file. For all supported formats by the SPT tool, refer to the SPT manual. Here, use the s19 file format frdmmcxn947_led_blinky_red.s19. Open the SPT tool and use the workspace created for the first application image file. This will import the necessary keys directly. Then, import frdmmcxn947_led_blinky_red.s19. The Image firmware version should be greater than 0. Since we have not configured Set minimal firmware version, the minimum version is 0. This involves the anti-rollback feature, which will be explained in detail later. After configuration, hold the ISP key and power on the board to restart. Then, build the image to generate frdmmcxn947_led_blinky_red.sb. Program the New SB3 File Use the blhost receive-sb-file command to burn the file: blhost.exe -u 0x1fc9 0x014f receive-sb-file frdmmcxn947_led_blinky_red.sb After burning, restart the MCU. The red LED flashing indicates that the firmware update was successful. 3.2.5 Verify Security Features After enabling secure boot and configuring the lifecycle for field mode, the MCU cannot read the flash via SWD or ISP, ensuring the security of the customer's code against theft and tampering. To test if the configuration is successful, you can use the SWD and ISP interfaces. You should find that the SWD interface cannot connect, and while the ISP interface can connect, it cannot read or write. Note that before testing, you need to hold the ISP key and perform a software reset (not a power-on reset).     4. Notes By following this document, developers can learn how to configure and manage the security lifecycle on the MCXN947 microcontroller, ensuring the security and reliability of the device at different stages. Following the steps in this document can effectively achieve secure boot and operation, as well as firmware updates.  
View full article
In most cases, C project is generated and used. But assembly project has it’s own advantage, with assembly project, you can program with assembly language directly, can test assembly instruction with assembly mnemonic. Generally, C language is inefficient, so in order to test the performance of the core, or get peripheral highest performance, the assembly project is required. The doc discusses the procedure to create an assembly language project, in the end, gives an example to toggle a LED, which demos how to initialize the NVIC, CTimer, GPIO with assembly language. It also gives the example of subroutine.   1. The procedure to create an assembly language project based on MCUXPresso tools 1.1 Load MCUXPresso tools and drag SDK to the Installed SDK menu Then click “Create a new C/C++ project”   1.2 Select the board or processor, then clock “Next” software button   1.3 Name the project and Select the driver. In the menu, it is okay to use default configuration, then clock “Finish”   1.4 A New project called MCXN947_project is created with C language   1.5 Delete the MCXN947_project.c and add the main.s Click the “source” group with right mouse button, the click “New”->”source File”   1.6 Add the main.s as the following Fig and click “Finish”   1.7 The final project is like:   2.0 writing the assembly code in the main.s This is the code in main.s /* This assembly file uses GNU syntax */ .equ SYSCON_ANGCLKCTRLSET0,0x40000220 .equ SYSCON_AHBCLKCTRLSET1,0x40000224 .equ SYSCON_AHBCLKCTRLSET2,0x40000228 .equ SYSCON_CTIMER4CLKSEL, 0x4000027C .equ SYSCON_CTIMER4CLKDIV, 0x400003E0   /*PIO3_4 LED blue*/ .equ PORT3_PCR_BASE,0x40119000 .equ PORT3_PCR4,PORT3_PCR_BASE+0x90   .equ GPIO3_BASE,0x4009C000 .equ GPIO3_PDDR,GPIO3_BASE+0x54 .equ GPIO3_PDOR,GPIO3_BASE+0x40     /*PIT configuration*/ .equ CTIMER4_BASE,0x40010000 .equ CTIMER4_IR,CTIMER4_BASE+0x00 .equ CTIMER4_TCR,CTIMER4_BASE+0x04 .equ CTIMER4_MCR,CTIMER4_BASE+0x14 .equ CTIMER4_MR0,CTIMER4_BASE+0x18 .equ CTIMER4_MSR0,CTIMER4_BASE+0x78 .equ CTIMER4_PWMC,CTIMER4_BASE+0x74     /*NVIC configuration*/ /*refer to 4.2 Nested Vectored Interrupt Controller in Cortex-M4 Generic User's Guide.pdf*/ .equ NVIC_ISER0,0xE000E100 .equ NVIC_ISER1,0xE000E104   .equ NVIC_ICPR0,0xE000E284 .equ NVIC_ICPR1,0xE000E288   .equ NVIC_IPR12,0xE000E430 .equ NVIC_IPR14,0xE000E438           .global __user_mem_buffer1,__user_mem_buffer2     .text     .section   .rodata     .align  2     .LC0:       .text     .thumb     .align  2     .global main     .global CTIMER0_IRQHandler     .type main function   main:     push {r3, lr}     add r3, sp, #4     nop     BL peripheralInit     nop     nop     nop     nop     NOP     /*cpsie i*/ loop:     b loop     mov r3, #0     mov r0, r3     pop {r3, pc}     /*subroutine 1*/ /* copy 10 words from one place to another*/     .type MyFunc function     .func MyFunc:     push {r0,r1,r2,lr}     MOV R2,#0x00     LDR R0,=USER_MEM_BUFFER1     MOV R1,#0x00 loop1:     NOP     STR R1,[R0]     ADD R1,#0x10     ADD R0,#4     ADD R2,#1     CMP R2,#0x10     BNE loop1     AND R5,R1,R5 ;     ASR R3,R2,#1     ORR R5,R1,R5     ADD R3,R2,R3     ADC R3,R2,R3     AND R2,R1,R2 ; /*#0x0F*/     LDR R0,=0x1234     /*LDR R0, [R1], #4*/     nop     pop {r0,r1,r2,pc}     .endfunc /***************************************/   /*subroutine 2*/     .type peripheralInit function     .func peripheralInit:    //enable CTimer4 gated clock     LDR R0,=0x400000     LDR R1,=SYSCON_AHBCLKCTRLSET2     nop     STR R0, [R1]       MOV R0,#0x03 //select     LDR R1,=SYSCON_CTIMER4CLKSEL     nop     STR R0, [R1]         MOV R0,#0x09 //select     LDR R1,=SYSCON_CTIMER4CLKDIV     nop     STR R0, [R1]     /*setting CTimer0*/       //set Ctimer0_IR     MOV R3,#0x01     LDR R1,=CTIMER4_IR     Nop     LDR R2,[R1]     ORR R2,R2,R3     STR R2,[R1]     //set CTIMER4_MCR     MOV R3,#0x03     LDR R1,=CTIMER4_MCR     LDR R2,[R1]     ORR R2,R2,R3     STR R2,[R1]         LDR R0,=6000000     LDR R1,=CTIMER4_MR0     STR R0,[R1]       LDR R0,=6000000     LDR R1,=CTIMER4_MSR0     STR R0,[R1]         MOV R0,#00     LDR R1,=CTIMER4_PWMC     STR R0,[R1]       nop     nop //lop1: //  b lop1         /*setting interrupt, Ctimer4 IRQ 56*/     LDR R1,=NVIC_ISER1     LDR R0,[R1]     LDR R3,=0x01000000     ORR R0,R0,R3     STR R0,[R1]       LDR R1,=NVIC_ICPR1     LDR R0,[R1]     LDR R3,=0x01000000     ORR R0,R0,R3     STR R0,[R1]       MOV R0,#0x00     LDR R1,=NVIC_IPR14     STR R0,[R1]       /*pin mux setting*/     /*enable PORT3 and GPIO3 gated clock*/     LDR R0,=0x410000     LDR R1,=SYSCON_ANGCLKCTRLSET0     nop     STR R0, [R1]     /*set the GPIO3_4 as GPIO output mode*/     LDR R0,=#0x1000     LDR R1,=PORT3_PCR4     STR R0,[R1]         LDR R1,=GPIO3_PDDR     LDR R0,[R1]     LDR R3,=0x10     ORR R0,R0,R3     STR R0,[R1]       /*CTimer4 start*/     MOV R3,#0x01     LDR R1,=CTIMER4_TCR     LDR R0,[R1]     ORR R0, R0,R3     STR R0,[R1]     nop     nop     nop     /*cpsid i*/     BX LR     .endfunc /*********************************************/   /*subroutine 3*/     .text     .type testcal function     .func testCal:     LDR R0,=0x12345678     MOV R1,#0x0F     AND R0,R1     /*test saturation function*/     LDR R0,=0x8234     LDR R1,=0x8234     /*ADDS R5,R0,R1*/     QADD16 R6,R0,R1  /*saturation heppen, the R6 will become negative minumum 0x8000*/     nop     /***8888888*/       LDR R0,=0x6234     LDR R1,=0x6234     /*ADDS R5,R0,R1*/     SADD16 R6,R0,R1     nop     QADD16 R6,R0,R1 /*saturation heppen, the R6 will become negative minumum 0x7FFF*/     nop     SMUAD R6,R0,R1     BX LR     .endfunc /*********************************************/   /*interrupt service routine*/     .global CTIMER4_IRQHandler     .text     .align 2     .type CTIMER4_IRQHandler function     .func CTIMER4_IRQHandler:         /*clear interrupt*/     push {R0,R1,LR}     nop     nop     nop     LDR R1,=CTIMER4_IR     LDR R0,[R1] /*dummy reading*/     MOV R4,#0x10;     ORR R0,R0,R4     STR R0, [R1]     /*toggle a LED*/     LDR R1,=GPIO3_PDOR     LDR R0,[R1]     LDR R3,=0x10     EOR R0,R0,R3     STR R0,[R1]     NOP     POP {R0,R1,PC}     .endfunc     /******************************************************/ /*interrupt service routine*/     .global SVC_Handler     .text     .align 2     .type SVC_Handler function     .func SVC_Handler:     push {R0,R1,LR}            NOP     POP {R0,R1,PC} /******************************************************/       .align  2 .L3:     .word       .align 4     .section .contantData HELLO_TXT:     .space 0x100 Hello_END:     .ALIGN 4   /*.lcomm */   .lcomm USER_MEM_BUFFER1  0x100   .lcomm USER_MEM_BUFFER2  0x100     .end   3.0 code explanation   In the code, you have to define the main function, after the core has executed the code ResetISR(void), which is defined in startup_mcxn847_cm33_core0.c, it jump to main() function   The example code implement the function to initialize CTimer, GPIO and NVIC, SYSCON module so that the CTImer can generate interrupt, in the ISR of CTimer, a LED is toggled. After you run the code, you can see that the led is toggled. The peripheralInit Subroutine is used to initialize the CTimer, NVIC, GPIO, SYSCON module so that the CTimer can fire an interrupt and toggle a LED.The CTIMER4_IRQHandler is an ISR of CTimer4, which is defined in startup_mcxn847_cm33_core0.   The MyFunc function and testCal  Subroutines are just for testing a specific assembly instruction, and test how to establish and call a subroutines, they do not have a specific target.
View full article
Sometimes connecting things requires a lot of cables because the component you need alone doesn't have the correct connector to mount on an evaluation board.   A few weeks ago, we needed to connect this display Adafruit 1.54" 240x240 Wide Angle TFT LCD Display to some FRDM boards. We started using cables but ended up making a small card to mount the board and plug it directly into the PMOD port of the FRDM board.   We decided to make it available in case you have the same problem 😊   Adafruit 1.54" 240x240 Wide Angle TFT LCD Display PMOD Adapter Gerber files for fabrication are here Final Assembly   3D render     This is how it looks connected to a FRDM-RW612 board  enjoy!    
View full article
The open source hardware community is please to offer ECAD schematic symbols for the new MCX A153 and MCX N947 microcontrollers.     The MCX A153 schematic library has the QFP32, QFN48 and LQFP64 variants. The MCX N947 schematic library has the BGA184 and LQFP100 variants. The symbols were generated using data from the MCUXpresso Pin Config tool to ensure accuracy. The pin names include all pin mux options to make it easy to see all available peripheral functions and further simplify the symbol for your own design purpose The symbol data is provided in the open source KiCad V7 format and is attached to this post. The symbols can be imported into commercial tools such as Altium Designer. Enjoy!  
View full article
An open-source PCB template for creating a custom shield for the FRDM-MCXA153  
View full article
An open-source PCB template for creating a custom shield for the FRDM-MCXN947  
View full article
FRDM Boards Enclosures (3D Print)   Hi NXP FRDM enthusiasts! we want to share some 3D files that you can use to 3D print your own enclosures for the FRDM-MCX family!    FRDM-MCXN947 case step files are here   FRDM-MCXA153 case step files are here   FRDM-MCXW71 case step files are here
View full article
1. RS485 hardware connection RS-485 is a multiple drop communication protocol in which the LPUART transceiver's driver is three-stated unless LPUART is driving. The transmitter can uses the RTS_B signal to enable the driver of a transceiver. The polarity of RTS_B can be configured by firmware to match with the polarity of the transceiver's driver enabling signal. The following figure shows the receiver enabling signal asserted. This connection can also connect RTS_B to both DE and RE_B. The transceiver's receiver is disabled when the uart transmitter is sending char. A pullup can pull RXD to a non-floating value during this time. You can refine this option further by operating LPUART in Single-Wire mode, freeing the RXD pin for other uses.     When the uart transmits character via TXD pin, the RTS_b signal is asserted automatically, after the RS-485 transceiver, the urat transmitter can drive the differential signals Y/Z. When the uart dose not transmit character, the RTS_b signal is unasserted, so the RS-485 transceiver is in tr-state, the differential signal Y/Z is NOT driven by this RS-485 transceiver. For receiver part of the RS-485 transceiver, if the RTS_b sigbal is connected to the RE_b pin of receiver of RS-485 transceiver directly or via an inverter depending on the required logic of the RS-485 transceiver , when the uart transmits character, the receiver of  RS-485 transceiver is disabled, the RO pin of the RS485 is in tri-state, so a pull-up resistor is required on the RO pin and the RXD pin of LPUart can not receive any character from it’s own transmitter.  The RTS_B signal can function as hardware flow control, but note the application uses RTS_b signal to control RS485 enabling instead of hardware flow control. )   2. RTS_b pin assigmnet.   For the uart module of MCXN family, the FCx_P0 is RXD pin of UARTx module, the FCx_P1 is TXD pin of UARTx module, the FCx_P2 is RTS_b of UARTx module. For MCXN94x family, the P1_8 pin can function as FC4_P0 or RXD pin of UART4; the P1_9 pin can function as FC4_P1 or TXD pin of UART4; the P1_22 pin can function as FC4_P2 or RTS_b pin of UART4 with setting up PORT1_PCR22[MUX] bits as decimal 3;   3)software 3.1 pin assignment void BOARD_InitPins(void) {     /* Enables the clock for PORT1: Enables clock */     CLOCK_EnableClock(kCLOCK_Port1);       const port_pin_config_t port1_8_pinA1_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 FC4_P0 */                                                     kPORT_MuxAlt2,                                                     /* Digital input enabled */                                                     kPORT_InputBufferEnable,                                                     /* Digital input is not inverted */                                                     kPORT_InputNormal,                                                     /* Pin Control Register fields [15:0] are not locked */                                                     kPORT_UnlockRegister};     /* PORT1_8 (pin A1) is configured as FC4_P0 */     PORT_SetPinConfig(PORT1, 8U, &port1_8_pinA1_config);       const port_pin_config_t port1_9_pinB1_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 FC4_P1 */                                                     kPORT_MuxAlt2,                                                     /* Digital input enabled */                                                     kPORT_InputBufferEnable,                                                     /* Digital input is not inverted */                                                     kPORT_InputNormal,                                                     /* Pin Control Register fields [15:0] are not locked */                                                     kPORT_UnlockRegister};     /* PORT1_9 (pin B1) is configured as FC4_P1 */     PORT_SetPinConfig(PORT1, 9U, &port1_9_pinB1_config);       //* PORT1_22 (pin L4) is configured as FC4_P2 with ALT3*/       const port_pin_config_t port1_22_pinC3_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 FC4_P1 */                                                        kPORT_MuxAlt3,                                                        /* Digital input enabled */                                                        kPORT_InputBufferEnable,                                                        /* Digital input is not inverted */                                                        kPORT_InputNormal,                                                        /* Pin Control Register fields [15:0] are not locked */                                                        kPORT_UnlockRegister};        /* PORT1_9 (pin B1) is configured as FC4_P1 */        PORT_SetPinConfig(PORT1, 22U, &port1_22_pinC3_config); }   The   //P1_22 function as RTS_b signal void RTS_b_init(LPUART_Type *base) {  base->MODIR |=LPUART_MODIR_TXRTSE(1); //                   (((uint32_t)(((uint32_t)(x)) << LPUART_MODIR_TXRTSE_SHIFT)) & LPUART_MODIR_TXRTSE_MASK)   }   4)uart timing tested by scope   Conclusion: From the above scope screen shot, you can see that when the uart transmitter sends char, the RTS_b signal becomes low, so it can function as RS485 transceiver enabling signal.  
View full article
The Serial Peripheral Interface (SPI) is ubiquitous in embedded systems for interfacing to external peripherals such flash memories, EEPROMs, analog to digital converters and sensors. SPI controllers are essentially shift registers. When combined with DMA, SPI can be used for interesting use cases. In this paper we will look at an LED lighting application and hint at some other interesting use cases such as PDM audio streams.
View full article
The NXP MCXA153 is a useful microcontroller for small, embedded USB devices. Combined with the USB stack built into the SDK, or with the open source TinyUSB stack,  it is easy to creak your own USB protocol bridges and test tools. In this paper we showed to how to integrate TinyUSB into an MCUXpresso project and demonstrated  with a USB CDC / WebUSB application for a BLDC Motor controller test application.
View full article
The table below contains notable updates to the current release of the Reference Manual. The information provided here is preliminary and subject to change without notice. Affected Modules Issue Summary Description  Date MCXNx4x Pinout xlsx Attachment Defeature PF* pins Erroneous pinouts to PF* signals on ALT11 are removed.  Before:    After:    01 March 2024 System Boot ROM API Missing Boot Modes sections in ROM API chapter of System Boot New sections added: 15.3 Boot modes 15.3.1 Master boot mode Master boot mode supports the following boot devices: Internal flash memory boot FlexSPI NOR flash memory boot SPI 1-bit NOR recovery boot Secondary bootloader boot Table 229. Image offsets for different boot media   Boot media Image offset Internal flash memory boot 0h FlexSPI NOR flash memory boot 1000h SPI 1-bit NOR recovery boot 0h Secondary bootloader boot 0h   15.3.2 Secondary bootloader mode   The Secondary bootloader mode can be enabled by setting the CMPA[BOOT_SRC] as 2, the image loaded in the Bank1_IFR0 region (0x0100_8000 to 0x0100_FFFF) will be set as primary boot mode, and the secondary boot image will boot first after the device reset. The secondary boot image type can be plain, crc or signed image, but cannot set as the SB file.   Based on the CMPA[OEM_BANK1_IFR0_PROT](0x01004004[5:7]) setting, after the secondary boot image boot, the Bank1_IFR0 region will be configured with different MBC setting:   Lifecycle CMPA[OEM_BANK1_IFR0_PROT] Secondary bootloader mode MBC IFR0 recovery boot MBC Develop (0x3) NA GLABC0 GLBAC0 Develop2 (0x7), In-field (0xF), In-field Locked (0xCF), Field Return OEM (1F) 0 GLBAC4 GLBAC4   1 GLBAC4 2 GLBAC2 3 GLBAC6 4 GLBAC4 5 6 7     01 March 2024 Input Multiplexing (INPUTMUX) Clarification to CMP trigger input registers Update to the CMPx_TRIG Register function description for the following registers: CMP0_TRIG (260h), CMP1_TRIG (4EOh), and CMP2_TRIG (500h)  Before:  Function This register selects the CMPx trigger inputs   After: Function This register selects the CMPx SAMPLE/WINDOW input 01 March 2024  
View full article
Introduction The MCX N has a Programmable Logic Unit (PLU) capable of creating combinational and sequential logic circuits that operate independently of the cores. The PLU does this by preprogramming look up tables or LUTs that dictate the behavior of designated outputs for all inputs of the PLU. The features of the MCX N PLU module includes: An array of 26 inter-connectable, 5-input look-up table (LUT) elements. 4 flip-flops. Six primary inputs pins. Eight primary output pins. An external clock to drive the four flip-flops if a sequential network is implemented. Capability to generate interrupts and wakeup requests from Sleep and Deep Sleep modes.   Module architecture The PLU is composed of 3 main elements: Look Up Tables (LUTs), Multiplexers and Flip Flops. Look Up Tables are used to create the actual logic of the PLU’s network, while multiplexers route these logic signals to and from other LUTs, as well as the PLU’s input and output pins. Flip Flops provide a method of gating logic signals from LUT elements to a shared clock input, adding a mechanism of synchronization and delay to the logic network.   Look Up Table (LUT) The PLU module has 26 inter-connectable Look Up Tables (LUTs), which can implement any combinational function with up to five inputs at once. The LUTs work by storing a pre-programmed output for every combination of inputs. This allows the look up tables to reproduce a specific output of logical 0 or 1 as soon as the input is changed without any processing required. By interconnecting LUT elements with one another, more complex programmable networks can be achieved, providing functionality of many logic gates at once.   Multiplexers The PLU module includes a variety of multiplexers that select the inputs and outputs for each Look Up Table (LUT) element. Each LUT element has 5 input multiplexers that route a signal to each of its 5 inputs. The available input signals for each LUT include: PLU Input pads. Other LUT element outputs. State Flip Flop outputs.   The PLU also has one output multiplexer for each PLU output pad (eight in total) that selects what Look-Up Table or Flip Flop state will drive each output pad.   Flip Flops The final PLU element is a type D flip flop that allows for retention of data, providing the means for sequential logic circuits and simple state machines.   The PLU module has 4 flip flops that are connected to the outputs of LUTs[3:0] as well as the external PLU_CLKIN signal that is used for timing and synchronization between flip flops. In order to use the flip flop elements, a clock signal must be supplied via the PLU_CLKIN pad. Note that since the flip flops are directly connected to the outputs of the first 4 LUT elements, the corresponding LUT elements must be set up in order to use each Flip Flop element.     PLU Setup The following steps must be done in order to achieve a logic network on the PLU module: Enable clocks for the PLU using the SYSCON_SYSAHBCLKCTRLx register and then toggle the PLU Reset bit from the SYSCON_PRESETCTRLx register. Assign pins using the PORTx_PCRn registers. Create logic network using the following steps: Write the logic behavior in the truth table register for each of the LUT elements that will be used. Program the input multiplexer registers to select the source of up to five inputs presented to each LUT. Program the output multiplexer register to select up to eight primary outputs from the PLU module. (Optional) Set the wakeup behavior by using the WAKEINT_CTRL register to select the outputs to be used as wakeup sources, as well as setting a deglitching method.   Creating logic networks Basic logic gates With a simple configuration of two inputs and one output on a single LUT element, all of the basic logic gates can be achieved. This would be achieved, for example, using a configuration of PLU_IN0 and PLU_IN1 pads as inputs and PLU_OUT0 pad as output for LUT0.   The first step of creating any logic network is to understand the truth table of the desired logic circuit. For a single AND gate using the previous configuration, the truth table would equate to the following: #   PLU_IN1 PLU_IN0 PLU_OUT0 0   0 0 0 1   0 1 0 2   1 0 0 3   1 1 1   The LUT would have to be set up in a way were the output is HIGH only when PLU_IN1 and PLU_IN0 are both HIGH, which is coincidentally the third combination of the LUT inputs for the previous truth table. Therefore, we need to program the LUT to output HIGH for combination #3. We can program this logic gate by writing a '1' on bit number 3 of the LUT’s truth table register. This way, when both LUT0 inputs are HIGH, the LUT element will “look up and find” a ‘1’, so it will output HIGH. On the other hand, for every other combination it will find a ‘0’ and output LOW. Combination # (Input) Truth table register (Output) 0 (0b00) 0 1 (0b01) 0 2 (0b10) 0 3 (0b11) 1   Taking this into account, it is easy to see that all the LUT element does is "look up" each combination of inputs on a predefined table to know what logic to output. This table is programmed via the 32 bit LUTa_TRUTH register for each LUT element. The 32 bit value required for the previous logic gate expressed in hexadecimal would then be as follows: AND gate LUT inputs[1:0] 11 10 01 00     LUT0_TRUTH 1 0 0 0 → 0x00000008 And, for the rest of the basic logic gates: OR gate LUT inputs[1:0] 11 10 01 00     LUT0_TRUTH 1 1 1 0 → 0x0000000E   XOR gate LUT inputs[1:0] 11 10 01 00     LUT0_TRUTH 0 1 1 0 → 0x00000006   NAND gate LUT inputs[1:0] 11 10 01 00     LUT0_TRUTH 0 1 1 1 → 0x00000007   NOR gate LUT inputs[1:0] 11 10 01 00     LUT0_TRUTH 0 0 0 1 → 0x00000001   XNOR gate LUT inputs[1:0] 11 10 01 00     LUT0_TRUTH 1 0 0 1 → 0x00000009   NOT gate LUT inputs[0] 1 0     LUT0_TRUTH 0 1 → 0x00000001   Buffer gate LUT inputs[0] 1 0     LUT0_TRUTH 1 0 → 0x00000002   Note that the truth table value for a NOR gate and a NOT gate is the same in this case, as both require an output of ‘1’ for the first combination of inputs and ‘0’ for the rest. This demonstrates how the PLU does not actually create an array of logic gates but rather, simply outputs predefined values from a table of all possible combinations of inputs. The previous tables show the register values to achieve all of the basic logic gates with the previous setup of LUT0. However, in order to achieve this configuration with input pins PLU_IN0 and PLU_IN1 as well as output pin PLU_OUT0, the multiplexers would have to be set up in the following manner:   In order to achieve this, pin PLU_IN0 must be routed as input[0] of LUT0 and PLU_IN1 as input[1] of LUT0. Additionally, the output of LUT0 will be routed to the PLU_OUT0 pad. This configuration to set up both input sources, route the output source and write the truth table register to result in an AND gate can be achieved with the following code:   /* Select input pin PLU_IN0 as LUT Input 0 (Input MUX0) for LUT0 on module PLU0 */ PLU_SetLutInputSource(PLU0, kPLU_LUT_0, kPLU_LUT_IN_0, kPLU_LUT_IN_SRC_PLU_IN_0); /* Select input pin PLU_IN1 as LUT Input 1 (Input MUX1) for LUT0 on module PLU0 */ PLU_SetLutInputSource(PLU0, kPLU_LUT_0, kPLU_LUT_IN_1, kPLU_LUT_IN_SRC_PLU_IN_1); /* Set Truth Table 0x08 for LUT element 0 on module PLU0 */ PLU_SetLutTruthTable(PLU0, kPLU_LUT_0, 0x08); // This will result in an AND gate /* Select LUT0 output as driver for PLU_OUT0 pin on module PLU0 */ PLU_SetOutputSource(PLU0, kPLU_OUTPUT_0, kPLU_OUT_SRC_LUT_0);   Conclusion The PLU module of the MCX N is modest when it comes to the complexity of the inner components as it is only made up from a series of look-up tables, multiplexers and flip flops. In spite of that, more elaborate and powerful logic networks can be achieved from those basic elements, providing on-chip solutions to many essential digital circuits and avoiding the need of external components for these digital applications. Not only that, but its interruption and wake up capabilities also enable the PLU to be a simple but effective addition to many low power applications. The PLU’s flexibility and built-in features enable this module to be a very effective addition to the MCX N series of MCUs that should not be overlooked. More information as well as example codes for combinational, sequential, and low-power applications can be found on the full article on Application Code Hub.
View full article
Ⅰ、Introduction MCXA153 supports Read Out Protection (ROP) to protect code from reading from the device internal flash. This read out protection is a mechanism that allows user to enable different levels of protection in the system. This article explains in detail the configuration of the four ROP levels as well as the relationships between the different levels and the corresponding life cycles. Ⅱ、Four levels of Read Out Protection (ROP) The ROP is controlled by ROP_STATE bits, It is a 32-bit field stored in IFR0. It can be programmed by customer. Below is an introduction to the four ROP levels: 1.ROP_LEVEL0 ROP_STATE = 0xFFFF_FFFF (erased FLASH value), No ROP. Default for blank state. 2.ROP_LEVEL1 ROP_STATE = 0x0000_0003 Debug is disabled and unlocked, however it can be modified by customer, only limited debug mailbox commands are available. 3 .ROP_LEVEL2 ROP_STATE = 0x0000_0001 Debug is disabled and locked, it cannot be modified by customer, only limited debug mailbox commands are available. 4.ROP_LEVEL3 ROP_STATE = 0x0000_0000 Debug is disabled and locked, it cannot be modified by customer, no debug mailbox commands are available NOTE:Anything else = ROP3-like behavior (Debug disabled/Locked, ISP disabled). When the ROP level is 0, we can change the ROP level to 1, 2, and 3 by modifying the value of ROP_STATE in IFR0.When the ROP level is 1 or 2, we can change the ROP level to 0 through the ISP or DM-AP command. ROP level 3 is a one-way trip, so be careful. Below is a diagram of the relationship between the four levels:   Ⅲ、Life cycle and ROP When the chip is delivered to the customer from NXP, the life cycle is “NXP Provisioned”, we can also call it “OEM Open”, ”OEM Field return”, “NXP Field Return”. Because at this point, the chip is completely blank, and ISP and debugging functions are allowed. Of course, the ROP level at this point is 0. In this lifecycle, customers can develop and debug. During customer production, customers can impose certain restrictions on ISP and debugging based on their needs through ROP. Customers can choose between ROP level 1 or ROP level 2. The lifecycle at this point is “OEM Closed”. In this lifecycle, when there are some quality issues, customers can use the ISP or DM-AP command to erase the entire chip, or use the DM-AP command “set FA” to transfer the chip life cycle to the initial state, and return it to NXP’s factory for analysis without storing any IP assets. In some scenarios, customers may need to completely disable ISP and debugging functions. In that case, customers can set the ROP level to 3, and the chip’s lifecycle is “OEM No Return”. Please note that at this point, even NXP cannot restore the chip. So once there are some CQC issues, our factory cannot conduct further analysis. Also, we can transfer the chip to a ‘Bricked’ state in any lifecycle. During “Bricked” lifecycle, the chip will not be booted and will become a brick. The following table shows the relationship between life cycle and ROP: Ⅳ. Impact of different ROP levels on SWD and ISP The supported SWD and ISP commands are different at different ROP levels. From ROP0 to ROP3, fewer commands are supported. The following figure shows the commands supported by SWD and ISP at different ROP Levels. ISP commands supported in ROP0-ROP3:   SWD DM-AP commands supported in ROP0-ROP3:   Ⅴ、Configure ROP with SEC tool We can configure ROP through the MCUXpresso Secure Provisioning( SEC) tool. The MCUXpresso Secure Provisioning Tool is a GUI-based application provided to simplify generation and provisioning of bootable executables on NXP MCU devices. Hardware requirements: FRDM-MCXA153 board、Type-C USB cable Software requirements: MCUXpresso Secure Provisioning (MCUXpresso Secure Provisioning v8_b240110 or later.) Configuration steps: Step1. Create a new workspace After opening the software, click File->New Workspace, select "MCX A14x/A15x" -> MCXA153 -> Click "create". Refer to the following figure: Step2. Connection with Target Processor Enter ISP mode:Press and hold SW3(ISP key) => Press and release SW1 (RESET key) => Release SW3 Go to your workspace and click “Target”->Connection, the Connection with Target Processor window is displayed. Here, we make Connection through UART and select port and baud rate. Refer to the following figure: We can click "Test connection" to check whether the connection is successful. If the connection is successful, the result will display "OK". We can also see the life cycle of the current board: OEM Open. Refer to the following figure: Step3.Select Life Cycle Settings ROP Click on the toolbar "OEM Open" According to the requirements, select the appropriate ROP, in this case ROP 2. NOTE: Use ROP 3 with caution. Refer to the following figure: Step4. Build image After completing the above operations, we need to load the .s19 or .hex file generated by MCUXpresso IDE into the Source executable image. After the file is loaded, the start address is automatically identified. If the start address is not 0x00000000, you cannot "built image". Then click on "built image". Refer to the following figure: After completing the built image, "SUCCECC: built image" will be displayed. Click "close". Refer to the following figure: Step5. Write image We can see that the required .bin file has been generated automatically in "write image", or we can import the corresponding .bin file we wrote by "import". The Image path file will be automatically loaded. Clicking "write image" will pop up to confirm, and then click "ok" to run the script automatically. After the file is successfully written, the message "SUCCESS: write image" is displayed. Refer to the following figure: Step6. Check When we complete the configuration of ROP 2, we can check the status of registers through "PFR configuration". The used registers cannot be read out and unknown is displayed, as shown in the following figure: Finally, by pressing the RESET key on the board to exit ISP mode. At this point, the board has entered ROP 2, debug is disabled. The method of entering other ROP levels is the same. So how do we get back to the other ROP levels? ROP 2 state debugging is disabled, even the IDE cannot operate, we can only use ISP command and SWD command to operate. The SEC tool integrates SWD bulk erase command to return to ROP 0. However, we can also use the Blhost software to use ISP command, enter the ISP mode, enter “blhost -p comxx -- flash-erase-all” and return to ROP 0. Next, we'll look at using the SWD bulk erase command. Click on the toolbar "Dbg": The Select Debug Probe window is displayed. Refer to the following figure: Select “Probe: ”and click “erase”. After the erase succeeds, the following message is displayed: Flash mass erase succeeded! So we've successfully returned to ROP 0. Ⅶ、Summary ROP function protects the security of the chip, users can set different levels of ROP according to the requirements of their own applications. Using MCUXpresso Secure Provisionin simplifies the ROP configuration process. Configuring different ROPs requires modifying the status bits of ROP_STAT and ROP_STAT_DP in CMPA. The SEC tool helps us automate this work through a GUI interface.                               
View full article
Developing code for MCXN family from Scratch The MCX family is a newly released MCU family, of course, the SDK package includes almost all the examples of the MCXN modules based on the SDK driver, for example led_blinky which shows the method of toggling GPIO, CTimer interrupt, etc. While the program in this article doesn’t use SDK driver. It focuses on understanding the related module from register level which is friendly to beginners to understand MCX working mechanism. The doc introduces how to toggle a GPIO, how to have CTimer generate interrupt, and in the CTimer ISR, toggle a LED, while it also describes how to initialize the NVIC so that CTimer can generate ISR by writing the module registers without calling the SDK driver. Environment: FRDM-MCXN947 board MCUXPresso IDE v11.9.0 IDE on Win10 OS   1. Toggle a LED On the FRDM-MCXN947 board, the PIO0_10(P0_10) of MCXN947 is connected to a LED. With MCUXPresso IDE with v11.9.0, you can add the code to test the LED toggling and CTimer interrupt function.   1.1 Configure the PIO0_10 pin as GPIO0_10 pin SYSCON->AHBCLKCTRLSET[0]=1<<13; PORT0->PCR[10]=0x1000; Before you initialize the PORT0 register to assign the PIO0_10 function, you have to enable the PORT0 gated clock in the SYSCON->AHBCLKCTRL0 reg. Write the PORT0->PCR[10]=0x1000; to configure the PIO0_10 as GPIO0_10 function. 1.2 Configure the GPIO0_10 pin as GPIO output mode and toggle the GPIO pin. SYSCON->AHBCLKCTRLSET[0]=1<<19; GPIO0->PDDR|=1<<10; GPIO0->PTOR=1<<10; Before you initialize the GPIO0 registers, you have to enable the GPIO0 gated clock in the SYSCON->AHBCLKCTRL0 reg. Set the bit 10 of GPIO0->PDDR so that the GPIO0_10 is in GPIO output mode. Toggle GPIO0_10 pin by writing the bit 10 in GPIO0->PTOR reg   Set a break point in the debugger on the GPIO0->PTOR=1<<10; line,and run step by step, you can see that led toggles.   2. Initialize CTimer 2.1 enable Ctimer gated clock and clock source and divider. Before you initialize the CTimer register, you have to enable the CTimer gated clock. For example, enable CTimer4 gated clock with the line: SYSCON->AHBCLKCTRLSET[2]=1<<22; You have to also select the CTimer clock source and Ctimer clock divider. For example, set the CTimer4 clock source and divider. SYSCON->CTIMERCLKSEL[4]=0x04; SYSCON->CTIMERCLKDIV[4]=0x02; //P0_10 is LED red void GPIOInit(void) { SYSCON->AHBCLKCTRLSET[0]=1<<13; PORT0->PCR[10]=0x1000; //enable gated clock of GPIO SYSCON->AHBCLKCTRLSET[0]=1<<19; GPIO0->PDDR|=1<<10; GPIO0->PTOR=1<<10; //set break point here GPIO0->PTOR=1<<10; GPIO0->PTOR=1<<10; GPIO0->PTOR=1<<10; GPIO0->PTOR=1<<10; } 2.2 Initialize the CTimer register. CTIMER4->CTCR=0x00; CTIMER4->PR=0x00; //set the CTimet4 mode and enable interrupt for match0 CTIMER4->MCR=0x03; CTIMER4->PWMC=0x00; //set the CTimer4 cycle time CTIMER4->MR[0]=2000000; CTIMER4->MSR[0]=2000000; //Start up CTimer4 CTIMER4->TCR=0x01; 2.3 Initialize the NVIC The IRQ number of CTimer4 is 56, so you have to set the bit 24 of both NVIC->ISER[1]|=1<<24; NVIC->ICPR[1]|=1<<24; and set the priority of NVIC->IPR[56] with 0x00; NVIC->IPR[56]=0x00;   //CTimer4 IRQ 56, 56-32=24 void cTimer0Init(void) { //CLOCK_SetClkDiv(kCLOCK_DivCtimer4Clk, 1u); //CLOCK_AttachClk(kFRO_HF_to_CTIMER4); //enable Ctimer4 gated clock SYSCON->AHBCLKCTRLSET[2]=1<<22; SYSCON->PRESETCTRLSET[2]=1<<22; SYSCON->PRESETCTRLCLR[2]=1<<22; SYSCON->CTIMERGLOBALSTARTEN|=1<<4; //select CTimer4 clock source SYSCON->CTIMERCLKSEL[4]=0x04; SYSCON->CTIMERCLKDIV[4]=0x02; //init the CTimer0 CTIMER4->CTCR=0x00; CTIMER4->PR=0x00; CTIMER4->MCR=0x03; CTIMER4->PWMC=0x00; CTIMER4->MR[0]=2000000; CTIMER4->MSR[0]=2000000; //CTIMER0->IR=0x01; CTIMER4->TCR=0x01; NVIC->ISER[1]|=1<<24; NVIC->ICPR[1]|=1<<24; NVIC->IPR[56]=0x00; } 2.3 Each interrupt source has unique interrupt service routine in the file startup_mcxn947_cm33_core0.c For the CTimer4 ISR, it is called: CTIMER4_IRQHandler So it is okay to fill the function: void CTIMER4_IRQHandler(void) { //clear flag CTIMER4->IR|=0x01; //toggle LED GPIO0->PTOR=1<<10; } In conclusion, the doc gives a snippet which can toggle a LED by writing the register directly. It also give the code to configure CTimer4 so that it can generate interrupt, in the ISR, toggle a LED. Appendix This is the entire source code:   /* * Copyright 2019 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "pin_mux.h" #include "peripherals.h" #include "board.h" /******************************************************************************* * Definitions ******************************************************************************/ void clockOUTInit(void); void GPIOInit(void); void cTimer0Init(void); void MRTInit(void); /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ /******************************************************************************* * Code ******************************************************************************/ /*! * @brief Main function */ int main(void) { /* Board pin init */ CLOCK_EnableClock(kCLOCK_Gpio0); BOARD_InitPins(); BOARD_BootClockFRO12M(); //FlexPWMPinInit(); GPIOInit(); cTimer0Init(); //MRTInit(); __asm("nop"); while (1) { } } //P0_10 is LED red void GPIOInit(void) { SYSCON->AHBCLKCTRLSET[0]=1<<13; PORT0->PCR[10]=0x1000; //enable gated clock of GPIO SYSCON->AHBCLKCTRLSET[0]=1<<19; GPIO0->PDDR|=1<<10; //set a break point here and run step by step GPIO0->PTOR=1<<10; GPIO0->PTOR=1<<10; GPIO0->PTOR=1<<10; GPIO0->PTOR=1<<10; GPIO0->PTOR=1<<10; GPIO0->PTOR=1<<10; GPIO0->PTOR=1<<10; GPIO0->PTOR=1<<10; GPIO0->PTOR=1<<10; } //CTimer4 IRQ 56, 56-32=24 void cTimer0Init(void) { // CLOCK_SetClkDiv(kCLOCK_DivCtimer4Clk, 1u); // CLOCK_AttachClk(kFRO_HF_to_CTIMER4); //enable Ctimer4 gated clock SYSCON->AHBCLKCTRLSET[2]=1<<22; SYSCON->PRESETCTRLSET[2]=1<<22; SYSCON->PRESETCTRLCLR[2]=1<<22; SYSCON->CTIMERGLOBALSTARTEN|=1<<4; //select CTimer4 clock source SYSCON->CTIMERCLKSEL[4]=0x04; SYSCON->CTIMERCLKDIV[4]=0x02; //init the CTimer0 CTIMER4->CTCR=0x00; CTIMER4->PR=0x00; CTIMER4->MCR=0x03; CTIMER4->PWMC=0x00; CTIMER4->MR[0]=2000000; CTIMER4->MSR[0]=2000000; //CTIMER0->IR=0x01; CTIMER4->TCR=0x01; NVIC->ISER[1]|=1<<24; NVIC->ICPR[1]|=1<<24; NVIC->IPR[56]=0x00; } void CTIMER4_IRQHandler(void) { //clear flag CTIMER4->IR|=0x01; //toggle LED GPIO0->PTOR=1<<10; } //MRT0 interrupt IRQ is 30 void MRTInit(void) { SYSCON->AHBCLKCTRLSET[1]=1<<0; SYSCON->PRESETCTRLSET[1]=1<<0; SYSCON->PRESETCTRLCLR[1]=1<<0; MRT0->CHANNEL[0].INTVAL=6000000; MRT0->CHANNEL[0].INTVAL|=1<<31; MRT0->CHANNEL[0].CTRL=0x01; NVIC->ISER[0]|=1<<30; NVIC->ICPR[0]|=1<<30; NVIC->IPR[30]=0x00; } void MRT0_IRQHandler(void) { if(MRT0->CHANNEL[0].STAT&0x01) { MRT0->CHANNEL[0].STAT|=0x01; } //toggle LED GPIO0->PTOR=1<<10; }
View full article