● 実験テーマ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へ →