● 実験テーマ58
「PIC32MX_BMP画像表示実験」
(SDカードに収録した、128x64ドットの白黒BMPファイルを、同じ解像度のモノクロ液晶に表示する実験をしてみました。)
■ 2014.10.2
・この実験の目的
@ BMPデータフォーマットの理解(今迄、何となくの知識しかなかったので・・・)
A 行く行くは、オシロ画面の保存に応用したいと考えている。
・この手の実験をしているサイトはないかと検索したら、アマチュア無線家が運営しているサイト
「趣味のホームページ」/「dsPIC30F4013による、BMP画像表示」というページが
あったので、そこのソースを参考にしてまずは、進めることにした。
・ここで、自分なりに、BMPデータフォーマットについて学習したことを、簡単にまとめて
みましたので、下記を参照してください。
■ 2014.10.3
・プログラム検討を開始した。
まずは、サイトのソースを参考にと、ぼちぼち始めた。
このソースでは、ピクセル描画関数を使った簡単なものになっている。
BMPデータは、画面左下隅から、右下隅に向かい、上に向かってバイト単位で配列され
ているので、このビット列をシフト命令を使ってシフトしながら、1ビット毎に、'1'か、'0'かを
判定して液晶の1ドット毎に、ON/OFF制御し描画する仕組みである。
たぶん全画面を表示するのに時間は掛ると思うが、その時間を実測してみる。
プロジェクト名は、「PIC32MX_BMP_TEST_1」とした。
・もう1つの方法としては、後閑氏が作成されたライブラリの、イメージ描画関数を使う手が
あるが、これは、標準のBMPフォーマットには対応していない。
標準のBMPフォーマットを、VBで作成したフォーマット変換ソフトで、液晶に表示し易いように
変換してから、C言語で扱えるデータテーブル形式にしてソースにその部分を貼り付けて
使うようになっている。
これを利用するには、そのフォーマット(配列)変換処理部分を、C言語で記述してやらない
といけない。
この部分の,VBで作成されたソフトは公開されてないので、自分で考える他ない。
結構面倒そうなので、これはこの次に試してみることにする。
■ 2014.10.6
・ソフトは未だ、まとまってないが、実験ハードを用意しないといけない。
新たに組むのは面倒なので、モノクロ液晶+SDカードスロットのハードを持つ今迄製作してきた
物の中から、「音楽ファイルリスト表示形式のMP3プレーヤ」のハードをそのまま使うことにした。
ケーシングされているので、スペースも取らず、スマートに実験できる。
・流用元のソフトは、私作成の、「SD_File_List_Select_MID_Player_TEST.c」と、
WEBページの、「「BMPdsPIC30.c」
・一応、プロジェクトを作成し、コンパイル〜 HEX書込みまで、OKとなった。
描画がおかしい・・・
最初の実験結果を、下にアップしました。
■ 2014.10.7
・描画が遅いといっても、感覚で、0.5秒強といったところ。
描画経過を目でかろうじて追えたが、もう少し確実に動きを見てみることにした。
1ライン描画間に、0.3秒のウエイトを入れて再確認してみた。
結果は、以下の通りです。(昨日の目視は正しかった。)
・1つWEBのソース例で気が付いたことあり。
オリジナルソースでは、i= 63;//初期値として、forループが終わった後に、i--;とやっているが
これでは、ちょっと解りにくいので、i= 0;//初期値として、forループが終わった後に、i++;
と書いても同じはず。
こう書いた方が、私には解り易い。
やはり、こう書いても結果は同じだったので、ここは修正した。
あと、result値をチェックするタイミングが、おかしいような気もする。
SD→ バッファ転送関数実行後でないと、result値は返ってこないので、後でチェックしないといけない
はずが、毎回バッファ転送前で行った後に、無条件で描画している。
つまり毎回、1つ前のデータの、result値をチェックしていることになるので、おかしいし、
EOFの位置のデータがない状態も読込んで描画関数を実行後、そのresult値=
0(EOF)
を判断して描画を終わるため、1ステップ無駄な動きをすることになる。
そこで、SD→ バッファ転送後に、直ぐ、result値のチェックを行い、result値が、'0'でない時(ノットEOF)
だけ、1ライン描画し、Yポジションを1段上に上げ、result値が、'1'の時(EOF)は、
ファイルの終わりなので、1画面のイメージ描画が完了したことになり、ここでファイルクローズという
フローに修正してみた。
■ 2014.10.8
・昨日の通りに、ソースを修正しても、結果は同じだった。
相変わらず、1度、1画面正しく描画後に、上部がゴミデータで上書きされるような動きをする。
現在テスト用に使用している、中華オシロの、ビットマップファイル:014.bmpには、正規の、
EOFの位置の後にも、数バイトの余計なデータが存在している可能性がある。
そこで、014.bmp以外の、BMPイメージでも試すことにした。
Window7標準でついてくる、「ペイント」ソフトで作成した、128x64サイズのイメージを、
ファイルの種類を、「モノクロビットマップ(*bmp,
*dib)に指定して保存した、bmpファイルを
sdカードにコピーしたものは、問題なく描画することを確認した。
やはり、014.bmpには、本来のEOFの位置移行も数バイト余計なデータが存在している
と思われるので、バイナリエディタでもう一度確認してみることにした。
(最初の、学習の時には、頭の部分しかよく見ていなかった。)
確認してみると、やはり、BMPイメージデータエリア:1024バイト後に、66バイトの余計なデータ
が入っていた。
余計なデータとは、0xDFの後、65バイト0xFFが続き、その後、ファイルデータ無し(ファイルの終わり)
になっていた。
(無論、このファイルを、Windows標準の、ビューワで開いた時は、正常に描画するが・・)
一方、OKなBMPイメージを見ると、BMPイメージデータエリア:1024バイト後、余計なデータは無く
ファイルデータ無し(ファイルの終わり)に、きっちりなっていた。
ちなみに、駄目な、014.bmpを、「ペイント」ソフトで開いて、
ファイルの種類を、「モノクロビットマップ(*bmp,
*dib)に指定して別の名前「014A.bmp」で保存
したファイルを、バイナリエディタで見ると、余計なデータは無くなっていて、1024バイト後は
直ぐにファイルデータ無し(ファイルの終わり)の状態になっていることを確認した。
■ 2014.10.9
・ここで仕切り直しして、正規のフォーマットの、014A,bmpを使って、WEB例そのままの記述の
プログラムを動かした場合どうなるか確認してみた。
このプログラムでも、表示上は何の問題もなく動くようだ。
データが無い状態を、バッファに読込んで、描画してしまうはずだが、表示には影響ないようだ。
しかし、フロー上しっくりいかないので、自分が修正したフローの現行のプログラムを採用する
ことにした。
・これで、TEST1はOKになったので、TEST1(ピクセル描画関数を使った方法)での、1画面分の
イメージ描画に掛る時間を実測してみた。
実測は、LEDポートを利用して行った。
結果、約0.7秒であった。(下の、負パルス幅が、その時間になる。)
・現在のプログラムは、超単純化したため、複数BMPファイルの、順次繰返し描画は省略してあるので
そのような仕様に修正した。
但し、SW送りは省略した。
これもOKになる。
■ 2014.10.10
・ここから、TEST2(イメージ描画関数を使い、8ビットまとめてライトする方法)プロジェクトの開始である。
<概要>
@ 元々後閑氏のオリジナルライブラリには、lcd_Image(char
*ptr)という
イメージ描画関数が用意されている。
この関数からコールしているのは、lcd_Write関数のみである。
主要部分は、次の、3ステップになる。
Step1: lcd_Write(cs, 0xB8+page, 1);
どのページ(page0〜 7)に描画するかの、コマンドライト
Step2: lcd_Write(cs, 0x40+Xpos, 1);
どのXポジションに描画するかの、コマンドライト
Step3: lcd_Write(cs, *pte++, 0);
イメージバッファのポインタをインクリメントして、そのデータをライト
A 問題は、BMPイメージデータの格納形式が、そのままだと、このモノクロ液晶の、表示仕様に
合わないということである。
そこで、後閑氏は、別途、「グラフィク画面変換ツール」を、Visual
Basic 2005で作成し、
Windows標準の、BMPイメージのデータ配列を、このモノクロ液晶に合わせて変換している。
残念ながら、PCアプリの中身は公開されてないので、独自に、C言語で、そのアルゴリズムを
考え、変換ソフトを書くしかない。
B 後閑氏のイメージ描画関数は、上から下に向かって描画させているが、このままだと、1回
元データである、Buffer[*]の配列を、そっくり上下逆さにする変換処理が余計に入ることになる
ので、今回は、下から上に向かって描画させることを考え、もう1つイメージ描画関数を用意する
ことにした。
(現在の、イメージ関数は、もう既に他のプログラムで使用しているので残すことにし、
新たに作成のイメージ関数は、lcd_Image2(char
*ptr)として、ライブラリに追加するのではなく
メインソース上に、サブルーチン化することにした。)
・下から上へ向かって描画する関数を使うとして、横方向の8ビット列データを、縦方向の8ビット列データ
に変換するアルゴリズムを考える。
これが、なかなか面倒で、頭が、こんがらがるが、Excelシート状に、128x64ビット(8x8ビットx128ブロック)
のマス目を書きながら、考えだした。
■ 2014.10.11
・TEST2プログラム検討
バッファエリアとしては、元BMPバッファ:Buffer[1024]エリアと、
変換データを格納する表示用バッファ:Disp_BUF[1024]エリアの、計2048バイト必要だが、
PIC32MX340F256Hの、DATAメモリ容量は、32Kバイトなので十分余裕がある。
<イメージデータ配列変換プログラム作成基本方針をまとめてみた>
@ 転送元のバッファ(オリジナルBMP)の配列名を、Bufferとする。
SDカードに収録されている、BMPデータ:1024バイトの、Bufferへの転送は、
以下の記述で簡単に出来る。
FSfread(Buffer, 1, 1024, fptr);
A Bufferの内容を、配列変換して、表示用のバッファ:Disp_BUFに格納する。
この処理が済んだら、lcd_Image2関数を使って、最下段より、上に向かって描画する。
B 変換は、下段の、128バイトブロック(page7相当)より行い、page6→5→4→3→2→1→0と
上段に向かい、全画面(128バイトx8=1024バイト)の変換を行う。
<補足>
この変換は、8ビット単位で行うので、8ビットx8ビット=64ビットブロックが、最小単位
となり、その変換が、大元になる。
つまり、8x8ビットブロックの中で、横→縦8ビット列の変換を行い、
それを、128ブロックについて繰返すという流れになる。
・この大元の変換が胆である。
シフト命令と、マスク処理、その演算結果の、OR処理などの論理演算処理が基本となるが、
これが、各ラインで、まちまちの処理になるため、forループ等を使っての、短いステートメント
記述にまとめにくく、無い頭を使った結果書き上げたソースは、ベタに近い書き方に
なってしまった。
しかしこの方が見た目には理解し易いと自分では思っている。
■ 2014.10.12〜 2014.10.13
・ソース作成が清み、コンパイルまでOKになった。
早速、HEXを書込んで動かしてみたが、まずは、駄目!!
014A.bmpをテストファイルとしてやっているのだが、最下段16ブロックの描画は正常だが、
その上の段も、最下段と同じような描画をしてしまう。
・これは、割とすぐひらめいた。
上段ブロックのデータ送りのところで、無条件で、Bufferポインタ:iを、+1しているが、
上段ブロックに移動する時は、
if(i == 16) i= 128; // 最下段(page7相当)の、16ブロック分の変換が終了したら、次の上段(page6相当)の、開始位置に移動
というように条件付にしないといけない。
イージーミスと言えば、イージーミスであるが・・・
※ この修正で、ついに、上手く行く。
描画時間を実測してみた。
思ったより速く、約40mSほどであった。詳細は下を参照してください。
オシロの時間軸レンジは、見にくいが、10mS/Dです。
・最後にいつもの通り、イメージ表示のサンプル取りを行った。
TEST2も、複数ファイルの順次繰返し描画にしたので、割と楽に取れた。
このページ冒頭の、写真を参照してください。
・これで、今回の実験の目的は達せられたので、今後は、出来たら、オシロ画面を、イメージデータ化
して、SDカードに書込むところまで実験したいと思っているが・・・
どうなることやら。
<最終回路図>
・今回は、実験テーマ41(MID/MP3プレーヤ)のハードを流用しました。以下がそれです。
「テンポ可変式MIDプレーヤ_PIC32MX基板」
<最終ソース>
・こちらから、どうぞ→ PIC32MX_BMP_TEST_1.c (ピクセル描画関数を使ったソース)
PIC32MX_BMP_TEST_2.c (イメージ描画関数を使ったソース)
← 実験テーマ1に戻る TOP PAGEに戻る 実験テーマ59へ →