ArduinoでVGA信号を読む
「VGA端子 - Wikipedia」を参考に、5, 6, 7, 8, 10ピンをGNDに、1, 2, 3ピンをそれぞれアナログピンに、13, 14ピンをデジタルピンに接続した。出力値が変動しているのを観察することができた。
ハードウェアをやる時も「早すぎる最適化は諸悪の根元」を唱えながらやるべきだな。ついついサイズを最適化したせいで半田付け大変だった。
横に伸びている3本はDisplay Data Channelとかいう、モニタのサイズや周波数を伝えるための信号線で、「繋がなくても大丈夫なはず、でも一番下の列だから『やっぱ繋がなきゃ』ってなったら後からハンダ付けは至難」と思って一応引っ張りだしておいた。結論から言うとこの3本はオープンなままで大丈夫だった。RGBの3本をアナログピンに、HSYNCとVSYNCをデジタルピンにつなぐ。
で、こんな感じのプログラムを走らせる。
void loop() { valR = analogRead(pinR); valG = analogRead(pinG); valB = analogRead(pinB); Serial.print(valR, HEX); Serial.print(','); Serial.print(valG, HEX); Serial.print(','); Serial.println(valB, HEX); }
「白と黄色と淡い緑が多いかな」ぐらいはわかるようだ。
ところでATMEGA168のクロックは16MHz、VGA信号は25MHz、1ピクセル単位で読むのが無理なのはわかっていたが、横方向のシグナルは8の倍数だから間引いて読むことができるんじゃないかなーと思っていた。しかし、カラーバーを出力する場合と違って、ただ読んだだけでは何も面白くない。読んだ結果を出力しないと。で、読んだものを送信するのにSerialライブラリを使うと当然そこがクロック数を食う。
水平同期信号を1バイトで送信する実装をしてみた。
void loop() { val = digitalRead(pinH); // read the input pin if(val == HIGH){ Serial.write(49); // ASCII for '1' }else{ Serial.write(48); // ASCII for '0' } }
結果に78文字ごとに改行を入れて1を.に置き換えて見やすくしたもの:
..........................................................................0... 0...0...0...0...0...0...0...0...0........................0.....0.........0.... ..0.........0......0.........0......0.........0......0.........0.............. ..0................0.........0......0.........0......0.........0.............. ..0......0.........0................0.........0......0.........0......0....... ..0......0.........0................0......0.........0.........0......0....... .........0.........0......0.........0......0.........0......0.........0......0 .........0................0................0.........0......0.........0......0 .........0................0................0................0................0 .........0......0.........0......0.........0................0................0 ................0.........0......0.........0......0.........0......0.........0 ................0................0................0.........0......0.........0 ......0.........0......0.........0......0.........0................0.........0 ......0.........0......0.........0......0.........0......0.........0.......... ......0................0................0................0.........0......0... ......0......0.........0......0.........0................0................0... ......0......0.........0......0.........0......0.........0................0... ...0.........0.........0......0.........0......0.........0......0.........0... .............0......0.........0......0.........0................0.........0... ...0.........0......0.........0......0.........0................0............. ...0.........0......0.........0......0.........0......0.........0......0...... ...0................0......0.0.......0................0.........0......0...... ...0......0.........0................0................0......0..0......0...... ...0......0.........0......0.........0......0.........0................0...... 0.........0......0.........0................0.........0......0.........0...... 0.........0......0.........0................0................0................ 0.........0......0.........0......0.........0................0................ 0.........0......0.........0......0.........0......0.........0......0......... 0......0.........0......0.........0.........0......0.........0......0......... 0......0.........0......0.........0......0.........0......0.........0......... 0......0................0.........0......0.........0......0.........0......0.. .......0......0.........0.........0......0.........0......0.........0......0..
うーむ、全然サンプリング周波数が足りてない感。
void loop(){ if(micros() < 1000000){ Serial.write(48); // ASCII for '0' } }
これで1089個の0が送られてくる。1文字あたり918usec。VGA信号の1行は 800クロック / 25.175MHzで 31.8usec。シリアルで送るのは無理だなぁ。
画面のある領域が特定の色になったらデジタルピンに出力、とかだとできるかもしれないけど深追いはやめておこう。