🛠 Transformer la carte en clavier USB HID avec TinyUSB
Objectifs
Le RP2040 intègre un contrôleur USB 1.1 full-speed device ET host (datasheet, key features) — aucune puce externe nécessaire. Avec TinyUSB (la pile USB embarquée dans le Pico SDK, github.com/hathach/tinyusb), ta carte générique peut se faire passer pour un clavier HID : le bouton GP2 enfoncé envoie la touche « A » à n'importe quel PC, sans driver. C'est la base des raccourcis matériels, déclencheurs de présentation et autres ponts série→HID.
Matériel
- 1 × carte RP2040 générique avec broche USB reliée (les Zero exposent USB par le connecteur d'origine)
- 1 × bouton entre GP2 et GND
- Pico SDK ≥ 1.5 avec la lib
pico_sdk_init+ TinyUSB : copie le templatepico_sdk/examples/lib_pico_stdlibpuis ajoutepico_sdk_initettinyusb_board/tinyusb_deviceviapico_sdk_init+include(../../lib/tinyusb/src/tinyusb.cmake)— la voie simple est de copier l'exemple officieltinyusb/01_device_hellodu dépôt raspberrypi/pico-examples et de passer à00_hid_keyboard-style (HID) ; la doc d'installation TinyUSB : raspberrypi/pico-sdk lib/tinyusb
Code complet
// hid_clavier.c — squelette HID clavier (inspiré de la pile TinyUSB)
#include "pico/stdlib.h"
#include "tusb.h"
#define BTN 2
// descripteur de rapport clavier standard (boot protocol, 8 octets)
#define REPORT_ID_KEYBOARD 1
static const uint8_t hid_desc[] = TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(REPORT_ID_KEYBOARD));
const uint8_t desc_cfg[TUD_CONFIG_SIZE(1) + TUD_HID_DESC_SIZE(1)] = {
TUD_CONFIG_DESCRIPTOR(1, 1, 0, TUD_CONFIG_DESC_LEN, 0, 100),
TUD_HID_DESCRIPTOR(0, 0, HID_ITF_PROTOCOL_KEYBOARD, sizeof(hid_desc),
0x81, sizeof(hid_desc), 10), // EP 0x81, 10 ms
};
uint8_t const *tud_hid_descriptor_report_cb(uint8_t itf) { (void)itf; return hid_desc; }
uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t t, uint8_t *b, uint16_t len) { (void)itf;(void)report_id;(void)t;(void)b;(void)len; return 0; }
void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t t, uint8_t const *b, uint16_t len) { (void)itf;(void)report_id;(void)t;(void)b;(void)len; }
int main(void) {
gpio_init(BTN); gpio_set_dir(BTN, GPIO_IN); gpio_pull_up(BTN);
tusb_init;
uint8_t prev = 1;
while (true) {
tud_task; // fait tourner la pile USB
uint8_t now = gpio_get(BTN);
if (tuh_mounted(0) || tud_mounted) {
if (now != prev) { // front : envoyer touche 'A' puis relâcher
hid_keyboard_report_t press = {0, 0, {HID_KEY_A, 0, 0, 0, 0, 0}, 0};
hid_keyboard_report_t rel = {0, 0, {0, 0, 0, 0, 0, 0, 0}, 0};
tud_hid_report(REPORT_ID_KEYBOARD, &press, sizeof(press));
sleep_ms(10);
tud_hid_report(REPORT_ID_KEYBOARD, &rel, sizeof(rel));
prev = now;
}
}
}
}
Vérification attendue
Branche la carte : le PC voit un périphérique clavier (pas de port série, pas de pilote). Ouvre un éditeur de texte, appuie sur GP2 : un « a » est tapé. lsusb (Linux) ou le Gestionnaire de périphériques (Windows) liste un appareil HID. C'est la preuve que l'énumération USB device complète (descripteurs, endpoint 0x81, protocole keyboard) fonctionne.
Erreurs fréquentes
- Coder l'application avant que
tud_tasktourne : sans appel régulier de la pile, l'énumération échoue et le PC affiche « périphérique inconnu ». - Oublier le rapport de relâchement : le PC voit une touche restée enfoncée (répétition infinie de « a ») — envoie toujours press puis release.
- Descripteur de rapport incohérent avec la trame envoyée : Windows est strict, le device est rejeté — garde le descripteur standard
TUD_HID_REPORT_DESC_KEYBOARD. - Confondre
tud_mounted(on est device, l'hôte nous a ouverts) ettuh_mounted(on est host) : en device simple, seul le premier a du sens. - La carte « disparaît » quand tu branches aussi le debug USB : deux contrôleurs USB natifs sur un même PC, deux énumérations — un seul câble suffit pour tester.
- Boot protocol vs rapport complet : certains BIOS ne parlent que le protocole de boot 8 octets — le descripteur standard ci-dessus est compatible les deux.
- 12 Mbit/s seulement : l'USB du RP2040 est full-speed (12 Mbit/s max), largement suffisant pour du HID, jamais pour de la webcam.
Autres tutoriels pour cette carte
- Piloter la LED RGB embarquée WS2812 d'une carte RP2040 générique
- Avoir une console série sur une carte sans pont USB (UART0)
- Jouer une mélodie avec un buzzer passif et le PWM
- Afficher sur un OLED I2C SSD1306 et déboguer le bus
- Logger sur carte microSD en SPI (mode carte)
- Interruptions GPIO et alarmes matérielles avec le Pico SDK
Exemples de code pour cette carte
clignotante.pyPythonbouton-interruption.pyPythonpwm-servo.pyPythonlecture-adc.pyPythonneopixel.pyPythonoled-i2c.pyPython