Raspberry Pi Zero OTG Mode

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).

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.

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)

First, flash Jessie (only tested on full, lite version may also work though) onto a blank microSD card.

(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.

Next we need to make sure we are using the dwc2 USB driver echo "dtoverlay=dwc2" | sudo tee -a /boot/config.txt.

And enable it in Raspbian echo "dwc2" | sudo tee -a /etc/modules

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.

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.

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?

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

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...

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)

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?

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?

**editI 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:

write a fresh raspbian download to SD card

mount the dos partition on my linux box and execute @gbaman step 4 to modify config.txt to include dtoverlay=dwc2

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?

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.

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):

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

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).

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.

Does anyone know of a otg controller that i can use in my projects? I don't want to use the raspberry pi zero for just otg. I'd rather have just the parts needed for otg to work. Seems like a stupid question but does anyone know if I can use a usb hub to be able to connect multiple otg devices?

systemctl enable getty@ttyGS0.service isn't enough for the gadget serial getty. You need to add -w to the agetty command line. You need to copy /lib/systemd/system/getty@.service to /lib/systemd/system/gadget-getty.service and modify it a little bit, including adding -w before --noclear in ExecStart, then enable gadget-getty@ttyGS0.service.

If you don't do this, the agetty will hang when a host is not connected, preventing proper shutdown and reboot.

hi, I cant get a mouse or keyboard to work with the micro usb port via my OTG cable (tried two OTG cables and think they're ok, the mouse and keyboard work on another rpi). I can see the mouse pointer but it does not move. Should I assume that there is a fault with the Pi Zero W?
I tried SSH but understand that this is now defaultng to disabled. So apart from seeing the Pixel desktop I cant do anything).

Regarding dwc2 on raspberry A+. After some search I found this very interesting for me: https://github.com/raspberrypi/firmware/blob/master/boot/overlays/README.
I managed to make it work without hw modifications, so just added:dtoverlay=dwc2,dr_mode=peripheral in file /boot/config.txt.
Of course you can't change mode dinamically but for my purpose it does the trick!@gbaman if you update HowToOTG.md with this maybe will be useful for others.
Many Thanks!