ブラウザの Javascript を有効にして下さい。
This site requires your browser to be JavaScript enabled.

マウスの製作 ①ハードウェア編

「2020年は子年だし、マウスを作ろうかな?」ぐらいのノリでマウスの作成をはじめました。

まずは有線のUSBマウスを作ります。
BLEを使って無線マウスを作るのも面白そうですが、敷居が高そうなので次の子年あたりに。。

要件

簡単に要件を整理します。

  1. 光学式マウス
  2. 有線(USB接続)
  3. USB Low-Speed(1.5Mbps)
  4. HID(Human Interface Device)
  5. 左/中/右/サイド1/サイド2 の5ボタン + 縦ホイール + サイドホイール
  6. AVRマイコン ATmega328P で制御
  7. ホイールのプラスチック部分をLEDで光らせる

サイドホイール(横方向のホイール)の付いたマウスってあまり見かけませんが、昔Logicoolから発売されていた MX-R というマウスに搭載されていました。

サイドホイールがあると色々作業がはかどるんだろうなぁって思っていましたが、当時使っていた別のマウスが結局10年以上壊れず、その間にMX-RはEOLになってしまいました。
一度使ってみたかった。

調査

制作するにあたって調査・検証した内容をここに残しておきます。

CMOSセンサー選定

まずはマウスの心臓部のCMOSセンサー。せっかく作るので、どうせなら精度や評判がよいものをと、PixArtの PMW3360DM-T2QU (以下、PMW3360)を選定。
ゲーミングマウスでも採用されているチップですね。

日本ではチップだけを売っている店がなかったのですが、AliExpressならレンズが付属して1200円ぐらいで売っていました。
動く保証がない段階ではちょっと高いなと思いながらも、これがないと始まらないので深く考えずにこれに決めました。

買った後で気付いたのですが、PMW3360は3.3Vと1.9Vの2つの電源が必要で、USBからの給電は5Vなので2種類降圧しないと使えません。
また、ピンの間隔はよくある2.54mmではなく1.78mm。そんなピッチのユニバーサル基板なんて持っておらず、別途買う必要がありました。。
なんとも面倒なチップを選んでしまったもんです。面倒でもデータシートをよく確認しないとだめですね。

PMW3360 の制御については、PMW3360のデータシート にリファレンス回路もあり、それを参考にすればよいのですが、いくつか不明点があったので書いておきます。

PMW3360の制御


SPIの動作速度

マイコンとPMW3360とはSPIで接続します。
PMW3360のシステムクロックは70MHzでマイコンは16MHzなので、SPIのクロックに fosc / 2 を指定しても問題なく動作しました。


//  SPI2X  SPR1 SPR0  SCK Freq
//  -----------------------------
//     1    0    0    fosc / 2
//     0    0    0    fosc / 4
//     1    0    1    fosc / 8
//     0    0    1    fosc / 16
//     1    1    0    fosc / 32
//     0    1    0    fosc / 64
//     1    1    1    fosc / 64
//     0    1    1    fosc / 128

SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << CPHA) | (1 << SPI2X);

MOTIONピン

マウスの動き検出用の出力ピンです。
動き検出自体はMOTIONピンを使わなくてもSPI経由で取得できるので、使い道がいまいちわかりません。
もしかしたら無線マウスとかで一定時間動きがなければスリープモードに移行して、そのスリープから復帰するための割り込み用途で使うのかもしれませんね。
今回はスリープ等も行わないのでMOTIONピンからの情報は使いませんでした。

SPI経由での動き検出は、以下のようにMOTフラグと、Lift_Statフラグを確認すればよさそうです。


// [7] MOT: Motion since last report or PD
//     0 = No motion
//     1 = Motion occurred

// [3] Lift_Stat: Indicate the lift status of Chip
//     0 = Chip on surface
//     1 = Chip lifted

return (PMW3360_ReadReg(REG_Motion) & 0x88) == 0x80;

起動手順にある「SROM download」

データシートのP.26「7.0 Power Up」の手順「6. Perform SROM download」で、firmwareをロードするとありますが、何をロードすればよいのかがよくわかりません。
そもそもメーカ公表のSROMが見つからないですし。。
ロードしなくても問題なく動作するので、きっとメーカー毎に個別にカスタマイズできるようにするための仕組みなんだろうな、と判断して今回はこの手順はスキップしました。

最終的な初期化部分のコードは以下になりました。
Config1は、0x00 ~ 0x77 (100cpi~12000cpi) の範囲で指定できます。


// Drive NCS high, and then low to reset the SPI port.

CS_H;
CS_L;

// Write 0x5A to Power_Up_Reset register (or, alternatively toggle the NRESET pin).

PMW3360_WriteReg(REG_Power_Up_Reset, 0x5a);

// Wait for at least 50ms.

_delay_ms(50);

// Read from registers 0x02, 0x03, 0x04, 0x05 and 0x06 one time regardless of the motion pin state.

PMW3360_ReadReg(0x02);
PMW3360_ReadReg(0x03);
PMW3360_ReadReg(0x04);
PMW3360_ReadReg(0x05);
PMW3360_ReadReg(0x06);

// Load configuration for other registers

PMW3360_WriteReg(REG_Config2, 0x00);	// Disable Rest mode
PMW3360_WriteReg(REG_Config1, 12);		// CPI = 1300

マウス移動量取得

移動量は Delta_X_H, Delta_X_L, Delta_Y_H, Delta_Y_L の4つのレジスタから取得できます。
動きが検出された場合は値を取得し、値は16bitなので8bitに丸めてレポートを作成しました。

USB関連

HID(Human Interface Device)に準拠すればPCにドライバ等をインストールしなくてもマウスとして動作します。
さすがにこのコアな部分を自分で実装するのは無理なのでAVRマイコン向けのライブラリ「V-USB」を利用することにします。

マイコンの周波数

V-USBの解説ページによると、12MHz, 12.8MHz, 15MHz, 16MHz, 16.5MHz, 18MHz, 20MHzの中から選択できるようです。
手持ちの16MHzのセラロックで問題なく動作したのでそれに決めました。

レポートディスクリプタ

Microsoft社から「Enhanced Wheel Support in Windows」というホイールマウスを実装する際のディスクリプタの記述方法について詳しい資料が公開されています。
これを元にレポートディスクリプタにして公開されているページの情報を参考にしました。

気になる水平ホイールですが、試しにホイールを回転させたときの値を入れてデータ送信すると、Chromeの水平スクロールバーが動きました。すごい。
親指のところにサイドボタンを置き、その後方にホイールを設置予定です。

データ送信

マイコンのメインループはボタンやホイールの状態変化やマウスが移動があれば、レポートを作成してV-USBの関数 usbSetInterrupt() でデータ送信する、という処理になります。

ボタン、ホイールの状態は、ピン変化割り込みを使って更新しました。


// ピン変化割り込み(PCINT)
// 対象ピン番号(内容): 9(L), 10(R), 11(M), 12(F), 13(B), 21(ENCH_B), 23(ENCV_B)
#define MASK_PCMSK1							0b00111110
#define MASK_PCMSK2							0b10100000

	:

// ピン変化割り込み
PCMSK1 	= MASK_PCMSK1;
PCMSK2 	= MASK_PCMSK2;
PCICR 	= (1 << PCIE0) | (1 << PCIE1) | (1 << PCIE2);

ロータリーエンコーダ

マウスには変わった形のロータリーエンコーダが使われますが、普通のロータリーエンコーダしか持っていなかったので、これもAliExpressで探します。

色々なサイズ(5mm~13mm)の詰め合わせ10個入で、なんと100円(しかも送料無料!)という安さに惹かれてしまいましたw

普通のタイプのロータリーエンコーダと同じ回路で動きましたが、予想通り品質は安かろう悪かろうで、オシロスコープで確認するとホイール回転時のノイズ(チャタリング)が凄まじく、コンデンサでしっかり吸収する必要がありました。
手でホイールを速く回転させたところでA/B相のL⇔Hの間隔は大したことないので、マイコンが反応できる範囲でコンデンサの容量をできるだけ大きくしました。
これでエンコーダを交換する時はどんな粗悪品を使っても問題なく動作できそうですw

LED

マウスが光ったところでどうせ見てないし、無駄に電力を消費するだけなのでLEDなんて無くてもいいんですが、フルカラーLEDを使ういい機会なので、あまり主張しない(ランダム周期のサインカーブで徐々に様々な色に変化していく程度)でホイールのプラスチック部分を光らせてみます。

PWMでLEDを制御したいので ATtiny85 を別途用意します。USBの5Vから直接給電して ATmega328P 側とは独立させて動かしました。
ATtiny85 では OC0A, OC0B, OC1B で3つのPWMを同時に動かせるので、赤/青/緑のLEDをそれぞれ調光しました。

設計

回路図

LM317LZの電圧調整のための抵抗 107Ω は、39Ω + 68Ω で作成しています。電圧が1.8V~2.1Vに収まれば他の値で問題ありません。

また、マイコン側のボタン、ロータリーエンコーダの入力ピンは、マイコン内部でプルアップしています。

全体構成

一般的なマウスのサイズに収まるように、およその配置を決めます。
チップ部品は使わないのと、サイドホイールのためのスペースを確保すると、場所が足りなくなったので2階建てにしました。
左の緑のI/Fの四角が2階部分で、ボタンやホイール入力をまとめるI/F基盤になります。

部品レイアウト

なるべく省スペースになるよう部品のレイアウトを決めていきます。
ユニバーサル基盤で設計しています。
※センサー基盤のレイアウトは割愛しました

メイン基板

I/F基板

LED基板

組み立て

基盤組み立て

基盤をすべて作成して接続してみます。

ピンヘッダは高さが結構あるので、各基盤間はXHコネクタにして、2階のI/F部分はピンヘッダを水平にして並べることで、サイズの問題もクリアできました。

まだテープでの固定で、ボディー、サイドボタン、サイドホイールはありませんが、完成イメージはこんな感じです。
空いたところにボタンとサイドホイールが入る予定です。

ホイールがウロウロしないように、ホイールの右側の軸の動ける範囲を硬めの針金で制限しました(特に前後方向と右方向)。
また、ホイールクリック時にスイッチが押しやすくなるように薄い板を挟んで、テコの原理で押せるようにします。

LEDは横から入れてホイールの中で拡散させました。
外から直接LEDの光が見えないよう、黒の熱収縮チューブで覆いながら中に入れて、中でLEDキャップで拡散させます。
光っている場所が均一ではありませんが、ボディから顔をだす部分だけ光ればいいので、だいたいこれでOKです。

動作確認

組み立てたので動作確認です。
ボタン操作、ホイール操作、マウス移動も問題なく動作ました!!
ソフトウェアと違って、ハードウェアはうまく動かないとき調査がかなり大変で絶望感が半端ないので、1発で無事動いてほんとよかったです。

後はボディーを作れば完成です!

ボディー

2022年になりようやくボディーが完成しました → こちら