先ごろ、ATMELが新しいARM9製品としてSAM9X等を発表したのですが、気が付くと自分がいままで使ってきたSAM9260はLegacy Productsに区分されていまっています。すぐに生産中止になるわけではなさそうですが、9G20あたりへの移行が進んでいく気配が感じられます。
ちょっと遊んでみたいことができて、久しぶりにCMOSカメラ実験用のARM9ボードをひっぱりだしました。
ところが、USBケーブルをつないで電源を入れても、何の反応も無し。仮想シリアルポートとして動くはずなのに、どうしたことか? しょうがないのでフラッシュの内容を書き直してみようと思い、SAMBAジャンパを飛ばして、電源を入れ直し。ところが、それでも何の反応も無し。SAMBAが動きません。ちょっと、あせってきました。
原因調査のためにJTAGで見るかと考え、急遽JTAGコネクタを付けてみました。ところが、それでもデバイスがつながって見えていないようです。「JTAGでも見れないということは、AT91SAM9260を飛ばしてしまったんだろうか?」かなり不安になってきました。
電源を示す赤色LEDは点灯しているので、電源はちゃんと入っています。回路図で再度確認すると、LEDの点灯は3.3Vが来ていることを示しています。と、ここまできて、ようやく気が付きました。ボードにはもうひとつの電源 -- VDDBU、すなわちバックアップ用電池があることに。このボード、出荷時の結線ではDC電源が供給されていても、VDDBUは常に電池から供給されるようになっています。バックアップ電池のCR2032を取り出して、電圧を計ってみると...0.2Vしかありません!! 長らく放置している間に完全に放電されていたようです。
電池を入れ代えると、問題無く動いてくれました。AT91SAM9260は、ブート直後は32KHzのスロークロックで動作を開始するのですが、この部分の電源がVDDBUなので、電池が切れて全く動けなくなっていたというオチでした。
ところが、USBケーブルをつないで電源を入れても、何の反応も無し。仮想シリアルポートとして動くはずなのに、どうしたことか? しょうがないのでフラッシュの内容を書き直してみようと思い、SAMBAジャンパを飛ばして、電源を入れ直し。ところが、それでも何の反応も無し。SAMBAが動きません。ちょっと、あせってきました。
原因調査のためにJTAGで見るかと考え、急遽JTAGコネクタを付けてみました。ところが、それでもデバイスがつながって見えていないようです。「JTAGでも見れないということは、AT91SAM9260を飛ばしてしまったんだろうか?」かなり不安になってきました。
電源を示す赤色LEDは点灯しているので、電源はちゃんと入っています。回路図で再度確認すると、LEDの点灯は3.3Vが来ていることを示しています。と、ここまできて、ようやく気が付きました。ボードにはもうひとつの電源 -- VDDBU、すなわちバックアップ用電池があることに。このボード、出荷時の結線ではDC電源が供給されていても、VDDBUは常に電池から供給されるようになっています。バックアップ電池のCR2032を取り出して、電圧を計ってみると...0.2Vしかありません!! 長らく放置している間に完全に放電されていたようです。
電池を入れ代えると、問題無く動いてくれました。AT91SAM9260は、ブート直後は32KHzのスロークロックで動作を開始するのですが、この部分の電源がVDDBUなので、電池が切れて全く動けなくなっていたというオチでした。
JPEGの伸長、表示ができたので、次は当然の帰結として(?)スライド・ショーです。とは言っても、単純に順に表示していくだけで、何の芸当もないんですけど。でも、自作環境で、デジカメで撮った画を表示してみたかったんですよぉ。これまでは、SDカードに保存された画像を表示するにしても、BMPとかに変換していましたからね。JPEGファイルのままで表示できるだけで、単純に嬉しいです。
JPEGを伸長した結果を直接LCDに書き出してもいいのですが、そうすると伸長処理に時間がかかっているのが丸見えなので、いったんメモリ中に展開した後に一気にLCDにコピーすることで表示を切り替えています。
JPEGを伸長した結果を直接LCDに書き出してもいいのですが、そうすると伸長処理に時間がかかっているのが丸見えなので、いったんメモリ中に展開した後に一気にLCDにコピーすることで表示を切り替えています。
ATMEL用語ではI2CインタフェースのことをTWI (Two Wire Interface)と呼んでいます。MCKを100MHzにしつつCMOSカメラをI2Cで使いたいのですが、どうもAT91SAM9260のTWIを使ってI2C制御しているとうまく動いてくれません。検索をかけてみるといくつかのMLでも同様の問題が報告されているようです。
思ったように動いてくれないという点では、わたしもまったく同感です。そこで、LM-Sensorな人たちと同じようにTWIを使うのをあきらめて、Bit-Bang、すなわちソフトウェアI2Cすることにしました。TWIの割り当てられているポートの設定を変更して、ドライバを書き直すだけですから、配線の変更は必要ありません。ソフトの修正だけで対応できます。
はい、きれいに動くようになりました。もちろん、MCKももとどおりです。これまではレジスタダンプを実行すると、少なくとも5回に1回はエラーが発生していたのですが、もうそんな問題は発生しません。CMOSカメラには何の問題もないことがわかってスッキリですが、TWIがどのように悪いのかはまだはっきりとわかっていません。
- LM-sensorsを使っている人なんかは、TWIを使わずにGPIOでBit-Bangして動かしているようです。
- AT91SAM9260のデータシートにはTWI関連のErrataは載っていないのですが、AT91SAM9261のデータシートにはErrattaがあります。AT91SAM9260のTWIはちゃんと動くの?
AT91SAM9260のTWIはいかれていて、ドキュメントのとおりにはちっとも動かん
と言い切っている人もいるようです。
思ったように動いてくれないという点では、わたしもまったく同感です。そこで、LM-Sensorな人たちと同じようにTWIを使うのをあきらめて、Bit-Bang、すなわちソフトウェアI2Cすることにしました。TWIの割り当てられているポートの設定を変更して、ドライバを書き直すだけですから、配線の変更は必要ありません。ソフトの修正だけで対応できます。
はい、きれいに動くようになりました。もちろん、MCKももとどおりです。これまではレジスタダンプを実行すると、少なくとも5回に1回はエラーが発生していたのですが、もうそんな問題は発生しません。CMOSカメラには何の問題もないことがわかってスッキリですが、TWIがどのように悪いのかはまだはっきりとわかっていません。
JPEGの圧縮と伸長の両方が動くようになったものの、ちょと時間かかり過ぎているなぁと感じていたのですが、大事なことを忘れていたことに今頃になって気がつきました。
カメラをつなげた際に I2Cがうまく動いてくれずに悩んでいましたが、MCKを半分にしたところ動くようになったので、この設定で動かしていたのでした。MCKはほとんどのペリフェラルでのマスタークロックですので、これを半分にするということは、ほとんどのI/O処理時間が倍になることを意味します。JPEG圧縮/伸長はI/OではなくてCPU boundな処理だからということで、DTCの計算方式を確認してみたりしていたのですが、MCKはそのままSDRAMへのクロック供給信号であるSDRAMCになっていることに気付かずにいました。つまり、これまでメモリは100MHz近いクロックで動かせるところを半分の50MHzで動かしていたことになります。
さっそくMCKを元に戻して、JPEG伸長を確認してみました。
しかしながら、MCKを速くするとカメラのI2C制御がうまくできなくなってしまう問題が発生してしまいます。そのため、画像の撮影ができません。まずはこのI2Cの問題をなんとかしないといかんようです。
カメラをつなげた際に I2Cがうまく動いてくれずに悩んでいましたが、MCKを半分にしたところ動くようになったので、この設定で動かしていたのでした。MCKはほとんどのペリフェラルでのマスタークロックですので、これを半分にするということは、ほとんどのI/O処理時間が倍になることを意味します。JPEG圧縮/伸長はI/OではなくてCPU boundな処理だからということで、DTCの計算方式を確認してみたりしていたのですが、MCKはそのままSDRAMへのクロック供給信号であるSDRAMCになっていることに気付かずにいました。つまり、これまでメモリは100MHz近いクロックで動かせるところを半分の50MHzで動かしていたことになります。
さっそくMCKを元に戻して、JPEG伸長を確認してみました。
やっぱり!です。こんなに簡単に2倍近く速くなるとは。
しかしながら、MCKを速くするとカメラのI2C制御がうまくできなくなってしまう問題が発生してしまいます。そのため、画像の撮影ができません。まずはこのI2Cの問題をなんとかしないといかんようです。
CMOSカメラで撮影した画像をJPEG圧縮できたので、次の実験は当然ながらその伸長です。今回はファイルから読みだして、伸長しながら表示してみることにしました。libjpegはもともとstdioを使って開いたファイルから画像を読み出すためのモジュールとして jpeg_stdio_src()が用意されていますので、こいつをチョットいじってFatFsのAPI に変更してやればいいだけのことでした。
元画像は先週圧縮したものでVGA(640X480)サイズです。LCDのサイズはQVGAですので縦横を半分にしてやる必要があります。幸いなことにlibjpegでは伸長の際のパラメータとして縮小率を 1/1, 1/2, 1/4 または1/8のいずれかを指定できるようになっていますので、この機能を使って1/2に縮小し、スキャンライン毎にLCDに表示してやります。
例によってISLOWとIFASTの両方を試してみましたが、圧縮の時ほどの差異はみられません。処理時間は圧縮の時と比べて短いですが、縮小しているために画素数が少なくなっているのも影響しているのでしょう。
わたしはいつもブログで使う写真はVGAサイズで撮っていますので、これらのファイルも表示できるはずです。試しにこの画像ファイルで実験してみると。。
おやおや、ずいぶんと時間がかかるようになりました。デジカメで撮ったJPEGファイルとの大きな違いはファイルのサイズです。自分で撮影、圧縮する際にはqualityを85に設定していたので、PIC001.JPGのファイルサイズは44KBほどです。それに対してデジカメで撮影したPIC002.JPGでは200KB近い大きさになっています。当然、quality=100に相当するファイルになっているのでしょう。この違いが、処理時間の違いとして現われてきているようです。
と、ここまで書いてlibjpegがバージョンアップされていることに気が付きました。ショック! 現在の作業は5月にダウンロードした Version 6bに基づいています。98年にリリースされていらい更新されていないすっかり枯れたコードだと思っていたのですが、先月11年ぶりにVersion 7が出ているようです(驚き)。このバージョンでは N/8 (1<=N<=16)のスケーリングができるようですので、こっちの方が便利かも。
元画像は先週圧縮したものでVGA(640X480)サイズです。LCDのサイズはQVGAですので縦横を半分にしてやる必要があります。幸いなことにlibjpegでは伸長の際のパラメータとして縮小率を 1/1, 1/2, 1/4 または1/8のいずれかを指定できるようになっていますので、この機能を使って1/2に縮小し、スキャンライン毎にLCDに表示してやります。
例によってISLOWとIFASTの両方を試してみましたが、圧縮の時ほどの差異はみられません。処理時間は圧縮の時と比べて短いですが、縮小しているために画素数が少なくなっているのも影響しているのでしょう。
わたしはいつもブログで使う写真はVGAサイズで撮っていますので、これらのファイルも表示できるはずです。試しにこの画像ファイルで実験してみると。。
おやおや、ずいぶんと時間がかかるようになりました。デジカメで撮ったJPEGファイルとの大きな違いはファイルのサイズです。自分で撮影、圧縮する際にはqualityを85に設定していたので、PIC001.JPGのファイルサイズは44KBほどです。それに対してデジカメで撮影したPIC002.JPGでは200KB近い大きさになっています。当然、quality=100に相当するファイルになっているのでしょう。この違いが、処理時間の違いとして現われてきているようです。
と、ここまで書いてlibjpegがバージョンアップされていることに気が付きました。ショック! 現在の作業は5月にダウンロードした Version 6bに基づいています。98年にリリースされていらい更新されていないすっかり枯れたコードだと思っていたのですが、先月11年ぶりにVersion 7が出ているようです(驚き)。このバージョンでは N/8 (1<=N<=16)のスケーリングができるようですので、こっちの方が便利かも。
SDカードが直ったので、撮影した画像をJPEG形式でSDカードに保存できるようにしようとしています。まずは、画像をJPEG圧縮すべくIJGのライブラリをARM9にもってきました。AT91SAM9260のISIでキャプチャした画像はSDRAM上に展開されていますので、メモリ上のイメージを圧縮して別のメモリ上にいったん保存してから、SDカードに書き出すことにします。
IJGのライブラリに付属するサンプルプログラムはファイルを入出力対象としていますので、メモリを入出力対象としたプログラムを用意してやる必要があります。この部分については先人のコードをそのまま流用させていただきました。
さっそくVGA画像を撮影、圧縮してみると....
圧縮処理で4.3秒かかっています。実際に待っていると、かなり長く感じます。もうちょっと短くならないと。。。 圧縮時に指定している quality が85となっていたので、これを下げることで圧縮処理時間が短縮できないかと思ったのですが。。。
確かに短くはなるのですが、ごくわずかですね。時間よりもサイズの方の効果が大ですね。これなら quality は85でもよろしいかと。
DCTの計算ルーチンを変更すると、精度は落ちるものの処理速度が向上できるらしいので、次回はこれを試してみようと思います。
IJGのライブラリに付属するサンプルプログラムはファイルを入出力対象としていますので、メモリを入出力対象としたプログラムを用意してやる必要があります。この部分については先人のコードをそのまま流用させていただきました。
さっそくVGA画像を撮影、圧縮してみると....
圧縮処理で4.3秒かかっています。実際に待っていると、かなり長く感じます。もうちょっと短くならないと。。。 圧縮時に指定している quality が85となっていたので、これを下げることで圧縮処理時間が短縮できないかと思ったのですが。。。
確かに短くはなるのですが、ごくわずかですね。時間よりもサイズの方の効果が大ですね。これなら quality は85でもよろしいかと。
DCTの計算ルーチンを変更すると、精度は落ちるものの処理速度が向上できるらしいので、次回はこれを試してみようと思います。
トランジスタ技術7月号のCMOSイメージ・センサの特集記事を読んでいたら、自分のCMOSカメラももう少し遊んでみたくなってきました。記事のレジスタ解説をみると、型番こそ違いますが、どうやら同じOmniVisionのCMOSカメラをベースとしたカメラモジュールを使っているようです。
カメラの実験に使用したMMnet1002ボードにはマイクロSDのソケットが載っていますが、いつの間にかSDカードのアクセスが全く動作しなくなっていました。そのために、カメラ画像の確認はSAM-BAを使ってPCに吸い上げてから、フォーマット変換をおこなってPC上で確認していました。SDカードさえちゃんと動作してくれれば、MMnet1002上でJPEGに変換してSDカードに書き出すことができるはずです。せっかく買ったMMnet1002ですので、SDカードを再度使えるようにして、この実験もやってみたいものです。
そんなわけで、SDカードを修理してみることにしました。以前はちゃんと動作していたので、おそらくはSDカード・ソケットの接触不良に違いありません。SDカード関連の信号線はカメラでは全く使っていませんし。マイクロSDソケットの配線を確認してみると、案の定 ソケット5番ピン(CLK)とCPUのPA8/MCCKピンの接続が不良になっていることが判明。どうやらマイクロSDソケットのはんだ付け不良のようです。コテにハンダを少量つけて、5番ピンにハンダを盛りなおしたところ、接続回復。以前実験した、FatFsでのLFN機能の動作が再度確認できました。
どうやらSDカードを何度か抜き挿ししているうちに、ハンダ不良だった5番ピンが完全に浮いてしまっていたようです。SAM-BAジャンパの100Ω抵抗のつけ忘れといい、どうもこのMMnet1002の製造品質には問題多いようです。
カメラの実験に使用したMMnet1002ボードにはマイクロSDのソケットが載っていますが、いつの間にかSDカードのアクセスが全く動作しなくなっていました。そのために、カメラ画像の確認はSAM-BAを使ってPCに吸い上げてから、フォーマット変換をおこなってPC上で確認していました。SDカードさえちゃんと動作してくれれば、MMnet1002上でJPEGに変換してSDカードに書き出すことができるはずです。せっかく買ったMMnet1002ですので、SDカードを再度使えるようにして、この実験もやってみたいものです。
そんなわけで、SDカードを修理してみることにしました。以前はちゃんと動作していたので、おそらくはSDカード・ソケットの接触不良に違いありません。SDカード関連の信号線はカメラでは全く使っていませんし。マイクロSDソケットの配線を確認してみると、案の定 ソケット5番ピン(CLK)とCPUのPA8/MCCKピンの接続が不良になっていることが判明。どうやらマイクロSDソケットのはんだ付け不良のようです。コテにハンダを少量つけて、5番ピンにハンダを盛りなおしたところ、接続回復。以前実験した、FatFsでのLFN機能の動作が再度確認できました。
どうやらSDカードを何度か抜き挿ししているうちに、ハンダ不良だった5番ピンが完全に浮いてしまっていたようです。SAM-BAジャンパの100Ω抵抗のつけ忘れといい、どうもこのMMnet1002の製造品質には問題多いようです。
LPC2388でRTCを使ってみたので、AT91SAM9260のRTTも使ってみることにしました。RTCとちがって、RTT(Real-time Timer)では時刻情報を保持するのは、32bitのタイマ・カウンタひとつだけです。日付と時刻を表示するには、ソフトでこのタイマ値を変換してやる必要があります。
RTT機能自体はAT91SAM7にもあったのですが、内蔵RC発振器によって動作するため、時刻精度が悪く使う気になれませんでした。AT91SAM9260では32Kの外部水晶を使って動作するうえに、電池でのバックアップもできるので、これを実験してみることにしました。
日付と秒数の変換にはnewlibのmktimeを利用しています。Unixのtime_tでは1970年1月1日(EPOCH)からの秒数を数えているので、RTTのカウンタをこの秒数に合わせておき、毎秒インクリメントさせるのが一番素直で簡単です。しかし、RTTのカウンタであるRTT_VRは Read-onlyのレジスタであり、RTT_MRを介してリセットすることはできても、任意の値に設定することはできません。そこで、次のような方法を採ることとしました。
これで、めでたく電源を切っても時計は電池でバックアップできるようになりました。
ちなみに、AT91SAM9260には電池でバックアップできるレジスタは、4つ(16バイト分)しかありません。LPC2388には2KBもバックアップ可能領域があるようですが、おまけ基板では電池バックアップができないのが残念なところです。
RTT機能自体はAT91SAM7にもあったのですが、内蔵RC発振器によって動作するため、時刻精度が悪く使う気になれませんでした。AT91SAM9260では32Kの外部水晶を使って動作するうえに、電池でのバックアップもできるので、これを実験してみることにしました。
日付と秒数の変換にはnewlibのmktimeを利用しています。Unixのtime_tでは1970年1月1日(EPOCH)からの秒数を数えているので、RTTのカウンタをこの秒数に合わせておき、毎秒インクリメントさせるのが一番素直で簡単です。しかし、RTTのカウンタであるRTT_VRは Read-onlyのレジスタであり、RTT_MRを介してリセットすることはできても、任意の値に設定することはできません。そこで、次のような方法を採ることとしました。
- 日付/時刻を設定した時にRTT_VRをリセットする。日付/時刻に対応するEPOCHからの秒数を求め、それを電池でバックアップされるレジスタに保存する。
- 日付を表示する際には、バックアップ・レジスタの値にRTT_VRの値を足したものを、変換して表示する。
これで、めでたく電源を切っても時計は電池でバックアップできるようになりました。
ちなみに、AT91SAM9260には電池でバックアップできるレジスタは、4つ(16バイト分)しかありません。LPC2388には2KBもバックアップ可能領域があるようですが、おまけ基板では電池バックアップができないのが残念なところです。