Petit boîtier USB autour d’un RP2040 Zero (Waveshare) sous CircuitPython 10.x : il lit 2 à 4 potentiomètres 10 kΩ et les expose à l’ordinateur soit en MIDI (messages de contrôle), soit en HID gamepad (axes de joysticks). Un interrupteur sur la carte choisit le mode sans reconfigurer le firmware : d’un côté tu as un contrôleur MIDI classique, de l’autre une manette reconnue par le système comme un gamepad.
Les sketchs code.py (boucle principale) et boot.py (USB + descripteur HID) vont à la racine du volume CIRCUITPY. Sans boot.py adapté, le MIDI peut marcher, mais le gamepad HID risque d’être absent ou incorrect.
- Deux modes USB : MIDI (CC sur les mouvements de potars) ou HID gamepad (même potars pilotent des axes X/Y et, avec 4 potars, Z/Rz pour un second stick).
- Bascule MIDI / HID sur GP5 : interrupteur 2 broches vers GND uniquement ; le code active un pull-up interne — contact fermé = MIDI, ouvert = HID (pas de fil 3V3 sur l’interrupteur).
- Numéros de CC MIDI générés à partir de
5°(défaut 31) : avec 2 pots, 32 puis 31, puis 33, 34… si tu ajoutes des voies (_midi_cc_list). - Lissage sur plusieurs lectures par pot avant envoi, pour limiter le bruit et le spam MIDI.
- MIDI entrant : un
NoteOffcanal courant, note 64 demande au boîtier de renvoyer l’état actuel de tous les pots en CC (pratique pour resynchroniser une appli). - LED NeoPixel : flash court à chaque changement de valeur traité (couleur selon le pot).
- Bouton / ligne boot sur GP4 : lu dans
boot.pyau démarrage (options USB commentées dans le fichier).
Le boîtier est pensé pour être simple à exploiter dans une page web selon la position de l’interrupteur :
- Mode MIDI : utilise l’Web MIDI API (
navigator.requestMIDIAccess). Tu reçois les Control Change sur les numéros décrits plus haut ; tu peux envoyer leNoteOffnote 64 pour forcer un rafraîchissement des valeurs. - Mode HID gamepad : utilise l’Gamepad API (
navigator.getGamepads()+ événementsgamepadconnected). Les axes apparaissent comme ceux d’une manette standard ; pas besoin de pilote spécifique côté navigateur.
HTTPS ou localhost selon les exigences du navigateur pour Web MIDI ; la Gamepad API fonctionne en général dès que le périphérique est vu comme gamepad.
| Élément | Connexion |
|---|---|
| Boot | GP4 + GND |
| Interrupteur MIDI / HID | GP5 + GND (2 broches, pull-up firmware) |
| Potars | Une entrée du tuple POT_GPIO = un pot ; broches ADC GP26–GP29 selon ton montage |
Ne pas court-circuiter GND et 3V3.
Découpe laser Trotec (PDF boîtier) : rouge = coupe, vert = coupe faible 30 %, noir = gravure.
| Fichier / symbole | À quoi ça sert |
|---|---|
POT_GPIO |
Liste des broches ADC = pot 0, 1, … ; 4 lignes → stick droit HID actif. |
addr, _midi_cc_list |
Base et liste des numéros de CC. |
USB_MIDI_channel |
Canal MIDI sortant (1–16). |
mode_switch, use_midi |
GP5, Pull.UP, logique not mode_switch.value. |
_hid_axes_from_omesure, _gamepad_move_joysticks |
Conversion pot → axes gamepad. |
boot.py |
Descripteur HID gamepad (report ID 4), GP4 au boot. |
Si le gamepad n’apparaît pas : boot.py bien à la racine, build CircuitPython compatible avec la carte, redémarrage après copie des fichiers.
Small USB enclosure built around a Waveshare RP2040 Zero running CircuitPython 10.x: it reads 2 to 4× 10 kΩ potentiometers and exposes them to the host either as MIDI (control messages) or as an HID gamepad (joystick axes). A switch on the board picks the mode without reflashing the firmware: on one side you have a classic MIDI controller, on the other a pad the OS sees as a standard gamepad.
Place code.py (main loop) and boot.py (USB + HID descriptor) at the root of the CIRCUITPY drive. Without a matching boot.py, MIDI may work, but the HID gamepad may be missing or wrong.
- Two USB modes: MIDI (CC when pots move) or HID gamepad (same pots drive X/Y axes, and with four pots also Z/Rz for a second stick).
- MIDI / HID toggle on GP5: 2-pin switch to GND only; firmware enables an internal pull-up — closed = MIDI, open = HID (no 3V3 wire on the switch).
- MIDI CC numbers derived from
addr(default 31): with two pots, 32 then 31, then 33, 34… if you add channels (_midi_cc_list). - Smoothing over several samples per pot before sending, to cut noise and MIDI spam.
- MIDI input: a
NoteOffon the current channel, note 64 asks the device to send the current state of every pot as CCs (handy to resync an app). - NeoPixel LED: short flash on each processed value change (colour depends on which pot changed).
- Boot button / line on GP4: read in
boot.pyat startup (USB options commented in that file).
The device is meant to be easy to use from a web page, depending on switch position:
- MIDI mode: use the Web MIDI API (
navigator.requestMIDIAccess). You receive Control Change messages on the controller numbers described above; you can sendNoteOffnote 64 to force a refresh of all values. - HID gamepad mode: use the Gamepad API (
navigator.getGamepads()andgamepadconnectedevents). Axes show up like a standard controller; no extra browser-side driver.
Browsers may require HTTPS or localhost for Web MIDI; the Gamepad API usually works as soon as the OS lists the device as a gamepad.
| Item | Connection |
|---|---|
| Boot | GP4 + GND |
| MIDI / HID switch | GP5 + GND (2 pins, firmware pull-up) |
| Pots | One entry in the POT_GPIO tuple = one pot; ADC pins GP26–GP29 per your layout |
Do not short GND and 3V3.
Trotec laser cut (enclosure PDF): red = cut, green = light cut 30 %, black = engraving.
| File / symbol | Purpose |
|---|---|
POT_GPIO |
List of ADC pins = pot 0, 1, … ; four lines → right-stick HID active. |
addr, _midi_cc_list |
Base and list of CC numbers. |
USB_MIDI_channel |
MIDI output channel (1–16). |
mode_switch, use_midi |
GP5, Pull.UP, logic not mode_switch.value. |
_hid_axes_from_omesure, _gamepad_move_joysticks |
Pot readings → gamepad axes. |
boot.py |
HID gamepad descriptor (report ID 4), GP4 at boot. |
If the gamepad does not show up: ensure boot.py is at the drive root, use a CircuitPython build compatible with the board, reboot after copying files.

