マイコン工作実験日記

Microcontroller を用いての工作、実験記録

フレーム数が上がらない

2016-08-27 10:50:55 | CMOSカメラ
OV2640でのJPEG取得には成功したものの、使用しているPCLKが5MHzだと4フレーム/秒にしかなりません。これだと、動画撮影に使うには苦しいので、もう少し早くならないものかと試してみたのですが、うまくいきません。

これまでの設定だとXCLKとして20MHzを与えて、それをOV2640で4分周して5MHzのPCLKを作っていました。OV2640の設定を変更して、3分周にするとカメラからは次のように6FPSの信号が出力されるのですが、これを正しく受信できないでいます。実際の問題点は次の2点です。
  • JPEGデータの最初の1バイトが欠けてしまう
  • データ内容が化ける

まずは6FPSになった時の全体的なタイミングを確認。


4FPSの時と基本的に同じです。各フレームの間、VSYNCがLになっている期間はおよそ10msあります。VSYNCの立ち上がり部分を拡大してみると...


ここで示したPCLKはカメラからのPCLKとHREF信号のANDをとったもので、実際にデータを拾うべきタイミングを示しています。有効なPCLKは、VSYNCの立ち上がりから3μsほどで始まっっています。さらにZoomしてPCLKの周波数を確認してみると...


PCLKが7.5MHz近くになっています。20MHzを3分周する設定に変更したので、PCLKは6.6MHz程度になるものと思っていたのですが、そういうわけでもなさそうです。予想以上にPCLKが高いことがわかったので、対策としてPCKとHREFのANDをとるのに使っていた74HC00を74LCX08に変更することでゲート遅延を短縮してみたりもしてみましたが、状況に大きな変化無し。ちょっと残念ではありますが、4FPSが限界かな。

JPEG取得成功

2016-08-20 22:53:32 | CMOSカメラ
部品箱から74HC00を探し出したので、次のようにカメラとの接続を変更。


前回同様、PCLK 5MHz, 画像サイズQVGAで実験したところ、JPEG画像の取得に成功しました。



試行錯誤しながら実験してみてわかったかのは
  • タイマーの設定においてFilterを0に設定していると しばしば正常に画像がキャプチャできないことがあったので、フィルタ値として1を設定したところ安定して画像が取得できるようになった。
  • CLKRCの値を変更してPCLK周波数を6MHz以上にあげてみると、正しく画像データが取得できないみたい。
  • カメラからはSOIに始まってEOIで終わる完全なJPEGフォーマットが出力されるので、そのままファイルに落としてやれば画像ファイルとして使える。

タイマーキャプチャのクロックがHREFでゲートされたので、DMAバッファには綺麗にSOIで始まるデータが取得できるようになりました。



PCLKを早くすると、DMAでデータを取得するタイミングがうまく合わなくなるのか、データが正しく取得できないようです。74HC00を入れたためにPCLKにゲート遅延が生じてしまいキャプチャするタイミングがそれだけ遅くなってしまうことも悪影響を与えていると思われます。5MHzのPCLKでは、4フレーム弱程度の速度でしか画像を取得できないので動画撮影には遅すぎます。7フレーム/秒程度の動画撮影は出来るんじゃないかと想像していたので、ちょっと残念な実験結果です。

JPEG出力信号を確認する

2016-08-19 00:13:18 | CMOSカメラ
OV2640の出力する信号を確認するために、SaleaeのLogic 8を接続。8chなので、VSYNC, HREF, PCLKに加えてD7..D3の5ビット分のデータをキャプチャしてみました。

まずはJPEGモードではない、通常形式での出力の場合。



ひとつのVSYNC区間の間に、HREFがライン数回変化していることがわかります。PCLKは出っぱなし。
出力形式をJPEGに変更すると次のようになりました。



通常形式とは全く異なる、なんだかちょっと不思議なところもある信号です。
  • VSYNCにはひとつヒゲが出ていますが、SYSCLKよりも短いようなので無視しても大丈夫そうです。
  • HREFにもヒゲのように見える部分がありますが、こちらは10us程度の長さがあり、無視はできません。
  • HREFがLの時にPCLKが続けて出ていますが、この時のデータは無視しなければいけないようです。
  • HREFがHでもPCLKがでていない時の方が多い。


JPEG出力の始まりの部分をズームしてみると...



HREFが立ち上がって、すぐにSOI (0xFF, 0xD8) と APP0 (0xFF, 0xE0)がでているようです。
HREFでヒゲのように見えている部分も拡大してみると...



PCLKがしっかりと出ているので、この部分のデータは読み捨てなければいけないようです。GitHubにあった参考コードでは、HREFの変化を割り込みで検出してタイマーのキャプチャ動作を許可/禁止する仕掛けになっていましたが、PCLKの速度に比べてMCUのクロックが充分に早くないと処理が間に合いません。5MHzのPCLKでも画像がきちんと取得できなかったのは、これが原因ではないかと思われます。

HREFがLの期間のPCLKを無視するために、TIMERにはHREFとPCLKの論理積(AND)をとった信号を入れてやれば、問題を解決できるように思われます。

頭は見つかったものの...

2016-08-17 21:55:58 | CMOSカメラ
今回, OV2640を使ってみようと思い立ったのは、こちらの記事にて、「DCMIを使わずにSTM32にOV2640をつなぐ」というアイデアが紹介されていたのを見つけたのがきっかけです。また、STからはAN4666というAPノードが出ていることもわかりました。TIMERのインプットキャプチャ機能を使って、画素クロックの立ち上がりを検出してDMA要求を出させるというアイデアに、「なるほど、その手があったか!!」と感心したので、ぜひとも自分でも試してみたくなったのです。この記事では仕組みの概要やSTM32F4のコードも示されているものの、実際に取得してみた画像は示されておらず、あくまでもコンセプトを実証してみたという扱いにとどまっていることもちょっと気になったので、自分で確認してみようと思い立ったのです。わたしの場合、下図のようにつなげています。

  • PB6/PB7はもともとI2Cとして使っていましたが、OVとの相性が悪いことがわかったので、GPIOとして使い、ソフトI2Cにてレジスタ操作を行うことになりました。
  • PA8はMCOとして使い、SYSCLKの80Mhzを分周した20Mhzをカメラに供給。
  • PCLKからはカメラの設定に応じてXCLKを分周したものが出力されますが、TIM2をInput Captureモードで使うことで、その立ち上がりを検出します。
  • PB4とPB5はEXTIに設定して、同期信号の立ち上がり/立ち下がりを割り込みで検出します。
  • 実際にはPWDNとRESET信号もつないでいますが、図では省略。


ソフトI2Cにしたら、OV2640のレジスタアクセスは問題なく動作するようになったので、サンプルのコードを参考にしてSTM32CubeMXで生成したHALとFreeRTOSで動作するコードを作成。TIM2の入力キャプチャ動作を開始しておいて、VSYNCの立ち上がりを検出したらDMAでGPIOCの読みとりを開始させまます。JPEG画像情報の出力が終わるとVSYNCが落ちるのでDMAを止めて取得できたJPEG情報を確認するという具合です。

PCLKが5MHzになるようにOV2640のCLKRCレジスタを設定、画像サイズはQVGAに設定してやって、カメラから出力されるJPEGデータを取り込んだところ、次のようにJPEGファイルの頭の部分を見つけることができました。



0x2000135E番地からの 0xFF, 0xD8の2バイトがJPEGファイル構造の始まりを示すSOIになっており、続く2バイトの0xFF, 0xE0がAPP0の始まりになっています。そして、その後には量子化テーブルとハフマンテーブル定義が続いていますので、実際のフレーム情報はさらにその後ろに続いているだろうと思わます。DMAでメモリに読み込んだデータをファイルに落としてやれば、JPEGファイルとなるはずです。しかし、まだSDカードへの書き込みは作っていないので、確認のためにデバッガーを使ってメモリの内容をファイルに書き出してやることにしました。近頃、お気に入りのOzoneを使えばメモリ表示ウインドウからメニューを出してダンプしてやることができます。こんな手順で、JPEG画像ファイルが取得できるはずだったのですが....







何度試してみても綺麗な画像が取得できません。画像の途中でズレが生じてしまっています。途中で画素情報の取りこぼしが生じてしまっているように思われます。どうやら、1枚の画像情報を出力している間に何度かHREF信号が変化するらしく、この信号により画素情報の有効期間が通知されているようなのですが、その処理がうまくできていないようです。

そもそもカメラからどんな信号が出力されているのかを、ちゃんと確認しておかねばいけませんね。何しろ、ネットで入手できるOV2640のデータシートではそのあたりの詳細は説明されていませんので。

I2Cとの相性

2016-08-12 21:16:52 | CMOSカメラ
OV2460とNucleo-L476RGをつなぐための最低限の配線ができたので、続いてソフトの準備です。

まずはカメラのレジスタの読みとりができることの確認から。よく知られているようにOmnivisionのカメラの制御信号はSCCBと呼ばれていますが、物理的なインタフェースはI2Cと同じです。そこでSTM32L476側のI2CとつないでCubeMXのHAL_I2C_Mem_Read() APIを使ってアクセスを試みたものの、レジスタの読みとりができません。調べてみると、カメラに対してデバイスアドレスを送ったのに、ACKが返ってこないのでエラーとなっているようです。これがSCCBとI2Cの規格の違いで、I2Cにおいて ACKを返すべきところがSCCBではDon't careになっているために、このような不都合が生じます。この違いは想定内だったので、このエラーは無視して続いてレジスタの番号を送ろうとしたのですが、送信することができません。

マニュアルを読んで確認してみると、STM32L476のI2Cはアドレス指定の際にスレーブからのNAKを検出した時点で自動的にSTOPを送ってI2Cの動作を停止してしまうことが判明。確かにI2Cの機能としては便利な機能なんですが、これではSCCBとの接続には使えません。世の中にはSTM32とOminivionのカメラを接続している例はゴマンとあるので、みんなどうやっているのだろうかと思いSTM32F0やSTM32F4のマニュアルを確認してみると、I2C_CR1やI2C_CR2の構成が全然違います。HALレベルで使っていると、ハードの差異が隠蔽されてしまって気がつきませんが、どうやらこれまでのシリーズのI2CとSTM32L4のI2Cは別物と考えた方が良いようです。

こんなワケで、I2Cを使うのは断念して、GPIOを使ってのソフトI2Cでつなげることにします。

カメラのつなげ先

2016-08-07 23:54:00 | CMOSカメラ
OV2640を動かしてみるべく、さっそく接続動作試験用のボードを作成しました。OV2640はJPEGでの画像出力が可能なので、取得したJPEG画像をSDカードに記録してみようと思います。その先のことはまだ考えていないので、とりあえずスペースだけは残しておくことにします。



カメラのつなぎ先としては、SLICプロジェクトでも使ったNucleo-L476を使うことにしました。SLICプロジェクトで使ってみて、そのコスパの良さが気に入ったので、追加で買い置きしておいたものを使うことにします。SLIC遊びで使ったものはMouserで買ったのですが、このボードは後からRSで購入したのですが、今になってESシールが貼られていることに気がつきました。確かにESのチップが載っています。後から買ったボードの方が古いなんて。。(T_T)



STM32を使ってCMOSカメラをつなぐのであれば、本来であればDCMIを持ったデバイスを選択するのが一般的です。Nucleo64シリーズではSTM32F446を載せたNucleo-F446REがこれに相当します。しかしながらNucleo-F446REでは、DCMIに割り当てられた端子ががSDIOの端子とダブってしまっているために、DCMIを使うことにするとSDカードはSPIモードでつながざるをえなくなってしまいます。今回は手持ちのNucleo-F446REもないことですし、DCMIはないけどSDMMCをサポートするNucleo-L476RGを使ってCMOSカメラをつなげることにします。

OV2640

2016-08-05 12:49:59 | CMOSカメラ
SLIC遊びも発着信が一通りできるようになってから、いまひとつ新たな意欲がわかずに放置状態です。そんなこともあって、気分転換に久しぶりにCMOSカメラを買ってみました。



2MピクセルのOV2640です。じつは6月の終わりにeBayで買ったのですが、中国からの配達が遅れに遅れて1ヶ月かかりました。普通、2週間もあれば届くのに、予定配達期間を過ぎても届かないので、いい加減連絡しようと思ったら届きました。こんなに配達に時間がかかったのははじめてです。まぁ、送料無料で1,000円ちょっとなので、このくらいは覚悟しなければいけません。



裏側には1.8Vと2.8Vのレギュレータが載っているので、手間いらずでマイコンにつなげられます。このモジュールは正面左側にレバーみたいなものが付いています。横から見るとモジュール自体に結構厚みがあるので、これでズームの切り替えとかできるんでしょうか?





どうやら、レバーは3段階での切り替えができるようなんですが、どのように画像が変わるのかは動かしてみてのお楽しみです。