LoginSignup
7
6

More than 1 year has passed since last update.

【連載】Arduinoを使って学ぶ、Win/Macドライバ開発①~Arduinoの仕様~

Last updated at Posted at 2021-11-10

はじめに

この記事は「Arduinoを使って学ぶ、Win/Macドライバ開発講座」のシリーズ初回の記事になります。
シリーズタイトルにもあるように、この講座ではArduinoを使ってWindowsおよびMacのドライバ開発の基礎を解説していきます。

今回のシリーズで使うArduinoはArduino Uno Rev3です(公式紹介ページ)
arduino.png

このデバイス用のドライバを作成して、専用アプリからドライバを通してArduinoを操作するのが今回の目的です。

なお、Arduino Uno Rev3をUSB接続した場合にCDCクラス(Communication Device Class)の標準ドライバがインストールされますが、本シリーズではUSBデバイスのドライバを開発するのが目的のためArduinoをCDCデバイスとしては扱わず、vendor-specificとみなして開発を行います。

開発対象

今回はWindowsとMacで同一の機能実現するためにそれぞれのOS用に以下を開発対象とします。

  • Arudino用ドライバ
  • デバイス操作用アプリ

実現する機能は以下です。

  • アプリから値を送信し、その値によりArudino上のLEDの光の強さを変化させる。

"図1:機能

目的はドライバの開発なのでArduinoの機能はシンプルにしてます。

WindowとMacの開発環境

以下の環境で開発を行いました。

Windows Mac
OS Windows10 20H2 (OSビルド19042.985) MacOS (11.4)
開発環境 Visual Studio 2019(16.8.4) Xcode (12.5)
フレームワーク UMDF(User-Mode Driver Framework) DriverKitフレームワーク (XCode 12.5)
ソフトウェア開発キット WDK(10.0.18346.1000) -

Arduinoデバイス情報

ドライバを設計する前に、開発対象になるデバイスがどのようなデバイスか調べる必要があります。
開発対象のArduino Uno Rev3がどのようなデバイスなのか知らないと、ドライバでなにを実装すればいいのか分かりません。

前述しましたが、Arduino Uno Rev3は、USB-CDC互換デバイスであるため、CDCの規格に則ったインターフェースとなっているはずです。

PC接続するとUSBデバイスとして認識されますので、実際にどういったインタフェースを持っているのかを確認してみようと思います。
デバイスのUSB情報をMicrosoftが配布しているUSBViewを使って見ていきましょう。

デバイスディスクリプタ

まずはじめにデバイスディスクリプタの情報です。

deviceDesc2.png

ドライバに必要となるものをいくつかピックアップします。

項目 説明
bDeviceClass デバイスクラス 0x02 CDCクラス
idVendor ベンダーID 0x2341
idProduct プロダクトID 0x0043
bNumConfigurations コンフィグレーション数 0x01

bDeviceClassは0x02であり、これはCDCクラスのデバイスを表しています。
CDCクラスについて、このブログが非常に分かり易いのでおすすめします。

idVendor:0x2341とidProduct:0x0043はドライバとデバイスのマッチングに必要な情報です。
この情報を使ってデバイスに適切なドライバが選択されます。

bNumConfigurationsは0x01であり、コンフィグレーションを1つのみ持っていることを表しています。

次に、コンフィグレーションディスクリプタの情報を見てみましょう。

コンフィグレーションディスクリプタ

configDesc2.png

コンフィグレーションディスクリプタではインターフェースの数が分かります。

項目 説明
bNumInterfaces インターフェース数 0x02

Arduino Uno Rev3にはインターフェースが2つあるようです。

インターフェースの情報を見ていきましょう。

インターフェースディスクリプタ

インターフェースは2つあるため、インターフェースディスクリプターも2つあります。

インターフェース0
interface0Desc2.png

インターフェース1
interface1Desc2.png

主要な項目を以下にまとめます。

項目 説明 インターフェース0 インターフェース 1
bInterfaceNumber インターフェース番号 0x00 0x01
bNumEndpoints エンドポイント数 0x01 0x02
bInterfaceClass インターフェースクラス 0x02 CDC Control 0x0A CDC-Data

1つ目のインターフェース(インターフェース0)はインターフェースクラスが0x02であり、CDC Controlクラスのインターフェースということが分かりました。
こちらのインターフェースはデバイスの設定や管理を行うためのインターフェースですが、本講座ではCDCとしてのコントロールは行わないため、使用しません。
その代わりに、デバイスの初期設定などには、既定のエンドポイントであるEndpoint0を使用します。
既定エンドポイントについては、以下を参照ください。
"既定のエンドポイントについて"

2つ目のインターフェース(インターフェース1)はインターフェースクラスが0x0AでありCDC-Dataクラスのインターフェースです。
このインターフェースを使ってデバイスとデータのやり取りができます。
エンドポイントが2つあり、このエンドポイントを使ってデバイスと通信ができます。
最後にインターフェース1のエンドポイントの情報を見てみましょう。

エンドポイントディスクリプタ

endpointDesc2.png

エンドポイント 説明 エンドポイント1 エンドポイント2
bmAttributes 属性 0x02 Bulk 0x02 Bulk
bEndpointAddress エンドポイントアドレス 0x04 Out 0x83 In
wMaxPacketSize 最大パケット長 0x0040 0x0040

属性は下位2ビットにて、転送方式を表します。

  • 0x00:Control 転送
  • 0x01:Isochronous 転送
  • 0x10:Bulk 転送
  • 0x11:Interrupt 転送

bEndpointAddressは最上位ビットで転送方向を表し、下位4ビットにてエンドポイントアドレスを表します。
* bit7:IN=1、OUT=0
* bit 3-0:エンドポイントアドレス

両方ともデータのやり取りを行うためのバルク転送用のエンドポイントがということが分かります。
エンドポイント1のアドレスは0x04なため、バルクアウトです。
エンドポイント2のアドレスは0x83なため、バルクインです。
この講座ではデバイスにデータを送るだけで受け取ることはないのでバルクアウトのエンドポイント1のみを使います。バルクインのエンドポイント2は使いません。

そのため、今回使うエンドポイントのアドレスは0x04になります。

デバイスの初期化処理(CDCデバイスの設定)

USBデバイスは、一般的にドライバからデバイスに対して何らかの転送を行うことでデバイス側を初期化し、使用可能な状態になります。
vendor-specificのデバイスである場合は独自の初期化処理を定義することができますが、今回はArduinoを使用するため、初期化処理としてはCDCデバイスとしての初期化処理が必要となります。
CDCの初期化処理としては、SetLineCodingSetControlLineStateの2つのリクエストが最低限必要となります。

SetLineCodingではデバイスのシリアル通信を設定します。
SetControlLineStateはフロー制御の信号を設定します。

ドライバの開始時にこの2つのリクエストをコントロール転送でデバイスに送信することで、これ以降にバルク転送ができるようになります。

CDCのリクエストに関する細かい説明は省略しますが、以下のデータをコントロール転送することで初期化することが可能です。

リクエスト bmRequestType bRequest wValue wIndex wLength データ
SetLineCoding 0x21 0x20 0 0 7 {0x80, 0x25, 0x00, 0x00, 0x00, 0x00, 0x80}
SetControlLineState 0x21 0x22 0 0 0 -

ArduinoのCDCのリクエストについて興味のある方は、前述のブログこの記事をご参考ください。

Arduino用コード

Arduinoに書き込むコードはこの記事で紹介しているソース(リンク)を基に、複数の種類のコマンドを処理できるように変更しました。
現時点ではLEDの光の調整コマンドしか実装していませんが、後のことを見越して拡張性を持たせました(gist)。

バルク転送で受け取ったデータの値によってArduino Uno Rev 3のPIN13に挿してあるLEDの光を調整します。
コマンド種別と値が格納されている構造体のデータを受け取って、コマンド種別を確認してLEDの光調整コマンドだった場合、LEDの光の強さを構造体の値に合わせます。

おわりに

デバイスの詳細を調べることでデバイスと通信するためにドライバで実装する機能が判明しました。

  • コントロール転送でのCDCデバイス設定
  • バルクアウト転送でのデータの送信

次回からはこの情報を基に早速ドライバの開発に取り掛かります。

参考資料

https://docs.arduino.cc/hardware/uno-rev3
https://android.serverbox.ch/?p=549
https://blog.oino.li/posts/usbcdc/
https://docs.microsoft.com/ja-jp/windows-hardware/drivers/usbcon/usb-control-transfer

7
6
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6