STM32F4シリーズを使ってみる5 -libpngを実装する-
誘惑に負けて買ってしまった…盈钰電子のSTM32F4ボード…
176pinなSTM32F407IGT6,1MBSRAM,NAND&NORFlash,HS-USBPHY,Ethernet,I2SCodec,camera....
そして3.2inchのTFT-LCDまでついてオトクな699RMB!
日本円単純換算でも10000円以下の超格安です(2012/5上旬現在)
本来ならばREDBULLの基板をベースにやるべきですが費用対効果が最高なので購入した
方が早いっちゅーことで…しかもSTM3240G-EVALの回路にほぼ互換なのでSTさん提供
のサンプルなんかもほとんど素で動かせられますのでこいつでいろいろ学習していき
ましょ♥
だめだ私すっかりSTM32漬けだ…
さて、前回さらっとご紹介しましたが、libpngのSTM32F2/4への移植についてお伝え
します。私たち虹メにとってpng形式の画像ファイルはコラ等で非常に身近なもので、
jpeg形式と同じく大量に扱われています。それをマイコンでデコードし表示できる
というのはとても有用性があるわけで、かねてからの悲願がかなった形でもあります。
今回は実際の移植の手順も合わせてご紹介します。
●必要なもの
libpng
これは必須ですね。少し前にlibpngのセキュリティホールが発見されているためバー
ジョンには気を付けてください。今回は"libpng 1.5.10"を使用します。
zlib
pngファイルの実画像データは可逆圧縮されていてDeflateと呼ばれる圧縮技術が使用
されています。libpngはDeflateアルゴリズムを処理するためそのライブラリである
zlibの一部コードを必要としています。今回は"zlib 1.2.6"を使用します。
MCU
libjpeg(IJG Jpeg Library)と同じくlibpngはRAMを大量に消費します。
内部SRAMが96kByte以上あるマイコンならQVGAサイズまでなら何とか表示可能です。
●ファイルI/O
こちらはlibjpeg(IJG Jpeg Library)と同じ要領でChaN氏のFatFsと連動させます。
sirius506氏、そら。氏のlibjpegの移植例を参考にしています。
実際にどうやってるかは私のサンプルの./lib/display/abstract/src/ts_fileloads.c
にあるload_png関数の上にあるfatfs_read_data()を読み進めてください(丸投げ!)
●makefileに追加するCソースファイル
こちらのSTM32F4サンプル中にあるlibpng.mkを見ていただければわかりますが、
pngファイルの読み取りのみに限ると以下のファイルだけが必要となります。
-libpng
png.c
pngerror.c
pngget.c
pngmem.c
pngpread.c
pngread.c
pngrio.c
pngrtran.c
pngrutil.c
pngset.c
pngtrans.c
上記のうちpngerror.cは一部内容の書き換えが生じます(後述)
-zlib
adler32.c
crc32.c
inffast.c
inflate.c
inftrees.c
zutil.c
ヘッダファイルの方については念のためオミットせずに全部ぶっこんどいてください。
また、libpngを解凍したディレクトリ中の./scripts/pnglibconf.h.prebuildをリネ
ームしpnglibconf.hとしてソースと同じディレクトリにぶっこんでください。
●ARMマイコン上で動作させるための少しの変更
x86なWindowsシステムで動作させるわけではないため、エラー表示などのコンソール
I/Oの処理のオミットは必須です。
pnglibconf.h中のPNG_CONSOLE_IO_SUPPORTEDとPNG_STDIO_SUPPORTEDの
定義はコメントアウトしておき、さらにpngerror.c中のpng_default_error
関数はfprintfからprintfに変えておきます。
(printfのリダイレクトが必要無い場合はすっからかんでもいいです)
ねむいさんの環境では書き換えたファイルはpngerror_std.cとしています。
20140731追:
↑バージョンが上がってヘッダの#defineをコメントアウトすればよくなりましたので
pngerror.cに手を加える必要がなくなりました。
また、txtとハードウエアの倍精度浮動小数点演算、インターレースのサポートも
行わないのでpnglibconf.h中の以下の定義もコメントアウトです。
PNG_READ_INTERLACING_SUPPORTED
PNG_FLOATING_ARITHMETIC_SUPPORTED
PNG_WRITE_zTXt_SUPPORTED
PNG_WRITE_iTXt_SUPPORTED
PNG_READ_zTXt_SUPPORTED
PNG_READ_iTXt_SUPPORTED
PNG_zTXt_SUPPORTED
PNG_iTXt_SUPPORTED
元からコメントアウトされていたものについてはそのままにしておいてください。
さらにpnglibconf.h中のZBUFFERの確保量(PNG_ZBUF_SIZE)をSDカードのセクタ
サイズである512バイトに合わせてください。これ以上の
値にすると512バイト以上読み込んだ際にエラーになりデコード不可能になります。
また、残念ながらlibpngにはlibjpegのような1/(2^x)にするサイズスケーリングは
ありません。
●libpngを呼び出し、画像データを表示する
大まかに分けて以下の順番で実行します。これらは必須です。
1.png_create_read_struct関数でpngファイル全般を制御するポインタ確保
2.png_create_info_struct関数でpngファイルの情報に関するデータをストアする
ポインタ確保(IHDRとIENDチャンクの分)
3.エラーハンドリングの設定
4.png_set_read_fn関数でfatfsのpngファイルポインタと連結
5.png_get_IHDR関数でIHDRチャンクの読み出し
6.画像の形式を24bitRGBに変換する。
7.画像のx,yサイズのチェック(1280pixel以上は撥ねる)
8.png_get_rowbytes関数で1行あたりのバイト数取得
9.png_malloc関数で"6."で取ったバイト数分の配列確保
10.png_read_row関数でIDATチャンクを一行ずつ読み出し、さらにRGBデータ幅を24bit->16bit
に落としてTFT-LCDに表示していく
11.表示が終わったらpng_free関数"7."で確保した配列を解放
12.png_read_end関数でIENDチャンクを読みだす。
13.png_destroy_read_struct関数で"1.""2."で確保したポインタの解放
気を付けなければならないのは各処理ごとにエラーを検知しておかしい場合は先の
処理に進ませないようにすることです。これを怠るとHardFaultに簡単に陥ってし
まいます。またIDATを読み切ってない場合にpng_read_endを実行すると即座にエラ
ーになりますのでTFT-LCDの解像度より画像サイズが大きい場合でも必ず空読みして
読み切ってください。この手順は24bitのpngを想定していますが異なる形式の場合は
24bitに変換するために"5.""6."の間に各種transformの処理が必要です。
実際にどうやってるかは私のサンプルの./lib/display/abstract/src/ts_fileloads.c
にあるload_png関数を読み進めてください(丸投げ!)
一回の表示で消費されるRAMはlibpng自体が必要とする量が約33kByte(デバッガの
追跡により使用量を算出),それに加えてTFT-LCDに表示する際のデコード済みの
データを置くバッファも必要とされるため結局以下の計算式で総消費量が求められます。
NEEDED_RAM_AMOUNT = ((XSIZE-1)*4)Byte+33kByte
式中のXSIZEはTFT-LCDのX軸方向最大ピクセル数ではなくpng画像データのX軸方向
最大ピクセル数です。つまり幅が広くなればなるほど使用するRAMの量が増えます
(libjpegもこの点は同じ)。また、今回のデモはアルファチャンネルを強制付与して
いるため(RGBAのならびになるため)(XSIZE-1)*3ではなく((XSIZE-1)*4)になります。
●実際の表示
今回の検証用のTFT-LCDとして320x480なTFT1P2797-Eを使用します。大規模マイコン
用のディスプレイとしてねむいさんのイチオシです♥
検証用の画像はこちら。こちらのサイトのキャラクタージェネレーターを使って作成した画像に
さらにコラージュを加えた私服のいないさんです。メイド服にコラしたかった
のですが髪型だけで力尽きましたorz…これをTFT-LCDに表示してみます。
ビット深度は24bitのトゥルーカラーです。
表示ルーチンとしてまず画面左上に画像の情報を出すようにしました。
col_depthはビット深度で8*(RGB)で上記の24bitとなります。
col_typeはpngの画像タイプで0がグレイスケール、3がインデックスカラー、
2がトゥルーカラー、6がアルファチャンネル付トゥルーカラーです。
実際の表示に関し、グレイスケールやビット深度が小さい画像も24bitに変換してい
ます。また透過pngやアルファチャンネルつきの物はいったんアルファチャンネルに
変換して、1ピクセルごとのアルファチャンネルを示すバイトは書き込み時に無視して
います。インターレースpngの表示はは私のサンプルではサポートしていません。
誰か腕に覚えのある方実装おねがします…。
てわけでPCとまったく遜色ないレベルでいなちゃんを表示することができました!
メモリが豊富な環境ではpng_read_image関数で一気に読み込みできるのですが、STM32
等のマイコンでは到底足らないので、1行ずつバッファに読みだして表示を行います。
読みだしたデータはRGBの順番で並んでいて8+8+8=24bitで1ピクセルとなります。
最終的にTFT-LCDには5+6+5=16bitにして書き込み、表示させます。
透過PNGを表示させるとこんな感じになります。前述の通りアルファチャンネルは
読み捨ててるので透過部分はRGB(0,0,0)の黒色で表現されています。また解像度の
関係で表示が隠れてしまったのですが、アルファチャンネル付トゥルーカラーに
変換された透過pngを示しています(赤で囲った部分)。
TFT-LCDのサイズよりオーバーする場合の画像では当たり前ですが画面外のデータは
表示できません。また画面からはみ出ている部分もpng_read_rowで全部読み切ってし
まわないとエラーになったりHardFaultに陥ってしまうので注意です。
ChaN氏のbmp表示ルーチンを見習って大きい画像でもUARTからのコマンドで仮想的な
表示開始位置を変えて表示できるようにするのが今後の課題ですね〜
ちなみのこのaraiさんの描いたねむいさんの絵はアダルツなのでこのブログ的にも
見えてない部分は…ゲフンゲフフン失礼
減色とかグレースケールにした時の比較です(注:表示の際はすべて24bitのトゥルー
カラーに変換されています。左上の数値は変換前の情報です)。
ビット深度24bitトゥルーカラーの標準的なねむいさんです。
col_depthが8になってますが実際は8bit*3で24bitとなります。
256色のインデックスカラーはこんな感じに。
24bitのグレースケールはこんな感じ。
8bitに落とすとこんな感じ。
さらに4bitに落とすとこんな感じです。
というわけで通常のPCと同じようにpngファイルの表示もSTM32F4上で可能と
なりました。しかしながらメモリはかなり食いますので内蔵SRAMが豊富にある
STM32F4専用の機能ですね〜。
libjpegと絡めると空いた時間でお茶が飲めてしまうくらいビルド時間も
倍加されてしまいますのでご注意ください。
-
免責・連絡先は↑のリンクを
↓SNSもやってます↓
powered by まめわざ- ARM/STM32 (116)
- OpenOCD (27)
- ARM/NxP (34)
- ARM/Cypress (5)
- ARM/Others (3)
- ARM/Raspi (1)
- AVR (13)
- FPGA (4)
- GPS/GNSS (19)
- MISC (81)
- STM8 (2)
- Wirelessなアレ (16)
- おきぱ (1)
- ブラウザベンチマーク (28)
- 日本の自然歩道 (26)
- STM32U0はぢめました
⇒ ねむい (08/07) - STM32U0はぢめました
⇒ ひかわ (07/28) - STM32H5を使ってみる3 -待ち受ける初見殺しの罠たち-
⇒ ねむい (05/17) - STM32H5を使ってみる3 -待ち受ける初見殺しの罠たち-
⇒ どじょりん (05/16) - STM32H5を使ってみる3 -待ち受ける初見殺しの罠たち-
⇒ どじょりん (05/16) - いろいろ試す61(と今年の反省会)
⇒ ねむい (01/02) - いろいろ試す61(と今年の反省会)
⇒ ひかわ (01/02) - いろいろ試す61(と今年の反省会)
⇒ ひかわ (01/01) - STM32H5を使ってみる3 -待ち受ける初見殺しの罠たち-
⇒ ねむい (12/31) - STM32H5を使ってみる3 -待ち受ける初見殺しの罠たち-
⇒ ひかわ (12/31)
- November 2024 (1)
- October 2024 (1)
- September 2024 (1)
- August 2024 (1)
- July 2024 (1)
- June 2024 (1)
- May 2024 (1)
- April 2024 (1)
- March 2024 (1)
- February 2024 (2)
- January 2024 (1)
- December 2023 (4)
- November 2023 (2)
- October 2023 (2)
- September 2023 (1)
- August 2023 (2)
- July 2023 (1)
- June 2023 (2)
- May 2023 (3)
- April 2023 (1)
- March 2023 (1)
- February 2023 (1)
- January 2023 (1)
- December 2022 (2)
- November 2022 (1)
- October 2022 (1)
- September 2022 (1)
- August 2022 (1)
- July 2022 (1)
- June 2022 (1)
- May 2022 (1)
- April 2022 (1)
- March 2022 (1)
- February 2022 (1)
- January 2022 (1)
- December 2021 (2)
- November 2021 (2)
- October 2021 (1)
- September 2021 (1)
- August 2021 (1)
- July 2021 (1)
- June 2021 (1)
- May 2021 (1)
- April 2021 (1)
- March 2021 (1)
- February 2021 (1)
- January 2021 (1)
- December 2020 (3)
- November 2020 (1)
- October 2020 (1)
- September 2020 (1)
- August 2020 (1)
- July 2020 (1)
- June 2020 (2)
- May 2020 (1)
- April 2020 (1)
- March 2020 (1)
- February 2020 (1)
- January 2020 (1)
- December 2019 (3)
- November 2019 (1)
- October 2019 (1)
- September 2019 (2)
- August 2019 (1)
- July 2019 (1)
- June 2019 (1)
- May 2019 (1)
- April 2019 (1)
- March 2019 (1)
- February 2019 (1)
- January 2019 (1)
- December 2018 (3)
- November 2018 (2)
- October 2018 (1)
- September 2018 (1)
- August 2018 (1)
- July 2018 (1)
- June 2018 (1)
- May 2018 (1)
- April 2018 (2)
- March 2018 (1)
- February 2018 (1)
- January 2018 (1)
- December 2017 (2)
- November 2017 (2)
- October 2017 (1)
- September 2017 (1)
- August 2017 (1)
- July 2017 (1)
- June 2017 (1)
- May 2017 (1)
- April 2017 (1)
- March 2017 (2)
- February 2017 (2)
- January 2017 (2)
- December 2016 (7)
- November 2016 (2)
- October 2016 (2)
- September 2016 (1)
- August 2016 (1)
- July 2016 (1)
- June 2016 (1)
- May 2016 (2)
- April 2016 (1)
- March 2016 (2)
- February 2016 (1)
- January 2016 (1)
- December 2015 (3)
- November 2015 (1)
- October 2015 (3)
- September 2015 (2)
- August 2015 (2)
- July 2015 (3)
- June 2015 (3)
- May 2015 (4)
- April 2015 (2)
- March 2015 (4)
- February 2015 (1)
- January 2015 (3)
- December 2014 (3)
- November 2014 (2)
- October 2014 (1)
- September 2014 (2)
- August 2014 (2)
- July 2014 (3)
- June 2014 (2)
- May 2014 (1)
- April 2014 (1)
- March 2014 (4)
- February 2014 (4)
- January 2014 (3)
- December 2013 (5)
- November 2013 (4)
- October 2013 (3)
- September 2013 (2)
- August 2013 (2)
- July 2013 (2)
- June 2013 (3)
- May 2013 (2)
- April 2013 (2)
- March 2013 (2)
- February 2013 (2)
- January 2013 (3)
- December 2012 (4)
- November 2012 (2)
- October 2012 (2)
- September 2012 (4)
- August 2012 (1)
- July 2012 (3)
- June 2012 (2)
- May 2012 (3)
- April 2012 (3)
- March 2012 (2)
- February 2012 (3)
- January 2012 (3)
- December 2011 (5)
- November 2011 (3)
- October 2011 (2)
- September 2011 (2)
- August 2011 (2)
- July 2011 (2)
- June 2011 (2)
- May 2011 (2)
- April 2011 (2)
- March 2011 (2)
- February 2011 (2)
- January 2011 (3)
- December 2010 (7)
- November 2010 (1)
- October 2010 (1)
- September 2010 (1)
- August 2010 (3)
- July 2010 (4)
- May 2010 (1)
- April 2010 (2)
- March 2010 (2)
- February 2010 (2)
- January 2010 (3)
- December 2009 (3)
- November 2009 (8)
- October 2009 (7)
- September 2009 (5)
- August 2009 (4)
- July 2009 (6)
- June 2009 (6)
- May 2009 (14)
- January 1970 (1)
Copyright(C) B-Blog project All rights reserved.