Using USB Flash with the USB High Speed Interface on the STM32F7 Print

 

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 Emcraft Systems STM32F7 SOM Starter Kit, which is comprised of the STM32F7 system-on-module (SOM) plugged into the SOM-BSB-EXT development baseboard.

This demo assumes that a Mini-B to USB 2.0 A Female cable is plugged into the USB OTG interface connector on the SOM-BSB-EXT baseboard 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:


Logging Data onto USB Flash

On power-up or reset, U-Boot loads the Linux and Device Tree images from the NOR Flash to the SDRAM and passes control to the kernel entry point:

U-Boot 2010.03-cortexm-2.1.0 (Sep 19 2016 - 11:18:48)

CPU : STM32F7 (Cortex-M7)
Freqs: SYSCLK=200MHz,HCLK=200MHz,PCLK1=50MHz,PCLK2=100MHz
Board: STM32F7 SOM Rev 1.A, www.emcraft.com
DRAM: 32 MB
Flash: 16 MB
In: serial
Out: serial
Err: serial
Net: STM32_MAC
Hit any key to stop autoboot: 0
## Booting kernel from Legacy Image at 60020000 ...
Image Name: Linux-4.2.0-cortexm-2.1.0
Image Type: ARM Linux Multi-File Image (uncompressed)
Data Size: 5773859 Bytes = 5.5 MB
Load Address: c0008000
Entry Point: c0008001
Contents:
Image 0: 5756576 Bytes = 5.5 MB
Image 1: 17271 Bytes = 16.9 kB
Verifying Checksum ... OK
## Flattened Device Tree from multi component Image at 60020000
Booting using the fdt at 0x6059d6ec
Loading Multi-File Image ... OK
OK
Loading Device Tree to c1ff8000, end c1fff376 ... OK

Starting kernel ...

The kernel proceeds to boot-up, initializing the configured I/O interfaces and sub-systems:

Booting Linux on physical CPU 0x0
Linux version 4.2.0-cortexm-2.1.0 (psl@skywanderer.emcraft.com) (gcc version 4.4.1 (Sourcery G++ Lite 2010q1-189) ) #2 Mon Sep 19 11:19:44 +0400 2016
CPU: ARMv7-M [410fc271] revision 1 (ARMv7M), cr=00000000
CPU: WBA data cache, WBA instruction cache
Machine model: EmCraft Systems STM32F7-SOM board
Built 1 zonelists in Zone order, mobility grouping off. Total pages: 8128
Kernel command line: stm32_platform=stm32f7-som console=ttyS0,115200 panic=10 user_debug=8
ip=192.168.1.132:192.168.1.65:::stm32f7-som:eth0:off
PID hash table entries: 128 (order: -3, 512 bytes)
Dentry cache hash table entries: 4096 (order: 2, 16384 bytes)
Inode-cache hash table entries: 2048 (order: 1, 8192 bytes)
Memory: 25624K/32768K available (2295K kernel code, 165K rwdata, 508K rodata, 2652K init, 96K bss, 7144K reserved, 0K cma-reserved)
Virtual kernel memory layout:
vector : 0x00000000 - 0x00001000 ( 4 kB)
fixmap : 0xffc00000 - 0xfff00000 (3072 kB)
vmalloc : 0x00000000 - 0xffffffff (4095 MB)
lowmem : 0xc0000000 - 0xc2000000 ( 32 MB)
.text : 0xc0008000 - 0xc02c5000 (2804 kB)
.init : 0xc02c5000 - 0xc055c000 (2652 kB)
.data : 0xc055c000 - 0xc05856a0 ( 166 kB)
.bss : 0xc0586000 - 0xc059e284 ( 97 kB)
NR_IRQS:16 nr_irqs:16 16
clocksource: arm_system_timer: mask: 0xffffff max_cycles: 0xffffff, max_idle_ns: 298634427 ns
ARM System timer initialized as clocksource
/soc/timer@40000000: STM32 clockevent driver initialized (32 bits)
sched_clock: 32 bits at 100 Hz, resolution 10000000ns, wraps every 21474836475000000ns
Calibrating delay loop... 395.67 BogoMIPS (lpj=1978368)
pid_max: default: 4096 minimum: 301
Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
devtmpfs: initialized
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
pinctrl core: initialized pinctrl subsystem
NET: Registered protocol family 16
stm32-pinctrl pin-controller: nbanks = 11
stm32-pinctrl pin-controller: nfunctions = 14
stm32-pinctrl pin-controller: ngroups = 15
stm32-pinctrl pin-controller: GPIOA bank added.
stm32-pinctrl pin-controller: GPIOB bank added.
stm32-pinctrl pin-controller: GPIOC bank added.
stm32-pinctrl pin-controller: GPIOD bank added.
stm32-pinctrl pin-controller: GPIOE bank added.
stm32-pinctrl pin-controller: GPIOF bank added.
stm32-pinctrl pin-controller: GPIOG bank added.
stm32-pinctrl pin-controller: GPIOH bank added.
stm32-pinctrl pin-controller: GPIOI bank added.
stm32-pinctrl pin-controller: GPIOJ bank added.
stm32-pinctrl pin-controller: GPIOK bank added.
stm32-pinctrl pin-controller: Function[0 name:i2c_1, groups:1]
stm32-pinctrl pin-controller: Function[1 name:i2c_2, groups:1]
stm32-pinctrl pin-controller: Function[2 name:i2c_3, groups:1]
stm32-pinctrl pin-controller: Function[3 name:mac, groups:2]
stm32-pinctrl pin-controller: Function[4 name:sdio, groups:1]
stm32-pinctrl pin-controller: Function[5 name:spi_2, groups:1]
stm32-pinctrl pin-controller: Function[6 name:spi_4, groups:1]
stm32-pinctrl pin-controller: Function[7 name:spi_5, groups:1]
stm32-pinctrl pin-controller: Function[8 name:usart1, groups:1]
stm32-pinctrl pin-controller: Function[9 name:usart6, groups:1]
stm32-pinctrl pin-controller: Function[10 name:usart7, groups:1]
stm32-pinctrl pin-controller: Function[11 name:usb_fs, groups:1]
stm32-pinctrl pin-controller: Function[12 name:usb_hs, groups:1]
stm32-pinctrl pin-controller: Function[13 name:ltdc, groups:1]
stm32_dma 40026000.dma: STM32 DMA Controller ( slave ), 8 channels
stm32_dma 40026400.dma: STM32 DMA Controller ( slave ), 8 channels
SCSI subsystem initialized
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
soc:phy_hs supply vcc not found, using dummy regulator
soc:phy_fs supply vcc not found, using dummy regulator
pps_core: LinuxPPS API ver. 1 registered
pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti
<giometti@linux.it>
PTP clock support registered
Bluetooth: Core ver 2.20
NET: Registered protocol family 31
Bluetooth: HCI device and connection manager initialized
Bluetooth: HCI socket layer initialized
Bluetooth: L2CAP socket layer initialized
Bluetooth: SCO socket layer initialized
clocksource: Switched to clocksource arm_system_timer
NET: Registered protocol family 2
TCP established hash table entries: 1024 (order: 0, 4096 bytes)
TCP bind hash table entries: 1024 (order: 0, 4096 bytes)
TCP: Hash tables configured (established 1024 bind 1024)
UDP hash table entries: 256 (order: 0, 4096 bytes)
UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
NET: Registered protocol family 1
RPC: Registered named UNIX socket transport module.
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
RPC: Registered tcp NFSv4.1 backchannel transport module.
futex hash table entries: 16 (order: -5, 192 bytes)
jffs2: version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
fuse init (API version 7.23)
Block layer SCSI generic (bsg) driver version 0.4 loaded (major 251)
io scheduler noop registered
io scheduler cfq registered (default)
stm32-pinctrl pin-controller: maps: function ltdc group ltdc-0 num 29
stm32_lcdfb 40016800.ltdc: fb0: fb device registered successfully
STM32 USART driver initialized
stm32-pinctrl pin-controller: maps: function usart1 group usart1-0 num 3
40011000.serial: ttyS0 at MMIO 0x40011000 (irq = 21, base_baud = 6250000) is a stm32f7-usart console [ttyS0] enabled
stm32-pinctrl pin-controller: maps: function usart6 group usart6-0 num 3
40011400.serial: ttyS5 at MMIO 0x40011400 (irq = 22, base_baud = 6250000) is a stm32f7-usart
physmap-flash.0: Found 1 x16 devices at 0x0 in 16-bit bank. Manufacturer ID 0x000001 Chip ID 0x002101 Amd/Fujitsu Extended Query Table at 0x0040
Amd/Fujitsu Extended Query version 1.5.
number of CFI chips: 1
3 ofpart partitions found on MTD device physmap-flash.0
Creating 3 MTD partitions on "physmap-flash.0":
0x000000000000-0x000000020000 : "flash_uboot_env"
0x000000020000-0x000000a20000 : "flash_linux_image"
0x000000a20000-0x000001000000 : "flash_jffs2"
stm32-pinctrl pin-controller: maps: function mac group mac_rmii num 10
stmmac - user ID: 0x10, Synopsys ID: 0x35
Ring mode enabled
DMA HW capability register supported
Enhanced/Alternate descriptors
Enabled extended descriptors
RX Checksum Offload Engine supported (type 2)
TX Checksum insertion supported
Wake-Up On Lan supported
Enable RX Mitigation via HW Watchdog Timer
libphy: stmmac: probed
eth0: PHY ID 00221560 at 0 IRQ POLL (stmmac-0:00) active
eth0: PHY ID 00221560 at 1 IRQ POLL (stmmac-0:01)
PPP generic driver version 2.4.2
PPP BSD Compression module registered
PPP Deflate Compression module registered
usbcore: registered new interface driver rt2800usb

The USB controller and USB mass storage device driver are initialized:

stm32-pinctrl pin-controller: maps: function usb_hs group usb_hs-0 num 13
dwc2 40040000.usb: DWC OTG Controller
dwc2 40040000.usb: new USB bus registered, assigned bus number 1
dwc2 40040000.usb: irq 40, io mem 0x00000000
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 1 port detected
usbcore: registered new interface driver cdc_acm
cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters
usbcore: registered new interface driver usb-storage
stm32-rtc 40002800.rtc: rtc core: registered 40002800.rtc as rtc0
i2c /dev entries driver
stm32-pinctrl pin-controller: maps: function i2c_1 group i2c_1-0 num 3
crtouch_drv 0-0049: failed to read size of screen
crtouch_drv: probe of 0-0049 failed with error -5
stm32f7-i2c 40005400.i2c: I2C Controller i2c-0 at 40005400,irq=19
usbcore: registered new interface driver btusb
usbcore: registered new interface driver usbhid
usbhid: USB HID core driver
NET: Registered protocol family 17
Bluetooth: RFCOMM TTY layer initialized
Bluetooth: RFCOMM socket layer initialized
Bluetooth: RFCOMM ver 1.11
stm32-rtc 40002800.rtc: setting system clock to 2000-01-01 00:01:27 UTC (946684887)
IP-Config: Guessing netmask 255.255.255.0
IP-Config: Complete:
device=eth0, hwaddr=c0:b1:3c:88:88:86, ipaddr=192.168.1.132, mask=255.255.255.0,
gw=255.255.255.255
host=stm32f7-som, domain=, nis-domain=(none)
bootserver=192.168.1.65, rootserver=192.168.1.65, rootpath=
vmmc: disabling
Freeing unused kernel memory: 2652K (c02c5000 - c055c000)
init started: BusyBox v1.17.0 (2016-09-19 11:07:14 +0400)
stm32-dwmac 40028000.ethernet eth0: Link is Up - 100Mbps/Full - flow control off
/ #

The USB Flash device is detected and configured:

/ # usb 1-1: new high-speed USB device number 2 using dwc2
usb-storage 1-1:1.0: USB Mass Storage device detected
scsi host0: 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] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA
sda: sda1
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     1322       3910450+       6      FAT16

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:

/ # cat /mnt/data.log
Sat Jan 1 00:12:53 UTC 2000
Sat Jan 1 00:12:54 UTC 2000
Sat Jan 1 00:12:55 UTC 2000
Sat Jan 1 00:12:56 UTC 2000
Sat Jan 1 00:12:57 UTC 2000
Sat Jan 1 00:12:58 UTC 2000
Sat Jan 1 00:12:59 UTC 2000
Sat Jan 1 00:13:00 UTC 2000
Sat Jan 1 00:13:01 UTC 2000
Sat Jan 1 00:13:02 UTC 2000
Sat Jan 1 00:13:03 UTC 2000
Sat Jan 1 00:13:04 UTC 2000
/ #

Now, let's unmount the USB Flash and unplug the device from the USB connector:

/ # umount /mnt
/ # usb 1-1: USB disconnect, device number 2

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: new high-speed USB device number 3 using dwc2
usb-storage 1-1:1.0: USB Mass Storage device detected
scsi host1: 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] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA
sda: sda1
sd 1:0:0:0: [sda] Attached SCSI removable disk

/ # mount /dev/sda1 /mnt
/ # ls -lt /mnt
-rwxr-xr-x 1 root root 348 Jan 1 00:13 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.465603 seconds, 6.8MB/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.936494 seconds, 10.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)
devtmpfs on /dev type devtmpfs (rw,nosuid,relatime,mode=0755)
devpts on /dev/pts type devpts (rw,relatime,gid=5,mode=620,ptmxmode=000)
/dev/sda1 on /mnt type vfat (rw,sync,relatime,fmask=0022,
dmask=0022,codepage=437,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.