Using USB Flash with SmartFusion2 under uClinux Print


This application note explains how to use a USB Flash device with SmartFusion2 under uClinux.

Note that this application note is not applicable to the M2S050-FG484 SOM since the M2S050 SmartFusion2 device does not support USB at this time.

Hardware Platform

The hardware platform is Emcraft Systems' M2S-FG484 system-on-module (SOM) plugged into the SOM-BSB-EXT baseboard. The Cortex-M3 core is configured to run at 166 MHz. The on-chip cache is enabled by software for LPDDR.

The demo documented in this application note assumes that the 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 empty FAT32 partition is plugged into the USB 2.0 A Female connector of the above cable.

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 SmartFusion2 uClinux distribution.

Note: The Linux image and the sample project have been built and validated in context of the Emcraft Systems Release 1.12.0. If you are using a different release, some porting changes may be needed.

Logging Data onto USB Flash

On power-up reset, U-Boot loads the Linux image from the SPI Flash to the LPDDR and passes control to the kernel entry point:

U-Boot 2010.03-linux-cortexm-1.12.0 (Nov 25 2013 - 15:25:13)

CPU : SmartFusion2 SoC (Cortex-M3 Hard IP)
Freqs: CORTEX-M3=166MHz,PCLK0=83MHz,PCLK1=83MHz
Board: M2S-FG484-SOM Rev 1A,
In: serial
Out: serial
Err: serial
Net: M2S_MAC
Hit any key to stop autoboot: 0
16384 KiB S25FL128S_64K at 0:0 is now current device
## Booting kernel from Legacy Image at a0007fc0 ...
Image Name: Linux-2.6.33-arm1
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 1209376 Bytes = 1.2 MB
Load Address: a0008000
Entry Point: a0008001
Verifying Checksum ... OK
Loading Kernel Image ... OK

Starting kernel ...

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

Linux version 2.6.33-arm1 (psl (gcc version 4.4.1 (Sourcery G++ Lite 2010q1-189) ) #16 Mon Dec 9 21:21:03 +0400 2013
CPU: ARMv7-M Processor [412fc231] revision 1 (ARMv7M)
CPU: NO data cache, 8K instruction cache
Machine: Actel M2S
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 16256
Kernel command line: m2s_platform=m2s-fg484-som console=ttyS0,115200 panic=10
ip= ethaddr=C0:B1:3C:83:83:83
PID hash table entries: 256 (order: -2, 1024 bytes)
Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
Memory: 64MB = 64MB total
Memory: 63752k/63752k available, 1784k reserved, 0K highmem
Virtual kernel memory layout:
vector : 0x00000000 - 0x00001000 ( 4 kB)
fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB)
vmalloc : 0x00000000 - 0xffffffff (4095 MB)
lowmem : 0xa0000000 - 0xa4000000 ( 64 MB)
modules : 0xa0000000 - 0x01000000 (1552 MB)
.init : 0xa0008000 - 0xa0055000 ( 308 kB)
.text : 0xa00fd448 - 0xa0121000 ( 143 kB)
.data : 0xa0122000 - 0xa012f420 ( 54 kB)
Hierarchical RCU implementation.
Calibrating delay loop... 154.82 BogoMIPS (lpj=774144)
Mount-cache hash table entries: 512
bio: create slab <bio-0> 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 mss_timer2

The USB controller is initialized:

musb_hdrc: version 6.0, musb-dma, host, debug=0
musb_hdrc: USB Host mode controller at 40043000 using DMA, IRQ 20
musb_hdrc musb_hdrc: MUSB HDRC host driver
musb_hdrc musb_hdrc: new USB bus registered, assigned bus number 1
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 1 port detected
NTFS driver 2.1.29 [Flags: R/O].
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: 8250/16550 driver, 2 ports, IRQ sharing disabled
serial8250.0: ttyS0 at MMIO 0x40000000 (irq = 10) is a 16550A
console [ttyS0] enabled

The USB mass storage device driver is initialized:

Initializing USB Mass Storage driver...
usbcore: registered new interface driver usb-storage
USB Mass Storage support registered.
usbcore: registered new interface driver usbhid
usbhid: USB HID core driver
Freeing init memory: 296K
init started: BusyBox v1.17.0 (2013-01-02 14:41:06 +0400)

The USB Flash device is detected and configured:

~ # usb 1-1: new high speed USB device using musb_hdrc and address 2
scsi0 : usb-storage 1-1:1.0
scsi 0:0:0:0: Direct-Access Kingston DT 101 II 1.00 PQ: 0 ANSI: 2
sd 0:0:0:0: [sda] 7827392 512-byte logical blocks: (4.00 GB/3.73 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 FAT32 partition:

~ # fdisk -l /dev/sda

Disk /dev/sda: 4007 MB, 4007624704 bytes
32 heads, 63 sectors/track, 3882 cylinders
Units = cylinders of 2016 * 512 = 1032192 bytes

Device Boot Start End Blocks Id System
/dev/sda1 1 3882 3913024+ 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:46 UTC 1970
Thu Jan 1 00:01:47 UTC 1970
Thu Jan 1 00:01:48 UTC 1970
Thu Jan 1 00:01:49 UTC 1970
Thu Jan 1 00:01:50 UTC 1970
Thu Jan 1 00:01:51 UTC 1970
Thu Jan 1 00:01:52 UTC 1970
Thu Jan 1 00:01:53 UTC 1970
Thu Jan 1 00:01:54 UTC 1970
Thu Jan 1 00:01:55 UTC 1970
~ #

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

~ # umount /mnt
~ # usb 1-1: USB disconnect, address 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.

Read / Write Performance

Write throughput to a 4GB Kingston USB Flash is measured to be the following:

~ # dd if=/dev/zero of=/mnt/10m bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10.0MB) copied, 2.491694 seconds, 4.0MB/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, 1.925311 seconds, 5.2MB/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
~ #

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.