Programming eMMC with USB for OSD335x (AM335x System in Package)

Published On: February, 15, 2019 By: Neeraj Dantu | Updated: January 31, 2020 by Neeraj Dantu

One of the key steps in producing an embedded design is to program the device with production software or firmware. For a microprocessor-based design, the production software generally consists of a custom Linux image which is programmed into the non-volatile memory on the design. Because the size of a Linux image can be a few gigabytes and the interface of the non-volatile memory may only be connected to the processor, programming this image can be costly and time consuming when scaling for a large quantity of devices. This app note describes a procedure for programming eMMC with USB for OSD335x (AM335x System in Package) via a USB client interface.

The procedure described in this app note requires only a single USB cable to both power the embedded design and transfer all the necessary information. However, this procedure does not require that the embedded design be powered off of the USB cable and can be easily modified to support different power designs. A host computer is required to serve the custom Linux image which will be programmed on to the devices. This solution can scale because one host computer can be used to program many devices in parallel with minimal human interaction, allowing production quantities of devices to be programmed in a cost effective and timely manner. Scaling does have hardware limitations such as the processor and the USB data speeds of the host computer, which can be chosen based on target program time.

The procedure for programming eMMC with USB for OSD335x (AM335x System in Package) described in this document assumes that the OSD335x embedded design has a USB client port connected to USB0 and an eMMC memory connected to MMC1. Additionally, the host computer is assumed to be running Ubuntu 16.04.

Table of Contents

1.Introduction
2.Procedure Overview
2.1.Terminology
3.Requirements for Procedure
4.Initial Setup
4.1Setup TFTP Server on Host Computer
4.2Setup DHCP Server on Host Computer
4.3Boot Components for “Target Device”
4.3.1Pre-Built Boot Components
4.3.2Customizing Boot Components
4.4Automated “Target Device” Programming on “Host Computer”
4.4.1Detect USB Storage Gadget
4.4.2Copy Production Software Image to “Target Device
5.Programming Setup Overview
6.Programming “Target Devices”
7.Helpful Debugging Tips
8.Revision History

 

A PDF version of this App Note can be found here.

Files associated with this App Note can be downloaded here.

 

Notice
The information provided within this document is for informational use only. Octavo Systems provides no guarantees or warranty to the information contained.

2       Procedure Overview

Figure 1 shows an example hardware setup for the procedure for shows an example hardware setup for the procedure of programming eMMC with USB for OSD335x (AM335x System in Package). The “OSD335x Target Device” is connected to the “Host Computer” via USB. Optionally, the USB connection can utilize a “USB Hub” so that multiple devices may be programmed at the same time. The USB port on the “Target Device” is a USB client port and will be used as the boot interface of the device. The USB port on the “Host Computer” is a USB host port and will be used to transfer the information to the device.

Hardware setup for programming eMMC with USB for OSD335x (AM335x System in Package)
Figure 1 Hardware setup for programming eMMC with USB for OSD335x (AM335x System in Package)

The programming procedure has two major steps: 1) A small, light-weight, initramfs (Initial RAM Filesystem) based Linux image is booted on the “OSD335x Target Device” using TFTP over the USB interface 2)The minimal image booted on the target will provide the “Host Computer” access to the attached eMMC memory as a mounted mass storage device, similar to a USB flash drive; 3) The “Host Computer” will copy the production Linux image to the eMMC memory.

Programming flow for programming eMMC with USB
Figure 2 Programming flow for programming eMMC with USB

 

2.1       Terminology

Before continuing, please familiarize yourself with the Linux Boot Process on the OSD335x Family of Devices. The following sections will refer to different components of the boot process described in this article.

Additionally, understanding networking concepts such as:

while not necessary, can provide additional context for the steps described in the procedure.

3       Requirements for Procedure

These are the basic requirements for implementation of the procedure described in this document:

  1. Host Computer. Current tested platforms include:
    1. Ubuntu (16.04 LTS)
  2. OSD335x Target Device with
    1. USB client port attached to USB0
    2. eMMC memory attached to MMC1
    3. Boot Mode setting (i.e. SYSBOOT[4:0] value) that includes USB0 as a boot device (e.g. SYSBOOT[4:0] = 11000b has boot peripherals of SPI0, MMC0, USB0 and UART0)
    4. Optional LED indicators to be set at different points of the flashing process to act as feedback
  3. Optional USB Hub

The boot components can be modified to support different hardware configurations of the “Target Device”. See Section 5.3.2 for more details.

4    Initial Setup

The example hardware setup was shown in Figure 1. This procedure assumes that the production Linux image (.img) has already been prepared and has been stored on the “Host Computer”. The initial software setup consists of the following steps:

  1. Setup a TFTP server on “Host Computer”
  2. Setup a dummy ethernet connection to assign IP address to ethernet interface of “Host Computer” when a “Target Device” is connected
  3. Setup a DHCP server on “Host Computer”
  4. Download or create the boot components necessary to bootstrap the “Target Device”
  5. Setup automatic scripts on the “Host Computer” to boot and program eMMC on “Target Device”

4.1    Setup TFTP Server on Host Computer

The TFTP server is used to serve the boot components for the “Target Device”. The following steps describe the process of installing and setting up a TFTP server on an Ubuntu (16.04 LTS) computer:

  1. Install required packages:
  2. Edit configuration file for the TFTP server in file /etc/xinetd.d/tftp. If the file is not present, it needs to be created. Modifying this file also requires root privileges. Note that the “server_args” variable refers to the folder where files that need to be served are located.
  3. Create the folder referenced by variable “server_args” and set appropriate permissions:
  4. Restart xinetd service to run the TFTP server:
  5. To verify whether the service is running properly:

4.2    Setup DHCP Server on Host Computer

To communicate over TFTP, the “Host Computer” and the “Target Device” need to be on the same IP subnet. This is accomplished by running a DHCP server on the “Host Computer”. When the “Target Device” tries to boot, it will send BOOTP requests over the USB RNDIS interface. The DHCP server running on the “Host Computer” will then assign the “Target Device” an IP address. This will then allow the “Target Device” to request the necessary boot components from the TFTP server. The procedure to setup a DHCP server is described in the following steps:

  1. Install required packages
  2. Edit the DHCP server parameters in existing /etc/dhcp/dhcpd.conf dhcp configuration file or create a new one.
    Note that the configuration file sets up the “Host Computer” (i.e. the DHCP server) at 192.168.0.1 and will assign IP addresses between 192.168.0.2 and 192.168.0.100. These parameters are arbitrary and can be changed if needed. The configuration file also sets the files to be transferred for different BOOTP requests using vendor class identifiers. These file names will be used to name the boot components that will be defined later in this document.
  3. Configure the DHCP server to automatically run on the dynamically created USB RNDIS network interfaces which needs to have the IP address of the server (192.168.0.1) through an interface startup script:
    1. Create /etc/network/if-up.d/dhcp-restart
      First, the script checks whether the name of the interface matches with any known interfaces. The example “Host Computer” had two network interfaces: eno1 (i.e. wired Ethernet port) and lo (Loopback). If your “Host Computer” has different or additional network interfaces, the if statement(line 8) needs to be modified appropriately so that nothing will occur for those interfaces. If the name does not match, the script then sets the IP address of the “Host Computer” on the new interface. Then it checks whether the interface is already configured for the DHCP server using the /etc/default/isc-dhcp-server configuration file. If the interface is not present, the script adds the name of the new interface to the INTERFACES variable in the file. Finally, it restarts the DHCP server with the new configuration.
    2. Modify the permissions of the file to make it executable
  1. Create a dummy ethernet connection to set an IP address to the network interface of the “Host Computer” the “Target Device” is connected to. This will complete the initial setup of the ethernet connection and will allow to execute the “dhcp-restart” script created in step 3.
    1. Select the Ethernet Connections menu on the desktop and select on ‘edit connections’
      enable networking
    2. Select “Add” in the Network Connections window. Edit the new Network Connection configuration: Select “IPv4 Settings” tab and enter any valid, IP address, netmask and gateway.Edit the network configuration
Caveat

Restarting the DHCP server during the TFPT activity required to boot the “Target Device” can result in an incomplete boot. Therefore, each additional “Target Device” to be programmed should not be connected to the “Host Computer” until the previous “Target Device” has completed booting. This state can be indicated by an LED as described in section 5.4.2.

4.3    Boot Components for “Target Device”

Now that the TFTP and DHCP server are configured on the “Host Computer”, the “Target Device” can download the necessary boot components from the “Host Computer”. These components available in the project download folder must be copied to the tftpboot folder set by variable server_args in file /etc/xinetd.d/tftp. There are five (5) boot components needed (Note: component names match names used in previous sections):

  1. u-boot-spl-restore.bin: Second stage bootloader (SPL) requested by ROM code. Performs device initialization including DDR setup.
  2. u-boot-restore.img: U-Boot bootloader requested by the SPL. Loads the Linux kernel, file system and device tree into memory.
  3. uImage: Linux kernel image with a U-Boot header describing the image. This kernel needs to be built to support a RAM based filesystem and have the necessary USB gadget drivers to expose the eMMC device via USB as a mass storage device.
  4. initramfs: Small filesystem built from Busybox that can live entirely within the DDR memory. This file is an archived zipped version of the filesystem generated by the busybox utility with minor modifications and a U-Boot header.
  5. osd3358-bsm-refdesing.dtb: Device Tree Binary (dtb) describing the hardware configuration of the “Target Device”. This file is responsible for setting up the eMMC and the USB interfaces.

4.3.1    Pre-Built Boot Components

You can find pre-built versions of the boot components here: Project Download Folder. The folder should contain the file mentioned above. The pre-built components can be used if the “Target Device” has:

  1. USB0 configured as a client port
  2. eMMC memory attached to MMC1
  3. Boot Mode setting (i.e. SYSBOOT[4:0] value) that includes USB0 as a boot device

If the target board does not satisfy the above conditions, some modifications are required for the bootloader and the filesystem.

4.3.2    Customizing Boot Components

If the embedded design cannot use the pre-built boot components, then custom boot components will need to be created. The source files of the bootloader and the RAM filesystem can be found here: Project Download Folder.. To modify the boot components, both the bootloader and the filesystem will need to be created.

4.3.2.1   Customizing U-Boot bootloader

There can be several reasons to modify the bootloader such as modifying boot arguments, booting from a different boot interface such at the ethernet or the UART. Configuration changes can be made via menuconfig. The U-Boot bootloader source files can be downloaded from here: Project Download Folder.

The following steps describe the how to modify configuration and build u-boot binaries (these steps are based those found at: https://www.digikey.com/eewiki/display/linuxonarm/BeagleBone+Black):

  1. Download and extract cross compiler (each command separated by ‘$’)
  2. Verify cross compiler
  3. Extract and change directory to U-Boot source(May require package libncurses. Command included to install it)
  4. Edit configuration using menuconfig:
    edit configuration using menuconfig
  5. To change the boot arguments, edit the “Enable boot arguments” field(Default: console=ttyO0,115200 root=/dev/ram rw initrd=0x88080000 g_mass_storage.removable=1 g_mass_storage.luns=1):change boot arguments
  6. To change the boot command, edit the “Enable a default value for bootcmd” field(Default: dhcp;tftpboot 0x82000000 uImage;tftpboot 0x88080000 initramfs;tftpboot 0x88000000 osd3358-bsm-refdesign.dtb;gpio set 54;bootm 0x82000000 0x88080000 0x88000000):
    change boot command
  7. To add support for another filesystem, select the appropriate option(s) in “Filesystems”:
    add support for another filesystem
  8. Additional modifications of tasks u-boot needs to perform such as turning on an LED to indicate the target has acquired and is running u-boot through TFTP are described in 5.3.2.3
  9. When finished modifying the configuration, save and exit menuconfig
  10. Build U-Boot
  11. Copy the SPL and U-Boot to the TFTP server folder specified in the TFTP server configuration (e.g. /tftpboot/)
    Cd

4.3.2.2   Customizing Filesystem

The filesystem is where changes to initialization scripts and board setup for programming can be made. For example, the eMMC attached to the OSD335x can be on an MMC interface other than MMC1, which can be changed by updating the “init” script. The Busybox filesystem source files can be downloaded from here: Project Download Folder.

The following steps describe how to modify and build a filesystem:

  1. Extract file system and change directory to the filesystem
  2. Edit the file init file in the root directory of the new filesystem. For example, to change the eMMC interface change the ‘/dev/mmcblk1’ to the appropriate /dev/ input. The trailing number of the dev input corresponds to the MMC interface the storage device is connected to. Additional shell commands can be added to perform functions such as programming a board identification into an EEPROM and turning on an LED to indicate Linux kernel has booted(described in section 5.3.2.3).
  3. Add the filesystem to a cpio archive (Command assumes current directory is */RFS_static/)
  4. Change directory to the parent directory and zip the cpio archive
  5. Add the U-Boot header to make the filesystem binary U-Boot compatible(May require package u-boot-tools. Command included to install it)
  6. Copy the initramfs to TFTP folder specified in the TFTP setup. For example, /tftpboot/

4.3.2.3     LED indicators

Since the boot and programming processes can be opaque to an operator, it can be useful to communicate progress using LEDs or other visual indicators on the “Target Device”. In the OSD335x reference designs, there are a number of “User LEDs” that can be used for this purpose. When communicating to an operator, there are two main points in the flashing process that should be indicated:

  1. When the “Target Device” has completed booting and is ready to have data transferred from the “Host Computer” to the eMMC.

Given that there are multiple boot components and multiple TFTP file transfers, it is important to indicate when the “Target Device” has completed booting. This indicates to the operator that it is safe to connect a new “Target Device” to the “Host Computer” to pipeline the programming process (DHCP server must not be restarted during the “Target Device” boot process). To do this, insert the appropriate commands when modifying “Enable a default value for bootcmd” during the U-Boot customization process described in Section 5.3.2.1. For example, the pre-built boot components set GPIO54, which is attached to a user LED, to ‘1’ after all of the TFTP file transfers of boot com0ponents have completed but before the kernel has booted. This can be found as part of the ‘bootcmd’ here:

  1. When the “Target Device” has completed programming the eMMC with data from the “Host Computer”.

When the “Target Device” has completed programming the eMMC, the “Target Device” is ready to be disconnected from the “Host Computer” and is ready for further verification and validation. There are multiple ways to indicate that the eMMC has finished being flashed. In the pre-built boot components, this is implemented by specifying an LED in the device tree to indicate eMMC activity. When the eMMC is being programmed, the LED will flash indicating activity on MMC interface. When the flashing is complete, the LED stops flashing and remains turned off. The snippet below shows part of the device tree used to configure pin 22 or GPIO bank 1 as the GPIO indicating MMC interface activity.

 

4.4    Automated “Target Device” Programming on “Host Computer”

In order to automate the “Target Device” programming, the “Host Computer” must:

  1. Detect the USB storage gadget presented by the “Target Device” once it has booted
  2. Copy the production software image to the “Target Device” via the USB storage gadget

The following subsections describe how each of these steps can be achieved. There are a number of files that need to created and or modified for this purpose available in the flasher subfolder of project download folder. The files and their assumed default locations are described below:

  • /home/lab/flasher/list_gen.sh
    • Script to be run by udev when USB storage gadget is detected
  • /home/lab/flasher/list.txt
    • List of current USB storage gadget devices; generated by sh
  • /home/lab/flasher/usb_flasher.py
    • Script to be run on “Host Computer” to monitor list of USB storage gadget devices and copy production software image to “Target Device”
  • /home/lab/flasher/bone-debian-9.3-iot-armhf-2018-03-05-4gb.img
    • Production software image to be copied to “Target Device”

These are arbitrary and can be modified to better match the filesystem of the “Host Computer”

4.4.1    Detect USB Storage Gadget

Once the “Target Device” has booted, it will expose the eMMC via a USB storage gadget to the “Host Computer”. By default, the “Host Computer” operating system will automatically detect when a new USB storage gadget is connected, similar to how the operating system automatically detects when a USB flash drive is inserted into a USB port. To perform an action when the USB storage gadget is detected, a udev rule can be added to the “Host Computer”.

  1. Create a script (e.g. list_gen.sh) to record the device names (e.g. /dev/sdb) when USB storage gadget is detected by “Host Computer” operating system
  2. Edit the script and add the following contents:
    Note that list.txt needs to be created and its path assigned to the OUTPUT variable in list_gen.sh script. Only device names that end in a character and not a number are added to the list of devices to be programmed (i.e. /home/lab/flasher/list.txt). This is because the udev rule will be triggered two times for each Linux file storage gadget detection. Once when the storage gadget is detected and the other when the storage gadget is mounted. For example, if the file storage gadget is attached to the “Host Computer” as /dev/sdb, the device /dev/sdb1 is also created to mount the storage gadget. Therefore, the script filters out the ‘sdb1’ interface and does not add it to the list of devices to be programmed to avoid duplicate copies of the same device.
  3. Make list_gen.sh executable
  4. Create /etc/udev/rules.d/98-osd335x-usb-flasher.rules
  5. Edit the new file and add the following contents replacing the filename /home/lab/flasher/list_gen.sh with the name and absolute path of the script created in step 1. The interface file name (e.g. /dev/sdX) is passed to the script as the input ‘%k’.:

4.4.2    Copy Production Software Image to “Target Device”

By using the udev rule and associated script to create a list of devices to be programmed, it makes it easy for a script to monitor the list for changes and create a new thread to copy the production software image to the “Target Device”. The monitor script (e.g. /home/lab/flasher/usb_flasher.py) is described below and can be modified based on the needs of the “Target Device”. Specifically, base_path, list_path and img_file variables need to be assigned to the proper file paths similar to the paths shown below. The monitor script uses the Linux command dd to copy the production software image to the “Target Device”. This script will be run on the “Host Computer” continuously while a “Target Device” needs to be programmed. The contents of the script are:

This python script required the python package “watchdog”. The package can be installed by executing the following command

5.    Programming Setup Overview

Each of the previous sections described individual parts of the production software programming application. This section will provide a step by step overview of the setup required for the application:

  1. Install TFTP server on “Host Computer” (Section 5.1)
  2. Configure the server by editing the TFTP server configuration file /etc/xinetd.d/tftp
    1. Note the server folder option
  3. Install DHCP server on “Host Computer” (Section 5.2)
  4. Configure the server by editing the DHCP server parameters in /etc/dhcp/dhcpd.conf
  5. Add /etc/network/if-up.d/dhcp-restart.sh to restart the dhcp server for every interface
    1. Note the IP address 192.168.0.1
  6. Create dummy ethernet interface on “Host computer” to complete ethernet interface initialization
  7. Create custom boot components or download the pre-built boot components (Section 5.3)
  8. Copy the boot components to the TFTP server folder
  9. Create sh (Section 5.4.1). Touch list.txt (Section 5.4.1). Create monitor.py (Section 5.4.2)
    1. File names and paths are examples and can be modified
  10. Add udev rule 98-osd335x-usb-flasher.rules to folder /lib/udev/rules.d/ (Section 5.4.1)
    1. Edit the file paths and names to match files created in Step 8
  11. Copy the production software image file to a local folder
    1. Edit the file path and names in py
  12. Execute py on “Host Computer” command line: sudo python3 monitor.py

6.    Programming “Target Devices”

This section will describe the step by step procedure to program a “Target Device” once the setup is complete:

  1. Plug a “Target Device” in to a USB port of the “Host Computer” or a USB Hub attached to the “Host Computer”
  2. Wait until the “Target Device” boot is complete (LED indication). By default, u-boot image provided in the download folder will turn gpio #54 ON.
  3. After “Target Device” boot is complete, plug in another “Target Device” and repeat steps 2 and 3 until all “Target Devices” are connected to the “Host Computer” or there are no more USB ports on the “Host Computer” or USB Hub
  4. Concurrently, monitor the output of py script indicating new USB storage gadgets being attached to the “Host Computer” to ensure script is running and operating properly
  5. Concurrently, monitor the “Target Device” to determine when the device has been programmed (LED indication)
  6. Once programming is done, unplug the “Target Device” from the “Host Computer”.

“Target Device” is now ready for any additional verification or validation as part of the manufacturing procedure.

7    Helpful Debugging Tips

As there are number of pieces in this procedure, the setup could require some level of debug to get it all working. Here are some tips that can help

  1. Use Wireshark to monitor the ethernet communication between the “Host computer” and the “Target device”. This will help determine whether an ethernet connection was established between the “Host computer” and the “Target device” and whether boot request/reply interactions are being sent. Packet transfer of various boot components over TFTP protocol can also be verified.
  2. The boot messages of the “Target device” can be used to monitor whether it is booting over TFTP and serving the storage gadget. The default interface where these boot messages can be read is via UART0. So, a UART to USB cable along with a serial terminal software such as minicom/putty can be used to identify and debug any issues related to target booting.

 

8    Revision History

 
Revision NumberRevision DateChangesAuthor
25/21/2019  Fixed project download file issue  N. Dantu