USB HID Device (STM32)

(2015.6.14 作成)

(2015.10.10 更新)

(2017.8.5 更新)

 このサイトで紹介しているUSB HIDライブラリは STM32Cube USB device libraryを利用したものです。STM32F3Discovery, NucleoF401REとSTM32F103C8T6のどれでも共通して使え、かつ64バイトの任意のデータを送受信できるようにしています。

 前提としているUSB Libraryのバージョンは2.4.2になります。

マイコン基板ごとの注意点

F3Discovery

 F3Discoveryを利用する場合は特に追加部品は必要ありません。黄色印のコネクタでプログラムを書き込んで、赤色のコネクタに接続することでHID USBとして動作します。両方接続するとデバッグ時にはステップ実行も可能になります。

 ただしEm::Blocksを用いてF3Discoveryを使用する場合一点注意事項があります。バージョン2.30の場合だけかもしれませんが、"startup_stm32f30x.S"の中身を以下のように修正する必要があります。(2箇所)

×: USB_LP_CAN1_RX0_IRQHandler

○: USB_LP_CAN_RX0_IRQHandler

Nucleo F401RE

 Nucleoの場合USBデバイス用のコネクタが搭載されていませんので、自分で接続する必要があります。下は秋月電子さんのUSBコネクタキットを使用した場合の例です。


 D+ピンを1.5KΩで3.3VにプルアップすることでハイスピードUSBデバイスとして認識させます。

環境設定

 ダウンロードページからDKSlib_STM32HALとDKSlib_STM32USBをダウンロードしてください。プロジェクトへのライブラリの追加方法はこちらで紹介していますので、同じようにプロジェクトへ追加してください。

 ただ一点注意していただきたいことはCDCクラスHIDクラスに対して共通のCoreクラスを使用することになっています。このためダウンロードして出てきたDKSlib_stm32USBフォルダ全体をプロジェクトに追加するのではなく、CoreフォルダとHIDフォルダ(またはCDCフォルダ)をそれぞれ追加するようにしてください。そうしないとHIDとCDCでファイルの重複が発生します。

使い方

 あまり設定することはないと思います。下のサンプルコードも合わせてご確認ください。

送信

 任意のタイミングで送信用関数を呼び出してください。1回に送信するサイズは64バイトに設定されています。この際、64バイトすべてを使用するバージョンと最初1バイトをヘッダとして利用する2バージョンの送信用関数が利用できます。

受信

 ホストからデータを受け取るとインスタンス作成時に設定したコールバック関数が呼び出されます。このコールバック関数から抜けることで受信完了となりますので、複雑な処理等は別途行うことを考慮してください。たとえばコールバック関数内で新たに通信を始めようとすることは避けるべきです。

関数リファレンス

コンストラクタ

プロトタイプ

UsbHid(int8_t (*DataReceive)(uint8_t *Data) = 0,

        int8_t (*Init)(void) = 0,

        int8_t (*DeInit)(void) = 0);

戻り値

なし

引数

DataReceive

データ受信時に毎回呼び出されるコールバック関数を設定します。Data長は64バイト固定です。

Init

コネクタが接続されたときに呼び出される関数です

DeInit

コネクタが外されたときに呼び出される関数です

備考

 

ホストへデータを送信する(ヘッダなしバージョン)

プロトタイプ

bool SendData(const uint8_t *data,

                       const uint8_t &length)const

戻り値 接続が確立しておらず、送信に失敗するとfalseが返ります
引数

64バイトまでの任意のデータ

備考 64バイト以上を設定しても超える部分は送信されません。

ホストへデータを送信する(ヘッダありバージョン)

プロトタイプ

bool SendNumber(const uint8_t *data,

                           const uint8_t &length)const;

bool SendText(const std::string &text)const;

bool printf(const char* format, ...)const;

戻り値 接続が確立しておらず、送信に失敗するとfalseが返ります
引数

63バイトまでの任意のデータ

備考

63バイト以上を設定しても超える部分は送信されません。

最初の1バイトにヘッダ情報が記載されています。

7bit目: 0=文字列, 1=数字

0~6bit目:データ数[バイト]

その他、各種状態の取得など

WaitUntilIdle()

前回の通信が完了し、アイドル状態になるまで停止

WaitDoneStartup()

ホストとのエニュメレーションが確立するまで停止

最初の接続時等に使用します。

IsConnected()

有効な接続が確立しているか

サンプルコード

 F3Discoveryに以下のコードを書き込んでください。Discovery基板上のLEDとプッシュボタンで動作していることが確認できると思います。PC側のソフト例はこちらにあります。

#include "DKS_UsbHid.h"
#include "DKS_Util_DiscoF3.h"
#include "DKS_GPIO_DiscoF3.h"

DKS::UsbHid *hid;
DKS::DigitalOut *led5;
DKS::InterupptIn *button;
uint8_t c;

//データ受信時に呼び出される関数
int8_t DataReceive  (uint8_t *buff)
{
  if(buff[1]==0) led5->write(buff[2]);
  return 0;
}

//プッシュボタンを押した際にデータを送信する関数
extern "C"
void EXTI0_IRQHandler(void)
{
        __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
        uint8_t SendBuffer[2];
        if (button->Debounce()==0)
        {
                SendBuffer[0] = 0xf;
                SendBuffer[1] = c;
                c++;
                hid->SendData(SendBuffer,2);
        }
}

int main(void)
{
        DKS::InitSystem();

        led5=new DKS::DigitalOut(GPIOE, GPIO_PIN_10, DKS::Push_Pull, DKS::Pull_Up);
        button = new DKS::InterupptIn(GPIOA, GPIO_PIN_0, DKS::No_Pull, DKS::IT_Falling);
        hid=new DKS::UsbHid(DataReceive);//CustomHID_Init,CustomHID_DeInit,CustomHID_OutEvent);
        hid->WaitUntilIdle();

        c=0;

        while (1) {}
}

発展

ポーリング間隔変更

usbd_customhid.cの105行目、114行目を編集してください。105行目がDataIn(デバイスからPC), 114行目がDataOut(PCからデバイス)への間隔です。

マウスやキーボードとして動作させる

DKS_UsbHid.cppにレポートディスクリプタの本体が入っています。ここを修正すると動くようになる(ハズ)です。たぶん・・・