Raspberry Pi 3 Model B+ : USB Power Enable/Disable
The Raspberry Pi 3 Model B+ has 4 USB ports and an ethernet port. In our application we will be using a USB sound card to sample a hydrophone. But when not in use the sound card will need powering down to save battery energy. At the moment the sound card uses around 1.4W when powered up.
Raspberry Pi 3 Model B+ Ethernet and USB ports
A number of resources and forum discussions centred around power cycling USB ports on other Raspberry Pi editions. The hub-ctrl.c software does allow us to control the power of the USB ports on the RPi3B+, however, the internal configuration of the ports and how they are addressed is not quite as simple as A-D corresponding to ports 1-4 on a hub as we shall see below.
USB Hierarchy
Listing the usb devices shows all the ports as “bus-port.port.port…port:config.interface”. More information about this can be found at linux-usb.org.
$ ls /sys/bus/usb/devices/
1-0:1.0 1-1 1-1.1 1-1:1.0 1-1.1.1 1-1.1:1.0 1-1.1.1:1.0 usb1
Here we can see Bus01 with ports and sub-ports. If we now list the usb tree structure using lsusb we see the root hub, with a 4 port hub (hub/4p), which then holds a 3 port hub (hub/3p), and finally the Ethernet LAN driver chip.
$ lsusb -t
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
|__ Port 1: Dev 3, If 0, Class=Hub, Driver=hub/3p, 480M
|__ Port 1: Dev 4, If 0, Class=Vendor Specific Class, Driver=lan78xx, 480M
Connecting a sound card to each of the USB ports in turn, and printing the USB device tree shows each of the following.
Raspberry Pi 3 Model B+ Ethernet and USB ports labelled
Connected to USB A:
$ lsusb -t
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
|__ Port 1: Dev 3, If 0, Class=Hub, Driver=hub/3p, 480M
|__ Port 1: Dev 4, If 0, Class=Vendor Specific Class, Driver=lan78xx, 480M
|__ Port 2: Dev 7, If 0, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 7, If 1, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 7, If 2, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 7, If 3, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 7, If 4, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 7, If 5, Class=Human Interface Device, Driver=usbhid, 12M
Connected to USB B:
$ lsusb -t
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
|__ Port 1: Dev 3, If 0, Class=Hub, Driver=hub/3p, 480M
|__ Port 1: Dev 4, If 0, Class=Vendor Specific Class, Driver=lan78xx, 480M
|__ Port 3: Dev 8, If 0, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 8, If 1, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 8, If 2, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 8, If 3, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 8, If 4, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 8, If 5, Class=Human Interface Device, Driver=usbhid, 12M
Connected to USB C:
$ lsusb -t
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
|__ Port 1: Dev 3, If 0, Class=Hub, Driver=hub/3p, 480M
|__ Port 1: Dev 4, If 0, Class=Vendor Specific Class, Driver=lan78xx, 480M
|__ Port 2: Dev 9, If 0, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 9, If 1, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 9, If 2, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 9, If 3, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 9, If 4, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 9, If 5, Class=Human Interface Device, Driver=usbhid, 12M
Connected to USB D:
$ lsusb -t
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
|__ Port 1: Dev 3, If 0, Class=Hub, Driver=hub/3p, 480M
|__ Port 1: Dev 4, If 0, Class=Vendor Specific Class, Driver=lan78xx, 480M
|__ Port 3: Dev 10, If 0, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 10, If 1, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 10, If 2, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 10, If 3, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 10, If 4, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 3: Dev 10, If 5, Class=Human Interface Device, Driver=usbhid, 12M
Based on the original usb device listings (“bus-port.port.port…port”) the following table describes each of the ports:
- Eth0: 1-1.1.1.1
- USB A: 1-1.1.1.2
- USB B: 1-1.1.1.3
- USB C: 1-1.1.2
- USB D: 1-1.1.3
hub-ctrl.c
First we compile the hub-ctrl.c as per the instructions in the readme.
Checking how hub-ctrl labels the respective usb hubs (4 port, and 3 port) we use the command as follows:
$ sudo ./hub-ctrl -v
Hub #0 at 001:003
INFO: individual power switching.
WARN: Port indicators are NOT supported.
Hub Port Status:
Port 1: 0000.0503 highspeed power enable connect
Port 2: 0000.0100 power
Port 3: 0000.0100 power
Hub #1 at 001:002
INFO: individual power switching.
WARN: Port indicators are NOT supported.
Hub Port Status:
Port 1: 0000.0503 highspeed power enable connect
Port 2: 0000.0100 power
Port 3: 0000.0103 power enable connect
Port 4: 0000.0100 power
Hub #2 at 001:001
INFO: ganged switching.
WARN: Port indicators are NOT supported.
Hub Port Status:
Port 1: 0000.0503 highspeed power enable connect
In this case, the 4 port hub is labelled as hub #1 by hub-ctrl.
So using hub-ctrl.c as per the instructions in the readme. We can switch off the power to USB D as follows:
$ sudo ./hub-ctrl -h 1 -P 3 -p 0
This command needs to be sent twice in quick succession to keep the sound card switched off. Otherwise, it re-powers up after one second. Not sure why at this stage, but will explore further.
The power can then be brought back on to USB D with the simple change:
$ sudo ./hub-ctrl -h 1 -P 3 -p 1
Other Raspberry Pi versions and models may well have different USB port configurations, the above approach should allow us to discover the setup on any new devices.