OV7670カメラを液晶に動画として表示するための資料とポイント。
OV7670をマイコンで制御して、ちっこいTFT液晶に動画表示させるための資料集めと、ポイントを記録しておきます。2年ぐらいたつとほとんど忘れてしまうので。
概略 随時更新予定。
ざっくりした制御は、3つの割り込み信号に同期して、垂れ流しにされてくる8ビットパラレルピクセルデータを、1バイトずつ拾って行く作業になります。
ピクセルデータが溜まったら、TFT液晶に行または、ページデータを転送します。次のデータが来る前に、データを液晶に、転送させます。RAMが十分大きければ、1画面全体をRAM上に展開できます。
おおまかな流れは、これだけで、思ったほど複雑なことはしていません。
繰り返しになりますが、基本動作は、カメラからの3つの割り込みに同期した8ビットパラレルデータを取得するだけです。
カメラの設定項目がかなりあるので、最初は、ネット上のOV7670カメラのコードを参考にするのが、ベストです。
カメラの設定は、I2C似たSCCBという通信規約で行います。PICマイコンの場合、I2CモジュールのACK確認を素通りさせるだけで、通信できます。
カメラの設定と、液晶の設定を合わせること。ハードの選定と、回路をくみ上げること。地道な作業が、続きますが、一つ一つ丁寧にこなしていくことになります。
ソフト開発を楽にするために、できるだけ高スペックなマイコンを選定、特に、32ビットマイコンがおすすめです。
OV7670のレジスタ初期化値で参考にしたもの。
1.ネット上のarduinoのソースコード
レジスタ名もdefine定義されているので、可読性がよい。
2.トラ技2012年3月号掲載P.65
0x01から、0xe9までのレジスタ設定値一覧。
◆adurinoの初期化値を参考にして、移植するのがベスト。
◆画面の大きさは、液晶を使うならQQVGA(120×160)。
◆液晶は、ST7735S 1.8inch 120×160ピクセル
◆液晶側の初期化と、カメラの初期値を合わせる必要がある。
液晶側の初期化処理もある程度理解しておくこと。色相反転などの設定や、RGB444、RGB565などバイトの色設定もカメラと合わせる。ここがあいまいだと、カメラと液晶側の不具合切り分けができなくなる。
液晶側の設定を、カメラに対応できるよう、液晶ドライバーを先に完成させておくと楽です。
マイコンの処理速度と必要メモリ
システムクロックが最低50Mhz、DMAが搭載しているもの。180Mhz以上ならDMAを使わなくても、QQVGAに動画表示可能。
問題なく動作させたいなら、
1.システムクロック 50Mhz以上。
2.できれば、DMA転送 2つ以上搭載したマイコン。
3.28ピン以上のマイコン。もしくは、28ピン2台で、SCCB担当と、カメラ表示担当に分ける。
4.RAMはQQVGAの場合、行データ160×2byte=320byteをバッファとして使用。一画面キャプチャーだと160×120×2=38kb必要。
動画表示だけなら、一行ずつ、TFT液晶のRAMに転送して、1画面表示できるので、さほど大きなRAMは必要としません。
先に表示画面の大きさを決めてから、マイコンを選定するといいです。
今回は、PIC32MX370F512 SYSCLK=96MHz RAM=128kBで動かしました。
OV7670カメラに供給するクロック
OV7670のXCLK端子に10Mhzから24Mhzを供給します。
1.マイコンから供給
システムクロックを端子から出力できるマイコンがあります。注意点は、高速になるにつれ、出力波形が崩れる可能性があります。PIC32MXには、システムクロックを端子から出力する機能があります。
※24.11.17 プルダウン抵抗をつけたら、調子が良くなって速度が安定しました。
※24.12.11 システムクロックを、内臓RCオシレータから、外付けセラロックにしたら安定しました。
2.セラロックと、74HC04のクロック回路から供給。
この場合、マイコン端子からの供給より確実に20Mhzくらいのクロックを正確に供給できますが、回路が増えます。28ピンマイコンで制御する場合、この方法がベスト。
OV7670 SCCB通信
上記で触れた、カメラの初期化、レジスタを設定する通信規約です。I2Cとほぼ同じ動作です。
基本的に、選定したマイコンのI2Cモジュールがレジスタベースの制御で通信できているのなら、ACK返信のところをSCCB規約に変更するだけで、使用することができます。
PICマイコンの場合、I2Cモジュールのレジスタを使って、スタート、ACK確認、送信、受信、ストップを制御して通信しているコードの、ACK確認のところだけを改造するだけで、動きます。
具体的には、ACK確認のシーケンスが来たら、ACK,NACKの判定をせず、素通りさせるようにします。
bool I2C2_Wait_Ack(bool _sccb)
{
signed int i;
if(_sccb)return true;
for(i=0x7FFF; i; i--)
{
if(!I2C2STATbits.ACKSTAT)
return true;
}
return false;
}
OV7670 垂直同期、水平同期、ピクセル同期
OV7670から3つの信号線が出ています。この3つの信号線と、8ビットパラレルラインがあります。
VSYNC:垂直同期:画面同期。画面表示スタート時、Highになる信号。
HREF:水平同期:1行データ出力時、High。出力終了で、lowになる信号。
PCLK:ピクセル同期:8bitパラレルのピクセルデータがこの信号に同期して出力。
この3つの信号線を、マイコンの3つの外部入力割り込みで補足し、8ビットデータを受信します。
先に3つの割り込み入力を作成して、物理スイッチのON,OFFでLEDを点滅させるコードを作っておきます。
3つの割り込みが正確に動作できれば、あとは、この3つの割り込みに、水平、垂直、ピクセルの3つの同期信号を割り振るだけで済みます。
液晶表示方法(行単位)
マイコンのシステムクロックが遅く、RAMが小さい場合に有効です。
1画面分(QQVGA120×160)をRAMに確保する場合、RAMは、38kB以上必要になります。32ビットマイコンなら、スペックとしてありますが、16ビット、8ビットマイコンで、画面をすべてを、RAMに確保することは難しいです。
なので、1行単位で処理することになります。
QQVGAの場合、1行データ160×2バイト(RGB565)を受信したらすぐに、液晶に行データを送信します。
SPI通信を使用して液晶にデータを送信しますが、ここでDMA転送を使用すれば、圧倒的に転送が速くなり、
次の行データの受信に間に合います。行と行のデータ受信の合間に、液晶に行を表示させるので、転送スピードが必要になってきます。この辺は、実際に回路を組んでみて、動かしながら調整することになります。