マイコン工作実験日記

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

UXGA画像の取得

2016-09-20 23:27:09 | CMOSカメラ



ようやくとNucleo-L476RGを使って、OV2640で撮影できる最大サイズのUXGA(1600×1200)の画像の取得ができました。

JPEG画像取得用のバッファ(jpeg_buffer)としては60KB分を用意しておき、

HAL_DMA_Start_IT(&hdma_tim2_ch1, (uint32_t)(&GPIOC->IDR), (uint32_t)jpeg_buffer, JPEG_BUFSIZE);

としてDMAでの読み出しを開始しています。DMAにはCircularモードを使っているので, バッファが一杯になったならば、バッファの最初に戻って読み込みデータが保存されていきます。バッファの半分まで読めた時と、最後まで読めた時に割り込みがかかりますので、それをトリガにすることでダブルバッファリングの処理を行うことができます。バッファの後半にカメラからのデータを読み出している間に、読み込みの終わったバッファ前半の内容をSDカードに書き出してやれば良いわけです。

このようにタイマーのキャプチャ機能を使ってDMAをかけることで画像を読み取ることはできましたが、UXGAでは1フレームの取得に1秒近くかかってしまっています。カメラの性能としては15fps出るはずですので、この点は残念なところです。

画像が安定するまで

2016-09-18 18:17:23 | CMOSカメラ
SDへの書き込みができるようなったので、連続して取得したJPEG画像をSDに保存してみました。

OV2640は連続して動かしていると、結構モジュールの基板が暖かくなります。データシートを読むと、YUVでデータ出力するよりもJPEG圧縮して出力する方が消費電集が増え、取得する画像のサイズにもよりますが100mA程度流れるようです。そこで普段はパワーダウンモードにしておき、撮影トリガが入ったら、カメラをアクティブにして画像を取得するのが良いだろうと考え、パワーダウンから回復した際の画像を確認してみました。実際の動作としては、パワーダウン状態を解除したのちに、カメラの初期化を行っています。露出やカラーバランスの設定は基本的にオートを選択していますが、オートの機能が有効に機能するためにはカメラモジュール内のDSPが取得した画像を調べて撮像するパラメータを調節するための時間が必要となります。そのため、初期化してから安定した画像が得られるまでにはしばらく時間がかかります。

今回は画像サイズとしてXGA(1024×768)を選択して、1フレーム取得したらそのデータをSDに保存してみました。


















最初のうちは妙に黄色っぽい画像だったのが、だんだんと白くなっていくのがわかります。STM32L476でXGAの画像データを安定して拾うためには、OV2640のCLKRCレジスタの分周比には8を設定する必要がありましたが、そうすると1フレーム分のデータを取得してデータを保存していると、次のフレームの始まりを検出するまでには4秒近くかかってしまっています。そのため、安定した画像を得られるまでには20秒以上も待たねばなりません。うーん、ちょっと時間かかりすぎるなぁ、やっぱDCMIを使って早いクロックで画像取り込まないと辛いなぁ。

今回はXGAで画像を取り込んでみましたが、JPEGでのデータサイズはおよそ60KBになっています。OV2640はUXGA(1600×1200)までのサイズの画像を撮影可能ですが、一旦すべての画像データを取り込んでからファイルへの書き込みを行っている現在の方式ではXGAが扱えるデータ量の限界です。STM32L476はSRAM1とSRAM2の領域が連続しており、合計で96KBの容量があるので画像の内容によってはSXGA(1280×1024)の画像を取得することもできるかもしれませんが、一度のDMAで指定できるデータ長が16ビット長, 64KBバイトという制限があるので、64KBを超える画像の取得のためにはDMA転送を複数回に分けて処理する必要が生じます。

9/19訂正
カメラからの画像は、5フレーム分を読み捨てた後に、1フレーム分のデータを取得しています。したがって、6フレーム毎にデータを取得して、それをSDカードに保存していますが、その間隔が4秒程度になっています。

JPEG画像をSDに保存しようとしたら

2016-09-17 11:33:23 | Weblog
これまでOV2640で撮像したJPEG画像はメモリ中にDMA転送して、そのデータをデバッガーの機能を使ってPCに書き出していました。実験ボードにはせっかくSDカードソケットを用意したので、次の段階としてJPEGデータをSD上に保存することにしました。STM32CubeMXを使えば、SDのドライバコードは生成してくれるし、FatFsもボタン一発で組み込んでくれるので、単純にFatFsのAPIを使ってメモリの内容を書き出してやればいいだけのはずだったのですが...

どういうわけか、SDへ書き込もうとするとエラーが発生してしまいます。エラーの原因を調べるとCRCエラーが発生しています。SD端子のプルアップを確認したり、クロック速度を大幅に落としてみたりもしたのですが。全く症状が変わりません。どうやら、原因はハードでは無いらしいと判断して、SDMMCのドライバコードの動作を確認していきました。使っているのは、STM32CubeMXが生成してくれたコードであり、自分が書いたコードでは無いので、当然動くものと思っていたのですが、動きを追っていくとCubeL4が提供するコードが間違っていることが判明しました。

SDのブロックを読み書きする際には


/* Configure the SD DPSM (Data Path State Machine) */
sdmmc_datainitstructure.DataTimeOut = SD_DATATIMEOUT;
sdmmc_datainitstructure.DataLength = BlockSize * NumberOfBlocks;
sdmmc_datainitstructure.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
sdmmc_datainitstructure.TransferDir = SDMMC_TRANSFER_DIR_TO_CARD;
sdmmc_datainitstructure.TransferMode = SDMMC_TRANSFER_MODE_BLOCK;
sdmmc_datainitstructure.DPSM = SDMMC_DPSM_ENABLE;
SDMMC_DataConfig(hsd->Instance, &sdmmc_datainitstructure);



というようにSDMMCを使って読み書きするブロックの長さを設定しています。上の例では512バイト長を指定しており、最終的にはSDMMC_DCTRLレジスタのDBLOCKSIZEフィールドに1001が設定されなければいけないのですが。実際には0101が設定されていることが判明。指定されたブロック長が間違っているので、計算したCRCの値が間違っており、エラーになっていたようです。指定が間違った原因を調査すると、STM32CubleL4 (V1.5)のデバイス依存部分を定義している stm32l476xx.hファイル中のSDMMC_DCTRL_DBLOCKSIZE_Xの定義が間違っていることがわかりました。

他のデバイス定義ファイルも見てみましたが、STM32L4シリーズのファイルは、全部間違っていました。こいうところが、STM32CubeとHALが嫌われる要因でしょうかね。


アイテムラボ閉店

2016-09-10 19:20:24 | Weblog
「ピッチ変換基板」や「パワーメッシュ基板」で知られるアイテムラボが今月いっぱいで閉店してしまいます。そろそろ補充注文しようと思って、久しぶりにホームページをおとずれたところ、閉店を知りました。

近頃では秋月でも変換基板やパワーメッシュ基板が購入できるようになり便利になりましたが、アイテムラボはその先駆けとして良質で使いやすい製品を提供してくれていました。パワーメッシ基板については、秋月のものよりもハンダブリッジがしやすくてとっても使いやすくて気に入っていたので、閉店はとっても残念です。そんなわけで、慌てて最後となる補充注文を済ませました。

商品は在庫がなくなり次第、販売終了とのことですので、皆さんもお早めに。


IEEE Maker Contest

2016-09-06 11:01:43 | Weblog
IEEEが Maker コンテストをやっているとは知りませんでした。
しかし、これはコンテストの応募ページが遊び場にされてしまったというお話です。



コンテストの応募作品には「トンデモ」なものも混じっていたのですが、まぁそこまではありがちな話。傑作なのは応募作品の「いいね!」ボタンを自動的に押すスクリプトというのが、応募作品のひとつとして掲載され、その方法がビデオで丁寧に説明されてしまったというところ。その影響もあってかどう見ても不正な投票数を持った作品が複数現れてしまったようです。

EEBlogでこの悲惨な状況とツールの存在が周知されてしまったことも災いしたのか、コンテストのページには「いいね! ボタン攻撃」が続いた模様。昨日はしばらくページにアクセスできない状態になっていました。今現在はサイトは回復し、不正なエントリーは削除されたようです。

画像サイズを変えてみる

2016-09-03 16:30:43 | CMOSカメラ
STM32L476を使ってのOV2640からのJPEG画像取得はフレームレートが上がらないようなので、今度は取得する画像サイズを変えて試してみました。画像サイズが大きくなると、サイズが小さい時と同じレートで画像を出力するにはPCLKの周波数を高くする必要が生じます。今回の実験ではPCLK周波数が高くなると画像をうまく読み取れないので、PCLKを低く抑えなければなりません。そのt目には画像サイズを大きくするに従い、PCLKを設定するための分周比を大きめに設定してやる必要があります。以下に、実験の結果取得できた画像とCLKRCレジスタに設定した分周比(DIV_CLK)の値を示します。

QVGA (DIV_CLK = 3)


VGA (DIV_CLK = 6)


SVGA (DIV_CLK = 7)


SVGAの画像ではおよそ1.7フレーム/秒程度になってしまいました。JPEGデータのサイズはSVGAでも32KBに満たない程度しかありませんので、STM32L476のRAM上に設けったバッファーにDMAで一度に読み取って保持しておくことができます。


ESP32とESP-WROOM-32

2016-09-02 22:01:03 | Weblog
EspressoのESP32の関連資料が整ってきています。TaobaoではすでにEPS32のチップの販売も始まっているようですが、中国国内限定のようで、国外の購入希望者はSalesにコンタクトしろとのこと。EPS32の資料ページによれば、モジュールとしてはESP-WROOM-32というのが用意されているらしいので、一般ユーザはこれ待ちですね。そして一部のデベロッパーは、デモボードも入手しているようです。

資料ページの記述を読んで初めて知ったのは、BluetoothがClassicとBLEのデュアルだということ。てっきり、Wifi+BLEだと思っていました。SDKを覗いてみると、RTOSはFreeRTOSでTCP/IPスタックにはLWIPが使われるようです。WiFi関連のAPIはあるようですが、Bluetooth関連のAPIはまだ何も無いようです。データシートによるとHCIをサポートしており、UART/SPI/SDIOのいずれか経由でHCIを使うようです。そのうちに、上位のプロファイルやAPIも用意されるのでしょうか?

JPEGデータの終わり

2016-09-01 20:45:50 | CMOSカメラ
OV2640の出力するJPEGデータについては、これまで始まりの部分にばかり着目していましたが、終わりの部分にも目を向けてみます。JPEGデータ出力の終了はVSYNC信号の変化で検出できますので、これを検出してGPIOからのDMA読み出しを止めてやることができます。実際に受信してみると、こうなりました。




左側のメモリ表示ウィンドウが、受信データ内容を示します。JPEGデータのDMA受信に先立って、あらかじめメモリは0xa5でフィルしてあります。EOIである0xFFD9を受信した後に、0x00を173(0xad)バイト受信していることがわかります。

右側のウインドウはVSYNCがかかる度ごとに、DMA受信したバイト数とEOIまでの有効データバイト数を示しています。このように、EOIの後ろに不要な0x00が何バイトが続いているようです。DMA受信バイト数がいつもキリのいい数字になっているので、おそらく出力処理の際にある程度バッファリングしている都合上、このようなデータが出力されるのでしょう。余分なデータは、そのままJPEGファイルに落としてしまっても害はありませんが、EOIの後のデータは捨ててしまうことにします。