それでは、前回に引き続き、main 関数のポーリング部分です。割り込みで処理も出来るのですが、取り敢えずポーリングで処理するのが楽です。
main関数ポーリング部
まずは main 関数の while(1)
内部を御覧いただきましょう。
while(1) {
static enum {
RIGHT, DOWN, LEFT, UP, SIZE
} dir = RIGHT;
if( !(EP2CS & (1 << 3)) ) {
static int cnt = 0;
cnt++;
if( cnt == 10 ) {
cnt = 0;
EP2FIFOBUF[0] = 0;
EP2FIFOBUF[1] = (dir == LEFT) ? -1 : ((dir == RIGHT) ? 1 : 0);
EP2FIFOBUF[2] = (dir == UP) ? -1 : ((dir == DOWN) ? 1 : 0);
EP2BCH = 0;
EP2BCL = 3;
static unsigned int cnt2 = 0;
cnt2++;
if( cnt2 == 1000 ) {
cnt2 = 0;
dir = (dir + 1) % SIZE;
IOA ^= 1;
}
}
}
}
プログラム解読
では中身を見ていきましょう。以前までの記事で重複する部分はスルーしていきます。
型定義・変数の宣言
マウス(HID デバイス)の方向を定義する型です。特に深い意味は無いのですが、なんとなく書きました。
static enum {
RIGHT, DOWN, LEFT, UP, SIZE
} dir = RIGHT;
この無名列挙型を定義すると同時に、dir
という static 変数を宣言しています。
if文の内部
if( !(EP2CS & (1 << 3)) )
の内部は FULL
ビットが立ったときに実行されます。このビットは前の記事で述べたように、ホストから転送要求が出た時に内部が実行されると考えてください。以下に中身をかる~く説明します。
cntによる分周
ではマウスとしてポインタを動かす動作を記述したいのですが、そのままだとほとんどポインタが進んでくれません。ですので一定の移動距離を得るために cnt
という整数型変数をインクリメントしていき、その値が10に達したときに処理をするというようにしました。
レジスタへの代入
EP2FIFOBUF[0] = 0;
EP2FIFOBUF[1] = (dir == LEFT) ? -1 : ((dir == RIGHT) ? 1 : 0);
EP2FIFOBUF[2] = (dir == UP) ? -1 : ((dir == DOWN) ? 1 : 0);
EP2BCH = 0;
EP2BCL = 3;
こちらの説明ですね。インタラプト転送で転送するデータを書き込んでいます。その形式は HID レポートディスクリプタに記載されているとおりとなります。表にするとこんな感じ。
説明 | |
---|---|
0byte目 | 0 |
1byte目 | X方向移動量(-127〜127) |
2byte目 | X方向移動量(-127〜127) |
ということで値を入れた後に EP2BCH:L
にその送信 FIFO サイズを入力します。今回は 3bytes ですね。
IOA
はデバッグ用にLチカをさせているだけです。深い意味はありません。
〆
一通り USB マウスとしての解説は終了しました。ですが、アラインメントの問題も残っています。
ということでこれらやオートベクター機能を含めた追加の記事を、続きとして書きたいと思います。乞うご期待!