USBデバイス開発

Suzuno32RV / Suzuduino UNOはUSBデバイスとして振舞うことができます。たとえばキーボードやマウスといった入力デバイス、MIDIデバイス、マスストレージデバイス、シリアル通信デバイスになることができます。公式サンプルコードと、TinyUSBライブラリが利用できます。

Arduino IDEでTinyUSBを利用するには、「ツール」→「USB support」から「Adafruit TinyUSB with USBD」を選択してください。

USBデバイス機能が暴走したなどの緊急時には、USB書き込み待機モードでリセットしてください。

USBシリアル

Arduino LeonardoやUNO R4のように、USB接続上でシリアル通信をすることができます。

Arduino IDEでボードを正しく選択したあと、「ツール」→「USB support」→「USBD」を選択します。これで Serial が自動的にUSBシリアルへと置き換わります。

#include <Adafruit_TinyUSB.h>

void setup() {
  // 動作確認用のLED
  pinMode(PA5, OUTPUT);
  // USB有効時、これはUSBシリアルになる
  Serial.begin(115200);
  // Serial1はPA9,PA10ピンに引き出されたシリアルポート
  Serial1.begin(115200);
}

void loop() {
  digitalWrite(PA5, HIGH);
  delay(100);
  digitalWrite(PA5, LOW);
  Serial.println("Hello from USB Serial");
  Serial1.println("Hello from Hardware Serial (PA9, PA10)");
  delay(1000);
}

USB入力デバイス(TinyUSB利用)

#include "Adafruit_TinyUSB.h"

#define PIN_SWITCH_1 PA15
#define PIN_SWITCH_2 PB3
#define PIN_SWITCH_3 PB4
#define PIN_SWITCH_4 PB5


// TinyUSBのテンプレートを利用したHIDレポートディスクリプタ
uint8_t const desc_hid_report[] = {
    TUD_HID_REPORT_DESC_KEYBOARD()
};

Adafruit_USBD_HID usb_hid;


void setup() {
  Serial1.begin(115200);
  Serial1.println("Initializing...");
  Serial1.println("USB keyboard sample code with TinyUSB");

  pinMode(PIN_SWITCH_1, INPUT_PULLUP);
  pinMode(PIN_SWITCH_2, INPUT_PULLUP);
  pinMode(PIN_SWITCH_3, INPUT_PULLUP);
  pinMode(PIN_SWITCH_4, INPUT_PULLUP);

  // Setup HID
  usb_hid.setBootProtocol(HID_ITF_PROTOCOL_KEYBOARD);
  usb_hid.setPollInterval(10);
  usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
  usb_hid.setStringDescriptor("TinyUSB Keyboard");
  // usb_hid.setReportCallback(NULL, hid_report_callback);
  usb_hid.begin();

  Serial1.println("Ready.");
}


void loop() {

  if (!TinyUSBDevice.mounted()) {
    // まだUSB接続されていない場合は処理をスキップ
    return;
  }

  if (!usb_hid.ready()) {
    // 前回のHIDレポートの送信が終わっていない場合は処理をスキップ
    return;
  }

  // HIDレポートディスクリプタでReportIDを指定していた場合は、その番号。無指定ならば 0
  uint8_t hid_report_id = 0;
  // 修飾キーの状態 (Ctrl, Alt, Shift, GUI)
  uint8_t modifiers = 0;
  // 押されているキーのキーコード (Usage ID。最大6キー)
  uint8_t keycodes[6] = { 0 };

  keycodes[0] = digitalRead(PIN_SWITCH_1) == LOW ? HID_KEY_A : 0;
  keycodes[1] = digitalRead(PIN_SWITCH_2) == LOW ? HID_KEY_B : 0;
  keycodes[2] = digitalRead(PIN_SWITCH_3) == LOW ? HID_KEY_C : 0;
  keycodes[3] = digitalRead(PIN_SWITCH_4) == LOW ? HID_KEY_D : 0;

  usb_hid.keyboardReport(hid_report_id, modifiers, keycodes);
}

// void hid_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) {

// }

USB入力デバイスは HID という仕様で動作します (Human Interface Deviceクラス)。HIDのデバイスは、HIDレポートという単位でパソコンと情報をやりとりし、そのレポートの内容はHIDレポートディスクリプタというバイナリで定義します。 USBキーボードの場合、典型的には8バイトのHIDレポートを用いてパソコンへ入力の状態を送信します。これに対応するHIDレポートディスクリプタはTinyUSBに用意されています。

USBキーボードのHIDレポートは、

  • 修飾キーの状態(1バイト)
  • 固定値 0x00
  • 入力キー 1
  • 入力キー 2
  • 入力キー 3
  • 入力キー 4
  • 入力キー 5
  • 入力キー 6 という構造です。「いま入力されているキー」のキーコード (Usage ID) を送信します。キー入力を表さない値として 0x00 で穴埋めができます。

USB入力デバイス(公式サンプルをベースに)

公式サンプルコードでも同様に、HIDレポートを送信することでキーボード入力が実現できます。

公式サンプルコードはMounRiver Studioで利用することが前提のC言語コードなので、Arduino IDEでもコンパイルできるように修正します。

HIDまわりの仕様についてはTinyUSBと同じです。ただし設定用の関数などは用意されていないため、USBまわりの挙動は各種のディスクリプタを直接書き換えてください。

コンパイル時にはArduino IDEの「USB support」は「None」にしてください。

コードはGitHubにて公開しています。

https://github.com/verylowfreq/arduino_ch32v203_usbdevice_keyboard