Using i.MX RT1060 as the USB Mass Storage Gadget |
This application note explains how to make NXP i.MX RT1060 EVK visible as a USB storage device to a USB host such as, for instance, Windows, Linux PC or notebook. The most typical example of when this functionality is required is a "data harvesting" application. In such an application, a remote i.MX RT1060 device collects data readings from various sensors and then stores collected readings into non-volatile storage such as SD Card. Once in a while, a technician visits the remote site to offload harvested data and take it to the main site for further processing. Using the functionality described in this note, the data offloading is as simple as connecting the i.MX RT1060 as a USB device to a technician's notebook, which immediately recognizes it as USB storage. Collected data can then be simply copied from the USB storage to other disks on the notebook. A variation of the same application is a movable device that is periodically taken to the main office for data offloading. In this scenario, the embedded device is simply connected to a PC as a USB device and data is copied from the USB storage to the host computer.
The hardware platform for this application note is NXP i.MX RT1060 EVK.
We will use the Linux Mass Storage Gadget (MSG) to implement what we need. The main idea is that the MSG presents a partition on the SD Card as a storage device to the USB host. The backing partition is given to the Mass Storage Gadget as a parameter. To make data sharing workable using a Windows host, the USB storage must be formatted as a FAT file system. This way, data gathered by the target into the USB storage can be copied or manipulated otherwise, using standard Windows tools on the USB host end. The implication of the above is that the backing storage must be mounted as a FAT32 file system on the target side. This is not really a problem since Linux supports the FAT32 file system (along with many other file systems). Clearly, a file system can be mounted on a block device. One more thing we should discuss here is the fact that the SD Card is detected late during the initialization process. Thus, when the Linux Mass Storage Gadget driver attempts to use a SD Card partition as a backstorage during init, the appropriate /dev/mmc* device file does not exist yet. As a workaround, you can:
To summarize all the above, the architecture we want to implement will be as follows:
Software Platform Perform the following in the Emcraft i.MX RT1060 BSP:
[yur@ubuntu linux-cortexm-2.5.2]$ . ./ACTIVATE.sh echo "/dev/mmcblk0p2" > /sys/devices/platform/soc/soc\:aips-bus@40000000/402e0000.usb/ci_hdrc.0/gadget/lun0/file [yur@ubuntu rootfs]$ make Install the resultant rootfs.uImage to the target as described in Installing Linux images to the SD Card, and update the U-Boot environment as follows: => setenv bootargs_gadget g_mass_storage.iSerialNumber=123456 g_mass_storage.stall=0 g_mass_storage.removable=1
This section explains how to prepare the USB Mass Storage for deployment. This command sequence is a once-off procedure that needs to be performed on a device at software manufacturing time. With the bootable Linux image (rootfs.uImage) installed, U-Boot loads the Linux image from the SD Card to the SDRAM and passes control to the kernel entry point. The default installation procedure described in SD Card partitioning assumes there is a single partition on the SD Card. This partition holds rootfs.uImage, uboot.env, and some other system files. It is mounted from /etc/rc during init:
Let's create a new partition on SD Card (32 MB in this example). Before proceeding, unmount the first partition (to be able to write to the MBR then):
Now, restart the i.MX RT1060 EVK board, and let the Mass Storage Gadget run with the backing partition: ... Connect the NXP i.MX RT1060 EVK J9 connector to the host using an appropriate USB cable. At this point the i.MX RT1060 should become visible as a USB storage device to the host, however the storage still needs to be formatted as a FAT32 file system to allow using it with standard host software. The formatting is done on the host using standard software. For instance, on a Windows machine, go to My Computer and then locate an icon for the new removable disk. Ask to format it and agree with anything that Windows suggests, until the storage is formatted as a FAT32 file system.
Ok, so now everything is ready to start deploying the i.MX RT1060 as a "data harvesting" device. In all probability, the commands shown below would be put into the /etc/rc start-up script by any reasonably application, but in order to make the set-up command sequence easier for understanding, let's run the required commands manually. For the sake of running a clean test, let's power-cycle the device. As expected, Linux comes up to the shell: ... Mount the back-storage partition: ~ # mount /dev/mmcblk0p2 /mnt/ Let's "harvest" some data and store what is collected into a file in the FAT32 file system. In this demo, we emulate a data stream by taking a snapshot of the system time each second: / # while true; do date >> /mnt/data.log; sleep 1; done Having let the "data harvesting" run for a while, let's interrupt it (by pressing ^-C) and take a look at what data we have collected: ^C All looks as expected, so we are ready to try accessing the FAT32 file system from a USB host. Umount the back-storage on the target side: / # umount /mnt/
Given the above setup, the host will be able to see the i.MX RT1060 as a removable disk as soon as a USB connection is made between a free port on the host and the USB OTG interface on the target. A message similar to the following will appear on the target console when connection to the host has been made:
Host software should recognize the newly plugged USB device as a storage device and mount it as a FAT32 file system. Data collected on the target can be copied to other host disks for further processing. Note that the format of Windows and Unix text files differs slightly. In Windows, lines end with both the line feed and carriage return ASCII characters, but Unix uses only a line feed. As a consequence, some Windows applications will not show the line breaks in Unix-format files. Assuming that data is stored in a text file (vs a binary file) and Windows is a data processing host, Linux data harvesting applications should take care of the difference by adding a carriage return character to data logs.
It is important to note that it is not safe to update the USB storage both on the target and host sides at the same time. Here is what the Mass Storage Gadget documentation has to say about this: AN IMPORTANT WARNING! While Mass Storage Gadget is running and the gadget is connected to a USB host, that USB host will use the backing storage as a private disk drive. It will not expect to see any changes in the backing storage other than the ones it makes. Extraneous changes are liable to corrupt the filesystem and may even crash the host. Only one system (normally, the USB host) may write to the backing storage, and if one system is writing that data, no other should be reading it. The only safe way to share the backing storage between the host and the gadget's operating system at the same time is to make it read-only on both sides. Given that the primary use of this technology is to let the host copy harvested data for further processing, this should be an acceptable limitation for most applications. It is important to understand however that the host will see the USB storage in a state it was in when the USB cable was connected between the target and the host. Further updates made to the storage by the target will not be visible on the host until a next plug-in. As mentioned above, updates made on the host side may be unsafe in case the target continues harvesting data when the host is connected. Probably, the best strategy is to assume a read-only mount of the USB storage on the host side and let application code on the target take care of purging data at appropriate times. Note the Mass Storage Gadget provides a special flag (g_mass_storage.ro=1) to allows mounting the USB storage for read-only access by the host. |