Pi Zero as a universal USB stick
Multitool
In just a few simple steps, you can turn a Pi Zero into a universal USB flash drive that emulates storage, a serial port, Ethernet, and more.
Instead of taking along a separate USB gadget for every task, you can turn a Pi Zero into a universal device that provides storage, a network interface, and additional functions. This project relies on a rarely used feature of the Pi Zero: Its USB port supports USB On-The-Go (OTG). If you connect the small-board computer (SBC) to another computer, the Raspberry Pi logs in as a lower-level device (gadget).
Normally gadget mode [1] is undesirable. If you want to connect a memory stick to the Pi Zero, you need a special OTG cable; otherwise, it will not work (see the "How OTG Works" box). Conversely, plugging a normal cable into the USB port triggers the desired behavior.
How OTG Works
Normally, the role of a device in communication between two connected partners is defined. It either acts as a host or it doesn't. The host supplies power to the other device (slave, gadget, or peripheral) and controls its functions. In this way, accessories such as sticks, mice, or keyboards require minimal electronics.
In the first smartphones, the roles were still clearly defined. A smartphone connected to a PC advertised itself as a mass storage device, and the PC was able to read and write files. Later, the manufacturers decided that it would be practical to plug a USB stick into the smartphone and write to the stick from the device. To do this, however, the smartphone had to act as the host and also be intelligent enough to switch between roles, depending on the context. This was the impetus for the OTG extension of the USB specification.
The technical implementation was simple: In addition to the four existing pins at USB 2 (5V, ground, two data pins), a fifth ID pin was added. If it is connected to ground, a smartphone or a Pi Zero will switch to the active host role; otherwise (pin high or floating), it acts as a slave.
Normal USB cables simply lack the appropriate coding, so devices connected to them assume their default roles: For the Pi Zero, the default means the typically unused slave role. OTG adapters and cables, on the other hand, only connect the pin to ground on one side and thus also define the roles.
In Figure 1, the USB cable is plugged into the left-hand USB port and is used both to supply power and exchange data. If you want to reproduce the project without much effort, just from the software point of view, you can skip the next steps.
However, the cable solution is not elegant when you're on the road. On a laptop, especially, the Pi Zero will dangle in the air. For this reason, you need to do some tinkering with the hardware before you tackle the software.
Hands On
If you have basic experience with a soldering iron, attach a USB connector to the bottom of the Pi Zero (Figure 2), making sure the pins on the connector are assigned correctly; if in doubt, consult diagrams found on the Internet.
The most difficult part might not be the soldering itself, but finding the optimal length for the wires. USB plugs for self-soldering are available for a few cents from the usual mail order companies. Because the project basically only needs a Pi Zero (<$10/CA$13/£10/AU$25/EUR6), the risk of financial loss is not very high. If you have a Zero W, everything works the same way.
Another alternatives does not require any soldering. From Geekworm [2], you can pick up a ready-to-use board (Figure 3) for about $14 (CA$19/£11/AU$22/EUR13). Here, pogo (spring-loaded) pins ensure contact with the solder joints from below.
The solution is elegant and very compact but has the twin disadvantages that the Pi Zero remains unprotected and the USB plug is exposed. The big advantage is that the conversion from a Pi Zero to a USB stick is non-destructive.
The second alternative is the Zero Stem for about $6 (CA$8/£5/AU$11/EUR6), which is sold by various vendors worldwide [3] (Figure 4). The small board requires some soldering, but the USB connector is then firmly attached to the SBC, thanks to the screw connection.
Makers have 3D-printed housings for both the Geekworm board [4] and the Zero Stem [5]. When traveling, it certainly makes sense to swap protection for compactness. However, these housings do not solve one problem: If a stick juts out of the laptop by more than a few centimeters, jostling by people in public spaces will tear it off – it's not a matter of if, but when. That's why I decided to go for the DIY soldering approach and designed a suitable housing with an angled connector (Figure 5).
If you want to 3D-print the case, you will find it on Tinkercad [6]. The holder for the connector is optimized for the components I used. The very tight tolerances might have to be adapted to the specific printer or material used.
Raspbian Tweaks
A normal Raspbian is not configured to be used as a peripheral, but it has all the necessary features. Even the tasks you have to complete for this project do not require any special knowledge.
The Linux kernel has now reached the second iteration of gadget support. Originally, it had specialized drivers for this purpose, such as g_ether
for emulating an Ethernet adapter. The configuration was very simple: The line
dtoverlay=dwc2
was added to the /boot/config.txt
file, and you had to add the line
modules-load=dwc2,g_ether
to the /boot/cmdline.txt
file, which is normally a one-liner.
Although this method still works, these drivers will eventually be removed from the kernel. Another disadvantage is that a simultaneous configuration with several device types (e.g., Ethernet and mass storage) never worked properly.
In the next sections, therefore, I describe the currently applicable configuration procedure. Although the dtoverlay
line in /boot/config.txt
remains, the Raspberry Pi can provide all the necessary information dynamically.
The procedure now is: (1) plug the Pi Zero into another computer to supply power and boot; (2) during the boot process, a script configures the computer as a gadget; (3) the computer then transmits all the appropriate information to its counterpart.
USB Configurations
When booting, a Linux system automatically creates an entry in the /sys/bus/usb/
virtual filesystem (Figure 6) for all connected USB devices, including the internal hubs. Among other things, the content of all files with bInterface in their names is important: They describe the kind of USB device you are using.
To structure this information, the Linux kernel (like its Windows counterpart) contains an internal table with corresponding information. When a device is plugged in, the kernel and device exchange information, and the Linux kernel automatically creates the sysfs files.
However, because the Pi Zero is now assuming the role of the peripheral device, the process is reversed. The Linux kernel now provides the information to the other side with the configfs virtual filesystem (/config
). Like sysfs, configfs only exists at run time, with very similar content. Creating the file is not difficult, but it is tedious: You have to create various files, directories, and links – which looks like the kind of task ripe for scripting.
Listing 1 shows excerpts from such a script (complete file are available from the GitHub project [7] or FTP [8]) and dynamically creates the required entries in configfs at boot time. The files differ depending on the role you assign to the stick. Because the USB specification allows a stick to provide multiple logical devices, you do not need to decide.
Listing 1
raspi2go.sh (Excerpts)
The script uses the init_start()
function (lines 23-46) to create the basic files, including things like information about the vendor and type and maximum power consumption of the gadget. The create_storage()
and create_serial()
functions, on the other hand, create specific files, directories, and links for a mass storage device and the serial interface.
You install the script, including the appropriate system service, from the GitHub project. The system service is started at boot time and applies the configuration once. The example is based on a current Raspbian Lite; the Pixel version also works, but the Pi Zero has problems with the graphical interface.
The commands
$ git clone https://github.com/bablokb/raspi2go.git $ cd raspi2go $ sudo tools/install
install the software and adjust /boot/config.txt
. Afterward, you need to configure various settings in the file /etc/raspi2go.conf
(e.g., which role the Pi assumes or what name the "product" goes by). Rebooting enables the settings.
For the installation itself, as well as for later updates, you connect the Pi Zero to the local network in the usual way with an OTG adapter or access it over a wireless network. As long as you avoid using the soldered USB port, everything stays the same. Once the service is installed, the Pi Zero will display some error messages in the system log in host mode, but you can safely ignore them.
In gadget mode, the Pi Zero only suffers one problem: Simply unplugging it does not shut the Pi down properly. The solution is to run the Pi Zero in read-only mode. You can find detailed instructions on how to do this online [9].
Buy this article as PDF
(incl. VAT)