ラベル PSoC の投稿を表示しています。 すべての投稿を表示
ラベル PSoC の投稿を表示しています。 すべての投稿を表示

2016/12/30

ゲーミングマウス向けのUSB HIDディスクリプタ

前に3ボタンマウスのデータパスを16Bit化したHIDディスクリプタを紹介しました.
この時のディスクリプタは,3ボタンでX,Y変位がそれぞれ16bitなディスクリプタですが,スクロールホイールの情報は転送できません.

本記事では,そこにスクロールホイールを加えたディスクリプタを紹介します.
USB HID Descriptor (3 button, 16bit data-path, wheel)
これによって,3ボタン(左・中・右クリック),16bitのXY変位,スクロールホイールの変位を転送できることになり,ゲーミングマウスとして最低限必要な情報を転送できます.

送られる情報は8bit×6の配列で,各バイトの情報は以下のようになります.
  • 1バイト目 : ボタンのON/OFF情報
  • 2,3バイト目 : X変位
  • 4,5バイト目 : Y変位
  • 6バイト目 : スクロールホイールの変位

実はこのディスクリプタを使ってポインティングデバイスを開発しました.

この記事もそのデバイス(と市販のキーボード)を使いながら書いています.自前でファームウェアを開発することで,機能の追加や微妙なチューニングができ,とても便利です.入力機器は様々な種類を経て拘りはじめると,「結局自分で作るしか無いじゃん」という展開になりがちですね.
この話を始めるととても長くなるので,またいずれ(書けるといいですが・・・).

2016/08/23

Overwatchのウィンドウモードごとの遅延


先日Twitterに書きましたが,Overwatchの描画遅延を測定しました.この検証により,どのウィンドウモードでプレイするのが「最も強いのか」ということを解き明かしました.
また,Windows10にアップデートしたので,ゲーマーにおけるWindows 10の最大のテーマ「Aero 3フレーム遅延説」についても簡単に議論します.


測定方法

測定方法は今までの記事と同様で,視点を左右に動かすようなデータをHID Device経由で送信すると同時に,LEDを点灯させます.ここで,LEDの点灯(HID Deviceのモーション送信)からディスプレイの映像が実際に動き始める時間を描画遅延とします.LED点灯からディスプレイの映像が動き始めるまでは数十msしかないので,Nikon1 V1のスローモーション撮影機能を用いて1200fpsで撮影しておきます.撮影されたスローモーション映像をPCでコマ送りで確認することで,描画遅延の時間を測定します.

この手順で,フルスクリーン・枠なしウィンドウ(フルスクリーンウィンドウ)・ウィンドウの3種のウィンドウモードの描画遅延を測定します.


評価環境 Experimental Setup

評価環境の概要は以下のようになります.OSとHID Deviceが変更になりました.
  • PC
    • OS : Microsoft Windows 10 Home
    • CPU : Intel Core i7 2600 (HT Enable)
    • GPU : NVIDIA GeForce GTX670
    • Display : BenQ XL2410T (120Hz)
  • Camera : Nikon1 V1 with 1 NIKKOR 10mm F2.8
    • F : 2.8,SS : 1/1250s
  • HID Device : CY8CKIT-059 PSoC 5LP Prototyping Kit (CY8C5888LTI-LP097)
  • Overwatch Settings
    • Resolution : 1920x1080 120Hz
    • Render Scale : 50%
    • Graphic Settings : Low or OFF
    • V-Sync : OFF


評価結果 Experimental Results

まず,測定したデータを時系列にまとめたものを図1に示します.
図1 時系列の遅延データ

図1のように,ディスプレイのリフレッシュレートが低いため描画遅延のフレーム数がバラけています.
また,Fullscreen(青線)では測定回が奇数の場合と偶数の場合で1フレームほど数値が異なります.
(※なぜこういう傾向になったのかは不明です.データは一発取りなのでもう少し詳しく測定する必要がありそうです.)

図1は描画遅延のフレーム数なので,わかりやすいようにミリ秒に換算し,平均値を出します.
Nikon1 V1のスローモーション撮影は1200fpsなので描画遅延の時間は,
描画遅延時間[ms] = 描画遅延のフレーム数×(1/1200)×1000
となります.この描画遅延時間から平均値を出したものが図2になります.

図2 描画遅延の平均時間

また,奇数/偶数を考慮した場合の平均値は図3のようになります.

図3 奇数/偶数を考慮した描画遅延の平均時間
図2,3のように,フルスクリーンの時が最も描画遅延が少ないです.要するに,フルスクリーンのほうが敵が早く見える上に,マウスの動きと画面の動きのラグが少なくなるのでAimもしやすいということになります.


Aero 3フレーム遅延説@Windows10

いわゆるAeroが有効だと,この環境では2フレームの遅延の差があると言えます.
(奇数偶数を考慮しない場合は1フレームですが,おそらく考慮した方が正しいデータであると考えています.)
Windows 10はWindows 7のようにAeroを明示的に切ることができないので,コンペティティブなタイトルは基本的にフルスクリーンに設定するのが無難だと言えるでしょう.
Windows 7のようにAeroを切れるOSであれば,そこまで大きな遅延は発生しないのですが・・・(それでもフルスクリーンが最速です)

参考 : Win8.1で測定されたデータ http://www58.atwiki.jp/grassan/pages/17.html


Overwatchのゲームエンジンは低遅延なのか?

今回の測定にあたり,OSをWindows7 → Windows10へと変更したため,他のゲームエンジンとの描画遅延の優劣は比較できないと考えています.

ただ,Windows7の時のデータを参考に考えるとOverwatchのエンジンはSource Engineと比較して大きな差はなく,結構リッチなグラフィックである割に低遅延なエンジンであると言えます.


まとめ

まとめます.
  • この環境では,フルスクリーンが最良
  • Windows 10ではウィンドウモードでは2(?)フレーム遅延する
    • 他のタイトルでも調べる必要がある
  • Overwatchのゲームエンジンは低遅延な部類だと思われる
  • (コマ送りで動画を再生して確認するので,とてもめんどくさい)


Appendix

撮影した動画を掲載します.







2016/08/06

USB HIDマウスのデータパスの16bit化

前からPSoC Creatorの3-button Mouseのサンプルのソースコードを弄って色々(これとかこれ)やってましたが,このサンプルはデータパスが8bitなので1回のポーリングで-127~127の範囲の値しか送れませんでした.そこで,データパスを16bit化することにしました.
16bit化することにより,最近のゲーミングマウスと同レベルの値の範囲を使用することができるようになるので,色々と調査が捗るはずです.

しかし,USB HID Noobな私にとっては「どこを弄ればよいのかさっぱり・・・」という感じでネットの海を彷徨うこと数時間・・・
Zowie EC2 EVOのディスクリプタを参考にすることでなんとか解決しました.
参考 : Zowie mouse wheel scroll up/down not working
(このログを出したアナライザー欲しいんですけど1ライセンス$200なんですよね・・・とりあえずはUSBViewとMicrosoft Message Analyzerで誤魔化しています)

デバイスが応答しなくなる問題の対策

ディスクリプタを弄りながらデバイスを何度も接続していると,デバイスの反応がなくなることがありますが再起動すると治るようです.

HID ディスクリプタの設定

最終的なHID Descriptorの設定は以下のようになりました.
(PSoC Creatorの3-button Mouseのサンプルから変更した部分は青線で囲んだ部分だけです.)


ディスクリプタの簡単な解説

前半がボタン関係です.3-button Mouseなので,ボタンのUSAGE_PAGEが3つあり,USAGE_MINIMUMが1でUSAGE_MAXIMUMが3,REPORT_COUNTが1になります.
ボタンは0/1しか表現できないのでLOGICAL_MINIMUMが0,LOGICAL_MAXIMUMが1となり,REPORT_SIZEが1になります.
3ボタンマウスだと,ボタンの状態表現に3bitしか必要ないため,余った5bitをパディングします(中段).

後半がカーソル関係のディスクリプタで,USAGE_PAGEはGeneric Desktop Controls(0x01)になります.USAGEは0x20がX軸で0x21がY軸です.
データパスを16bit化するので,LOGICAL_MINIMUMを-(2^15-1) = -32767 (0x8001)にして,LOGICAL_MAXIMAMは2^15-1=32767(0x7FFF)になります.また,REPORT_SIZEを16にします.
ここで,REPORT_COUNTは変更の必要はなく,XとYの2軸なので2になります.
(ちなみに,データパスが8bitの場合はLOGICAL_MINIMUMが-127,LOGICAL_MAXIMUMが127,REPORT_SIZEが8になります.)

コード

ボタンの状態を1byte(3bit+5bitパディング),X軸で2byte,Y軸で2byteになるので,USBFS_LoadInEP()に渡す配列は5byteになります.
例 : uint8 mouseData[MOUSE_DATA_LEN] = {0u, 0u, 0u, 0u, 0u}
この場合だと,{ボタン,X軸下位8bit,X軸上位8bit,Y軸下位8bit,Y軸上位8bit}という風になります.

X軸の変位をdxとして場合はこんな感じで代入すれば良いと思います.(あまりオーバーフローとか考慮してないですが・・・)
mouseData[1] = (uint8)dx;
mouseData[2] = dx >> 8;


ポーリングごとにdxを1ずつ増やしたり減らしたりするようなコードを書くと,こんな感じの応答になりました.
図のように,8bitデータパスの限界値である±127を超えてデータを送ることができています.

※超絶初心者なので,この記事の記述は間違っている可能性があります.

2016/04/22

マウスパッド表面評価のためのセンサー可視化デバイス

はじめに

ADNS-3090とADNS-9800というゲーミングマウスのセンサが、マウスパッドをどのように「見て」いるのか、というセンサの視界を人にも見える化するシステムを作りました。こういったシステムがあると、ソール厚に関する知識を深めたり、特定のマウスパッドへの相性問題を解決したり、モヤモヤした画像を見て悦に入ったりと色々なことが出来ます。
要するに、マウスとマウスパッドの間に問題が起きた時にデバッグしたり、更にマウスの性能を引き出したりする時に手助けとなる道具です。ただ闇雲にデバイスを買って試すのではなく、色々な道具を作って科学的/工学的な観点でデバイスを評価するのも私は良いと思うのです。

前の記事との差分としては、現役で活躍しているゲーミンググレードのレーザーセンサとLEDセンサの双方で「見る」ことが出来るようになったのは意義があるでしょう。記事のような色々なマウスパッドの表面画像についてはそのうちまとめます。

ハードウェア

まずはセンサとMCUについてハードウェアの面で説明します。

ADNS-9800

ADNS-9800は色々と訳あってセンサモジュールを購入しました。
ADNS-9800のセンサモジュール with ジャンパワイヤ
代理店を介さずにゲーミンググレードのセンサを購入できる場所は少ないです。結構探したのですがこのサイトしかありませんでした。送料が$60という恐ろしい数字だったので非常に痛い出費ですが、個人に売ってくれるだけありがたいです。
送料分を取り返すためにモジュールに加えてバニラなセンサとレンズのセットを数組購入しましたが、使用予定は・・・In progressということで。

センサモジュールはピンアサインがはっきりしているので説明通りに繋ぐだけで大丈夫です。
このモジュールは探せばArduinoのサンプルもあるので、Arduino持っていれば誰でも動かせると思います。

ADNS-3090

ADNS-3090はELECOM M-XG3Gのセンサを使用しました。
3000円程度で完動するセンサモジュールが手に入るのは素晴らしい・・・(とか考えてるのは日本で私くらいしか居ないのかもしれません。)

購入した時はマウス自体のMCUがセンサのマスタになっているので、データパスを切る必要があります。
ADNS-3090のSROMがなかなか見つからないのでデータパスを切る前にSROMを事前に吸い出す予定でしたが、「ADNS-3090は部品としては手に入らないセンサなのでSROMを持っておく必要もないのかな」と考えてデータパスをぶった斬りました。RIP。
データパス切断の図。中央の傷の部分でレジストごと配線を切っています。
切る必要があるのは、NCS、MISO、SCLK、MOSI、RESET、NPDです。
最近のマウスはほとんどが両面基板なのでビアを追うのが面倒ですが、センサ付近から追っていって切りやすい部分で切ればいいと思います。

外観はゴミを寄せ集めたみたいな手作り感溢れるアットホームな感じです。自分のMCUからの配線はセンサの足に直付けしています。こうすると基板の上側から配線を引き出せるので非常に便利です。
システム外観。

MCU

センサを制御してもらうMCUはいつものCY8CKIT-042 PSoC 4 Pioneer Kitです(上写真右の赤いボード)。
プログラマ不要の開発ボードで、秋月で税込み3000円で買えます。Arduinoみたいなピンアサインで、しかもリセットしてもCOMポートの接続が切れないのでとても便利です。
センサから生やしたジャンパワイヤをしかるべき所に繋ぐだけで準備完了。


ソフトウェアの実装

あんまり面白いことはしていないのですが、概要は下のようになります。
  1. MCUがセンサにFrameCaptureをリクエスト
  2. センサが画素データを返す
  3. MCUが画素データのバイナリをUART→USB経由でPCに転送
  4. ホストのアプリがバイナリを受け取り、グラフとして描画
  5. 1~4を繰り返す

ホスト(PC)のプログラム

ホスト側はネイティブアプリを書くのも面倒なのでPythonのserialモジュールと、matplotlibモジュールでお茶を濁していくスタイル。matplotlibは動画も撮れたり、画像の補完方法も豊富なので結構便利ですね。

MCUのファームウェア

MCU側はフンハフンハ言いながら実装するとできます。いくつかセンサを触った経験から言うと、とりあえずProductIDを取得出来るようにする→大体の事は出来るようになる。という感じなのでデータシートをよく読みながら実装すればよいでしょう。

注意する点としては、ADNS系のセンサはNCSの扱いが特殊なので、そこに工夫が居る点です。
MCUからのレジスタアドレスとして1バイトの送信が終わってNCSをHIGHにしていまうと、うまく動きません。なので、NCUはMCUのSPIの処理とは別に制御する必要があります。
PSoCの場合は、SPIのNCS(SS)はSPIコンポーネントには接続せず、別にDigital Output Pinを用意すれば良いです。
基本となるRead/Write Operationsコードはこんな感じになります。ここでは、NCSとしてSSというピンを用意して、適宜HIGHにしたりLOWにしたりしています。
--------
void Write_Operation(uint8 address , uint8 value )
{
    address = address | 0b10000000; //MSBを1にしてWriteだと伝える
    SPIM_ClearRxBuffer(); //バッファクリア
    SPIM_ClearTxBuffer();
    SPIM_ClearFIFO();
    
    SS_Write(0); //NCSをLOWに。送信開始
    CyDelayUs(1); //ディレイが必要。時間はセンサによる。
    
    SPIM_WriteTxData(address); //書き込み先のレジスタアドレス送信
    
    SPIM_WriteTxData(value); //書き込み先のレジスタに書き込む値を送信
    while(!(SPIM_ReadTxStatus() & SPIM_STS_SPI_DONE)){}; //終わるまで待つ
    CyDelayUs(1);
    SS_Write(1); //NCSをHIGHに。送信終了
    SPIM_ReadRxData(); //SPIのRxに入ったゴミデータを捨てる
    SPIM_ReadRxData(); //SPIのRxに入ったゴミデータを捨てる
    CyDelayUs(120u); //ディレイが必要。時間はセンサによる
}

uint8 Read_Operation(uint8 address)
{
    address = address | 0b00000000; //MSBを0にしてReadだと伝える
    SPIM_ClearRxBuffer(); //バッファクリア
    SPIM_ClearTxBuffer();
    SPIM_ClearFIFO();

    SS_Write(0); //NCSをLOWに。送信開始
    CyDelayUs(1); //ディレイが必要。時間はセンサによる

    SPIM_WriteTxData(address); //取得先のレジスタアドレス送信
    while(!(SPIM_ReadTxStatus() & SPIM_STS_TX_FIFO_EMPTY)){}; //送信が終わるまで待つ
    CyDelayUs(100); //ディレイが必要。時間はセンサによる

    SPIM_WriteTxData(0x00); //0x00を送る間にデータが帰ってくる
    while(!(SPIM_ReadTxStatus() & SPIM_STS_TX_FIFO_EMPTY)){}; //送信が終わるまで待つ
    while(!(SPIM_ReadRxStatus() & SPIM_STS_RX_FIFO_NOT_EMPTY )){}; //RxFIFOに1個目のデータが来るまで待つ
    SPIM_ReadRxData(); //一個目はゴミなので捨てる
    while(!(SPIM_ReadRxStatus() & SPIM_STS_RX_FIFO_NOT_EMPTY )){}; //RxFIFOに2個目のデータが来るまで待つ
    SS_Write(1); //NCSをHIGHに。送信終了
    CyDelayUs(120u); //ディレイが必要。時間はセンサによる
    return  SPIM_ReadRxData(); //レジスタから取得したデータを呼び出し元に返す
}
--------
弱いコードですが大目に見て下さい。
ちなみにFrameCaptureを動かすだけならSROMは必要ないので色々なセンサで試すことが出来るでしょう。


動かしてみた

画像や動画はCOUGAR Control Mouse Padの滑走面を撮影したものです。

ADNS-3090の画像

ADNS-3090は画素が0~63の値をとるようなので、ADNS-9800(0~127)の値から2倍になるようにしています。
ADNS-3090
ADNS-5090(下図)を高解像度化したような印象です。センサ素子がADNS-5090は19x19ですが、ADNS-3090は30x30になったためですね。視野の範囲などの考察はまたいずれ。
ADNS-5090


ADNS-3090の動画

動画にするとこんな感じです。適当に動かしています。後半でマウス全体を一度持ち上げていますが、3090ではシャッター値がMAXになると白飛びに近い状態になるようです。



ADNS-9800の画像

ADNS-9800はこんな感じに映ります。
ADNS-9800
見た印象だと全然同じマウスパッドに見えません。これはLED式センサと比較すると、見えている範囲がものすごく小さいためです。LED式センサでは「山」が2個くらい画面内に映るのですが、「山」ひとつでフレームアウトするような感じです。詳細な比較はまたいずれ。

また、ADNS-5090やADNS-3090のようなLEDセンサと比較すると、「のっぺり」とした印象になります。これは、レーザの射角が滑走面に対して深いためです。LED式センサではほぼ真横にLEDが付いていて、それをレンズで屈折させて滑走面を照射しており射角が浅いのですが、レーザ式の場合はセンサダイの真横にレーザ素子があり、そこから下図のようにレンズで屈折させて射角が深くなっています。射角が深いため、「影」となる部分が少なく、LED式と比較してコントラスト比が小さくなると考えれます。
Pixart ADNS-6190-002 データシートより
他にも「レーザースペックルがどうのだからDPIが・・・」みたいな考察もあるので、もう少し裏を取ってから別記事で上げたいと思います。

2016/01/27

浅草ギ研 感圧センサー 「AS-FS」レビュー

はじめに

感圧センサのAS-FSに関する情報がWEBにあまりないので簡単に紹介します.
ちなみにゲーミングデバイスは出てきませんのでその筋の方にはあまり意味のない情報です.
(低レイヤ系のゲーミングデバイス勢の皆さんは,おそらく私と同じことを考えると思うので必読です.)

力センサ事情

気圧センサなどは結構色々選べるのですが,機械的な圧力を測れるセンサは種類が少なく,個人で気軽の買える圧力センサはAS-FS以外だとInterlink ElectronicsのFSRシリーズくらいという感じで結構珍しいです.
力の計測の王道としてはロードセルを使えばよいのですが値段やサイズが・・・というのがあって個人で手を出すのは結構際どいラインだと思います.
ちなみに,まともな力センサを安く手に入れる方法として「電子秤を分解してセンサ部を使う」という手があります.

AS-FS概要

詳細 : 浅草ギ研 感圧センサーAS-FSの紹介
センサを買うとデータシート的な1枚の紙が付いてきますが,内容は公式サイトの紹介ページとほぼ同じでした.
抵抗値が変化するFSR系と違い,電圧出力なので出力ピンをADCするだけで力が測れてお手軽です.それに小型,安価なので導入もしやすいと思います.


センサ構成

分解画像

大きく分けて基盤とゴム部の2つから構成されています.2つはネジとナットで組んでありました.
白いゴムの感触はモノ消しゴムのような感じ.

原理的は渦巻きのパターンの部分に黒い導電性のゴムが当たって,当たってる具合で抵抗値が変化するような感じでしょう.


評価

簡単に使ってみました.(かなり適当なので参考程度にお願いします)

評価環境

MCU :CY8CKIT-050 PSoC® 5LP Development Kit

ADCにはΔΣ型ADCを使いました.センサの出力はADC_INピンに直入れします.
コンフィグ

評価

ノイズ的には,サーミスタと同じようなモノなので回路の頑張り次第です.ちなみに適当に繋いでも8bitで揺れがないくらいでした.
最小感度はゴムを固定しているネジの閉め具合で決まります.ゴムが基盤から浮くくらいネジを緩めると,かなり感度が上がりますが0N付近の出力の安定性が大きく下がります.まともに測れるレンジは100g以上だと思います.それ以下は検出自体は出来ますがかなり不安定な感じです.
最大感度はデータシート通りの2kgくらいでしょうか.思い切り握っても値は上下しているような気もするのでもう少し高いかもしれません.

ヒステリシス

これがかなりの曲者です.無負荷→押す→無負荷という手順を行うと,前後の無負荷の出力が異なります.例を挙げると,950→1200→980,みたいな出力になります.
センサの原理を考えれば当然ですが,絶対値の測定などは結構厳しいです.

また,ネジの閉め具合で無負荷時の値が大きく変化します.そういう意味でも再現性がかなり低いです.原理から言うと気温とか湿度とかそういう影響も受けそうですね.

瞬間的な圧力の相対値とか,圧力の増加/減少は測れるのでそういう所には使えると思います.
長期的に運用しながら絶対値を測るような使い方には向いていません.ゴムの固定方法を工夫した上でキャリブレーションを丁寧にすればなんとかなるかも?,みたいな感じだと思います.


まとめ


  • 導入は簡単
    • 出力ピンをADCするだけ
  • ヒステリシスが大きい
    • 0N→押す→0N のような操作をした時に前後の0Nで値が異なる
  • 絶対値の測定には向かない
    • ゴムの状態によって出力値が変わる+ヒステリシス
結論から言うと,私が使いたい用途には向きませんでした.
このセンサはあくまで感圧センサで,圧力センサではないです.
「インテリジェントな検出スイッチ」みたいな使い方が向いていると思います.

2015/05/31

Logitech G400 のデータパスを解析してみる

--------------------------------------------
2015/05/31 初出
2015/06/04 rafa様の関連記事を追記
--------------------------------------------
rafa様の記事(-rafalog: 鼠とオシロ)に便乗する形でLogitechの名機であるG400のデータパスをマイコンを使って覗いてみました.

ハードウェア (Hardware)

ハードはこんな感じに,ポリウレタン線でMISO,MOSI,SCLK,SSをセンサのピンから引き出します.

基盤が載っている筺体が違うことに気がついた方は相当の鼠ソムリエですが,コイツです.筺体のデザインに関しては,今まで触った100種以上(店頭で触ったものも含む)のマウスの中で最も良いです.
「ワクワクしながら家に持ち帰ったら,センサー性能と実装に絶望した」という悲しい過去があります.事務用マウスも一応ウォッチしていると良いことがあったりなかったりですね.

極めて良い筺体形状なので,一年ほど前にG400の基盤を無理やり載せました.その作業内容や顛末とかも記事にすると面白そうですが,「ひたすら筺体と基盤を弄って物理的・電気的整合性をとるだけ」という単純作業なので割愛します.基盤にメモが書いてあるのはその時の名残です.

マイコンはいつもの CY8CKIT-042 PSoC® 4 Pioneer Kitを使用します.このキットは色々な所で売っています.(秋月)


ソフトウェアの実装(Software implementation)

IDEは,PSoC Creator  3.0 SP2 (3.0.0.3140)を使用します.コードは全世界に公開できるクオリティに達していないので,「見たい」という奇特な方はご連絡を・・・ということで.
データのキャプチャにはSPI Slave コンポーネントを使用します.このコンポーネントはMaster(MCU)にぶら下がってSlaveとして振る舞います.MCUと本当のSlaveであるセンサ間でのみ通信が行われるので,全バイトデータをキャプチャすればMCUとセンサのやりとりを(理論上は)キャプチャできます.
図のように,2入力(マウス側のMOSI,MISO)をORゲートのコンポーネントで論理和にし,SPI SlaveのMOSIに入力します.SCLKとSSはマウスから引っ張ってきたものをそのまま使用します.このコンポーネントからマウスへのデータ転送は行わない(というよりMasterはG400の基板上のMCUなのでデータを送ると何が起きるか分からない)ので,NC(No Connect)とします.

SPI Slaveの設定はこんな感じにします.

ADNSシリーズはCPHA=1,CPCL=1なのでそのように設定します.ビットレートは1.5Mbpsとします.
もし違うマウスで調べる場合は,対象マウスのMCUからでているSCLKのビットレート調べて,それと同じ値にする必要があります.他の項目はDefaultで問題ありません.

プログラム

プログラムは,MCUかセンサからデータが来たら保存するという事を2000byte分行うだけです.
データレートも見たいので,2000byte分の取得の開始時間と終了時間もTimerを使用してマイクロ秒単位で記録しておきます.
2000/取得にかかった時間 でデータレートを算出できます.


データ (Data Result)

データは本来は2000バイト取得していますが似たようなデータは割愛しています.
もし,特定の条件でのデータが見たいという奇特な方がいらっしゃればコメントして下さい.

データレート(Data Rate)

以下がデータレートの測定結果です.
Stream Read Info ->
Size    :       2000
Start   :       5814 us
End     :       17684 us
Time    :       11870 us ( 12 ms )

Data Rate : 168 Byte/ms

このように,約12msの間に2000Byteをやりとりしていることが分かります.つまり,1msあたり168Byte程度になります.MotionBurstはMCUがセンサに1Byte分の命令を送り,7Byte分のデータを受け取るので,1通信に8Byteのやりとりが発生します.(詳しくはデータシートのMotion Readの項を参照)
これらを勘案すると,MCUはセンサーへ1msの間に複数回アクセスしている可能性が高いと言えます.168/8=21なので,大体20回変位データを取得してるんじゃないの?と考えられます.とりあえず生データを見てみましょう.

2015/06/04追記
rafa様がオシロスコープでRazer Abyssusの解析をしてくださいました.
-rafalog: 初代AbyssusのSPI通信解析
これを見ると,AbyssusはMotion→Delta_X→Delta_Yレジスタの転送をしたところで,NCS(SS)をプルアップして強制的に転送を止めています.確かに,これだと変位のスループットが稼げます.記事によると,Abyssusは1msで6回程度アクセスしているようです.
データシートには「転送後にNCSをHIGHにする必要がある」,とは書いてありましたが「転送中にNCSをHIGHにすれば転送を中断できる」ことには気づきませんでした.ゲーミングデバイスは奥が深いですね.

生データ(Raw Data)

以下から生データになります.前半はマウスが静止している時のもので,後半はマウスを動かしている時のものです.静止時はMOSIのみとMISOのみのものも取りました.

移動中に0x80になっている部分は,Motionレジスタなので7bitが1になっているはずなので,本当は0xf0になります.つまり,データのキャプチャが1Clock分遅れており,データが微妙にずれているという結果になります.もう少しちゃんと書く必要がありますね.

MOSI&MISO (No Motion)

55 50 00 00 00 bd 00 50 00 00 00 0a 01 1f 55 50 00 00 00 50 00 00 00 3d c3 0a 01 1f
55 50 00 00 00 bd 00 50 00 00 00 0a 01 1f 55 50 00 00 00 50 00 00 00 3d c3 0a 01 1f
55 50 00 00 00 bd 00 50 00 00 00 0a 01 1f 55 50 00 00 00 50 00 00 00 3d c3 0a 01 1f
55 50 00 00 00 bd 00 50 00 00 00 0a 01 1f 55 50 00 00 00 50 00 00 00 3d c3 0a 01 1f


MOSI (No Motion)

55 00 00 00 00 00 00 00 00 00 00 00 01 00 55 00 00 00 00 00 00 00 00 00 c3 00 01 00
55 00 00 00 00 00 00 00 00 00 00 00 01 00 55 00 00 00 00 00 00 00 00 00 c3 00 01 00
55 00 00 00 00 00 00 00 00 00 00 00 01 00 55 00 00 00 00 00 00 00 00 00 c3 00 01 00
55 00 00 00 00 00 00 00 00 00 00 00 01 00 55 00 00 00 00 00 00 00 00 00 c3 00 01 00


MISO+Data Offset (No Motion)

※MOSIのデータで1列目のバイトを決めているので,MISOのみのデータは行がずれています.
00 50 00 00 00 3d 00 0a 00 1f 00 50 00 00 00 bd 00 50 00 00 00 0a 00 1f 00 50 00 00
00 50 00 00 00 3d 00 0a 00 1f 00 50 00 00 00 bd 00 50 00 00 00 0a 00 1f 00 50 00 00
00 50 00 00 00 3d 00 0a 00 1f 00 50 00 00 00 bd 00 50 00 00 00 0a 00 1f 00 50 00 00
00 50 00 00 00 3d 00 0a 00 1f 00 50 00 00 00 bd 00 50 00 00 00 0a 00 1f 00 50 00 00


Low Speed (MOSI&MISO)

-----Stream-----
55 50 80 00 fa bd 00 50 80 ff fd 0a 01 1f 55 50 80 00 fd 50 80 00 fb 3d c3 0a 01 1f
55 50 80 00 fc bd 00 50 80 00 fb 0a 01 1f 55 50 80 ff fd 50 80 00 fa 3d cb 0a 01 1f
55 50 80 00 fe bd 00 50 80 00 fa 0a 01 1f 55 50 80 00 fb 50 80 00 fb 3d c3 0a 01 1f
55 50 80 00 fe bd 00 50 80 00 f9 0a 01 1f 55 50 80 00 fc 50 80 00 fb 3d c3 0a 01 1f
55 50 80 00 fd bd 00 50 80 00 fd 0a 01 1f 55 50 80 00 fb 50 80 02 fa 3d c3 0a 01 1f
55 50 80 01 fd bd 00 50 80 00 fc 0a 01 1f 55 50 80 01 fb 50 80 01 fc 3d c3 0a 01 1f
55 50 80 01 f9 bd 00 50 80 01 fc 0a 01 1f 55 50 80 00 fb 50 80 00 fc 3d cb 0a 01 1f
55 50 80 02 fa bd 00 50 80 00 fb 0a 01 1f 55 50 80 02 fc 50 80 01 fb 3d c7 0a 01 1f
55 50 80 02 fb bd 00 50 80 00 fb 0a 01 1f 55 50 80 02 fb 50 80 01 fb 3d c3 0a 01 1f
55 50 80 00 fb bd 00 50 80 03 fa 0a 01 1f 55 50 80 01 fc 50 80 01 fb 3d c3 0a 01 1f
55 50 80 03 fa bd 00 50 80 01 fc 0a 01 1f 55 50 80 01 fb 50 80 00 fc 3d c7 0a 01 1f
55 50 80 03 fa bd 00 50 80 01 fa 0a 01 1f 55 50 80 02 fa 50 80 02 fd 3d cb 0a 01 1f
55 50 80 01 fa bd 00 50 80 03 fb 0a 01 1f 55 50 80 01 fa 50 80 03 fa 3d c3 0a 01 1f
...
-----Stream END-----


Middle Speed (MOSI&MISO)

-----Stream-----
55 50 80 06 1c bd 00 50 80 06 1c 0a 01 1f 55 50 80 07 24 50 80 04 1e 3d c7 0a 01 1f
55 50 80 05 1b bd 00 50 80 04 1d 0a 01 1f 55 50 80 04 1d 50 80 05 26 3d cf 0a 01 1f
55 50 80 02 1e bd 00 50 80 00 1e 0a 01 1f 55 50 80 fe 1c 50 80 04 26 3d c7 0a 01 1f
55 50 80 02 1d bd 00 50 80 00 1f 0a 01 1f 55 50 80 00 1e 50 80 00 1d 3d c7 0a 01 1f
55 50 80 00 28 bd 00 50 80 00 1d 0a 01 1f 55 50 80 ff 1e 50 80 00 1d 3d c7 0a 01 1f
55 50 80 00 29 bd 00 50 80 01 1d 0a 01 1f 55 50 80 fe 1c 50 80 00 1e 3d c7 0a 01 1f
55 50 80 fc 28 bd 00 50 80 01 1f 0a 01 1f 55 50 80 ff 1c 50 80 ff 1c 3d cf 0a 01 1f
55 50 80 fc 1f bd 00 50 80 01 1d 0a 01 1f 55 50 80 fe 1c 50 80 fb 1e 3d c7 0a 01 1f
55 50 80 fc 1e bd 00 50 80 fc 1d 0a 01 1f 55 50 80 fa 27 50 80 fc 1e 3d c7 0a 01 1f
55 50 80 fb 1c bd 00 50 80 fb 1e 0a 01 1f 55 50 80 f8 26 50 80 fa 1d 3d c7 0a 01 1f
55 50 80 fa 1e bd 00 50 80 fa 1d 0a 01 1f 55 50 80 f9 1a 50 80 f7 27 3d c7 0a 01 1f
55 50 80 f9 1c bd 00 50 80 f7 1c 0a 01 1f 55 50 80 f9 1c 50 80 f8 1c 3d cf 0a 01 1f
55 50 80 f4 23 bd 00 50 80 f8 1c 0a 01 1f 55 50 80 f9 1a 50 80 f7 1b 3d c7 0a 01 1f
...
-----Stream END-----


まとめ 

ここからわかったことをまとめます.
  • G400はMotionBurstを使用している
  • 1msの間にセンサから複数回(おそらく10回以上)変位を読んでいる
複数回アクセスは予想通りですね.(G300でもやっていました)
AnkerのマウスもMotionBurstを使っていましたし,ゲーミングマウスでのデータ取得はMotionBurstが基本なのかもしれません.

キャプチャを正確にしてデータが取れたら,さらに分かることが多そうです.なにか分かったら,また記事にしたいと思います.

2014/11/25

マウスの光学センサが見ている世界を見てみる


1 概要

今回作成したのは,AVAGO製光学センサが有する機能の1つであるPixel Grabberの可視化システムです.
--------------------------------------------------------------------------------------
2014/11/25 初出
2015/01/25 COUGAR CONTROL Mouse Pad 追加
2015/05/20 Artisan 紫電改 MID 追加
2015/11/23 HORI EDGE 401 追加,レイアウトを調整
2016/01/24 DHARMAPOINT DRTCPWシリーズ 7種 追加
--------------------------------------------------------------------------------------

2 このシステムの意義

通常のマウスのセンサシステムでは単一光源(通常はLED)から光源用レンズを通して単色光が照射され,それをレンズを通してセンサは受け取っています.これは顕微鏡や虫眼鏡等の通常の光学機器での表面の観察と大きく異るので,マウスパッドの滑走面の状態がどのようにセンサ性能に影響するかについて評価する時にはあまり意味がありません.

本システムを用いることで,「マウスパッドの滑走面の状態がセンサの視点ではどのように見えているのか?」ということを直感的に理解することが出来ます.これによってセンサの性能を引き出すようなセッティングを模索する補助や,悪いセッティングであることを認識し校正する手段としての使用が期待できます.

3 マウスに搭載されている光学センサについて

マウスに搭載されているセンサを大まかに例えるとモノクロのデジタルカメラのようなものです.このカメラは解像度が19x19や30x30で,19x19の場合だとTwitterのアイコンにもならないくらいです.このように,普通のデジタルカメラと比較すると圧倒的に低解像度です.
今回使用するADNS-5090では画素数19x19のピクセルアレイを有するセンサです.

マウスが滑走面に覆いかぶさるように置いてあるので,何も照射しないままだと滑走面が暗くて何も見えません.なので,搭載されているLED(もしくはレーザ)をカメラのフラッシュ代わりにして滑走面を照らします.そして前の画像と現在の画像を比較して移動距離を算出します.移動量の算出は毎秒数千~数万枚の画像を撮影して行われます.そしてMCUと呼ばれる制御チップが適宜動いた距離を転送するように要請してくるのでそれに応じて移動距離を転送します.

4 Pixel Grabber

Pixel GrabberはAVAGOの光学センサに搭載されている機能の1つで,センサの保有するピクセルアレイの1ピクセル毎の値を読み出すことが出来ます.これによってセンサが現在どのような画像を見ているかを知ることが出来ます.

5 使用ツール

PC側で主に使用したものは以下になります.
• Python3.4
    • PySerial
    • matplotlib

MCU側では,いつものように以下の物を使用しました.
• PSOC Creator3.0 SP1
• PSoC4 4 Pioneer Kit
• 光学センサ : ADNS-5090


6 動作

システムは大まかに分けてMCU側とPC側に分けられます.

MCU側では
  1. センサへPixel Grabberの指令を出す
  2. レジスタから1pixel毎に361 ( =19x19 ) 回読み出す
  3. 読み出した値をUART通信でPCへ転送する
というステップを繰り返します.

対して,PC側では
  1. UART通信で転送されてきたデータを読み出す
  2. データを元に描画する(必要であれば動画・画像の保存を行う)
というステップを繰り返します.この時の"2"のステップ時に表示を拡大するのですが,今回は補間フィルタとしてガウシアンフィルタを使用しました.

7 結果 : ピクセルアレイの様子

各マウスパッド上で撮影したピクセルアレイの様子の画像を以下に示します.
画像は原寸から10~20%程度へ縮小表示した方が見やすいです.

Steelseries QcK


Artisan 飛燕(Hien) VE MID


Artisan 紫電改(Shiden-Kai) MID


G-Pad 小間久商店(Koma-Q)



ROCCAT Tait (Taito)



Power Support AirPad ProIII



COUGAR CONTROL Mouse Pad ( 3D Texture Surface )



HORI EDGE 401



DHARMAPOINT DRTCPW30C



DHARMAPOINT DRTCPW30S



DHARMAPOINT DRTCPW35CS



DHARMAPOINT DRTCPW35GR



DHARMAPOINT DRTCPW35HB



DHARMAPOINT DRTCPW35RS



DHARMAPOINT DRTCPW35SD


Appendix. 滑走時の動画

Steelseries QcKの表面の様子を撮影した動画は以下のようになります.埋め込みサイズが小さいですが,小さい方がわかりやすいと思うのでこのままどうぞ.



動画を見ていただければ分かる通り,フレームレートは低めです.PC側ではなくマイコン側でデータの取得やら転送でかなり時間がかかっています.
前は速度を出すために色々やっていたのですが,ガリガリに最適化して書いていたらちょっと転けてしまって開発中断したので今回は手堅く行きました.


1-Day Projectにするつもりが丸々2日かかってしまいました.
最後にやったのが6月でソースコードや環境が散逸してしまい,それの回収と復旧の方にかなりの時間がかかった気がします XD

2014/11/16

USB HIDデバイスのクリックの最速応答を考える

rafa様が公開されている超有益かつ膨大なデータである下記事ですが,つい最近最速のマウスが更新されました.

rafalog: ゲーミングマウスのクリック応答特性を比較する The measurement of gaming mouse button lag
http://utmalesoldiers.blogspot.jp/2013/02/114.html

記事によると,TL8のG300と比較して1.2ms高速というのが最速値です.

「じゃあ,ただのデバイスオタクがファームウェアを書いたらどうなるの?というか限界まで簡略化すればどこまで速くなるの?」という疑問があるわけでして,レッツトライでございます.


ファームウェア

ソースはこんな感じ.
-------------------------------------------------------
ここまで初期化(USB,Clockのスタート等)
while(1)
    {

        //USBのACK待ち
        while(!USBFS_1_GetEPAckState(MOUSE_ENDPOINT));


        //Pin_1を読んで,Lowなら右クリックが押されたとして記録
        mouseData[0] = (!Pin_1_Read())*2;


        //USBコンポーネントに右クリックの状態のデータを送る
        USBFS_1_LoadInEP(1u, mouseData, MOUSE_DATA_LEN);
    }

-------------------------------------------------------
3行,というかACK待ちとかUSBのコンポーネントへデータ転送する処理以外は一行というファームウェアです.アセンブラで考えるとざっと数~十数クロックでしょうか.APIの処理時間は良くわかりませんが:D
これならCPUは33MHzで動いているので1μs以下で終わるはずです.

これでスイッチのON/OFFを読んでUSBで転送するだけのマウスの出来上がり.


測定方法,スイッチングについて

基本的な測定方法はrafa様の記事と同様ですので割愛.都合でマウスはG300rですがリネーム品なので変わらないはず.

しかし,私の書いたファームウェアの方はチャタリング処理を入れていないのでスイッチングはPSoC5LPで電子的にやってもらいます.

Pin_1が入力,つまり右ボタンです.G300の方を左ボタンとします.
Pin_2はスイッチです.1秒間に一度ONになります.(構成の都合で1024Hzを1024で割っています.)
このクロックは初期化時にClock_1_Start();を呼べば後はMCUのCPUを介さず勝手に動くので処理時間に影響はありません.


測定結果

生データです.良きに計らって下さい.
G300r vs LogicalGaming Advanced Technological Demonstrator Mouse
https://docs.google.com/spreadsheets/d/14YjSU0z3lwasOa2duRpI_JlFT0zq0COzGRFpRNL1nhQ/edit?usp=sharing

平均はG300rと比較して,0.76ms高速という結果になりました.

データを見ると0.1~0.3msのものと1.0~1.2msのものが多いですね.これはポーリングのタイミングにたまたまあぶれた時のばらつきだと考えられます.
ここで1ms以上差がある場合に関してのみデータを拾って平均を取ると,1.09msとなります.
これはIkariと同じくらいの値です.ここから考えると,TL8とIkariはおそらく割り込みを使っていて,スイッチが押された瞬間に最優先でボタンが押された旨を転送するルーチンを持っていそうです.
ここらへんの機種は,かなり気合が入っていると思います.



まとめ

測定結果から考えると以下のことが分かります.

・上位陣のIkariやTL8はおそらく割り込みを使って最優先で処理している
・G300から-1.1ms程度がUSBの仕様上の最速で,IkariとTL8より劇的に速い機種は存在しないはず

上位の機種はチャタリング対策は転送した後にやっているんだと思います.
おそらく,「押されたらまず転送,その後の十数msはスイッチの状態に関わらず押したままにする」という感じでしょう.確かに毎秒100連射出来る人なんていませんしこれでも良いです.
というか私も最近こういうコード書きました.

2014/10/19

ゲーム毎の描画遅延を測定してみる

---------------------------------------------------------------------------------
2015/05/20 : Baselineを追加 (当該記事参照)
2014/10/20 : QUAKE LIVEを追加
2014/10/19 : 初出
---------------------------------------------------------------------------------

                「このゲーム、視点移動がモッサリしてね?」

こんな感想を抱く事ありませんか?
良く「ヌルヌル」しているというポジティブな表現が用いられますが、私的にはせめて視点移動は「サクサク」している方が良いのです。
特にシューターだと、視点移動の描画遅延が少ない方が競技性的にも、ユーザビリティのためにも良いことだと思います。

本記事の目的は、体感では評価しにくいミリ秒単位の描画遅延を定量的に測定して公開することで、ゲーミングにおける描画遅延低減への取り組みを促進する事を意図しています。

このトピックは2年程前からやりたかったのですが、ひょんな事からUSB Mouseのcountを自由に制御出来る環境が整ったので実施。

測定方法

・撮影機材 : Nikon 1 V1 (レンズ : 1 NIKKOR 10mm f/2.8)
・MCU : CY8CKIT-050 PSoC® 5LP Development Kit

PSoC 5LP上にフルスピードUSBのHIDデバイスを作成し、3-button Mouseと設定。
今回はX軸のみに左右30 Countsを転送します。
また、MCUから0位外のカウントを送る際にLEDを点灯するようにプログラムしています。LEDの点灯からデータ転送間の遅延はμsオーダになっているはずなので無視できる範囲だと思います。


流れはこんな感じ。
・右に30countを128回(128ms)
・128回(128ms)停止
・左に30countを128回(128ms)
・128回(128ms)停止
これを繰り返して、LEDと画面の様子を撮影します。

Nikon 1 V1 のハイスピード撮影を使用して、ゲーム中の視点移動の様子を1200fpsでの撮影を行います。
そして、撮影データを1フレーム毎に表示し、LED点灯から描画の開始までのフレーム数を数え10回の平均を取り遅延時間を算出します。


最後に動画を載せるので雰囲気を掴んでいただければと思います。

結果

 結果は以下の通り。



Warsowがかなり優秀ですね。1.5系はかなり綺麗な描画ですので、「(体感は出来ないにしても)結構遅延がありそうだな」と予想していたのですが。

 BF4に関しては予想通り。自分が初めてBFBC2をプレイした時「何だこの描画遅延!?」と動揺したのですが、Battlefieldシリーズは描画遅延が多めな印象でした。特に3以降は輪にかけて遅延しているような。BF3とBC2も計測すべきですね。

もっと色々なタイトルで測定したいのですが、とりあえずプレイしている(していた)タイトルだけで計測しました。CoD:Gはかなり描画遅延があるようなので気になりますがゲームを持っていないのでフリーウィークエンド待ちだったり。

追記(2014/10/20) : 似たような事をしている方が居らっしゃいました。
rafa様、情報ありがとうございます。
ESR - Input lag tests QL/CSGO/Q3A - Hardware Forum
http://www.esreality.com/post/2640619/input-lag-tests-ql-csgo/

こちらとデータが違うのはシステムのコンフィギュレーションが原因なのか測定方法が違うことに依るのかは不明です。こちらとしては、最低でも±2msくらいの精度は出せる計測システムだと自負していますが :D

色々なマルチプレイヤー対応タイトルを計測して一覧でグラフを出せればよいのですが。
ゲームを買うお金がありません。gg.

おまけ

撮影した動画は以下。

2014/09/24

PSoCまつり2014

おそらくデバイスが絡まない最後の電子工作系エントリになるでしょう。

先日告知したPSoCまつり2014(詳細)に参加&登壇してきました。
スイッチサイエンスと言う電子工作界隈では有名な通販サイトの本社の会議室で行われましたが、例によって写真を取るのを忘れたので画像はありません。

プレゼンテーションで使用したスライドはこちら。
デモ機はこんな感じ。
プレゼンターとしては、知らない人の前で長時間話すというのは今後のためにも良い経験になったと思います。内容的にはPSoC特有の機能などは使用せず、基本機能の紹介+力技な感じなのでちょっとアレでしたが。

参加者・プレゼンターの方々が非常にレベルが高いのでかなり勉強になりました。
今までIDで基本部品を配置してAPIで読み出すだけで済ましてきましたが、複雑な部品配置・配線をしてよりPSoCのポテンシャルを引き出す、いわゆる”PSoCらしい”方法に関してかなり知識が深まりました。

日本サイプレスの協賛品として、CY8CKIT-050 PSoC® 5LP Development Kit(なんと99USDもします!)を頂いたので色々捗りそうです。

2014/06/24

マウスデバッガ

センサデバッガという記事は書きましたね。当たり前ですがセンサをデバッグしても特に意味はありません。そもそもセンサはデバッグするまでもなく、データシートがあります。
加えて、マウスというシステム自体の特性は、センサよりはMCUに依るところが大きいのです。

そんなわけで、最近コソコソと光学ナビゲーションシステム用リバースエンジニアリングツールを作ろうと画策しているのです。

Q. どんなツール?
マウスの基板上のSPIバスにコイツをぶら下げることでMCUとセンサの全通信を記録するツールです。

Q. どうやって?
センサから物理的に配線を引き出します。引き出すのはMISO、MOSI、NCS、SCLK。
MISOとMOSIをPSoC内の仮想ORゲートでOR演算して、SPI Slave ComponentのMOSIに突っ込みます。NCSとSCLKはそのままSPI Slave Componentに接続。
UART通信で通信内容をPCへ送信。

完成したら意味もなくプロジェクトファイルを上げて誰得感を楽しみたいのですが、非常に忙しいのでリリース時期は不明。

本題 :

なんとなんと面白いデータが出てきました。(データ内のCommentは後付です。)
あまりに面白いので思わずブログを更新するほどに。

 ・試験環境
環境 : PSoC Creator 3.0 SP7
検体 : Anker Laser Precision Gaming Mouse
MCU : PSoC 4 Pioneer Kit

データ内のCommentは後付です。
----------------------------------------------
3a 5a //RESET
24 00 //ゴミデータ?
24 3f //ゴミデータ?
7f 20 //ゴミデータ? FF 20かも。
03 00 //ここからはデータシート通りのスタートアップシーケンス
04 00
05 00
06 00
39 02 //SROMは3Kモードですね
13 1d //SROMのアップロードシーケンス
13 18 //同上

//これ以降の2900バイトは読みだして捨てている(SROMなので)。

//2900バイト捨てたあと↓
86 10 ab c3 75 e9 1f 86 53 4b               
8a 1f 01 f6 f0 3c 7a a8 cd 12 98 c5 9a 1c a8
68 4e 11 b0 08 12 6a 2d df 37 ff 52 b7 d2 e1
7a c5 00 fd 42 b4 30 e7 92 38 f8 e5 3e ff b6
5a 6f 33 7a 7a 0e 74 75 36 ef 82 9e 35 53 5e
2c f1 f6 54 35 e2 d6 c1 07 c2 f0 e0 99 b5 1b
fd a1 2f 43 5d b9 03 db 25 e2 c0 d8 b2 98 e7
91 4f 82 58 35 92 e1 55 86 8e 01 8d 10 29 dd
34 62 4e 16 22 4a 9a be f7 e1 c9 1c 32 6a db
3f f5 e1 4c 92 ae d7 a0 cf 90 ae d7 a1 48 1d
b5 60 cb 99 38 7a 7e 76 e3 4c 15 a4 c7 81 0b
9c b7 60 cb 1c 31 ed d1 2f d5 27 c7 63 60 83
2a a0 20 01 ff ff ff 33 ff ff ff ff ff ff ff
ff ff 20 7f 00 00 00 00 00 df 7f 7f 40 61 ff
ff ff 20 7f 00 00 00 00 00 df 7f 7f 3c 5b ff
ff ff 20 7f 00 00 00 00 00 df 7f 7f 38 96 ae

40 50 20 7f 00 00 00 00 00 df 7f 7f 31 bd ff
ff ff 20 7f 00 00 00 00 00 df 7f 7f 2e a2 ae
36 50 20 7f 00 00 00 00 00 df 7f 7f 28 fd ff
ff ff 20 7f 00 00 00 00 00 df 7f 7f 26 6e ae
2e 50 20 7f 00 00 00 00 00 df 7f 7f 24 08 ae
2c 50 20 7f 00 00 00 00 00 df 7f 7f 1f ac ae
27 50 20 7f 00 00 00 00 00 df 7f 7f 1d b2 ae
25 50 20 7f 00 00 00 00 00 df 7f 7f 1a 1a ae
22 50 20 7f 00 00 00 00 00 df 7f 7f 18 79 ff
ff ff 20 7f 00 00 00 00 00 df 7f 7f 16 f2 ae
1e 50 20 7f 00 00 00 00 00 df 7f 7f 14 2b ff
ff ff 20 7f 00 00 00 00 00 df 7f 7f 12 e9 ff
ff ff 20 7f 00 00 00 00 00 df 7f 7f 10 a0 ae
18 50 20 7f 00 00 00 00 00 df 7f 7f 0e 9d ff

.......... //以下ずっと同じようなデータ
----------------------------------------------

MotionBurstを使っているとは・・・意外性を出していきますね・・・
確かにそっちのほうが速いかもしれないが・・・?
しかし、MCUからセンサに何か言うことは無いんですかね。

それと、レジスタアクセスが意味不明過ぎます。というかデータの精度がかなり悪い。ちゃんとSROMアップロード出来てるのかすら分かりません。
マウスの問題なのか、こっちの問題なのか判断するのにオシロスコープが必要ですね。
細かい解析はいずれ。他のメーカのマウスを試そうにも検体と時間がありません。

おまけ

もう一度取ったデータをば。
----------------------------------------------
3a 5a
24 00
24 3f
7f 20
03 00
04 00
05 00
06 00
39 02
13 1d
13 18
6a c3 8c 14 3e b9 7c 30 85 5e
1b af 48 fc 32 9a 5c 50 f8 0f b7 81 e3 d5 46
68 94 c6 2c d0 e5 43 42 70 8d 80 40 93 51 6e
f9 bf fa 95 be 97 0b d6 28 07 ea 15 a1 87 3c
91 c7 c7 29 f7 fd b2 d3 79 9b d3 d0 73 a3 a9
b7 7c 14 f1 aa 9a f1 67 8f b2 a1 af 16 b6 08
3e 17 87 04 cd a8 df ed 09 7a 1a ed c8 1e d9
2f 16 06 c5 94 c7 3c 8a 7c 12 c1 ac 97 0a ac
34 70 0c 68 81 4e e9 a3 12 70 b1 12 54 d5 f7
bf 0e 48 e1 93 56 d9 ff af 0a 64 95 76 bd 06
7c 85 76 bd 0a 40 ed ab 06 5c c9 c3 d3 f3 b7
1a 60 ad 26 3c 08 5c e5 bb 06 58 e1 8f 6e 89
7e a9 3e 3b 1b 04 19 2a a0 20 01 ff ff ff 33
ff ff ff ff 67 ff ff ff ff 20 7f 00 00 00 00
05 db 7f 00 44 ab ff ff ff 20 7f 00 00 00 00
00 df 7f 7f 3c 5b ff ff ff 20 7f 00 00 00 00

----------------------------------------------

2014/06/04

PSoC 5LPと有機ELディスプレイで動画を描画させてみる

先日購入した有機ELディスプレイ(記事)、買った時から動画を表示させたいと思っていたので作りました。
むしろ、表示させるために買ったという表現のほうが正しいかもしれません。有機EL特有の応答速度とコントラスト比は動画で一層優位性が示されると思います。


前回(センサーデバッガ)は詰まる所もなくすんなり完成しましたが今回はそうは行かなかったです。
あの時は秋にやると書きましたが、目の前の諸問題が大きすぎる時、短期で終わるプロジェクトは非常に魅力的なものです。
「鉄は熱いうちに打て」と言いますしね :D

 開発後記的な物 ->

目標フレームレート

目標とするフレームレートは30fpsです。
動画の再生は、
データの読み込み → デコード → 転送
によって行われますので、1000ms / 30fps = 33.3ms の間に1フレームの全処理を行う必要があります。

ディスプレイへの転送時間

転送時間は事前の調査(記事)でおおよその見当はついています。
実際に計測した所、最適化の前後の差は、
  最適化前 : 105ms
  最適化後 : 25ms
でした。これは、1024byteのバイナリデータをI2Cの400kbpsで転送した場合です。
"理論値では3.22倍程度の最適化"と書きましたが、アプリケーションでは4倍程度の差がでます。MCUのI2CComponentの処理の減少分でしょうか。
 ちなみに1000kbpsへオーバークロックすることで、転送時間は、14ms程度まで減少します。

動画の変換の必要性

1ピクセル1バイト(0〜255)の輝度情報持ったバイナリデータをmicroSDから読み出すのは約26ms程度必要でした。それをマイコンのCPUでディスプレイに転送可能な二値画像に変換するのにさらに15ms程度必要です。
ディスプレイの転送を最適化したのみで実装した所、14fps程度しか出ません。

1フレームあたり1024byteしか必要ないので、わざわざ8192byteも読み込む必要はありません。事前にエンコードしてmicroSDカードに保存しておけば、デコード時間もなくせますし、転送時間も減らす事ができます。そんなわけでエンコーダーを作ります。

1bpp用エンコーダーの作成

使うのは私だけなので、機能を絞ります。
・1bppでSSDシリーズに直に転送出来るようなバイナリデータを吐き出すだけのソフト
・リサイズ機能なし(事前にMediaCoderでリサイズしておく)
・読めるのはRawVideoだけでいい(MediaCoderで事前に無圧縮フォーマット”.yuv”に変換しておく)
・極力ファイル容量を抑える

バイナリエディタを見ながら実装。BZのビットマップ表示機能がとても便利。


また、閾値の調整にMPCのシェーダー機能を利用していた(気がついたらHSLSがちょっとだけ書けるように・・・)のですが、もともと二値な動画以外は極端に見栄えが悪いことに気が付きました。というか何が映ってるのかよく分かりません。
輪郭抽出して描画させれば良いかな・・・? ということで輪郭抽出はまずHLSLで調整して、Cで実装します。

余談 :
二値の動画がどんな感じか見てみたい人は、下記コードをメモ帳に貼り付けて、1bpp.hlslというファイル名で"C:\ #MPCのインストールフォルダ# \MPC-HC\Shaders"に保存。オプション→再生→シェーダの画面でリサイズ後のシェーダに1bppを追加すると雰囲気が味わえます。
/*1bpp.hlsl*/
sampler s0 : register(s0);
float4 main(float2 tex : TEXCOORD0) : COLOR
{
 float4 c0 = tex2D(s0, tex);

 if (c0.r+c0.g+c0.b < 1.5) {
  c0 = float4(0, 0, 0, 0);
 } else {
  c0 = float4(1, 1, 1, 0);
 }
 return c0;
}


輪郭抽出

フィルタは一次微分(Roberts)を利用。
アルゴリズムとそれに与えるフィルタ(行列)が複数あり、二値化時の閾値も適切に決める必要がありますが、チューンは未定。
極端に低解像度の状況でのアルゴリズムは何が良いのでしょうか。

輪郭の細線化

抽出した輪郭をそのまま二値化すると線が太いことがあります。ですので、細線化(Thinning)を施します。アルゴリズムは、Hilditchですが、これももう少し詰める余地がありますね。

5LPへの移植

今までPSoC 4で開発していたのですが、SD_Card ComponentのUnsupportedな感じがプンプンします。サンプルはあるのですが、Creatorのdefaultに入ってませんし。
不穏だったので5LPへ移行。移植自体はスムーズに進みました。メモリもフラッシュも多く、配線の自由度も高いので非常に楽でした。


・・・弊ブログ、電子工作ブログになりつつあるので、そろそろGamingしていきましょうか。

2014/05/24

センサーデバッガ

今日半日使って作ってみました。

技術的にはこの2記事を組み合わせたものになります。
#LogicalGaming: PSoC 4 で有機ELディスプレイ
http://logical-gaming.blogspot.jp/2014/05/psoc-4-el.html

#LogicalGaming: ADNS系センサのRead / Write Operation
http://logical-gaming.blogspot.jp/2014/04/adnsread-write-operation.html

マウスセンサーのΔX、ΔYを読み込んでリアルタイムに可視化してくれるというスグレモノです。
(何に対して優れているかは分かりませんが・・・)
強いて利点を挙げるのならPCが必要ない事、つまりスタンドアロン動作することですね。モバイルバッテリ等の5V電源があればいつでもADNSセンサーのTracking特性を調査できます。

実際に動いている様子はこちら。XとY軸、両方の変位を表示しています。片方の手でカメラ(スマートフォン)を保持して、もう片方でマウスを振っているので映像が手ブレしています。

撮影環境が著しく悪くて申し訳ないです。手元にはレンズ交換式アドバンストカメラがあるのですが、充電器を紛失しました・・・

解像度は128x64ですので、8bitのΔX、ΔYを4で割っています。
シンプルに実装したので、フレームバッファを2枚用意しました。おかげでメモリが極端に圧迫されて使用率95%ほど。これ以上はPSoC 5LPが使いたくなってきます。

SQUALもグラフ化してみたのですが、ばらつきが極端に多く何のデータかよく分からない感じだったのでボツ。Shutter値やSQUAL等の変化の大きい物を表示するにはなんらかの統計処理が必要ですね。

これでディスプレイ遊びは一旦終了ですね。もしかしたら秋ごろにちょっとやるかもしれません。
そろそろゲーミング業界に貢献性の高い物を作りたいです。

2014/05/18

PSoC 4 で有機ELディスプレイ


有機ELディスプレイ(I2C、128x64、二値表示)をスイッチサイエンスから買ったので実装してみました。
2、3日かかると思ったのですが、2時間で動いてしまってちょっと拍子抜けですね。

状況

・PSOC Creator3.0 SP1
・PSoC4 4 Pioneer Kit

・GROVE - I2C OLEDディスプレイ128×64 SEEED-OLE35046P
国内 : http://www.switch-science.com/catalog/829/
輸入 : http://www.seeedstudio.com/depot/grove-oled-display-12864-p-781.html
詳細 : http://www.seeedstudio.com/wiki/Grove_-_OLED_Display_128*64
専用ライブラリ : https://github.com/Seeed-Studio/Grove_OLED_Display_128X64

コントロールチップ : SSD1308 [PDF] http://garden.seeedstudio.com/images/4/46/SSD1308_1.0.pdf
ディスプレイ : LY190-128064 [PDF] http://garden.seeedstudio.com/images/c/c4/LY190-128064.pdf
ライブラリと2つのデータシートを参考にしながら必要な部分を作成しました。

※SSD13xx系をAVRで制御されている方がいらっしゃったので参考にさせて頂きました。
UG-2864HSWEG01/SSD1306 I2Cで動作テスト
http://jsdiy.web.fc2.com/oled_ssd1306/
このページによく纏まっているのですが、このチップのデータの単位であるPage、Segmentの関係はよく理解しておく必要があります。

ディスプレイは二値情報のみなので、1x8の縦長のピクセルを1グループ(Segment)として、扱います。これは、計算機は1Byteでデータを扱う事が多いので理にかなっていますね。1x8ピクセルのグループを横に128個並べて1Page、Pageを縦に8段並べる事で1frame(1画面)になります。

I2C

I2C Componentのコンフィグを下図に示します。オーバーサンプリングの設定が中途半端なのは、ビットレートをちょうど400kbpsにするためです。なお、400kbpsにこだわった理由はフレームレート試算の為です。

PSoC 4はSCB利用のComponentを使用する場合、ピン配置が固定されるので注意が必要です。

CommandのWrite

以下のように実装を行いました。コマンドモードに遷移後、Command入力を行います。ADDRはスレーブアドレスです。

#define ADDR 0b0111100
void OLED_Write_Cmd(uint8 command){
    i2cMasterWriteBuf[0] = 0x80;
    i2cMasterWriteBuf[1] = command;
    I2C_I2CMasterWriteBuf(ADDR, (uint8 *) i2cMasterWriteBuf, 2u,  I2C_I2C_MODE_COMPLETE_XFER);

    while(0u == (I2C_I2CMasterStatus() & I2C_I2C_MSTAT_WR_CMPLT)){}
    (void) I2C_I2CMasterClearStatus();
}


OLEDの起動

OffのCommand、ディレイ、ONのCommand、ディレイのみです。本当はもう少し初期化が必要なのですが、デフォルト値として省略。

void OLED_Init()
{
    OLED_Write_Cmd(0xAE);
    CyDelay(5u);
    OLED_Write_Cmd(0xAF);
    CyDelay(5u);
}


BitmapのWrite

データモードに遷移後、所定のByte数のデータ入力を行います。
void drawBitmap(const uint8* bitmaparray,int bytes)
{
    int i;
    for(i = 0 ; i < bytes ; i++)
    {
        OLED_Write_Data(bitmaparray[i]);
    }
    while(0u == (I2C_I2CMasterStatus() & I2C_I2C_MSTAT_WR_CMPLT));
    (void) I2C_I2CMasterClearStatus();
}

 

最適化

ライブラリの通り、全部のセグメントでアドレス→コントロールバイト→データバイトを書くという実装では遅いです。
I2Cのクロックは最大400kbpsという仕様なのですが、この実装の場合10fps程度しか出ません。なので高速化を施します。
アドレス、コントロールバイトは1フレームに一度だけの転送で、残りのデータ1024バイトは一気に転送します。これによってACK等も含めた転送bit量は 1/3.22 に減少します。

 void drawBitmap_fast(uint8* bitmaparray,int bytes)
{
    int i;
    I2C_I2CMasterSendStart(ADDR, I2C_I2C_WRITE_XFER_MODE);
    I2C_I2CMasterWriteByte(0x40);
   
    for(i = 0 ; i < bytes ; i++)
    {
        I2C_I2CMasterWriteByte(bitmaparray[i]);
    }
    I2C_I2CMasterSendStop();
    (void) I2C_I2CMasterClearStatus();
}


なお、オーバークロックして1000kbpsでも稼働可能です。当方としては定格超えですので常用はしません。クロックを上げるとRESETをかけた後にデータを受け取れなくなる事がまれに発生します。

使用例

int main()
{
    I2C_Start();
  
    CyGlobalIntEnable;
    OLED_Init();

 
    //Set Brightness
    OLED_Write_Cmd(0x81);
    OLED_Write_Cmd(0x00);
   
    //Set Freq
    OLED_Write_Cmd(0xD5);
    OLED_Write_Cmd(0xF0);
   
    //Set Hori-mode
    OLED_Write_Cmd(0x20);
    OLED_Write_Cmd(0x00);
   
    //Set First Seg
    OLED_Write_Cmd(0x00);
    OLED_Write_Cmd(0x10);
    OLED_Write_Cmd(0x40);
   
    //OLED_Write_Cmd(0xA7); //Inverse color if needed

 
    //Draw
    drawBitmap(Image_array,1024);

 
    return 0;
}

画像データ生成ツール

このようなデータの扱い方に対応した配列を生成するツールが存在します。
Bitmap converter for mono and color LCD displays
http://en.radzio.dxp.pl/bitmap_converter/

今回の構成の場合、設定は以下のようにします。
Fileから画像のLoad、Saveが可能で、出力はテキストの配列データになります。
 
生成されたファイルとincludeするか、ソース内に貼り付けることで利用可能です。
リサイズ、二値化はPaint.NET等で行う必要があります。また、今回は8bit Bitmapの画像を使用しました。

 

画像の置き場所

画像1枚で1KBなのでメモリ上に展開してしまうと、メモリが圧迫されます。なので、チップのSRAMではなく、const unsigned char 変数名[]{0x00, ・・・・・};という風に、比較的容量に余裕のあるFlash内に画像を置くことが必要だと思われます。

2014/04/23

滑走面の拡散反射色によるセンシング性能への影響について

rafa氏が非常に面白い記事を発表されていて、気になることがあったので検証しました。

rafalog: QPAD CT Collector Editions Team Dignitas紹介
http://utmalesoldiers.blogspot.jp/2014/04/qpad-ct-collector-editions-team-dignitas.html
記事の後半のトラッキング性能の試験が素晴らしいですね。この試験により滑走面の拡散反射色が位置によって異なる(つまり柄のある)マウスパッドだとトラッキング性能が落ちる可能性を指摘できます。

そもそもマウスパッドに柄があるとトラッキングに悪影響があるような気はしていて、大半のマウスパッドが無地であるのもこういった理由なのかと思っていましたが、今回はもう少しだけ低レベルの部分まで調べてみましょう。

・試験マウスパッド
使用するのは、いつぞやに営業に来てくださった方に貰ったZOTACの販促用プラ製マウスパッドです。[ アサシンクリード ZOTAC マウスパッド ]等で検索するとちらほら引っかかるのでそれなりに数は出ているようです。摩擦係数が低く、滑走性は良いのですが、弊センサでは高速域でのトラッキングエラーが頻発してお蔵入りになっていました。やはり性能的には販促品なのでしょうか。そもそも"商品"ではなく景品なのでレビューは省略。

もともと柄物は好みではないので、手元にはこれしかありませんでした。本当はそれなりの柄付きのゲーミングマウスパッドがあると良いのですが・・・
手元にあるマウスパッドにもロゴ等の色違いの部分は存在しているのですが、滑走面の上にペイントされているタイプなので滑走面の状態自体大きく異なり、よい比較ではありません。そもそもそういった部分は摩擦係数も異なるので、使用するべきではないのというのが個人的な意見です。


このマウスパッドの上図のGray(色的には白~ライトグレー位)の部分と、Blackの部分についてログを取りました。
販促用の極めて安価なパッドを試験に使用していますし、全ての柄物のマウスパッドについて本記事の記載事項が当てはまる訳ではないと思うので、その点をご留意下さい。

・試験環境
環境 : PSoC Creator 3.0 SP7
センサ : ADNS-5090
MCU : PSoC 4 Pioneer Kit

Registerの設定 : 分かる範囲でパフォーマンス重視にしました。
RUN_DOWNSHIFT = 0xFF
REST1_DOWNSHIFT = 0xFF
REST2_DOWNSHIFT = 0xFF
AUTO_LED_CTRL = 0b00001110
MOUSE_CTRL = 0b00100100
MOUSE_CTRL_EN = 0x10

・出力データ
まずセットアップのdescriptionが出力、その後PixelGrabbeで現在のピクセルアレイの様子を出力をします。その後はループに入り、以下のデータを出力し続けます。頻度は毎秒10回程度。
データの並び順 :
⊿X、⊿Y、SQUAL、PIX_ACCUM、[PIX_MIN~PIX_MAX]、SHUT

SHUTに関しては、RegisterがSHUT_HIとSHUT_LOがありますので、
uint16 SHUT = (SHUT_HI << 8 ) + SHUT_LO;
とします。

・試験方法
1.センサのレンズ部がGrayの真上に来るように滑走面に接地し、MCUをリセットする。
2.センサ初期化と設定を行う。
3.PixGrabberを作動させピクセルアレイの輝度情報を得る。
4.マウスを数カウント動かしながらループデータを数十回記録する。
5.Blackの箇所についても同様の試験を行う。

・試験結果
1.Gray
Grayのログデータを以下に示します。

------------------------------------------------------------------
ADNS-5090 TEST Start
SPI Start
Sensor initialization finished
46 45 30 33 37 30 21 29 41 41 34 44 28 22 35 35 37 37 53
36 28 29 36 39 29 28 37 57 65 52 48 41 41 49 43 27 30 29
47 22 31 45 47 42 47 67 79 81 64 46 62 35 54 46 35 43 27
33 22 43 63 49 53 56 44 59 59 71 60 54 38 76 82 61 52 21
35 28 35 52 40 58 65 55 56 36 47 62 52 44 77 94 73 37 37
52 42 34 31 39 56 66 74 74 47 35 49 65 43 56 64 72 28 60
51 59 51 37 33 58 49 50 85 60 44 59 78 52 45 52 69 26 32
45 56 47 35 35 40 38 46 56 42 69 49 47 76 58 39 56 36 30
46 46 40 38 39 36 41 57 61 40 64 44 55 71 52 36 68 67 36
60 51 44 40 36 35 56 50 67 47 34 50 81 64 44 36 72 79 36
63 62 50 51 65 70 81 59 50 33 21 35 51 49 37 53 104 86 44
52 58 52 44 63 73 73 72 58 33 30 40 70 56 40 62 102 65 56
55 57 51 38 48 52 68 72 81 64 43 54 85 61 55 38 71 89 64
66 62 58 37 51 69 80 85 73 54 39 41 57 49 50 36 37 92 54
72 57 55 43 63 65 66 88 65 50 45 49 55 50 40 36 40 57 42
66 53 45 47 70 63 55 70 75 57 48 42 43 38 32 43 64 40 36
57 45 42 47 55 60 39 48 60 51 50 62 59 70 43 79 93 51 37
62 46 43 43 49 65 45 61 70 57 78 70 57 59 41 92 91 64 49
61 58 40 42 64 88 75 83 74 59 95 82 51 42 43 89 77 56 79
X 0 Y 0 SQUAL : 90 ACCUM : 74 [ 21~104 ] SHUT : 159
X 0 Y 0 SQUAL : 91 ACCUM : 74 [ 21~104 ] SHUT : 159
X 0 Y 0 SQUAL : 96 ACCUM : 74 [ 21~104 ] SHUT : 159
X 0 Y 0 SQUAL : 89 ACCUM : 74 [ 21~106 ] SHUT : 159
X 0 Y 0 SQUAL : 92 ACCUM : 74 [ 21~103 ] SHUT : 159
X 0 Y 0 SQUAL : 95 ACCUM : 74 [ 21~104 ] SHUT : 159
X 0 Y 0 SQUAL : 93 ACCUM : 74 [ 21~103 ] SHUT : 159
X 0 Y 0 SQUAL : 93 ACCUM : 74 [ 21~104 ] SHUT : 159
X 0 Y 0 SQUAL : 89 ACCUM : 74 [ 21~106 ] SHUT : 159
X 0 Y 0 SQUAL : 91 ACCUM : 74 [ 21~105 ] SHUT : 159
X 0 Y 0 SQUAL : 92 ACCUM : 74 [ 21~107 ] SHUT : 159
X 0 Y 0 SQUAL : 95 ACCUM : 70 [ 19~111 ] SHUT : 149
X -5 Y 0 SQUAL : 87 ACCUM : 70 [ 17~103 ] SHUT : 148
X -2 Y -1 SQUAL : 92 ACCUM : 66 [ 11~108 ] SHUT : 137
X 0 Y -2 SQUAL : 85 ACCUM : 63 [ 14~95 ] SHUT : 127
X 1 Y -4 SQUAL : 87 ACCUM : 86 [ 22~102 ] SHUT : 151
X 1 Y 0 SQUAL : 97 ACCUM : 86 [ 20~98 ] SHUT : 161
X 2 Y 7 SQUAL : 92 ACCUM : 69 [ 15~103 ] SHUT : 147
X -1 Y 2 SQUAL : 93 ACCUM : 68 [ 13~100 ] SHUT : 147
X -4 Y -3 SQUAL : 83 ACCUM : 65 [ 14~108 ] SHUT : 136
X -5 Y -10 SQUAL : 85 ACCUM : 79 [ 25~102 ] SHUT : 121
X 2 Y -1 SQUAL : 81 ACCUM : 80 [ 28~98 ] SHUT : 121
X 4 Y 0 SQUAL : 89 ACCUM : 86 [ 27~100 ] SHUT : 138
X 0 Y 5 SQUAL : 93 ACCUM : 79 [ 22~98 ] SHUT : 143
X -5 Y 0 SQUAL : 87 ACCUM : 82 [ 19~109 ] SHUT : 140
X -9 Y -6 SQUAL : 93 ACCUM : 80 [ 20~104 ] SHUT : 128
X -1 Y -5 SQUAL : 90 ACCUM : 75 [ 24~109 ] SHUT : 128
X 5 Y -1 SQUAL : 87 ACCUM : 82 [ 24~107 ] SHUT : 135
X 2 Y 0 SQUAL : 92 ACCUM : 81 [ 26~104 ] SHUT : 135
X 1 Y 7 SQUAL : 94 ACCUM : 82 [ 27~102 ] SHUT : 126
X -1 Y 3 SQUAL : 84 ACCUM : 84 [ 24~103 ] SHUT : 134
X -4 Y -1 SQUAL : 78 ACCUM : 69 [ 22~106 ] SHUT : 109
X -1 Y -6 SQUAL : 83 ACCUM : 82 [ 23~105 ] SHUT : 137
X 5 Y -3 SQUAL : 85 ACCUM : 77 [ 27~105 ] SHUT : 128
X 4 Y 4 SQUAL : 90 ACCUM : 82 [ 26~102 ] SHUT : 126
X 1 Y 5 SQUAL : 86 ACCUM : 85 [ 23~102 ] SHUT : 134
X -3 Y 5 SQUAL : 92 ACCUM : 82 [ 17~103 ] SHUT : 141
X -6 Y 0 SQUAL : 85 ACCUM : 78 [ 21~103 ] SHUT : 132
X -4 Y -7 SQUAL : 87 ACCUM : 86 [ 27~110 ] SHUT : 140
X 4 Y -4 SQUAL : 92 ACCUM : 86 [ 25~106 ] SHUT : 139
X 5 Y 0 SQUAL : 83 ACCUM : 85 [ 28~103 ] SHUT : 139
X 4 Y 3 SQUAL : 94 ACCUM : 83 [ 26~108 ] SHUT : 128
X 2 Y 7 SQUAL : 84 ACCUM : 76 [ 20~102 ] SHUT : 136
X -4 Y 3 SQUAL : 86 ACCUM : 72 [ 11~108 ] SHUT : 138
X -2 Y 1 SQUAL : 91 ACCUM : 73 [ 15~103 ] SHUT : 138
X -4 Y -6 SQUAL : 89 ACCUM : 82 [ 28~103 ] SHUT : 129
X 1 Y -6 SQUAL : 82 ACCUM : 80 [ 26~101 ] SHUT : 125
X 4 Y -2 SQUAL : 90 ACCUM : 78 [ 25~108 ] SHUT : 125
X 4 Y 1 SQUAL : 95 ACCUM : 85 [ 26~102 ] SHUT : 132
X 3 Y 7 SQUAL : 91 ACCUM : 87 [ 24~100 ] SHUT : 150
X -1 Y 5 SQUAL : 88 ACCUM : 63 [ 8~100 ] SHUT : 130
X -4 Y 2 SQUAL : 100 ACCUM : 69 [ 11~97 ] SHUT : 148
X -5 Y -3 SQUAL : 90 ACCUM : 74 [ 13~103 ] SHUT : 129
X 0 Y -7 SQUAL : 82 ACCUM : 77 [ 24~106 ] SHUT : 120
X 5 Y -3 SQUAL : 85 ACCUM : 79 [ 27~101 ] SHUT : 120
X 4 Y 3 SQUAL : 90 ACCUM : 85 [ 27~97 ] SHUT : 146
X 2 Y 7 SQUAL : 94 ACCUM : 72 [ 19~105 ] SHUT : 143
X 0 Y 6 SQUAL : 85 ACCUM : 69 [ 12~102 ] SHUT : 151
X 0 Y 2 SQUAL : 88 ACCUM : 72 [ 15~105 ] SHUT : 161
X -7 Y -2 SQUAL : 96 ACCUM : 76 [ 18~102 ] SHUT : 161
X 0 Y -10 SQUAL : 92 ACCUM : 89 [ 31~96 ] SHUT : 140
X 5 Y -5 SQUAL : 91 ACCUM : 84 [ 29~100 ] SHUT : 131
X 7 Y 3 SQUAL : 90 ACCUM : 83 [ 27~98 ] SHUT : 140
X 3 Y 6 SQUAL : 87 ACCUM : 68 [ 15~95 ] SHUT : 139
X -1 Y 5 SQUAL : 81 ACCUM : 63 [ 17~107 ] SHUT : 134
X -4 Y 2 SQUAL : 92 ACCUM : 67 [ 13~109 ] SHUT : 152
X -4 Y 0 SQUAL : 86 ACCUM : 69 [ 13~101 ] SHUT : 151
X -2 Y -7 SQUAL : 82 ACCUM : 68 [ 16~106 ] SHUT : 128
X 2 Y -5 SQUAL : 87 ACCUM : 91 [ 22~102 ] SHUT : 149
X 3 Y 0 SQUAL : 80 ACCUM : 82 [ 25~105 ] SHUT : 138
X 6 Y 5 SQUAL : 79 ACCUM : 68 [ 11~107 ] SHUT : 127
X 1 Y 7 SQUAL : 83 ACCUM : 66 [ 15~100 ] SHUT : 149
X -2 Y 8 SQUAL : 92 ACCUM : 72 [ 18~106 ] SHUT : 166
X -5 Y 0 SQUAL : 92 ACCUM : 71 [ 17~102 ] SHUT : 165
X -6 Y -6 SQUAL : 93 ACCUM : 75 [ 17~105 ] SHUT : 175
X 6 Y -9 SQUAL : 87 ACCUM : 84 [ 22~106 ] SHUT : 158
X 8 Y 3 SQUAL : 89 ACCUM : 60 [ 11~92 ] SHUT : 130
X -6 Y 10 SQUAL : 93 ACCUM : 71 [ 14~103 ] SHUT : 164
X 0 Y 0 SQUAL : 90 ACCUM : 70 [ 15~105 ] SHUT : 164
X 0 Y -1 SQUAL : 100 ACCUM : 74 [ 16~98 ] SHUT : 175
X 0 Y 0 SQUAL : 95 ACCUM : 74 [ 17~111 ] SHUT : 175
X 0 Y 0 SQUAL : 87 ACCUM : 70 [ 16~110 ] SHUT : 164
X 0 Y -1 SQUAL : 95 ACCUM : 74 [ 17~103 ] SHUT : 175
X -1 Y -1 SQUAL : 93 ACCUM : 74 [ 15~103 ] SHUT : 175
X 0 Y 0 SQUAL : 90 ACCUM : 74 [ 15~102 ] SHUT : 175
X 0 Y 0 SQUAL : 90 ACCUM : 74 [ 15~102 ] SHUT : 175
X 0 Y 0 SQUAL : 85 ACCUM : 74 [ 15~102 ] SHUT : 175
X 0 Y 0 SQUAL : 88 ACCUM : 75 [ 15~101 ] SHUT : 175
X 0 Y 0 SQUAL : 86 ACCUM : 75 [ 16~102 ] SHUT : 175
X 0 Y 0 SQUAL : 90 ACCUM : 75 [ 16~101 ] SHUT : 175
X 0 Y 0 SQUAL : 88 ACCUM : 75 [ 16~101 ] SHUT : 175
X 0 Y 0 SQUAL : 88 ACCUM : 75 [ 15~102 ] SHUT : 175
X 0 Y 0 SQUAL : 85 ACCUM : 75 [ 15~102 ] SHUT : 175
X 0 Y 0 SQUAL : 89 ACCUM : 75 [ 15~101 ] SHUT : 175
X 0 Y 0 SQUAL : 88 ACCUM : 75 [ 15~103 ] SHUT : 175
X 0 Y 0 SQUAL : 88 ACCUM : 75 [ 16~103 ] SHUT : 175
X 0 Y 0 SQUAL : 88 ACCUM : 75 [ 16~101 ] SHUT : 175
X 0 Y 0 SQUAL : 88 ACCUM : 75 [ 16~102 ] SHUT : 175
X 0 Y 0 SQUAL : 86 ACCUM : 75 [ 16~101 ] SHUT : 175

------------------------------------------------------------------

2.Black
Blackのログデータを以下に示します。

------------------------------------------------------------------
DNS-5090 TEST Start
SPI Start
Sensor initialization finished
28 48 34 34 26 39 34 18 41 43 11 13 27 24 23 17 22 7 5
13 26 25 26 24 36 45 22 13 12 7 7 5 8 11 58 35 7 28
20 34 25 30 28 18 31 33 16 19 20 8 4 7 5 30 20 47 97
27 34 25 38 29 31 34 23 15 37 32 10 6 13 13 8 7 52 54
29 21 13 19 24 34 28 14 17 76 85 27 29 19 16 8 53 64 42
20 15 17 31 51 58 22 11 16 74 100 67 15 13 8 10 31 53 49
12 15 23 68 74 36 27 26 23 25 78 90 31 15 8 34 23 8 15
13 15 24 72 71 27 36 77 60 9 60 70 38 8 5 38 51 13 16
24 24 29 48 60 51 23 32 29 12 23 44 63 14 3 17 83 51 34
21 23 40 27 28 33 12 22 24 23 34 34 81 34 7 8 44 91 32
12 18 51 34 13 14 26 46 20 44 43 15 65 55 62 31 22 92 11
7 18 57 39 11 16 36 30 39 40 22 8 44 55 78 52 20 32 12
10 22 32 26 10 15 33 47 53 72 15 14 108 59 59 72 12 13 80
30 42 40 35 28 18 35 62 29 27 6 11 48 22 46 55 10 8 78
38 40 25 29 48 23 55 44 27 21 6 36 23 8 23 41 20 16 40
19 19 15 25 23 30 54 56 26 20 30 71 33 9 21 41 44 38 23
16 22 32 41 34 56 53 66 35 13 55 62 21 9 37 33 20 29 19
22 27 31 31 44 53 68 57 41 18 78 82 19 6 29 20 13 30 22
42 24 19 31 39 35 45 70 67 27 57 74 40 44 54 19 8 21 14
X 0 Y 0 SQUAL : 96 ACCUM : 45 [ 3~108 ] SHUT : 239
X 0 Y 0 SQUAL : 95 ACCUM : 45 [ 3~108 ] SHUT : 239
X 0 Y 0 SQUAL : 96 ACCUM : 45 [ 3~108 ] SHUT : 239
X 0 Y 0 SQUAL : 98 ACCUM : 45 [ 3~108 ] SHUT : 239
X 0 Y 0 SQUAL : 97 ACCUM : 45 [ 3~106 ] SHUT : 239
X 0 Y 0 SQUAL : 98 ACCUM : 45 [ 3~106 ] SHUT : 239
X 0 Y 0 SQUAL : 95 ACCUM : 45 [ 3~106 ] SHUT : 239
X 0 Y 0 SQUAL : 98 ACCUM : 45 [ 3~107 ] SHUT : 239
X 0 Y 0 SQUAL : 98 ACCUM : 45 [ 3~104 ] SHUT : 239
X 0 Y 0 SQUAL : 100 ACCUM : 48 [ 4~108 ] SHUT : 254
X 0 Y 0 SQUAL : 95 ACCUM : 47 [ 4~106 ] SHUT : 254
X 0 Y 0 SQUAL : 95 ACCUM : 44 [ 3~110 ] SHUT : 247
X 0 Y 0 SQUAL : 99 ACCUM : 46 [ 3~115 ] SHUT : 224
X 2 Y -3 SQUAL : 101 ACCUM : 46 [ 2~93 ] SHUT : 236
X 3 Y -4 SQUAL : 101 ACCUM : 47 [ 2~108 ] SHUT : 239
X 4 Y 6 SQUAL : 106 ACCUM : 54 [ 4~105 ] SHUT : 257
X 0 Y 7 SQUAL : 89 ACCUM : 45 [ 2~122 ] SHUT : 232
X -8 Y -3 SQUAL : 101 ACCUM : 46 [ 2~110 ] SHUT : 239
X -3 Y -13 SQUAL : 103 ACCUM : 45 [ 2~109 ] SHUT : 222
X 4 Y -3 SQUAL : 104 ACCUM : 47 [ 1~122 ] SHUT : 239
X 4 Y 3 SQUAL : 99 ACCUM : 46 [ 1~109 ] SHUT : 223
X 1 Y 9 SQUAL : 104 ACCUM : 51 [ 3~104 ] SHUT : 244
X -5 Y 3 SQUAL : 99 ACCUM : 44 [ 2~119 ] SHUT : 235
X -1 Y -2 SQUAL : 105 ACCUM : 43 [ 2~115 ] SHUT : 239
X 0 Y -7 SQUAL : 101 ACCUM : 46 [ 2~111 ] SHUT : 209
X 7 Y -3 SQUAL : 105 ACCUM : 47 [ 1~125 ] SHUT : 224
X 4 Y 2 SQUAL : 99 ACCUM : 46 [ 3~108 ] SHUT : 235
X 1 Y 9 SQUAL : 105 ACCUM : 52 [ 2~102 ] SHUT : 273
X -2 Y 3 SQUAL : 102 ACCUM : 52 [ 2~103 ] SHUT : 271
X -3 Y -2 SQUAL : 98 ACCUM : 48 [ 1~111 ] SHUT : 239
X -2 Y -7 SQUAL : 99 ACCUM : 46 [ 2~117 ] SHUT : 209
X 11 Y -2 SQUAL : 103 ACCUM : 46 [ 3~111 ] SHUT : 242
X 6 Y 3 SQUAL : 97 ACCUM : 43 [ 4~114 ] SHUT : 224
X 0 Y 8 SQUAL : 102 ACCUM : 43 [ 3~115 ] SHUT : 259
X -5 Y 7 SQUAL : 104 ACCUM : 43 [ 2~108 ] SHUT : 239
X -5 Y -5 SQUAL : 107 ACCUM : 45 [ 2~115 ] SHUT : 237
X 0 Y -6 SQUAL : 104 ACCUM : 46 [ 2~111 ] SHUT : 233
X 4 Y -2 SQUAL : 104 ACCUM : 46 [ 2~107 ] SHUT : 239
X 6 Y 1 SQUAL : 105 ACCUM : 43 [ 1~124 ] SHUT : 224
X 4 Y 10 SQUAL : 103 ACCUM : 47 [ 4~111 ] SHUT : 267
X -2 Y 7 SQUAL : 94 ACCUM : 45 [ 2~109 ] SHUT : 239
X -6 Y 0 SQUAL : 97 ACCUM : 47 [ 2~111 ] SHUT : 238
X -3 Y -10 SQUAL : 97 ACCUM : 46 [ 2~127 ] SHUT : 245
X 3 Y -9 SQUAL : 96 ACCUM : 42 [ 1~105 ] SHUT : 240
X 8 Y -3 SQUAL : 101 ACCUM : 44 [ 2~114 ] SHUT : 239
X 5 Y 8 SQUAL : 99 ACCUM : 47 [ 2~105 ] SHUT : 271
X -4 Y 10 SQUAL : 98 ACCUM : 47 [ 3~116 ] SHUT : 229
X -5 Y 5 SQUAL : 95 ACCUM : 48 [ 3~111 ] SHUT : 239
X -6 Y -8 SQUAL : 97 ACCUM : 44 [ 2~112 ] SHUT : 224
X 0 Y -8 SQUAL : 104 ACCUM : 46 [ 1~106 ] SHUT : 239
X 8 Y -7 SQUAL : 99 ACCUM : 45 [ 3~115 ] SHUT : 224
X 13 Y 0 SQUAL : 94 ACCUM : 51 [ 4~101 ] SHUT : 247
X 3 Y 6 SQUAL : 95 ACCUM : 46 [ 4~109 ] SHUT : 226
X 0 Y 8 SQUAL : 97 ACCUM : 49 [ 5~104 ] SHUT : 282
X -3 Y 7 SQUAL : 96 ACCUM : 48 [ 2~113 ] SHUT : 273
X -3 Y 1 SQUAL : 104 ACCUM : 48 [ 2~112 ] SHUT : 252
X -5 Y -12 SQUAL : 101 ACCUM : 42 [ 2~113 ] SHUT : 270
X 1 Y -7 SQUAL : 102 ACCUM : 48 [ 2~112 ] SHUT : 254
X 9 Y -2 SQUAL : 98 ACCUM : 45 [ 4~107 ] SHUT : 212
X 6 Y 5 SQUAL : 100 ACCUM : 52 [ 5~99 ] SHUT : 276
X 2 Y 11 SQUAL : 91 ACCUM : 41 [ 2~107 ] SHUT : 265
X -2 Y 9 SQUAL : 95 ACCUM : 42 [ 4~112 ] SHUT : 267
X -3 Y 2 SQUAL : 94 ACCUM : 46 [ 4~107 ] SHUT : 262
X -9 Y -4 SQUAL : 102 ACCUM : 46 [ 1~116 ] SHUT : 224
X 0 Y -8 SQUAL : 98 ACCUM : 47 [ 1~124 ] SHUT : 232
X 4 Y -9 SQUAL : 106 ACCUM : 43 [ 2~117 ] SHUT : 223
X 5 Y 0 SQUAL : 100 ACCUM : 43 [ 2~108 ] SHUT : 223
X 6 Y 7 SQUAL : 90 ACCUM : 47 [ 2~101 ] SHUT : 267
X 2 Y 9 SQUAL : 93 ACCUM : 45 [ 4~109 ] SHUT : 253
X -1 Y 5 SQUAL : 94 ACCUM : 46 [ 3~106 ] SHUT : 261
X -2 Y 2 SQUAL : 102 ACCUM : 43 [ 2~121 ] SHUT : 251
X -2 Y -4 SQUAL : 98 ACCUM : 42 [ 2~127 ] SHUT : 237
X -1 Y -10 SQUAL : 104 ACCUM : 45 [ 1~105 ] SHUT : 224
X 6 Y -7 SQUAL : 88 ACCUM : 44 [ 2~127 ] SHUT : 239
X 7 Y 0 SQUAL : 97 ACCUM : 50 [ 3~104 ] SHUT : 270
X 5 Y 10 SQUAL : 87 ACCUM : 45 [ 4~109 ] SHUT : 275
X -3 Y 10 SQUAL : 92 ACCUM : 50 [ 5~103 ] SHUT : 261
X -3 Y 2 SQUAL : 102 ACCUM : 56 [ 5~108 ] SHUT : 295
X -4 Y -3 SQUAL : 103 ACCUM : 47 [ 1~114 ] SHUT : 253
X 0 Y -7 SQUAL : 100 ACCUM : 44 [ 2~116 ] SHUT : 209
X 3 Y -2 SQUAL : 97 ACCUM : 45 [ 2~104 ] SHUT : 223
X 4 Y 3 SQUAL : 93 ACCUM : 47 [ 4~117 ] SHUT : 273
X 2 Y 10 SQUAL : 99 ACCUM : 51 [ 5~108 ] SHUT : 261
X -6 Y 5 SQUAL : 85 ACCUM : 47 [ 3~104 ] SHUT : 210
X -3 Y 0 SQUAL : 93 ACCUM : 48 [ 3~104 ] SHUT : 207
X -6 Y -8 SQUAL : 99 ACCUM : 43 [ 2~111 ] SHUT : 249
X -2 Y -9 SQUAL : 99 ACCUM : 43 [ 2~115 ] SHUT : 241
X 0 Y -7 SQUAL : 102 ACCUM : 45 [ 1~117 ] SHUT : 226
X 5 Y -1 SQUAL : 102 ACCUM : 46 [ 2~111 ] SHUT : 239
X 8 Y 2 SQUAL : 97 ACCUM : 48 [ 2~106 ] SHUT : 258
X 1 Y 8 SQUAL : 96 ACCUM : 47 [ 4~100 ] SHUT : 256
X -7 Y 13 SQUAL : 92 ACCUM : 46 [ 2~108 ] SHUT : 189
X -4 Y 1 SQUAL : 103 ACCUM : 46 [ 1~104 ] SHUT : 241
X 0 Y -8 SQUAL : 101 ACCUM : 43 [ 3~127 ] SHUT : 251
X 5 Y -7 SQUAL : 103 ACCUM : 46 [ 2~123 ] SHUT : 208
X 1 Y 5 SQUAL : 100 ACCUM : 45 [ 3~100 ] SHUT : 239
X -4 Y -4 SQUAL : 93 ACCUM : 45 [ 3~117 ] SHUT : 261
X -5 Y -10 SQUAL : 102 ACCUM : 47 [ 2~108 ] SHUT : 252
X 0 Y 0 SQUAL : 106 ACCUM : 46 [ 2~109 ] SHUT : 252
X 0 Y 0 SQUAL : 102 ACCUM : 46 [ 2~108 ] SHUT : 252
X 0 Y 0 SQUAL : 104 ACCUM : 46 [ 2~108 ] SHUT : 252
X 0 Y 0 SQUAL : 99 ACCUM : 46 [ 3~106 ] SHUT : 252
X 0 Y 0 SQUAL : 102 ACCUM : 46 [ 2~107 ] SHUT : 252
X 0 Y 0 SQUAL : 102 ACCUM : 46 [ 3~108 ] SHUT : 252
X 0 Y 0 SQUAL : 101 ACCUM : 46 [ 2~107 ] SHUT : 252
X 0 Y 0 SQUAL : 103 ACCUM : 46 [ 3~107 ] SHUT : 252
X 0 Y 0 SQUAL : 101 ACCUM : 46 [ 2~108 ] SHUT : 252
X 0 Y 0 SQUAL : 100 ACCUM : 46 [ 3~107 ] SHUT : 252
X 0 Y 0 SQUAL : 101 ACCUM : 46 [ 2~107 ] SHUT : 252
X 0 Y 0 SQUAL : 101 ACCUM : 46 [ 2~107 ] SHUT : 252
X 0 Y 0 SQUAL : 101 ACCUM : 46 [ 3~107 ] SHUT : 252
X 0 Y 0 SQUAL : 103 ACCUM : 46 [ 3~106 ] SHUT : 252
X 0 Y 0 SQUAL : 100 ACCUM : 46 [ 2~108 ] SHUT : 252
X 0 Y 0 SQUAL : 100 ACCUM : 46 [ 3~107 ] SHUT : 252
------------------------------------------------------------------



・試験結果から分かること
各パラメタについてGrayとBlackを比較しましょう。

・ピクセルアレイの輝度
Grayのほうが明るい像がセンサに写っている事がわかります。Shut値は最も明るいピクセルに依って定められるので、Blackの方が明るい部分が際立っており目立つ、ということですね。トラッキングにどちらの色が向いているかどうかは断定しかねますが、コントラスト比の高い黒の方が向いているように直感的には思えますね。

・SQUAL
Blackの方が良い(高い)ですね。値的には普通か、それよりは良いくらいです(その他のマウスパッドと比較して)。弊センサではなぜTracking出来ないのか謎は深まりますね。

・ACUUM
ピクセルアレイと同じ傾向です。灰 / 黒の差がよく出ていますね。

・MIN、MAX
MAXは127で飽和するギリギリの100ちょいになるように調整されているのか、比較的一定値ですね。対してMINはACCUMと同様の傾向。

・SHUT
PIX_MAXは、滑走面の状態によりますが、センシング用LEDの光が滑走面に「拡散反射」ではなく「鏡面反射」した光が入射したピクセルになると思います。要するに鏡面ハイライトの部分です。なので、白→黒で思ったよりShutter値が大きくならないし、ACUUMも小さくなるのでしょうね。

・トラッキングエラーの原因の予想
なんというか、データが予想外でした。

滑走面のコーティングのせいで鏡面ハイライトが出やすくなり、Shutter値が過剰反応して、実質的に使用できるダイナミックレンジが狭くなったことで上手くTrackingできなくなる、とかでしょうか。当該パッドでSQUALとか測ってみるとちょっと分かるのかもしれません。 そもそも鏡面ハイライトが原因である可能性があるというだけで断定ではないですが。
ちょっとやっただけでは原因は判明しそうもないですね。

当該マウスパッドでもトラッキングエラーをあまり出さないマウス(G400)もあるわけでして。実に奥が深いですね。
光路を弄って鏡面ハイライトが出にくいレンズ・・・とかあったり?
G400は純正レンズですが。MCUのコードを書いた人が凄腕なのでしょうか。さすがLogi・・・

・まとめ
まとめます。

・マウスパッドの拡散反射色によってピクセルアレイの(平均)輝度は変化する。
・鏡面ハイライトのピクセルがShutter値に大きく影響していると思われる。
・各マウスのセッティングに関しては考慮することが多くて断定できない。
・全ての柄パッドにこれが当てはまるとは限らない(と思います)。
- 個人的にはゲーム用途で柄パッドはもう買わない。定量的な根拠はないですが、これからは基本的に黒い無地パッドを選びます。

以上になります。1時間で済むと思ったらMCUのコードを書き直す事になり、2時間半かかりました・・・