Intervene in USB Controller I/O Streams with an MCU Interposer

Series: alt.ctrl activities; builds on Game controllers

Many modern MCUs have a USB device connector and can also support an additional USB host port, sometimes referred to as an OTG (on-the-go) port.

Materials

MCUs with USB host ports, and the cables sometimes required to plug common game controllers into them
ItemAmazonAdafruitSparkFunWaveshareMouserDigi-Key
The Adafruit Feather RP2040 with USB Type A Host board, a USB-A socket at one end.
Photo: Liz Clark, Adafruit (source), CC BY-SA 3.0
Adafruit Feather RP2040 with USB Type A Host
5723485-5723
ESP32-S3 boards with two USB-C ports (here an N16R8: 16 MB flash, 8 MB PSRAM), in the style of Espressif's ESP32-S3-DevKitC-1: one port is the ESP32-S3's native USB OTG, the other a USB-to-UART bridgeB0GBT212KM
Waveshare RP2350A USB Mini (RP2350-USB-A): USB-C for programming, and a USB-A host port driven by the RP2350's PIOB0DW8Z2K7C30274
Teensy 4.1: a USB host port on a 5-pin headerDEV-167711568-16771-ND
USB Host Cable for Teensy 4.1: the 5-pin host header to a USB-A socketCAB-283891568-CAB-28389-ND
Teensy 4.0: USB host on two pads on the underside, data only; the board does not power the USB deviceDEV-15583474-DEV-15583
USB-A socket to micro-USB plug OTG adapters, 2 pack: for host ports with a micro-USB socket, such as the USB Host BFF'sB0BX9FSCFH2910
Other cables for common game controllers: to be supplied.
Affordable USB host adapters based on the Maxim MAX3421E
ItemAmazonAdafruitSparkFunM5StackMouser
The USB Host FeatherWing stacked with a Feather board and a small display reading "USB Found".
Photo: Liz Clark, Adafruit (source), CC BY-SA 3.0
Adafruit USB Host FeatherWing with MAX3421E
5858485-5858
The USB Host BFF on a small board, with an OTG cable and a display connected.
Photo: Liz Clark, Adafruit (source), a still from the original animation, CC BY-SA 3.0
Adafruit USB Host BFF for QT Py or Xiao with MAX3421E, with a micro-B OTG port
5956485-5956
M5Stack Module USB v1.2 (MAX3421E), for the Basic, Core2 and CoreS3 controllersM020-V12170-M020-V12
The red SparkFun USB-C Host Shield: an Arduino-shaped board with a USB-C socket at one corner, a square controller chip in the middle and a grid of prototyping holes.
Photo: SparkFun Electronics, CC BY-NC-SA 3.0 (SparkFun, 2011)
SparkFun USB-C Host Shield with MAX3421E, an Arduino shield: the MAX3421E on the hardware SPI pins (D10–D13), and a USB-C socket that supplies 5 V to the device
DEV-21247474-DEV-21247
Mini USB Host Shield 2.0, SPI, sized for the Arduino Pro Mini. Amazon's listing does not name its chip; other sellers' listings of this board give the MAX3421E, 3.3 V and a USB-A socketB0DC9MFKJR

Tools

  • Tools not yet listed.

Skills

  • Programming an MCU with a USB host library

Instructions

  1. With the controller attached, identify the closest existing device that the host library already supports.
  2. Test that, then expand it with the special features the particular device exposes.
  3. Identify a USB profile similar to the device's, and create a pass-through that attempts to provide everything the controller does.
  4. Once this is tested, you can write your own remappings.

Variations

  • Variations not yet written.

Related resources

Coding Prompt Build Block

A prompt to give a coding assistant, to start the code for this activity. Copy the box, answer its questions about your board and pins, and test what comes back on the bench before you rely on it.

I am building "Intervene in USB Controller I/O Streams with an MCU Interposer", the activity at https://adrianfreed.com/usb-controller-mcu-interposer.html.

Write a program for a microcontroller with a USB host port that sits between a USB game controller and a computer. First, list the controller's descriptors and print its reports as they arrive, so that we can see what each control sends.

Then find the closest device that the host library already supports, and test that. Then make a pass-through: the microcontroller appears to the computer as a USB device of a similar kind, and passes on everything the controller does. Then add remappings, each in its own small function: swapping buttons, scaling an axis, adding a turbo button.

If the board cannot be a USB host and a USB device at once (on an ESP32-S3, the USB host takes the peripheral that the USB device stack would use), send the data to the computer another way, such as serial over the board's other port.

Libraries to explore:

Before writing anything, ask me what I am using: the board and its pins, or the software (such as Max, Pd or Python), and check its documentation for what this needs. Put the pin numbers, ranges and other settings in one block at the top, each with a comment. Say which of the libraries above you use, and why. Start with a test that shows the raw readings, so that I can check the wiring and the ranges before the rest.

This activity by Adrian Freed is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0): you may share and adapt it with attribution, for non-commercial purposes such as personal projects and teaching, and you must share adaptations under the same licence. Product names and links belong to their suppliers.

Design strategies: