Create a gist now

Instantly share code, notes, and snippets.

Simple guide for setting up OTG modes on the Raspberry Pi Zero

Raspberry Pi Zero OTG Mode

Simple guide for setting up OTG modes on the Raspberry Pi Zero - By Andrew Mulholland (gbaman).

The Raspberry Pi Zero (and model A and A+) support USB On The Go, given the processor is connected directly to the USB port, unlike on the B, B+ or Pi 2 B, which goes via a USB hub.
Because of this, if setup to, the Pi can act as a USB slave instead, providing virtual serial (a terminal), virtual ethernet, virtual mass storage device (pendrive) or even other virtual devices like HID, MIDI, or act as a virtual webcam!
It is important to note that, although the model A and A+ can support being a USB slave, they are missing the ID pin (is tied to ground internally) so are unable to dynamically switch between USB master/slave mode. As such, they default to USB master mode. There is no easy way to change this right now.
It is also important to note, that a USB to UART serial adapter is not needed for any of these guides, as may be documented elsewhere across the internet.

Which process should I choose?

There are 2 routes you can take for setting up the Raspberry Pi Zero as a USB Slave (OTG mode).
1. The quick route - The quick route doesn't require anything beside your Pi Zero, SD card and a Windows, Mac or Linux computer. It though only supports setting up the Pi Zero as a virtual Ethernet device (allowing full SSH, SFTP, VNC etc). For any of the other USB Gadget drivers (beside g_ether), use route 2.
2. The modular slower, but more flexible route - This route requires a screen and keyboard to configure your Pi Zero once it has completed its first boot.

1. Very quick way (No USB keyboard, mouse, HDMI monitor needed)

The newer method has now been brought out into a separate Gist, which can be found here.

2. Modular, but slower to setup method

For this method, a Pi Zero, SD card (with Raspbian Jessie lite or full), screen and keyboard are required.
You are able to set up any of the below modules using this method and are not just limited to g_ether. The required kernels are also now shipped with Raspbian 2016-05-10 releases and beyond. So no need to do a raspi-update.
No web connectivity is required, nor is a USB-UART adapter required for this method. This documentation is based off the initial excellent work done on this Github pull request.
Modules included

  • Serial (g_serial)
  • Ethernet (g_ether)
  • Mass storage (g_mass_storage)
  • MIDI (g_midi)
  • Audio (g_audio)
  • Keyboard/Mouse (g_hid)
  • Mass storage and Serial (g_acm_ms)
  • Ethernet and Serial (g_cdc)
  • Multi (g_multi) - Allows you to configure 2 from Ethernet, Mass storage and Serial
    In addition to the above modules, a few other (less useful) modules are included.
  • Webcam (g_webcam)
  • Printer (g_printer)
  • Gadget tester (g_zero)

  1. First, flash Jessie (only tested on full, lite version may also work though) onto a blank microSD card.
  2. (step only needed if running Raspbain version before 2016-05-10) Once it starts up again, run sudo BRANCH=next rpi-update. This will take a while.
  3. Next we need to make sure we are using the dwc2 USB driver echo "dtoverlay=dwc2" | sudo tee -a /boot/config.txt.
  4. And enable it in Raspbian echo "dwc2" | sudo tee -a /etc/modules
  5. Need to now pick which module you want to use from the list above, for example for ethernet echo "g_ether" | sudo tee -a /etc/modules. You can only pick one of the above modules to use at a time.

Using the modules

  • g_serial - To use the standard serial module, you need to tell the Pi to forward the serial console to it with sudo systemctl enable getty@ttyGS0.service, then you can connect to the device via Putty or Screen.
  • g_ether - Using virtual ethernet, you should simply be able to ssh into the address of your Raspberry Pi. To do this, there is a little extra configuration required though. There is a few ways we could set up the point to point networking. The proper way would be to set up a DHCP server on one of the ends. A far simplier was though is just to give the Raspberry Pi a fixed IP address. To do this, you will need to run echo -e "interface usb0 \nstatic ip_address=169.254.64.64" | sudo tee -a /etc/dhcpcd.conf. You can then access the Raspberry Pi Zero by connecting to 169.254.64.64, or by using raspberrypi.local if your computer has Bonjour installed (Mac and most Linux OSs including Raspbian). Note this method does not support adding a fixed address to the cmdline.txt file. For that, you have to use the Ethernet only kernel below.
  • g_mass_storage - To have your Pi Zero appear as a mass storage device (flash drive), first create a mini filesystem in a file on your Pi with sudo dd if=/dev/zero of=/piusb.bin bs=512 count=2880 and set it up as a fat32 filesystem with sudo mkdosfs /piusb.bin. Then, when enabling it, add file=/piusb.bin stall=0 onto the end, for example sudo modprobe g_mass_storage file=/piusb.bin stall=0.

In theory, most USB devices should work alongside these kernels, to switch to USB OTG mode, simply don't use an OTG adapter cable and use a standard USB cable to plug your Pi Zero into another computer, it should auto switch.

Legacy guides

The legacy guides can be found on a separate Gist.

@tyrower
tyrower commented Dec 24, 2015

Great getting to take a sneak peak at this. Thanks. Downloading the archives as I type....

@dblicken

Fantastic! Thanks for sharing...

@jarjartee

This is a brilliant Christmas Pressie ;0)

@mobluse
mobluse commented Dec 26, 2015

It seems as if the last tar.gz-file is the same as the first. I have a Raspberry Pi Model A (and not Zero) and I then need files that are hard-coded to gadget mode, because the OTG-ID-pin is connected to ground, i.e. always host.

@blackketter

This is awesome, thanks! My Zero arrives tomorrow and this will be the first thing I try. You mention HID support but I don't see it in the list of modules you mentioned. Is it included implicitly?

@bencord0
bencord0 commented Jan 2, 2016

Is there a reason why the Jessie lite images won't work?
Is it missing a specific package? or does it have a different configuration file somewhere? Is the kernel, or one of the boot files different in any meaningful way?

Or has nobody tried it yet?

@leopatras

Hi gbaman, do you have a tip how to enable HID devices ( mouse, keyboard ) ? Thanks a lot in advance

@shrx
shrx commented Jan 8, 2016

+1 @bencord0
Can you explain which packages are needed for it to work? I'd very much like to avoid running the whole Jessie image.

@Sephiroth87

+1 on the Jessie Lite questions :)

@t3chguy
t3chguy commented Jan 13, 2016

I have it functional with a Jessie Lite image based card.

@GM-Script-Writer-62850

sudo echo "string" >> /path/to/file does not work, you can either run sudo su then drop the sudo or run echo "string" | sudo tee -a /path/to/file
on jessie lite you need to install rpi-update: sudo apt-get in rpi-update

@Darkmelman

Hello,

i have updated to the new raspbian release of 2016-02-09 and the USB- Gadget isn’t working…can anyone confirm that or hast anyone a solution?

Thanks….

@ajfisher

Can anyone confirm this working on a A+ and do you need an OTG cable for it or a simple standard USB cable is sufficient?

@mrjoshuap

@Darkmelman: I can confirm it works on my PI Zero as I just performed these steps using 2016-02-09 and it worked properly for g_serial and g_mass_storage.

The only thing I am not sure of is, for g_serial, if there is a difference between:

systemctl enable getty@ttyGS0.service

and

systemctl enable serial-getty@ttyGS0.service

@quietbiker

pi_otg
Hopefully the screenshot appears, the g_serial is working very well here. Using RealTerm on my Win10 Laptop, USB cable between PC and Pi Zero, with nothing else plugged into the Pi.

I'm going to try to look into using the Pi Zero as an IO expander for a PC (so GPIO/SPI/I2C)

@strasharo

echo -e "interface usb0 \nstatic ip_address=169.254.64.64" | sudo tee /etc/dhcpcd.conf

Shouldn't this be a "tee -a", because it wipes out all of the default configuration from the file?

@simonbyrne

And same with 5 (tee /etc/modules)?

@ajfisher
ajfisher commented Mar 5, 2016

Am sure this will be awesome once Pi Zeroes are actually available. Unfortunately whilst everything appears to load and work on Pi A+, the Pi won't drop into peripheral mode so can't get it to talk to any computer I own :(

Plenty of docs that say "it should be possible" but unfortunately no instructions on what else needs configuring to make it happen...

@prudy
prudy commented Mar 13, 2016

It does work with my recent pull request. There was a problem in dwc2 gadget overriding hw configuration.

@DoomHammer

Since my Pi is headless: can you provide a preconfigured image at least from step 3 (or best step 6 with g_serial)?

@aarzee
aarzee commented Apr 22, 2016

I tried doing this with g_hid and I get this message when booting:

[    4.396884] systemd[1]: systemd-modules-load.service: main process exited, code=exited, status=1/FAILURE
[    4.415944] systemd[1]: Failed to start Load Kernel Modules.
[    4.423600] systemd[1]: Unit systemd-modules-load.service entered failed state.

Any assistance would be appreciated.

@aars
aars commented Apr 30, 2016 edited

I had g_ether working once, but my mac just won't detect the RNDIS device now. Everything loads fine on the pi. I have a usb0 interface configured with a static IP. I have no idea what (I) changed. Tried a fresh install, using the same (and other cables) that worked fine before.

Anybody have an idea what I'm missing here?

(Tested on a windows 10 machine as well, nothing)

EDIT: Apparently most, if not all, my cables are wonky. It works now (raspbian jessie lite)

@gritstub
gritstub commented May 3, 2016

When using the Pi Zero as a g_serial, do I connect it to my computer via the USB or PWR port? Can i provide power and have the device connected to serial at the same time, or do I need two separate cables?

@gritstub
gritstub commented May 3, 2016

What is missing from Raspbian Jessie lite that requires the full distribution?

@gbaman
Owner
gbaman commented May 9, 2016

@gritstub you use the USB port, as it can provide power also via back powering. (even though you aren't really meant to do that...).
That should provide power and data at the same time.

@aars
aars commented May 9, 2016

@gritstub It should work fine on Jessie Lite. I have no idea why this (and other) doc(s) mention not using Lite.

@ben-wing
ben-wing commented May 18, 2016 edited

Now that the official Raspbian (as of 2016-05-10 image) has rolled out with a 4.4 kernel (where the gadget mods have been accepted), should I be able to boot a vanilla SD card as a gadget?

**edit
I simply didn't pay attention to the fact that my Ubuntu 16.04 laptop (which is playing host to my PiZero) is running NetworkManager.
so, once i properly set a static IP on the usb network connection that was presented by the PiZero (after having applied updates described above), rather than trying to blindly configure a usb0 interface in /etc/network/interfaces i'm now happily SSH-ing to my PiZero via USB.

**end-edit

what i tried (and it worked!) was:

  1. write a fresh raspbian download to SD card
  2. mount the dos partition on my linux box and execute @gbaman step 4 to modify config.txt to include dtoverlay=dwc2
  3. mount the ext4 partition on my linux box and execute @gbaman step 5 to modify /etc/modules to append
 dwc2
 g_ether
  1. based on ladyada's guide append a static IP for the usb0 device to /etc/network/interfaces

anybody else tried something similar?

@rena2019
rena2019 commented Jun 7, 2016

I tried g_mass_storage without luck:
$ sudo dd if=/dev/zero of=/tmp/piusb.bin bs=512 count=2880
$ sudo mkdosfs /tmp/piusb.bin
$ sudo modprobe g_mass_storage file=/tmp/piusb.bin stall=0
modprobe: ERROR: could not insert 'g_mass_storage': No such device

@jazzycamel

I can't seem to get g_mass_storage to work. I've followed the guide (2) above and the modprobe succeeds, but it won't mount on an OSX or Ubuntu host. There is a message on boot "failed to start g_mass_storage -22". I'm using an original Zero with the latest version of Jessie Lite (2016-05-27). I can get the g_ether example to work fine, so I don't think this is a hardware issue. Anyone got any hints, tips or thoughts?

@belese
belese commented Jul 10, 2016 edited

Just a quick note for g_multi to load on boot,
as it seems /etc/modules doesn't allow parameter for modules,
my '/etc/modules' looks like this

# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
dwc2
g_multi

and i've to create a second file
/etc/modprobe.d/multigadget.conf (you can use whatever you want before .conf)
that contain :
options g_multi file=/dev/mmcblk0p3 host_addr=11:22:33:44:55:66

in this case, i've made a third partition formated in fat32 on sd card, and i set the mac adress so my pc don't detect new ethernet card at each time, and keep configuration for network.

and for info speed for mass storage is not so bad,
it copy at speed between 5 and 6 MB/sec (on ubuntu) and 3/4 on windows

Note for windows 10 (don't test others)

mass storage is detected but iv'e to recreate a partiton and format it inside windows (i've done it with gparted before, don't know why it wasn't recognize in windows). But now it work in ubuntu and windows

driver for usb rnis gadget don't install automaticaly, i need to install drivers form list, microsoft->network card->usb rnis gadget, and it was working too.

i continue my finding, as i share a block device, even if i create a partition in fat32, windows 10 detect it like no partition was create inside. (it was working ok on ubuntu), and i need to create a partition and formated it inside windows.

on the pi, if i done
`
sudo losetup /dev/loop8 /dev/mmcblk0p3

Disk /dev/loop8: 10.4 GiB, 11195645952 bytes, 21866496 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xc408fa62

Device Boot Start End Sectors Size Id Type
/dev/loop8p1 2048 21862399 21860352 10.4G c W95 FAT32 (LBA)
`

so i can see my windows create partition, and mount it with
sudo mount -o ro,loop,offset=$((2048 * 512)) /dev/mmcblk0p3 /mnt

and now i can access file copied with windows or ubuntu on the mass storage gadget partition.

@lost-hope
lost-hope commented Jul 14, 2016 edited

I get an error when I try to do modprobe g_serial
the error is modprobe: ERROR: could not insert 'g_serial': No such device

I have followed the guide to set up the OTG modes. Have I done something wrong?

@stephenstarkie

I am wondering whether this can be made to work on the Compute Module?

@exander77

I have exactly same question as stephenstarkie. Compute module has two usbs, one master, one slave. Can it be done on slave?

@bqian
bqian commented Nov 14, 2016

Can Chromebooks detect Pis on GTO mode?

@modelorona

Works great on windows 10, appreciate it! 😄

@PaintHat

I've been trying to get the g_multi setup to work for Ethernet and mass storage. I've not had any luck with the storage. The Ethernet works great though.

@aldajo92
aldajo92 commented Dec 28, 2016 edited

If I want to use the serial port not for connect for to do login but to for doing a serial communication... is it possible? I skip the step for enable service with sudo systemctl enable getty@ttyGS0.service and doing a simple code for try to send information through of the serial port on /dev/ttyGS0 with a python script but this not work... does anyone know if its necessary to enable something? the python script made is the following (its very very simple):

import time
import serial
ser = serial.Serial('/dev/ttyGS0', 115200)
while True:
	ser.write("hello...")
	time.sleep(1)
@aldajo92

I already resolve the last issue.... any additional step is needed... its only follow the same steps mentioned on gist and skip sudo systemctl enable getty@ttyGS0.service and after that... use the same code with python dependences already installed (in this case pyserial) and connect to a computer using a serial terminal... waiting until data is available... Ohh I forgot to mention something... also its necessary to start the script on /etc/rc.local with python /path/to/script & before exit 0

@CannonFodderSE

leopatras commented on Jan 6, 2016

Hi gbaman, do you have a tip how to enable HID devices ( mouse, keyboard ) ? Thanks a lot in advance

This seems to have gone unanswered, at least publicly.

I been banging around for almost a week and can't get HID mode working on pi zero. Has anybody got it to work and have a step by step guide? Seen many out there, but none work with the latest raspian release (November 2016).

Thanks,
Randy

@MitchDresdner

I now have it working on both Windows 7 and Windows 10 and it seems to be a simple as Mr gbaman described.

The problem I encountered was the result of a 2' USB Micro cable I was using. It applied power and the Zero booted, but (guessing) the data line was defective or not intended for use in the original device.

Couple other points:

For troubleshooting, you'll want Bonjour Browser
https://hobbyistsoftware.com/bonjourbrowser

Or to use cmd shell dns-sd.
i.e. dns-sd -B _services._dns-sd._udp

Also, raspberrypi.local is the default hostname of a virgin pi, if you change the hostname you'll be ssh'ing to yourHostname.local

Thanks gbaman!

@akiani
akiani commented Jan 26, 2017

@gbaman Any idea how I can share the OTG USB across the host device and a Wifi dongle?

The setup I have includes the Pi Zero acting as USB Mass storage (which I got to work) but want the Pi Zero to also have WiFi access (don't want to share internet with the host)

I tried using the power OTG port with no success. I also tried using a USB Hub and using a Male-to-Male USB cable, but again the device did not appear as Mass Storage.

Any help is appreciated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment