This application note explains how to use a USB Flash device with the USB High Speed (HS) interface of the STM32F7 microcontroller running uCLinux.
Hardware Platform
The hardware platform is the STM32F7 Discovery board.
The STM32F7 Discovery board is powered by the 5V DC power supply. The following power supply configuration should be used:
- Shortage between JP1 5V ext and JP1 5V;
 
- +5V DC power adapter connected to JP2.
 
This demo assumes that a Micro-A to USB 2.0 A Female cable is plugged into the USB HS interface connector on the STM32F7 Discovery board and that a pre-formatted USB Flash disk with an FAT32 partition is plugged into the USB 2.0 A Female connector of the above USB cable. The following picture illustrates the hardware set-up:
Installing the Demo
The procedure described here explains how to install the bootable Linux image (usbflash.uImage) to the target.
Here is how you can build and install the bootable Linux image from the project sources (usbflash.tgz), having installed them on top of the Emcraft Systems STM32F7 uClinux distribution. Contact Emcraft to obtain the bootable image and project source files.
 Note: The Linux image and the sample project have been built and validated in context of the Emcraft Systems Release 1.14.1. If you are using a different release, some porting changes may be needed.
Logging Data onto USB Flash
On power-up or reset, U-Boot loads the Linux image to the SDRAM and passes control to the kernel entry point:
U-Boot 2010.03-cortexm-1.14.2 (Sep 04 2015 - 20:10:20)
 
 CPU  : STM32F7 (Cortex-M7)
 Freqs: SYSCLK=200MHz,HCLK=200MHz,PCLK1=50MHz,PCLK2=100MHz
 Board: STM32F746 Discovery Rev 1.A, www.emcraft.com
 DRAM:   8 MB
 In:    serial
 Out:   serial
 Err:   serial
 Net:   STM32_MAC
 Auto-negotiation...completed.
 STM32_MAC: link UP (100/Full)
 Using STM32_MAC device
 TFTP from server 172.17.0.1; our IP address is 172.17.43.47
 Filename 'antonp/usb'.
 Load address: 0xc0007fc0
 Loading: T ################################################################# 	 #####################################################
 done
 Bytes transferred = 1721856 (1a4600 hex)
 ## Booting kernel from Legacy Image at c0007fc0 ...
  Image Name:   Linux-2.6.33-arm1
 Image Type:   ARM Linux Kernel Image (uncompressed)
 Data Size:    1721792 Bytes =  1.6 MB
 Load Address: c0008000
 Entry Point:  c0008001
 Verifying Checksum ... OK
 Loading Kernel Image ... OK
 OK
 
 Starting kernel ...
The kernel proceeds to boot-up, initializing the configured I/O interfaces and sub-systems:
Linux version 2.6.33-arm1 (
 This e-mail address is being protected from spambots. You need JavaScript enabled to view it
 ) (gcc version 4.4.1 (Sourcery G++ Lite 2010q1-189) ) #133 Tue Jun 30 15:00:10 +0400 2015
 CPU: ARMv7-M Processor [410fc271] revision 1 (ARMv7M)
 CPU: WBA data cache, WBA instruction cache
 Machine: STMicro STM32
 Built 1 zonelists in Zone order, mobility grouping off.  Total pages: 2032
 Kernel command line: stm32_platform=stm32f7-disco console=ttyS5,115200 panic=10 
ip=172.17.43.47:172.17.0.1:::stm32f7-disco:eth0:off ethaddr=C0:B1:3C:88:45:86
 PID hash table entries: 32 (order: -5, 128 bytes)
 Dentry cache hash table entries: 1024 (order: 0, 4096 bytes)
 Inode-cache hash table entries: 1024 (order: 0, 4096 bytes)
 Memory: 8MB = 8MB total
 Memory: 5344k/5344k available, 2848k reserved, 0K highmem
 Virtual kernel memory layout:
 vector  : 0x00000000 - 0x00001000   (   4 kB)
 fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
 vmalloc : 0x00000000 - 0xffffffff   (4095 MB)
 lowmem  : 0xc0000000 - 0xc0800000   (   8 MB)
 modules : 0xc0000000 - 0xc2000000   (  32 MB)
 .init : 0xc0008000 - 0xc005f000   ( 348 kB)
 .text : 0xc005f000 - 0xc0195000   (1240 kB)
 .data : 0xc0196000 - 0xc01ac5c0   (  90 kB)
 Hierarchical RCU implementation.
 NR_IRQS:258
 Calibrating delay loop... 397.31 BogoMIPS (lpj=1986560)
 Mount-cache hash table entries: 512
 NET: Registered protocol family 16
 stm32_flash_init: Unknown platform 0x6, exit
 bio: create slab  at 0
 SCSI subsystem initialized
 usbcore: registered new interface driver usbfs
 usbcore: registered new interface driver hub
 usbcore: registered new device driver usb
 Switching to clocksource cm3-systick
 NET: Registered protocol family 2
 IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
 TCP established hash table entries: 512 (order: 0, 4096 bytes)
 TCP bind hash table entries: 512 (order: -1, 2048 bytes)
 TCP: Hash tables configured (established 512 bind 512)
 TCP reno registered
 RPC: Registered udp transport module.
 RPC: Registered tcp transport module.
 RPC: Registered tcp NFSv4.1 backchannel transport module.
 JFFS2 version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
 Block layer SCSI generic (bsg) driver version 0.4 loaded (major 254)
 io scheduler noop registered
 io scheduler deadline registered
 io scheduler cfq registered (default)
 Serial: STM32 USART driver
 stm32serial.5: ttyS5 at MMIO 0x40011400 (irq = 71) is a STM32 USART Port
 console [ttyS5] enabled
 blackfin-eth: Using SRAM for DMA buffers from 20001000
 blackfin-eth: found MAC at 0x40028000, irq 61
 blackfin_mii_bus: probed
 found PHY id 0x7c131 addr 0
 eth0: using MII interface
 eth0: attached PHY driver [Generic PHY] (mii_bus:phy_addr=00:00, irq=-1)
The USB controller and USB mass storage device driver are initialized:
Initializing USB Mass Storage driver...
 usbcore: registered new interface driver usb-storage
 USB Mass Storage support registered.
 USB: DWC2 USB driver
 dwc2 dwc2.0: DWC OTG Controller
 dwc2 dwc2.0: new USB bus registered, assigned bus number 1
 dwc2 dwc2.0: irq 77, io mem 0x00000000
 usb usb1: New USB device found, idVendor=1d6b, idProduct=0002
 usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
 usb usb1: Product: DWC OTG Controller
 usb usb1: Manufacturer: Linux 2.6.33-arm1 dwc2_hsotg
 usb usb1: SerialNumber: dwc2.0
 hub 1-0:1.0: USB hub found
 hub 1-0:1.0: 1 port detected
 TCP cubic registered
 NET: Registered protocol family 17
 ARMv7-M VFP Extension supported
 IP-Config: Guessing netmask 255.255.0.0
 IP-Config: Complete:
 device=eth0, addr=172.17.43.47, mask=255.255.0.0, gw=255.255.255.255,
 host=stm32f7-disco, domain=, nis-domain=(none),
 bootserver=172.17.0.1, rootserver=172.17.0.1, rootpath=
 Freeing init memory: 348K
 init started: BusyBox v1.17.0 (2015-06-29 13:26:42 +0400)
 ~ # PHY: 00:00 - Link is Up - 100/Full 
The USB Flash device is detected and configured:
~ # usb 1-1: new high speed USB device using dwc2 and address 2
 usb 1-1: New USB device found, idVendor=0781, idProduct=556b
 usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
 usb 1-1: Product: Cruzer Edge
 usb 1-1: Manufacturer: SanDisk
 usb 1-1: SerialNumber: 200608757113E68174D9
 scsi0 : usb-storage 1-1:1.0
 scsi 0:0:0:0: Direct-Access     SanDisk  Cruzer Edge      1.26 PQ: 0 ANSI: 5
 sd 0:0:0:0: [sda] 7821312 512-byte logical blocks: (4.00 GB/3.72 GiB)
 sd 0:0:0:0: [sda] Write Protect is off
 sd 0:0:0:0: [sda] Assuming drive cache: write through
 sd 0:0:0:0: [sda] Assuming drive cache: write through
 sda: sda1
 sd 0:0:0:0: [sda] Assuming drive cache: write through
 sd 0:0:0:0: [sda] Attached SCSI removable disk
At this point, the USB Flash is accessible as a disk. The following command is used to examine the disk, which is detected as a 4GBytes disk partitioned to have a single empty FAT32 partition:
~ # fdisk -l /dev/sda
 Disk /dev/sda: 4004 MB, 4004511744 bytes
 116 heads, 51 sectors/track, 1322 cylinders
 Units = cylinders of 5916 * 512 = 3028992 bytes
 Device Boot      Start         End      Blocks  Id System
 /dev/sda1               1        1323     3910640   b Win95 FAT32
Let's mount the FAT32 file system. As expected, it is empty at this point:
~ # mount /dev/sda1 /mnt
 ~ # ls -lt /mnt
Let's "harvest" some data and store what is collected into a file on the USB Flash disk. 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 few seconds, let's interrupt it (by pressing ^-C) and take a look at what data we have collected:
^C
 ~ # cat /mnt/data.log
 Thu Jan  1 00:01:18 UTC 1970
 Thu Jan  1 00:01:19 UTC 1970
 Thu Jan  1 00:01:20 UTC 1970
 Thu Jan  1 00:01:21 UTC 1970
 Thu Jan  1 00:01:22 UTC 1970
 Thu Jan  1 00:01:23 UTC 1970
 Thu Jan  1 00:01:24 UTC 1970
 Thu Jan  1 00:01:25 UTC 1970
Now, let's unmount the USB Flash and unplug the device from the USB connector:
~ # umount /mnt
 ~ # hub 1-0:1.0: port 1 disabled by hub (EMI?), re-enabling...
At this point, the USB Flash device can be taken to a PC for further data processing. Just plug in the USB Flash into a USB port on your PC and the PC software will be able to mount the device as a FAT32 file system.
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.
Note further that you can hot plug your USB Flash device on the running system at any time:
usb 1-1: USB disconnect, address 
 usb 1-1: new high speed USB device using dwc2 and address 3
 usb 1-1: New USB device found, idVendor=0781, idProduct=556b
 usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
 usb 1-1: Product: Cruzer Edge
 usb 1-1: Manufacturer: SanDisk
 usb 1-1: SerialNumber: 200608757113E68174D9
 scsi1 : usb-storage 1-1:1.0
 scsi 1:0:0:0: Direct-Access     SanDisk  Cruzer Edge      1.26 PQ: 0 ANSI: 5
 sd 1:0:0:0: [sda] 7821312 512-byte logical blocks: (4.00 GB/3.72 GiB)
 sd 1:0:0:0: [sda] Write Protect is off
 sd 1:0:0:0: [sda] Assuming drive cache: write through
 sd 1:0:0:0: [sda] Assuming drive cache: write through
 sda: sda1
 sd 1:0:0:0: [sda] Assuming drive cache: write through
 sd 1:0:0:0: [sda] Attached SCSI removable disk
 ~ # mount /dev/sda1 /mnt
 ~ # ls -lt /mnt
-rwxr-xr-x    1 root     root           232 Jan  1  1980 data.log
Read / Write Performance
Write throughput to the above 4GB USB Flash is measured to be as follows:
~ # dd if=/dev/zero of=/mnt/10m bs=1M count=10
 10+0 records in
 10+0 records out
 10485760 bytes (10.0MB) copied, 1.497783 seconds, 6.7MB/s 
 ~ #
Read throughput using the same USB Flash device is as follows:
~ # umount /mnt
 ~ # mount /dev/sda1 /mnt
 ~ # dd if=/mnt/10m of=/dev/null bs=1M count=10
 10+0 records in
 10+0 records out
 10485760 bytes (10.0MB) copied, 0.730519 seconds, 13.7MB/s 
 ~ #
Data Synchronization Considerations
It is important to understand that VFAT supports write-back in Linux, which means that file changes do not go to the physical media straight away and instead are cached in memory and go to the Flash at a later time. This helps to reduce amount to I/O to the physical Flash, resulting in a better performance overall.
The write-back creates a certain issue for embedded devices however. If the power to the device is shut down unexpectedly, or the USB Flash is unplugged without a proper unmount or sync, some of latest file changes may be lost.
As it is typical with Linux, the issue can be handled in many ways. Data synchronization can be ensured on a per-file, per-subtree, per-filesystem or system-wide basis. Synchronization can be transparent for the user or may require issuing an explicit API call or a shell command.
The most obvious solution is to mount the file system in synchronous mode (note the -o sync parameter in the call below):
~ # mount -o sync /dev/sda1 /mnt
 ~ # mount
 rootfs on / type rootfs (rw)
 proc on /proc type proc (rw,relatime)
 sysfs on /sys type sysfs (rw,relatime)
 none on /dev/pts type devpts (rw,relatime,mode=600,ptmxmode=000)
 /dev/sda1 on /mnt type vfat 
(rw,sync,relatime,fmask=0022,dmask=0022,codepage=cp437,iocharset=iso8859-1,
shortname=mixed,errors=remount-ro)
 ~ #
When the file system is mounted for synchronous operation, Linux guarantees that data is written to the physical media before any write() returns to a calling application. The tradeoff is that written data is no longer cached in memory, which reduces the write performance substantially.