dxxk_mouse

Public

@segfau-yama

Share dxxk_mouse

Check access before sharing the link.

Who can open this board

Anyone can open this board. No sign-in is required.

This link opens the latest version. Copying it does not grant additional access.

Loading…

README

dxxk_mouse

ESP32-S3 上で動作する Rust 製 USB 入力デバイスの実験用リポジトリです。

ファームウェアは、USB HID のキーボードとマウス、USB Audio Class 1(UAC1)のマイクとスピーカーを一つの USB デバイスとして提供します。

対象環境

項目構成
MCUESP32-S3
Rust targetxtensa-esp32s3-none-elf
HALesp-hal
async runtimeEmbassy、esp-rtos
USBembassy-usb
実機テストembedded-test、probe-rs

ディレクトリ構成

dick_mouse
├── Cargo.toml
├── .cargo/config.toml
├── src
│   ├── main.rs
│   ├── lib.rs
│   ├── device
│   │   ├── button.rs
│   │   ├── encoder.rs
│   │   ├── joystick.rs
│   │   ├── microphone.rs
│   │   └── speaker.rs
│   └── tasks
│       ├── audio.rs
│       ├── hid.rs
│       ├── keyboard.rs
│       ├── mouse.rs
│       └── usb.rs
└── tests
    ├── device
    │   ├── button.rs
    │   ├── encoder.rs
    │   ├── joystick.rs
    │   ├── microphone.rs
    │   └── speaker.rs
    ├── main.rs
    ├── reexports.rs
    └── tasks
        └── mod.rs

設計図

flowchart TD
  subgraph Mode["mode"]
    direction TB
    UsbHidReports["CHANNEL: USB_HID_REPORTS"]
    ModeGpio["PERIPHERAL: GPIO21 slide switch"] --> HidTask["TASK: hid_task"]
  end

  subgraph Keyboard["keyboard"]
    direction TB
    ShortcutGpio["PERIPHERAL: GPIO6/7 shortcut buttons"]
    PushGpio["PERIPHERAL: GPIO42 joystick push"]
    KeyboardTask["TASK: keyboard_task"]
    KeyboardReports["CHANNEL: KEYBOARD_REPORTS"]
    ShortcutGpio --> KeyboardTask
    PushGpio --> KeyboardTask
  end

  subgraph Mouse["mouse"]
    direction TB
    ClickGpio["PERIPHERAL: GPIO38/39 click buttons"]
    JoystickAdc["PERIPHERAL: ADC1 GPIO1/2 joystick"]
    ScrollPcnt["PERIPHERAL: PCNT0 GPIO11/12 scroll encoder"]
    MouseTask["TASK: mouse_task"]
    MouseReports["CHANNEL: MOUSE_REPORTS"]
    ClickGpio --> MouseTask
    JoystickAdc --> MouseTask
    ScrollPcnt --> MouseTask
  end

  subgraph Microphone["microphone"]
    direction TB
    I2sMic["PERIPHERAL: I2S0 RX microphone"]
    MicMuteGpio["PERIPHERAL: GPIO4 microphone mute"]
    MicVolumePcnt["PERIPHERAL: PCNT1 GPIO13/14 volume encoder"]
    MicrophoneTask["TASK: microphone_task"]
    MicrophoneFrames["SPSC: MICROPHONE_RING"]
    I2sMic --> MicrophoneTask
    MicMuteGpio --> MicrophoneTask
    MicVolumePcnt --> MicrophoneTask
    MicrophoneTask --> MicrophoneFrames
  end

  subgraph Speaker["speaker"]
    direction TB
    SpeakerFrames["SPSC: SPEAKER_RING"]
    SpeakerMuteGpio["PERIPHERAL: GPIO5 speaker mute"]
    SpeakerVolumePcnt["PERIPHERAL: PCNT2 GPIO40/41 volume encoder"]
    SpeakerTask["TASK: speaker_task"]
    I2sSpeaker["PERIPHERAL: I2S0 TX speaker"]
    SpeakerFrames --> SpeakerTask
    SpeakerMuteGpio --> SpeakerTask
    SpeakerVolumePcnt --> SpeakerTask
    SpeakerTask --> I2sSpeaker
  end

  UsbTask["TASK: usb_task"]

  subgraph Usb["usb"]
    direction LR
    UsbHid["USB: HID keyboard / mouse"]
    UsbMic["USB: UAC microphone"]
    UsbSpeaker["USB: UAC speaker"]
    UsbPeripheral["PERIPHERAL: USB0 GPIO19/20"]
    UsbHid --> UsbPeripheral
    UsbMic --> UsbPeripheral
    UsbPeripheral --> UsbSpeaker
  end

  UsbTask --> UsbHid
  UsbTask --> UsbMic
  UsbSpeaker --> UsbTask

  KeyboardTask --> KeyboardReports
  MouseTask --> MouseReports
  KeyboardReports --> HidTask
  MouseReports --> HidTask
  HidTask --> UsbHidReports
  UsbHidReports --> UsbTask
  MicrophoneFrames --> UsbTask
  UsbTask --> SpeakerFrames

  class ShortcutGpio,PushGpio,ModeGpio,ClickGpio,JoystickAdc,ScrollPcnt,MicMuteGpio,MicVolumePcnt,I2sMic,SpeakerMuteGpio,SpeakerVolumePcnt,I2sSpeaker,UsbPeripheral peripheral
  class KeyboardTask,HidTask,MouseTask,MicrophoneTask,SpeakerTask,UsbTask task
  class KeyboardReports,MouseReports,UsbHidReports,MicrophoneFrames,SpeakerFrames channel
  class UsbHid,UsbMic,UsbSpeaker usb

  classDef peripheral fill:#ddf4ff,stroke:#0969da,color:#24292f
  classDef task fill:#dafbe1,stroke:#1a7f37,color:#24292f
  classDef channel fill:#fff8c5,stroke:#9a6700,color:#24292f
  classDef usb fill:#fbefff,stroke:#8250df,color:#24292f

実装概要

デバイス状態

型入力責務
ButtonGPIO level、時刻active level、debounce、押下状態を保持する
RotaryEncoderPCNT count、時刻count を安定化し、detent 算出に使う値を保持する
JoystickX/Y の ADC 値初期位置を中心として X/Y の差分を計算する
MicrophoneI2S RX frameUSB マイクへ送る音声フレームを保持する
SpeakerUSB speaker frameI2S TX へ送る音声フレームを保持する

各構造体は setter や &mut self を持たず、update(self) -> Self または new() で新しい状態を返します。

task のデータフロー

USB HID と USB Audio は、同じ列で入力、処理、出力を示します。

USB HID

task入力処理出力
keyboard_taskjoystick push、Back、Forward の GPIOButton を更新し、ボタン状態を集約するKEYBOARD_REPORTS
mouse_taskclick の GPIO、joystick の ADC、encoder の PCNTButton、Joystick、RotaryEncoder を更新し、マウス入力を集約するMOUSE_REPORTS
hid_taskmode GPIO、KEYBOARD_REPORTS、MOUSE_REPORTSmode に応じて入力を keyboard または mouse report に変換するUSB_HID_REPORTS
usb_taskUSB_HID_REPORTSreport ID を付けて HID endpoint へ書き込むUSB HID keyboard、mouse

USB Audio

task入力処理出力
microphone_taskI2S RX、mute GPIO、volume encoder の PCNTDMAを常時drainし、muteと音量を反映したmono S16を格納するMICROPHONE_RING
usb_task(microphone)MICROPHONE_RINGリングを待たずに47/48/49 sampleのmono packetを組み立てるUSB UAC1 microphone
usb_task(speaker)USB UAC1 speakermono S16を格納し、USB mute/volumeも監視するSPEAKER_RING
speaker_taskSPEAKER_RING、mute GPIO、volume encoder の PCNTUSBと物理入力のmute/volumeを反映し、連続DMAへstereo S32を補充するI2S TX

入力割り当て

GPIO21 のスライドスイッチに応じて、hid_task が通常モードとゲームモードを切り替えます。

入力通常モードゲームモード
joystick X/YMouse X/YArrow keys
joystick pushPrintScreenS
left clickMouse left buttonA
right clickMouse right buttonD
Back buttonCtrl+LeftSpace
Forward buttonCtrl+RightEnter
scroll encoderMouse wheel使用しない

ゲームモードでは joystick の X/Y 差分が 512 を超えた方向をキー入力へ変換します。

同時押しが HID keyboard の上限を超えた場合は、実装上の割り当て順で先頭の 6 キーを送信します。

USB インターフェース

インターフェースUSB class方向データ形式
KeyboardHID、report ID 1ESP32-S3 から PCmodifier、6 keycodes
MouseHID、report ID 2ESP32-S3 から PCbuttons、X/Y、wheel、pan
MicrophoneUAC1 sourceESP32-S3 から PC48 kHz、16-bit、mono、単一IN、feedbackなし
SpeakerUAC1 speakerPC から ESP32-S348 kHz、16-bit、mono(Left Front)

I2S は RX、TX ともに 48 kHz、32-bit slot で動作します。 RX はINMP441の左スロットだけをDMAへ取り込み、符号付き24-bitから16-bit PCMへ変換します(L/R端子はLow)。 TX はUSBのmono S16を32-bitの上位16 bitへ配置し、左右両スロットへ複製します。 マイクは未実装のUSB音量制御を広告せず、スピーカーはUSBのmute/volumeと物理ボタンをPCMへ反映します。 音声にはheaplessのSPSCキューを使用し、USB/I2S処理中にUARTログを出しません。

現在の試作機の配線と再録音の確認方法は AUDIO_CHECK.md を参照してください。 以下の回路設計用ピン表と試作機の main.rs は異なるため、配線の変更時には main.rs を確認してください。

ピン割り当て

機能信号peripheralGPIO所有する task
Modeslide switchGPIOGPIO21hid_task
Keyboardjoystick pushGPIOGPIO42keyboard_task
KeyboardBack buttonGPIOGPIO6keyboard_task
KeyboardForward buttonGPIOGPIO7keyboard_task
Mousejoystick XADC1GPIO1mouse_task
Mousejoystick YADC1GPIO2mouse_task
Mousescroll encoder APCNT0GPIO11mouse_task
Mousescroll encoder BPCNT0GPIO12mouse_task
Mouseleft clickGPIOGPIO38mouse_task
Mouseright clickGPIOGPIO39mouse_task
Microphonemute buttonGPIOGPIO4microphone_task
Microphonevolume encoder APCNT1GPIO13microphone_task
Microphonevolume encoder BPCNT1GPIO14microphone_task
MicrophoneBCLKI2S0 RXGPIO15microphone_task
MicrophoneWSI2S0 RXGPIO16microphone_task
MicrophoneDINI2S0 RXGPIO17microphone_task
Speakermute buttonGPIOGPIO5speaker_task
Speakervolume encoder APCNT2GPIO40speaker_task
Speakervolume encoder BPCNT2GPIO41speaker_task
SpeakerBCLKI2S0 TXGPIO8speaker_task
SpeakerWSI2S0 TXGPIO9speaker_task
SpeakerDOUTI2S0 TXGPIO10speaker_task
USBD-USB0GPIO19usb_task
USBD+USB0GPIO20usb_task

I2S RX と I2S TX は I2S0 と DMA_CH0 を共有します。

マイクとスピーカーの音量は起動時を 100% とし、エンコーダーの 1 detent ごとに 5% ずつ、0% から 100% の範囲で変更します。

GPIO0/3/45/46 は strapping、GPIO43/44 は UART0、GPIO19/20 は USB に使われるため、汎用入力には割り当てていません。

GPIO39/40/41/42 は外部 JTAG の既定信号と重なるため、現在の入力配線と外部 JTAG は同時に使用できません。

ビルドと書き込み

cd dick_mouse
cargo check
cargo run --release

通常実行時の runner は .cargo/config.toml に定義した espflash flash です。

実機テスト

テストはホスト PC 上の unit test ではなく、ESP32-S3 実機上で動作する embedded-test 形式です。

cargo test-hil

cargo test-hil は .cargo/config.toml の alias で、runner を probe-rs run --chip esp32s3 に上書きします。

test target検証対象
buttondebounce と押下状態
encodercount の安定化
joystick中心位置からの X/Y 差分
microphonemicrophone frame の状態型
speakerspeaker frame の状態型
reexportsdevice 型の公開 API
tasksPCM 変換、HID report 変換、task の入口
mainfirmware で使う peripheral の初期化

tests/ 配下の各ファイルは Cargo.toml の [[test]] で明示し、ESP32-S3 上の結合テストとして実行します。

制約

  • ビルドには xtensa-esp32s3-none-elf target に対応した Rust 環境が必要です。
  • 実機テストには probe-rs がデバイスへアクセスできる権限が必要です。
  • embassy-usb は UAC1 source を使うため、Embassy の git revision に固定しています。
Comments

No comments yet. Be the first to ask about this board.

Ask about this board

Sign in to BoardRepo

New here? Signing in creates your account; there is no separate sign-up.