Introduction.
i.MX8ULP boot partition is handled by imx-boot image as the 8M family processors and i.MX 9 series processors, keeping the usage of imx-mkimage and UUU tools for updating the firmware to the boot media.
The difference is that this processor is focus on working over Cortex-M, starting from boot which is handled by uPower ROM, it can boot Application Domain or Real Time Domain firmware images meanwhile other processors boot is less flexible, focusing on Cortex-A.
This guide will explore this flexibility and it's intended for board users that test prebuilt images, want to get started with imx-boot customization, want to run SDK/Standalone examples on Cortex-M or need to perform recovery to their boards.
1. Hardware Setup.
Retrieve your silicon revision from the TOP marking; BUILD A1 in this case. Identify your board in the base board silkscreen, you can work with MCIMX8ULP-EVK or MCIMX8ULP-EVK9. Connect 5V power source to P1. Connect USB type-A to type-C to USB0 J15. Connect USB type-A to type-micro-B to DEBUG J17.
2. Firmware Images Gathering.
$ cd ~/Projects/
$ git clone https://github.com/nxp-imx/imx-mkimage.git
Make sure that you use all images from the same release, this document uses first release for IMX8ULP; LF6.1.22.
Download Sentinel Firmware retrieving the version from Release Notes. After installation copy the firmware for the silicon revision owned, mx8ulpa1 is used for REV A1.
$ cd ~/Projects/
$ wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-sentinel-0.10.bin
$ chmod a+x firmware-sentinel-0.10.bin
$ ./firmware-sentinel-0.10.bin
$ cp firmware-sentinel-0.10/mx8ulpa1-ahab-container.img ~/Projects/imx-mkimage/iMX8ULP/
Remaining firmware will be obtained from a Yocto build, is the method that requires less steps. Make sure that the MACHINE variable matches your board.
$ mkdir ~/Projects/Yocto-BSP-i.MX
$ cd ~/Projects/Yocto-BSP-i.MX/
$ repo init -u https://github.com/nxp-imx/imx-manifest -b imx-linux-mickledore -m imx-6.1.22-2.0.0.xml
$ repo sync
$ MACHINE=imx8ulp-lpddr4-evk DISTRO=fsl-imx-xwayland source ./imx-setup-release.sh -b i.MX8ULPEVK
$ bitbake core-image-minimal
$ cd tmp/deploy/images/imx8ulp-lpddr4-evk/
$ cp bl31-imx8ulp.bin ~/Projects/imx-mkimage/iMX8ULP/bl31.bin
$ cp u-boot-imx8ulp-lpddr4-evk.bin-sd ~/Projects/imx-mkimage/iMX8ULP/u-boot.bin
$ cp u-boot-spl.bin-imx8ulp-lpddr4-evk-sd ~/Projects/imx-mkimage/iMX8ULP/u-boot-spl.bin
$ cp imx-boot-tools/upower.bin ~/Projects/imx-mkimage/iMX8ULP/upower.bin
Cortex-M firmware can be built with VS Code in Windows or by Standalone build in Linux, make sure that you have the GNU toolchain installed.
Build the Power Mode Switch demo, is easier to work with it later in this document we will explore other type of demos.
$ cd ~/Projects/
$ cp ~/Public/EVK-MIMX8ULP-power_mode_switch.zip .
$ unzip EVK-MIMX8ULP-power_mode_switch.zip
# Rename directory for this example, you can skip and use the default name.
$ mv power_mode_switch/ Standalone-IMX8ULP-Power-Switch
$ cd Standalone-IMX8ULP-Power-Switch/
$ ls
$ chmod a+x *.sh
$ ./clean.sh
$ export ARMGCC_DIR=/opt/arm-gnu-toolchain-12.3.rel1-x86_64-arm-none-eabi/
# Adding a custom line (607) to print a custom message.
# freq = CLOCK_GetFreq(kCLOCK_Cm33CorePlatClk);
# PRINTF("\r\n#################### Standalone Built 02/21 ####################\n\r\n");
# PRINTF("\r\n#################### Power Mode Switch Task ####################\n\r\n");
$ nano source/power_mode_switch.c
$ ./build_release.sh
$ cp release/sdk20-app.bin ~/Projects/imx-mkimage/iMX8ULP/m33_image.bin
$ ./clean.sh
3. Build and flash imx-boot firmware for Singleboot M33.
This test will use Single boot – eMMC 1000_0000 pin config mode.
Singleboot_M33 image stores AP FW and RT FW in eMMC, at boot time both cores work.
$ cd ~/Projects/imx-mkimage/
$ make clean
$ make SOC=iMX8ULP REV=A1 flash_singleboot_m33
$ cp iMX8ULP/flash.bin ~/Public/imx-boot.bin-flash_singleboot_m33
Set boot pins to 0100_0000 – Serial Download and power up the board.
Flash the image using a Windows or Linux host through UUU tool.
> uuu -b emmc .\imx-boot.bin-flash_singleboot_m33
Wait for UUU to print 'done' message for the command issued.
4. Test new imx-boot firmware.
Set the boot pins to the config you build for and power up the board. Cortex-A output is sent through 3rd COM port and Cortex-M output through 4th.
5. Board running freertos_swtimer_cm33 and hello_world_cm33 demos.
To run these demos build them through VS Code or Standalone build and copy them to imx-mkimage directory.
$ cp <path to binary>/sdk20-app.bin ~/Projects/imx-mkimage/iMX8ULP/m33_image.bin
$ cd ~/Projects/imx-mkimage/
$ make clean
$ make SOC=iMX8ULP REV=A1 flash_singleboot_m33
$ cp iMX8ULP/flash.bin ~/Public/imx-boot.bin-flash_singleboot_m33
When this demos are running, they don't allow Cortex-A to get to U-boot, this is an issue when trying to flash new or recovery images, the board just reboots with the new FW but it's not written to eMMC, you can identify this situation when UUU prompts 100%, the command appears to hang and 'done' is not displayed.
To flash a new firmware, IMX8ULP needs to boot from Serial Download pin config.
Then run the script attached and go to step 4.
> uuu .\uuu.auto
6. Running Dualboot demos for asynchronous operation.
Dualboot are two images, AP FW which must be stored in eMMC and RT FW stored at FlexSPI0 NOR, at boot time both cores work.
Boot is asynchronous and needs both images at the same time, this requires to flash two images at the same time, U-boot fastboot mode facilitates writing to eMMC while being able to use its console.
Issue the following command at U-boot.
=> fastboot 0
Build the firmware images for A35-eMMC M33-NOR – 1000_0010* pin config. * You can also boot from LP mode – 1000_0001 pin config, this allows only M33 code to boot initially.
$ make SOC=iMX8ULP REV=A1 flash_dualboot
$ cp iMX8ULP/flash.bin ~/Public/imx-boot.bin-flash_dualboot
$ make SOC=iMX8ULP REV=A1 flash_dualboot_m33
$ cp iMX8ULP/flash.bin ~/Public/imx-boot.bin-flash_dualboot_m33
> uuu -b emmc .\imx-boot.bin-flash_dualboot
> uuu -b fat_write .\imx-boot.bin-flash_dualboot_m33 mmc 0:1 spi.bin
=> Ctrl + c
=> fatload mmc 0:1 ${loadaddr} spi.bin; setenv erase_unit 1000; setexpr erase_size ${filesize} + ${erase_unit}; setexpr erase_size ${erase_size} / ${erase_unit}; setexpr erase_size ${erase_size} * ${erase_unit}; sf probe 0:0; sf erase 0 ${erase_size}
=> sf write ${loadaddr} 0 ${filesize}
Then go to step 4.
Conclusion.
This document explore all the boot configurations that feature the A35 storing its firmware in eMMC and M33 running its demo binary. Can help users that are looking to run demos on Cortex-M with their out-of-the-box board, continuing with them through the trial of different demos and boot modes to understand what are different outcomes, adapt the project in that way and develop the application over a template.
View full article