Arduino DUEのCPUパワー(@84MHz)を最大限使って制御した、VGAカメラOV7670モジュール(下図、および記事)を、今度はCmod A7ボード(FPGA)を使って、サクッと、制御してみたいと思います。
OV7670モジュールを、「再び、三度、四度、……」と、もっと気軽にサクッと使える様にハードウェア(FPGA)の底力を存分に発揮しようとするテーマの第4話(最終話)です(第1話は、こちら)。
以下に、CAM7670ユニットを使ってOV7670から画像データを取得するプログラムをリンクしておきます。
完成プログラム:digi_cam.asm、ov7670.incl
アセンブルしてCmod A7ボードに書き込むと、シリアルモニタから以下のコマンドを受け付けるようになっています。
シリアルモニタコマンド仕様:
OV7670内部I/Oレジスタアクセスは、データシート上、I2Cとは謳っておらず、SCCBインターフェイスという独自仕様です。ただし、基本的なプロトコルはI2Cなので、I2C通信としてアクセス可能です。
さてさて、OV7670のSCCBデータシートを探して読んでみたところ、SMBusプロトコルっぽいアクセスなのですが、I2Cで言う所の反復STARTコンディションが使えないみたいです。
今回、MoscoviumのSTWSERユニットを使ってI2C通信する時、反復STARTコンディション(R)を発行するプログラムを組んでいたため、OV7670にアクセスできない現象に遭遇しました。SCCBデータシートを確認したことで、反復STARTコンディションがダメだと判ったので、プログラムを修正して、問題は解決しました。
そもそも当初、何で反復STARTコンディションを使ってしまったのか?と言うと、実はDUEでOV7670を制御した時、「Wire.endTransmission (false);」として、反復STARTコンディション(R)を発行していたからなのです(DUEのプログラムはこちら)。
アレレ?それにもかかわらず、「DUEではアクセスできていたよね?」と、改めてDUEを接続してアクセスしてみたところ、やっぱりアクセスできてしまいました。
「これは、STWSERユニットのバグ🐞?」
と、焦って解析する羽目に……(下図)!
※我が事ながら、他人様の間違いより先に自分の間違いを疑ってみる辺り、歳は取っても技術者として、まだまだ腐っていないな、と思いました(1^−^)d。
上図は、DUEの「Wire.endTransmission (false);」で発行した、SMBusバイト読み出しサイクルの様子です。ロジアナで取り込んだ、実際の波形です。上段がSCL、下段がSDA信号の波形と、なっています。
I2Cプロトコル、読めますかね……?
192μs辺りに、「Wire.endTransmission (false);」にて発行された反復STARTコンディション(R)があるはず、なのですが……:
「Wire.endTransmission (false);」なのに、STOPコンディション(P)+STARTコンディション(S)が発行されています。
これは、「Wire.endTransmission (true);」の時に発行されるべきプロトコルで、誤りです。誤った結果、OV7670のプロトコルに即しているため、問題なくアクセスできていた事が判りました。
※引数falseは、「STOPコンディションを発行しない」という引数だからね!STOPコンディションが発行されたらダメなのよ。
結論としては、STWSERユニットの動作は正しくて、DUEのWireクラスライブラリが間違っている事が判明しました。DUEのWireクラスライブラリでは、「Wire.endTransmission (false);」を使っても反復STARTコンディションが発行されないので、I2Cバスをマルチバスマスタで使った場合に、SMBusプロトコルでのアクセスを誤る可能性があります。
あんまり、I2Cをマルチバスマスタで使う機会が無いので、特に問題発生しないかも?ですが、ご注意ください。
※シミュレーション波形ですが、STWSERユニットが発行する反復STARTコンディションの波形は、こちらでご確認いただけます。
システム検討、アダプタボード工作、ハードウェア設計、ソフトウェア設計、と進めてきて、ようやく実験で動作を確認できます。Cmod A7ボード(FPGA)には、こちらのマイコンMCOC115SV0832と、プログラムを書き込んでおいてください。
以下、実験中の様子です。
上写真の方向で、VGAサイズ(640×480[ドット]横長)の画像が取得できます。ただし、180°回転してしまうため、OV7670のI/Oレジスタで、ミラー反転&縦軸反転オプションを設定して、向きを修正してあります。
DUE+OV7670での実験中の様子と比べて、配線がスッキリしていますでしょう?苦労して工作したアダプタボードのお陰です。アダプタボードをPMODコネクタに装着して、追加の信号線(RET,PDN,SCL,SDA)4本をジャンパ線で接続したら終了です。
以下に、接続表を示しておきます。DUE+OV7670での接続表とは大違い、簡単です。これなら気軽にOV7670モジュールを使えそうですね?
Cmod A7ボード | 接続 |
アダプタボード (OV7670) |
PMODコネクタ | ⇔ | PMOD接続用ピンヘッダ |
port_iop[7] | → | RET |
GND | → | PDN |
stws_scl | ⇔ | SCL |
stws_sda | ⇔ | SDA |
※アダプタボードには、OV7670モジュールを装着してください。向きを間違えないように。
具体的に実験を進めましょう。
実験サンプル:【 】内はシリアルモニタからの送信データ
【rd1,0a】
OK: rd1[0x0a]=0x76
【rd1,0b】
OK: rd1[0x0b]=0x73
I2C通信で、OV7670のI/Oレジスタアドレス0x0aと0x0b(製品ID番号レジスタPID,VER)を読み出しました。OV7670データシートに記載の通り、0x76と0x73が読み出せたら、I/Oレジスタアクセスは、できています。
では、カメラを被写体に向けて、実験を継続しましょう。
【take】
OK: take
「OK:」応答が返ったら、1フレームの撮影が正常終了しました。もし、「ERR:」メッセージが返ったら、FIFOがフルになったエラー終了です。PCLK周波数が速すぎるので、周波数を落として再試行してください。PCLKの周波数制御方法に関しては、こちらを参照してください。
現在のプログラムでは、PCLK=XCLK÷8、XCLKは12MHzですので、PCLKは1.5MHzで調整してあります。
ハードウェアによるデータ取り込みは、30FPS(PCLK≒24MHz)取り込み可能な実力があるのですが、取り込んだデータをMoscovium @24MHzがハンドリングして、SRAM(512Kバイト)に書き込むのが間に合わないため、これ以上周波数を上げてしまうと、FIFOフルのエラーが発生します。
PCLK=1.5MHzは、約0.53[s/フレーム]のスピードです。DUE @84MHzで実験した時は、1.26[s/フレーム]でしたので、24MHzのMoscoviumが凌駕しています。これがハードウェアの実力です(1^−^)v。
※ハードウェアの実力では、30FPS(≒0.033[s/フレーム]以上)で取り込む能力があります、念のため。Moscoviumで0.53[s/フレーム]に留まっているのは、取り込んだ後のソフトウェア処理が追い付かないためです。
今、撮影したフレームデータはSRAMに蓄えられているので、これをPCにダウンロードしてみましょう。Tera Termなど、ログを記録可能な通信ソフトウェアを使い、ログ出力を有効にしてから、以下を実行してみてください。
【save】
SAVE
AAAAAAAAAAAAAAAM99//////////////////……
:
: (中略)
:
AAAAAAAAAAAAAAAM99//////////////////……
END
OK: save n_line=0x01e0
大量のデータ(VGAサイズだと、約300Kバイト)をダウンロードする事になりますので、通信速度を高速(115,200baudや、それ以上)に設定してお試しください。こちらの【vgaqq】コマンドなどで、画像サイズを小さく設定してから【take】コマンドを実行すれば、データ量を削減することもできます。
※Tare Term等、通信ソフトウェアの通信速度を変更設定した後で、Moscoviumに対して【U】コマンドを送信すると、自動的に新しい通信速度へ追従するようにプログラムしてあります。
ログファイルを閉じて、ファイル名を「ov7670_show_save.txt」に変更し、以下スクリプトを実行すると、画像を確認することができます。
画像表示スクリプト:ov7670_show_save.olv
※スクリプト(.olv)の実行には拙作Olive+をWindowsにインストールしてください。
スクリプトによる処理のため、描画は遅いです。一度描画したら、JPEG等の画像ファイルにセーブしておきましょう。……と、この程度の色数(64色)だと、JPEGよりPNGの方がファイルサイズが小さくなりました。Olive+なら、xPICの方が、さらに小さくセーブできます(お勧め)。
当方で撮影した、画像サンプルを以下に示します。
解像度はVGA(640×480[ドット])ですが、6ビットカラー(64色)のデータなので、画質としては、こんなもの(↑)です。ちなみにモデルさんは、再び登場のドロッセルお嬢様です。
色数が64色と少ないのは、OV7670が出力してくるデータバス8ビットの内、4ビットしか参照(接続)していないためです。全8ビットを取り込むと、接続すべき配線数が増えるし、1フレーム分のデータ容量も倍(1フレーム当たり600Kバイト必要)となってメモリも不足します。非力な組み込み用途マイコンで扱い易い様に画質を低下させたのは、意図した目標仕様通りです。
ご覧頂いた様に、画質が低く、「デジタルカメラ」として使うには不向きです。たったの64色なので、カラー画像とは思わず、グレイスケール画像に毛の生えたような物と考えて、画像認識や識別などの用途に活用するには、十分使い物になると推測します。
ひとまず、接続する信号線数の削減と、色数削減を実施して、OV7670モジュール(VGAカメラ)をCmod A7ボード(FPGA)に接続する所まで完了しました。まだ、1フレームのデータ容量300Kバイトと巨大なので、次は解像度の削減に取り組んで行きたいと思います。暫し、お待ちください。