- 01 Oct 2021
- 7 Minutes to read
- Print
- DarkLight
- PDF
Using U-boot's 'ums' Command to Write Flash Storage over USB-OTG
- Updated on 01 Oct 2021
- 7 Minutes to read
- Print
- DarkLight
- PDF
Introduction
One of the first things developers need to be able to do when working embedded products is to load images onto it.
An "image" in this case, is a monolithic digital file that comprises the entirety of the content of the EMMC (or microSD card, if applicable), from the boot partition, through the Secondary Program Loader (SPL), through the various partitions. Usually, there are a minimum of two partitions (boot, and root filesystem). However, there could be many partitions depending on the setup, if you have an A/B partitioning scheme.
This article discusses one of several possible methods used to load the Flash. This method is to use U-boot's ums
command. The main advantage of this method is convenience. You don't have to change any boot mode settings on the board (e.g. configuration jumpers or boot mode switches), and you can use off-the-shelf tools to perform the actual transfer via USB OTG.
The main drawback of this method is that you also have to have a serial console connection to the target board in order to execute the necessary U-boot commands.
Requirements
U-boot must be running on the target system
One requirement to use this method is that the board must also boot from either e.MMC or microSD card with a version of U-boot that has the ums
command enabled. We've enabled this command as a standard setting in our maintained version of U-boot version 2018.03 and later. This is the version of U-boot we utilize in Yocto 2.5 (Sumo), as well as Android 9 (Pie).
USB OTG connection
The target must also have an operating USB OTG connection. This is a standard feature on all TechNexion development kits. It is extremely useful for loading e.MMC. With Android, it is also the default communications port for the Android Debugger (ADB). If you're using a custom baseboard (or carrier board), you are highly recommended to put a USB connector on the board and to connect it to the USB OTG port on the SOM connector. You can use our baseboard schematics as a reference for this.
While TechNexion kits have a true dual-role (USB OTG) port, if you're using the USB port to load Flash or to debug, it only needs to operate as a device port.
Serial Console
To access the U-boot command prompt, you have to have a serial console connection between the target board and a host computer (usually the one you're using to load the flash). This can vary based on your baseboard. If you're using a TechNexion development kit baseboard, please review the baseboard user guide.
Using the ums
command
UMS stands for USB Mass Storage. Fundamentally, what this command does is it exports a chosen block device as a mass storage device over a chosen USB port. On the host computer, this causes the port to look like mass storage device (like a USB Flash drive). This flash drive can then be accessed using programs and applications on the host computer.
You may need to reboot your board in order to get into the U-boot prompt. As soon as your board boots, you need to hit any key to terminate the normal boot process and get to a U-boot prompt:
Once you have a prompt, you need to discover the number of the MMC device corresponding to e.MMC or microSD card. You can use the mmc list
command to do this:
u-boot=> mmc list
FSL_SDHC: 0
FSL_SDHC: 1 (eMMC)
In this example, for PICO-IMX8M-MINI running U-boot 2018.03, the e.MMC device is MMC device 1.
The MMC device number of the e.MMC may change from revision to revision of U-boot. For example, in U-boot 20.04 (Yocto 3.0), the MMC device is '2'.
Now, you can run the ums
command as follows:
u-boot=> ums [USB device number] mmc [mmc device number]
Where the USB device number is always 0 and the mmc device number is the one you discovered when running mmc list
. Thus:
u-boot=> ums 0 mmc 1
UMS: LUN 0, dev 1, hwpart 0, sector 0x0, count 0x1d34000
-
While UMS is running, you will see a rotating cursor (like a pinwheel), and you won't get another boot prompt until after you are done and have exited UMS.
At this point in time, your host computer should see a USB mass storage gadget connected. This should appear as a USB mass storage device (a block device). If there is no boot partition or anything else loaded onto it (i.e. the EMMC could be blank), you won't see any drives available.
Loading the image
At this point you can use a number of tools to load the device, depending on your host computer.
Linux Hosts using dd
On Linux host computers, a popular tool to use is the dd utility. First, you need to discover the device file that was assigned to the target's USB mass storage device. For this, you can open a terminal and use the lsblk
command:
~$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 40G 0 disk
├─sda1 8:1 0 512M 0 part /boot/efi
├─sda2 8:2 0 1K 0 part
└─sda5 8:5 0 39.5G 0 part /
...
sde 8:64 1 14.6G 0 disk
├─sde1 8:65 1 32M 0 part /media/john/Boot pico-i
└─sde2 8:66 1 1.4G 0 part /media/john/1ad5ef0d-c9d6-4881-b07b-0fd7737b8efb
sr0 11:0 1 1024M 0 rom
In above test, /dev/sde is the e.MMC device on the host computer for our attached target. It is already loaded with a couple of partitions that are mounted on the host. In order to write to them, we need first unmount the partitions:
~$ sudo umount /dev/sde1
~$ sudo umount /dev/sde2
Then, you can write your image to the disk using the dd
command:
~$ sudo dd if=<path/to/your/image/file> of=/dev/sde bs=1M status=progress
It is very important to only write uncompressed image files (no .xz or .bz2 files) using dd
. If you write a compressed image file, the SOC will not be able to load a bootable image from the storage media and then your board will not boot afterwards.
Once completed, you can then sync:
~$ sync
Then you can CTRL-C out of UMS in U-boot, and then reboot your board.
Mac OS hosts using dd
Loading with a Mac OS host is similar to using a Linux host when using the dd
tool. There are a couple of differences.
First, you can open a terminal and get the device file for the target's USB mass storage device. On Mac OS, you would use the diskutil
command:
% diskutil list
/dev/disk0 (internal, physical):
#: TYPE NAME SIZE IDENTIFIER
0: GUID_partition_scheme *960.2 GB disk0
1: EFI EFI 209.7 MB disk0s1
2: Apple_APFS Container disk1 960.0 GB disk0s2
...
/dev/disk2 (external, physical):
#: TYPE NAME SIZE IDENTIFIER
0: FDisk_partition_scheme *15.7 GB disk2
1: Windows_FAT_32 Boot pico-i 33.6 MB disk2s1
2: Linux 1.5 GB disk2s2
In this case, the device is /dev/disk2
and there is currently a partition from the target device already mounted at /dev/disk2s1
.
You need to unmount any mounted partitions:
% diskutil unmount /dev/disk2s1
Volume Boot pico-i on disk2s1 unmounted
Then, you can use the dd command in a similar fashion as on a Linux host. The main differences are that on a Mac, there are two devices you can use to access the disk. A "Raw Disk" device and a buffered disk device. Raw disk devices (/dev/rdiskN) are much faster to access than buffered disk devices (/dev/diskN).
Also, the block size (the bs
parameter) uses an uppercase 'M' to refer to megabytes in Mac OS:
% dd if=<path/to/disk/image> of=/dev/rdisk2 bs=1M
It is very important to only write uncompressed image files (no .xz or .bz2 files) using dd
. If you write a compressed image file, the SOC will not be able to load a bootable image from the storage media and then your board will not boot afterwards.
Once completed, you can then sync:
% sync
Then you can CTRL-C out of UMS in U-boot, and then reboot your board.
Cross Platform Tool: Balena Etcher
Balana Etcher is a cross-platform tool for loading raw disk images. There are versions for Linux, Windows, and Mac OS hosts.
Etcher will automate a number of tasks that we manually run if we are using 'dd'. For example, it understands how to parse compressed data file formats (e.g. .xz, .bz2, .zip files). It automatically detects the target devices that you may want to flash, unmounts any mounted partitions, and ejects the device after writing. After writing the data to the device, Etcher also performs a verification step as well.