HOWTO: Enable USB device mode on Pi Zero


68 posts   Page 1 of 3   1, 2, 3
by DaveB » Mon Dec 21, 2015 2:29 pm
Firstly, many thanks to ED6E0F17, notro and others on github who worked this all out. The original thread is here. I am Dave-0 in that thread but I didn't do the clever bits.

This is very new and a bit rough and ready so please chip in with corrections and improvements. Any mistakes are most likely to be mine. :)

To enable USB device mode (also referred to as peripheral mode or gadget mode) on a Pi Zero follow the steps below. If you are using device mode you can't plug in a keyboard or mouse to control the Pi. Because of this, I advise using a 3.3v USB-serial adapter connected to the 40 pin header when trying this out, that way you can get a shell. The following steps assume you are using a Linux host system and that you are modifying a Raspbian install. I won't be going into detail on compiling kernels as that's already documented here.

1. Download the 4.4.y branch of the Pi kernel.
You get this from github:
Code: Select all
git clone --depth=1 --branch=rpi-4.4.y https://github.com/raspberrypi/linux


2. Modify the bcm2708_common.dtsi file.
You can do this either my applying this patch or by editing arch/arm/boot/dts/bcm2708_common.dtsi and changing the section that reads:
Code: Select all
                usb: usb@7e980000 {
                        compatible = "brcm,bcm2708-usb";
                        reg = <0x7e980000 0x10000>,
                              <0x7e006000 0x1000>;
                        interrupts = <2 0>,
                                     <1 9>;

to read:
Code: Select all
                        compatible = "brcm,bcm2835-usb";
                        reg = <0x7e980000 0x10000>;
                        interrupts = <1 9>;
                        g-np-tx-fifo-size = <32>;
                        g-rx-fifo-size = <256>;
                        g-tx-fifo-size = <256 128 128 64 64 64 32>;


3. Change the kernel config.
Start with the default configuration (bcmrpi_defconfig) and make the following changes in menuconfig:
  • Go to Device drivers -> USB support
  • Deselect "Synopsis DWC host support"
  • Select "USB Gadget Support" as built-in
  • Enter the "USB Gadget Support" section
  • Select "USB Gadget Drivers" as built in
  • In that section, select the gadget type that you want, I'll use "Serial Gadget (with CDC ACM and CDC OBEX support)" here*
  • Go back up a level
  • Select "DesignWare USB2 DRD Core Support" as built in
  • Select "DWC2 Mode Selection (Dual Role mode)" and choose "Gadget only mode" [EDIT: or not, dual mode works]
  • Save and exit.
There is also a working .config here but this one has all modules switched off so you might not want to use that one.

4. Compile and install
Compile and install your new kernel, bcm2708-rpi-b.dtb and modules on to your Raspbian card. Take a backup first unless you're not bothered about losing anything if it goes wrong. You will also need to replace the standard config.txt with this one:
Code: Select all
device_tree=bcm2708-rpi-b.dtb


5.Boot and try it out.
Boot your modified Raspbian install. If you've connected a USB serial adapter as suggested, connect this first and start a session:
Code: Select all
screen /dev/ttyUSB0 115200,N,8,1

(It might be something other than /dev/ttyUSB0 depending on the hardware.)

When Raspbian boots you should get something like this on the host:

dmesg:
Code: Select all
[ 7330.929356] usb 2-3.2: new high-speed USB device number 35 using ehci-pci
[ 7331.031354] usb 2-3.2: New USB device found, idVendor=0525, idProduct=a4a7
[ 7331.031366] usb 2-3.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 7331.031373] usb 2-3.2: Product: Gadget Serial v2.4
[ 7331.031378] usb 2-3.2: Manufacturer: Linux 4.4.0-rc5+ with 20980000.usb
[ 7331.039935] cdc_acm 2-3.2:2.0: This device cannot do calls on its own. It is not a modem.
[ 7331.040093] cdc_acm 2-3.2:2.0: ttyACM0: USB ACM device


lsusb:
Code: Select all
Bus 002 Device 035: ID 0525:a4a7 Netchip Technology, Inc. Linux-USB Serial Gadget (CDC ACM mode)


Log into the PI using via the screen session that you started earlier. To enable a login session using the new USB serial gadget (device mode), do this:
Code: Select all
systemctl enable getty@ttyGS0.service


You should be able to start another screen session via the new USB gadget device:
Code: Select all
screen /dev/ttyACM0 115200,N,8,1

This is a persistent change so you should now be able to login without the USB serial adapter and nothing connected to the PI other than a normal USB cable.

Enjoy!
Last edited by DaveB on Mon Dec 21, 2015 5:07 pm, edited 1 time in total.
Posts: 29
Joined: Wed Sep 14, 2011 8:40 pm
by gregeric » Mon Dec 21, 2015 2:47 pm
That's great, and well done getting it going. Does your kernel switch between client & host OK when plugging in an OTG adapter (I'm assuming you will see the old issues we had with USB in host mode, since fixed with the FIQ magic)?
Posts: 1437
Joined: Mon Nov 28, 2011 10:08 am
by DaveB » Mon Dec 21, 2015 4:00 pm
gregeric wrote:Does your kernel switch between client & host OK when plugging in an OTG adapter (I'm assuming you will see the old issues we had with USB in host mode, since fixed with the FIQ magic)?


No, I can only get dwc2 to work in device mode if I compile it with the "Gadget only mode" option, regardless of which type of cable is connected.

I've not had any of the issues with USB lock ups yet but in device mode it's only got to handle the traffic of one device rather than the hub+ethernet+mouse+keyboard+whatever it would be dealing with in host mode.
Posts: 29
Joined: Wed Sep 14, 2011 8:40 pm
by DaveB » Mon Dec 21, 2015 5:05 pm
DaveB wrote:No, I can only get dwc2 to work in device mode if I compile it with the "Gadget only mode" option, regardless of which type of cable is connected.

I'm replying to myself here, but I've tried dual mode again and got it to work this time. I must have made a mistake the first time I tried it.

Anyway, it works but as gregeric said, you might get performance problems or USB lockups.
Posts: 29
Joined: Wed Sep 14, 2011 8:40 pm
by drazvan » Tue Dec 22, 2015 9:11 pm
Would you mind posting the resulting kernel.img (the one with no modules)? I've followed the instructions but I can't get the image to boot, all it says on the serial console is

"Uncompressing Linux... done, booting the kernel."

and stops there.

I've used your configuration with no changes, just wanted to see if I could make it work. I must be doing something wrong, not sure what though.
Posts: 14
Joined: Tue Jul 16, 2013 5:52 pm
by DaveB » Wed Dec 23, 2015 10:30 am
I had exactly the same problem until I changed config.txt. There is something in the standard Raspbian one that causes it to hang but I've not worked out what it is yet.

Try replacing config.txt with one that just has this in it and nothing else:
Code: Select all
device_tree=bcm2708-rpi-b.dtb
Posts: 29
Joined: Wed Sep 14, 2011 8:40 pm
by drazvan » Wed Dec 23, 2015 2:25 pm
Thank you, that did the trick! It's now booting up and shows a serial interface. I am now getting another error

unable to initialize libusb: -99

when doing lsusb, but everything else works. I'll try to figure it out.

Thanks again!
Posts: 14
Joined: Tue Jul 16, 2013 5:52 pm
by DaveB » Wed Dec 23, 2015 4:11 pm
I get the same error using gadget only mode. I think it's because there are no USB hosts present.
Posts: 29
Joined: Wed Sep 14, 2011 8:40 pm
by cookie545445 » Wed Dec 23, 2015 10:09 pm
Does anyone have the kernel.img for this with dual mode enabled? I'm not yet experienced enough with Linux to know how to (cross-) recompile the kernel :D
Posts: 1
Joined: Wed Dec 23, 2015 10:02 pm
by DaveB » Thu Dec 24, 2015 11:11 pm
Ladyada has posted a tutorial with pre-compiled kernel here. I'm not sure if this is dual mode or device only though.
Posts: 29
Joined: Wed Sep 14, 2011 8:40 pm
by gregeric » Fri Dec 25, 2015 9:55 am
And both Serial & Ethernet gadgets are provided :-)
Posts: 1437
Joined: Mon Nov 28, 2011 10:08 am
by DirkS » Fri Dec 25, 2015 10:05 am
DaveB wrote:Ladyada has posted a tutorial with pre-compiled kernel here. I'm not sure if this is dual mode or device only though.

Another one from 'gbaman': http://pi.gbaman.info/?p=699 / https://gist.github.com/gbaman/50b6cca61dd1c3f88f41
Posts: 6698
Joined: Tue Jun 19, 2012 9:46 pm
Location: Essex, UK
by Gbaman » Fri Dec 25, 2015 11:00 am
DirkS wrote:
DaveB wrote:Ladyada has posted a tutorial with pre-compiled kernel here. I'm not sure if this is dual mode or device only though.

Another one from 'gbaman': http://pi.gbaman.info/?p=699 / https://gist.github.com/gbaman/50b6cca61dd1c3f88f41

Yip, and just to add, the top one over on https://gist.github.com/gbaman/50b6cca61dd1c3f88f41 does include full standard USB support which continued to work, even when gadget mode drivers are loaded.
Included is serial, ethernet, mass storage drivers along with a few others like HID and MIDI, just need to load them.
Lead developer of PiNet, a free and opensource centralised user accounts and file storage system for Raspberry Pi classrooms used in over 200 schools across the world.
http://pinet.org.uk
Posts: 117
Joined: Mon Jan 21, 2013 2:43 pm
by mob-i-l » Sat Dec 26, 2015 5:30 pm
I have a Raspberry Pi Model A (and not Zero or A+) 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 any one that has files that work on Model A. I have a suitable cable (i think -- it works for powering): USB AM/AM: http://se.farnell.com/pro-signal/psg900 ... dp/1494745
Raspberry Pi 0&1 A&1 B2&1 B+&2 B w/ Raspbian. Started w/ BASIC on ABC80 & ZX81 then Forth, Z80… http://scratch.mit.edu/users/mobluse/ https://github.com/mobluse/ https://www.youtube.com/MOBiL4u/ https://twitter.com/mobluse/
Posts: 193
Joined: Sat Dec 29, 2012 2:45 am
Location: Lund, Skåne/Scania, Sweden
by gregeric » Sat Dec 26, 2015 7:52 pm
mob-i-l wrote:I have a Raspberry Pi Model A (and not Zero or A+) 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 any one that has files that work on Model A. I have a suitable cable (i think -- it works for powering): USB AM/AM: http://se.farnell.com/pro-signal/psg900 ... dp/1494745


If it's mass-storage you are looking for, then you can use the existing tools published for the Compute Module

I've verified those on a Model A+ with a cable similar-looking to that in your link.

To get it to work, remove the SD card & power cable from the A. Now connect the Pi to the host PC with your cable - your Pi will now be powered from the host PC, do not connect the power cable to the Pi. Next insert your SD card. Run the rpiboot program, & shortly the mass storage device will appear under Windows or Linux PC.

Not very convenient, but it works (also on the Zero).
Posts: 1437
Joined: Mon Nov 28, 2011 10:08 am
by mattmiller » Sun Dec 27, 2015 7:45 am
Lot of chatter on twitter by @gbaman1 over past few days about getting this going for users
Posts: 1128
Joined: Thu Feb 05, 2015 11:25 pm
by gregeric » Sun Dec 27, 2015 8:13 am
mob-i-l wrote:I have a Raspberry Pi Model A (and not Zero or A+) 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.

Just noticed that in Gbaman's github there are also kernels hard-coded, gadget-only for use on the A(+).
Posts: 1437
Joined: Mon Nov 28, 2011 10:08 am
by mob-i-l » Sun Dec 27, 2015 11:29 pm
gregeric wrote:
mob-i-l wrote:I have a Raspberry Pi Model A (and not Zero or A+) 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 any one that has files that work on Model A. I have a suitable cable (i think -- it works for powering): USB AM/AM: http://se.farnell.com/pro-signal/psg900 ... dp/1494745


If it's mass-storage you are looking for, then you can use the existing tools published for the Compute Module

I've verified those on a Model A+ with a cable similar-looking to that in your link.

To get it to work, remove the SD card & power cable from the A. Now connect the Pi to the host PC with your cable - your Pi will now be powered from the host PC, do not connect the power cable to the Pi. Next insert your SD card. Run the rpiboot program, & shortly the mass storage device will appear under Windows or Linux PC.

Not very convenient, but it works (also on the Zero).


I tried, but it didn't work so far. No SD-card in the Pi A was noted. I tested both Raspberry Pi B+ and 2B as hosts with most updated Raspbian Jessie (I also run sudo rpi-update). I compiled and installed rpiboot on both hosts. (I moved the host microSD between the hosts.) I tested both 8GB and 16GB SD-cards.

After connecting the A to the host and running dmesg I get:
Code: Select all
[ 1030.172850] usb 1-1.3: new full-speed USB device number 31 using dwc_otg
[ 1030.283123] usb 1-1.3: New USB device found, idVendor=0a5c, idProduct=2763
[ 1030.283175] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 1030.283189] usb 1-1.3: Product: BCM2708 Boot
[ 1030.283200] usb 1-1.3: Manufacturer: Broadcom

This seems to indicate that the cable is working.

After running sudo rpiboot and dmesg in another terminal I get:
Code: Select all
[ 1077.811494] usb 1-1.3: USB disconnect, device number 31
[ 1078.053312] usb 1-1.3: new high-speed USB device number 32 using dwc_otg
[ 1078.133319] usb 1-1.3: device descriptor read/64, error -71
[ 1078.323320] usb 1-1.3: device descriptor read/64, error -71
[ 1078.513322] usb 1-1.3: new high-speed USB device number 33 using dwc_otg
[ 1078.593322] usb 1-1.3: device descriptor read/64, error -71
[ 1078.783322] usb 1-1.3: device descriptor read/64, error -71
[ 1078.973327] usb 1-1.3: new high-speed USB device number 34 using dwc_otg
[ 1079.393323] usb 1-1.3: device not accepting address 34, error -71
[ 1079.473330] usb 1-1.3: new high-speed USB device number 35 using dwc_otg
[ 1079.893330] usb 1-1.3: device not accepting address 35, error -71
[ 1079.893524] usb 1-1-port3: unable to enumerate USB device


RPiBoot and output:
$ sudo rpiboot
Waiting for BCM2835 ...
Found serial = 0: writing file /usr/share/rpiboot/usbbootcode.bin
Waiting for BCM2835 ...

I shall also try this on an x86-computer with Ubuntu 14.04.
Last edited by mob-i-l on Mon Dec 28, 2015 10:57 pm, edited 1 time in total.
Raspberry Pi 0&1 A&1 B2&1 B+&2 B w/ Raspbian. Started w/ BASIC on ABC80 & ZX81 then Forth, Z80… http://scratch.mit.edu/users/mobluse/ https://github.com/mobluse/ https://www.youtube.com/MOBiL4u/ https://twitter.com/mobluse/
Posts: 193
Joined: Sat Dec 29, 2012 2:45 am
Location: Lund, Skåne/Scania, Sweden
by jacksonliam » Sun Dec 27, 2015 11:50 pm
Great work on getting this working all involved! Working well on the zero, opens up a lot of doors for more cool pi projects!
User avatar
Posts: 181
Joined: Tue Feb 07, 2012 10:09 pm
by gregeric » Mon Dec 28, 2015 5:19 am
@mob-i-l does that uSD have max_usb_current=1 in config.txt, might it be a power issue? It should re-enumerate serial=1, then the msd.elf gets squirted across & executed. Unlike the linux module method, this gives access to the whole SD. I haven't disassembled them but I guess usbbootcode.bin & msd.elf are both threadx/vc4, not running on the arm.

Here's my Zero mounting my A+ SD:
Code: Select all
[  339.317653] usb 1-1.4: new full-speed USB device number 8 using dwc_otg
[  339.427897] usb 1-1.4: New USB device found, idVendor=0a5c, idProduct=2763
[  339.427934] usb 1-1.4: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[  339.427952] usb 1-1.4: Product: BCM2708 Boot
[  339.427967] usb 1-1.4: Manufacturer: Broadcom
[  366.729140] usb 1-1.4: USB disconnect, device number 8
[  366.967845] usb 1-1.4: new high-speed USB device number 9 using dwc_otg
[  367.068585] usb 1-1.4: New USB device found, idVendor=0a5c, idProduct=2763
[  367.068612] usb 1-1.4: New USB device strings: Mfr=1, Product=2, SerialNumber=1
[  367.068625] usb 1-1.4: Product: Raspberry Pi
[  367.068637] usb 1-1.4: Manufacturer: Broadcom
[  367.068649] usb 1-1.4: SerialNumber: Broadcom
[  367.241260] usb 1-1.4: USB disconnect, device number 9
[  368.497808] usb 1-1.4: new high-speed USB device number 10 using dwc_otg
[  368.598787] usb 1-1.4: New USB device found, idVendor=0a5c, idProduct=0001
[  368.598815] usb 1-1.4: New USB device strings: Mfr=2, Product=1, SerialNumber=3
[  368.598828] usb 1-1.4: Product: Compute Module
[  368.598841] usb 1-1.4: Manufacturer: Raspberry Pi
[  368.598852] usb 1-1.4: SerialNumber: 0001
[  368.603803] usb-storage 1-1.4:1.0: USB Mass Storage device detected
[  368.604733] scsi host0: usb-storage 1-1.4:1.0
[  369.598651] scsi 0:0:0:0: Direct-Access     Raspberr y PiMass storage      PQ: 0 ANSI: 2
[  369.600707] sd 0:0:0:0: [sda] 15589376 512-byte logical blocks: (7.98 GB/7.43 GiB)
[  369.601518] sd 0:0:0:0: [sda] Write Protect is off
[  369.601548] sd 0:0:0:0: [sda] Mode Sense: 0f 00 00 00
[  369.601999] sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[  369.606685]  sda: sda1 sda2
[  369.617463] sd 0:0:0:0: [sda] Attached SCSI removable disk
[  369.644795] sd 0:0:0:0: Attached scsi generic sg0 type 0
[  371.103408] EXT4-fs (sda2): recovery complete
[  371.113366] EXT4-fs (sda2): mounted filesystem with ordered data mode. Opts: (null)
[  371.199698] FAT-fs (sda1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.

Very apt for the time of year - Raspberr y PiMass.

@DaveB Sorry, this is bit of a thread derail, but interesting nonetheless and sort of related.
Posts: 1437
Joined: Mon Nov 28, 2011 10:08 am
by DaveB » Mon Dec 28, 2015 12:11 pm
I'm getting confused, aren't we talking about two different things here? The USB device mode that the Pi boots into if no SD card is present is completely separate from USB device mode support under Linux. Even if you use the usbboot program you still need the dwc2 driver and the gadget driver loaded.
Posts: 29
Joined: Wed Sep 14, 2011 8:40 pm
by gregeric » Mon Dec 28, 2015 12:35 pm
Yes, they are two different things, which is why I apologised for the thread derail. I don't believe linux / dwc2 is involved at all - it's all done under threadx, the OS that the VC4 runs hidden behind the scenes. If my hunch is correct, a disassembly of msd.elf would reveal no arm/linux code, instead vc4/threadx.

It *is* possible to boot linux his way with no SDCard at all - see https://github.com/raspberrypi/tools/tr ... er/usbboot. I'm currently trying to compile the buildroot/fatimage, so far failing mid compile.
Posts: 1437
Joined: Mon Nov 28, 2011 10:08 am
by thagrol » Mon Dec 28, 2015 4:20 pm
I've been trying to get the usb gadget stuff working on a model A and A+ using the serial gadget driver. Unfortunately while the driver loads and creates the device, it is not recognised when connected to a PC host (windows & linux). Using the same SD card in Pi Zero it is recognised as a serial device by the host and can be connected to.

The kernek is configured for usb gadget only mode and teh debug options have been enabled. g_serial has been compiled as a module rather than a builtin and loaded via rc.local as follows:
Code: Select all
modprobe g_serial


dmesg output (from Pi A+):
Code: Select all
[   41.808275] udc 20980000.usb: registering UDC driver [g_serial]
[   41.847276] userial_init: registered 4 ttyGS* devices
[   41.862924] g_serial gadget: adding 'acm'/cd526f00 to config 'CDC ACM config'/bf0b2510
[   41.863099] g_serial gadget: acm ttyGS0: dual speed IN/ep1in OUT/ep1out NOTIFY/ep2in
[   41.863133] g_serial gadget: Gadget Serial v2.4
[   41.863151] g_serial gadget: g_serial ready
[   41.878001] dwc2 20980000.usb: bound driver g_serial
[   42.667087] gs_open: ttyGS0 (cd52ba00,cd6d2640)
[   42.667255] gs_close: ttyGS0 (cd52ba00,cd6d2640) ...
[   42.667279] gs_close: ttyGS0 (cd52ba00,cd6d2640) done!
[   42.667474] gs_open: ttyGS0 (cd52b000,cd6d23c0)
[   42.667584] gs_close: ttyGS0 (cd52b000,cd6d23c0) ...
[   42.667606] gs_close: ttyGS0 (cd52b000,cd6d23c0) done!
[   42.667778] gs_open: ttyGS0 (cd7b4200,cd6d2be0)
[   42.667962] gs_write_room: (0,cd7b4200) room=0
[   42.667985] gs_write_room: (0,cd7b4200) room=0
[   42.667999] gs_flush_chars: (0,cd7b4200)

Any suggestions on getting this working?
User avatar
Posts: 192
Joined: Fri Jan 13, 2012 4:41 pm
Location: Darkest Somerset, UK
by DaveB » Mon Dec 28, 2015 7:19 pm
How are you connecting the Pi to the host? I don't have one to try it out myself, but I think that the A and A+ models need a non-standard cable with a USB type A plug on both ends to use device mode.
Posts: 29
Joined: Wed Sep 14, 2011 8:40 pm
by thagrol » Mon Dec 28, 2015 9:50 pm
Yep tried several of those and an A-B cable with a B female to A male adaptor. Even tried hacking together a cable with D+ and D- crossed over.

All cables (bar the hacked one) are known good cables.
User avatar
Posts: 192
Joined: Fri Jan 13, 2012 4:41 pm
Location: Darkest Somerset, UK