これも大当たりであった。フォントファイルは、SRAMでなくフラッシュに埋め込まれた。いやあ、山勘が2つも当たってすこぶる機嫌が良い。これから同じようなことをしようとする人の参考のために、AVRでobjcopyを使うときの正しいコマンド例を以下にお示しすることにする。いうファイルを、m6x12.oというオブジェクトにして、フラッシュ領域に入れる。m6x12.o下線が、ChaNさんの例と異なる部分である。入力ファイル名はカレントディレクトリに置かないとフルパスが外部参照名になるので注意されたい。考えるより、このコマンド例で動くようにファイルをカレントディレクトリに持ってくるのが簡単だ。GLCDとフォントのスキャン方向が違う(1/6/2013)ソースコードを調整し、Makefileの定義を直して、新しい6X12フォントが出るようにプログラムを修正する。この手間は、フォントデータをオブジェクトファイルにするよりずっと簡単に終わった。しながらプログラムを動かす。ふーむ、出てきたフォントは、2つに分割され、位置が90°ずれている。さんが言っていたフォントのXY軸を変換したと言うのはこのことだな。6X12のフォントだから、8ドットのフォントグリフ(ビットマップ列のこと)が2つに分かれて横になってしまっている。さんは速度を理由に、フォントグリフそのものを変換されたようだが、こちらは余りフォントデータはいじりたくない。フォントグリフのXY変換は、以前LEDマトリックスの電光掲示板でやったことがあるので作業にそれほどの不安はない。沢山のフォントを試してみたい時に、いちいち変換していくのは大変である。それに、STM8Sはオブジェクトファイルを使わず、EEPROMにフォントデータを入れようと考えている。すると容量が大きくなるので、日本語フォントまで出せるかもしれない。フォントファイルはそのままにしておきたい。さんがフォントの方向をY軸に変換したのか、その理由はプログラムを調べるにつれて明らかになってきた。このGLCDのハードの構造からプログラム上での変換処理が恐ろしく面倒になるのである。このGLCDはドットの表示が縦(Y軸)に8ドットづつで1バイトのシリアルデータが入力単位である。GRAMバッファーは縦8ドット単位に128バイト(正確には129バイトで4ドット使わない)で1ページを構成し、これが8ページあることで全体のドットエリアをカバーする。FONTXデータは、横方向(X軸)に8ドット単位のフォントグリフを構成し、端数を切り上げて次の段のフォントとなる。この縦横変換は一筋縄では行かない。フォントの大きさが8ドットの倍数だったり、描きだすところが8の倍数単位なら、それほどでもないが、端数から描きだし、フォント幅が8の倍数以外の端数になると、とてつもなく難しくなる。GLCDのページアドレスに苦戦(1/10/2013)GLCDのページアドレスという構造そのもの自体が、簡単にプログラムが出来る代物ではない。端数からドットが始まる時は、1バイトデータの中のビット単位のシフト演算を繰り返して、隣接するバッファーにデータを埋め込む必要がある。いうことかと言うと、横線のように横にドットが並ぶ時は、1バイトの同一ビット位置にデータをセットし、これを、VRAMアドレス単位に繰り返して始めて直線が引ける。縦線は8の倍数なら、VRAMアドレスを横軸幅単位に飛び飛びにとって描きこめば描けるが、端数から始めたい時は、始点と終点でのビット演算が不可欠になる。横スキャンのフォントデータを、縦に8ドットづつスキャンしてレクタングル(四方形)に埋め込むソースコードを書き始めた。久しぶりの本格的なプログラミングである。擬似コーディングというより、一種のパズルに近い。何枚もメモ用紙にGLCDのページとフォントのビット列の図を書いては、ロジックを組み上げていく。参考にしているオリジナルのソースコードが難解である。このGLCDのVRAMバッファーに縦横ドット単位のレクタングル(四辺形)を埋め込む関数は、LcdWriteImage()という関数なのだが、これがさっぱり何をやっているのかわからない。コメントをこちらでいくつも追加して何とか理解しようとするが、わかったのは、レクタングルのデータのスキャン方向が縦であるということくらいである。縦のデータの配分は、シフト演算で埋め込んでいるようだが、VRAM側のシフトと、レクタングル側のビット単位のシフトが錯綜して、すっきり頭の中に入ってこない。いう構造の中の縦横変換である。8X8などの変換ならまだしも、今度のように6X12という端数の出るフォントの変換はとてつもなく難しい。ビット順がリトルエンディアンだとすると、2バイトにわたるデータでは見た目が逆になるので大変だ。何とかソースをでっちあげてテストするが、さっぱり文字の形にならない。軽い気持ちでフォントスキャンの方向変換を始めたことを後悔する。さんがやったようにフォントデータの方を変換して先に進みたい誘惑にかられる。負けず嫌いの性分だから簡単に引き下がるわけには行かない。UARTに途中経過の数値を吐き出させてはロジックを確認して先に進める。いつまでたっても画面はゴミのような斑点が出るだけで、一向に文字らしい図形はあらわれない。6X12フォントの表示に成功。速度はこれくらいなら問題ないか(1/13/2013)結局、何とか文字らしいものが出るまでに1週間もかかってしまった(旅行の3日が入っているが)。自分としては珍しく、プログラムの構造を途中で換えた。3段ループを2段ループに変えて、やっと目鼻がついてゴミが文字らしくなってきた。反省点はやっぱり擬似コーディングというか、抽象レベルでの念入りな検討が不足していたことにつきる。早くコーディングに入りすぎた何よりの証拠は、プログラムの構造を途中で変えたことである。人に偉そうに言う割には、つい目の前のソースコードに気を取られてプログラムを書いてしまう。時々ゴミが出るが、やっとのことで文字が正しく表示された。嬉しくて記念撮影する。横スキャンのフォントデータをビット単位に読み込んで縦方向に展開して表示しているので速度が心配されたが、全く気にならない。それでも、これまでの縦にバイト単位に展開するのに較べれば、単純に考えても処理時間は8倍になっているはずである。どれくらい速度が違うのか調べたいおきたいところである。いうことでロジアナを引っ張り出して測定してみた。オリジナルの16X8フォントを画面一杯に出すプログラムで全体の表示時間を調べたあと、新しく開発した12X6のプログラムの時間を測る。おやあ、最初が10.05msで、XY変換した方が9.75msだ。あ、そうか、フォントのドット数が違う。128ドットと、72ドットだ。表示するドットが2倍近く多い。条件を揃えて測定するのは、プログラムを書き直す必要があって面倒だ。そこで、ロジアナのチャートを見ながら、SPIの実測速度から転送時間を引いて(SPI速度は4Mhzあるが前後の準備で1Mhz程度)、XY変換にかかるロジックの時間だけを推定してみた。理論上は、同じ方向にバイト単位のフォントグリフを流し込む最初の方式にくらべ、ドット単位にデータを移していくので8倍は多くかかる勘定である。計算によると、6X12ドットの1文字あたりの処理時間は、87μsで、16X8ドットは44.4μsであった。意外に大きな差ではない。8MhzのCPUクロックなので、40μsの時間差は300ステップ位である。この程度なら、わざわざフォントを変換して入れ直さなくても大丈夫なのではないか。速度(クロック8Mhz)を上げればもう少し早くなる。見た目も殆ど変わりがない。スクロールの速度自体も6X12フォントだと、64X128画面で100文字ちょっと。全面書き換え(スクロール時)で16ms程度で納まる。これなら見た目もスムーズなスクロールになるはずだ(テレビの速度がインターレースで20ms)。スクロールは思ったより簡単に出来た(1/15/2013)まだ、文字の下にゴミが時々出たりして完全ではないが、FONTX形式のフォントを直接出力できるようになったので、次のステップのスクロール機能の開発に進んだ。今の画面(128X64)に6X12のフォントで文字を出してスクロールさせるのは、精々が21字、5行というわずかなスペースだが、ライブラリの形で開発しておけば、今後の汎用的な使い方につながる。スクロールの一番大変なところは、画面が一杯になったときに、画面全体を1行分上に描き直す処理をつくることである。commandというコマンドの紹介がある)、実装例がないので、そう簡単には手が出せない。なると、アプリケーション側にあるVRAMを全部描き直してもういちど出力させなければならない。文字の位置を決める画面管理はあとにして、まず、この画面を描き直す関数LcdScroll()を新たに開発し始めた。例のLcdWriteImage()の解析が相当進んで、ページアドレスのデータ処理に慣れてきたこともある。要するに、ひとつの8ドット(1バイト)のデータをシフトさせてY軸方向のバッファーに移動させて行くテクニックを連続して行うことである。思ったより早くコードが出来た。ステップ数もわずかだ。main.cにコマンドを新設してテストしてみた。おおお、一発で動いた。1ドットづつのスクロールも綺麗に動く(配布するソースには入っていません。テストのため暫定的に作ったコマンドです)。図形も入れてスクロールテストプログラムの完成(1/18/2013)勢いに乗って、直接キャッシュバッファーに書き込む一文字関数の開発に着手する。いうのは、文字の出力がどうも不安定で、文字の下の部分(恐らく縦12ドットの下、残り4ドット)にゴミがでるバグがつきとめられないからである。現行のやり方は、フォントをレクタングルに描いたあと、更にそのレクタングルを例のLcdWriteImage()を通してキャッシュバッファーに書き込むという2重の手間をかけている。どの部分が悪さをしているのか、どうしてもつきとめることが出来ない。いうときは、現行をあっさり諦めて、新規に作り直すほうが生産性が高い。一文字関数(LcdChr_Ank())に直接LCDバッファーに書き込むコードを追加する。経験値が上がってきているのだろう。こいつもそれほど時間もかからず完成した。