公開日:2021/10/23
title.png

18th Season


#18-5 MoscoviumとSPI-TFT

 前回、日本語フォントFONTJPユニットを設計しました。
 と、言うのも、1.8インチの小さなSPI-TFT表示器(下図)をMoscoviumで使おうと、購入したのがきっかけです。SPI-TFTのお試しはArduino DUEを使って済んでいます(「#18-3 SPI接続TFT表示器」)ので、今回はいよいよ、MoscoviumマイコンでSPI-TFTに表示してみるテーマとなります。

a183_spitft.jpg

 この小さなSPI-TFT表示器に、8×8ドットの日本語(漢字)フォントを表示してみようと思います。

8×8ドット漢字フォントの実力

 昔々、8ビットパソコンで使っていた漢字フォントは16×16ドット(フチあり)でした。
 今、Windows上にて、テキストエディタで使っているフォントは、1文字のサイズが12×12ドット(フチなし。隣接文字とくっつかない様に使うためには、実質13×13ドット)です。12×12ドットだと、複雑な漢字はデフォルメされています。

 それより小さいフォントは無理だろうと思っていたところ、フリー🆓の8×8ドット日本語(漢字)フォントを見つけました(下リンクを参照してください)。

  Little Limit (別ウインドウが開きます)

謝辞: しっかり第二水準までカバーした極小フォントを提供してくださっている「Little Limit」の作者(門真 なむ)様に感謝いたします。

 こちらの「美咲フォント」はフチあり(実質7×7ドットで構成)なので、ピッタリ8×8ドットで並べても隣接文字とくっついてしまうことは無く、非力な組み込み用マイコンで扱うのに優しい仕様です。

その実力は?

 例文でその実力を確かめてみましょう。

a185_dfclt.png

 カギ括弧「○」の中の漢字、読めますか?感の良い方なら、「多分あの漢字かな?」って、判るかもしれませんが、確信を持つには少し厳しいですね?

a185_sentence.png

 今度はどうでしょう?同じ漢字が含まれているのですが、なんとなく読めてしまったのではないでしょうか?特に、ファンタジー系のRPGやゲームなどがお好きな方なら一撃でしょう。
 そうでない方でも、「性」の文字は判別できるので、「○性」から類推して、本性、特性、気性、属性、男性、女性、中性、両性、真性、仮性、苛性、魔性、天性、急性、慢性、酸性、塑性、個性、……等が思い浮かびます。更に、「火の○性をもったドラゴン」の文脈だと、「特性」か「属性」くらいでしょうか?最後は、文字の形(部首)から、「属性」と推定できます。
 偉いもので、人間の脳はこのような判定を一瞬でこなし、情報を補完して「読めてしまう」みたいです。

いずれの御時にか

 では、もう少し長いサンプルをどうぞ(↓)。

a185_kiritubo.png

 PC上の表示だと思いますので、上のサンプルは倍角表示(1ドットを2×2ドットで表示)としました。フォント自体は8×8ドットの「美咲フォント」を使っています。
 読めましたか?そもそも古文で、かな遣いも違っているし、現代文の脳が補完し難いサンプルをあえて選んでみました。読めなかった方は、「源氏物語の冒頭」を検索して原文を知ってから戻ってみてください。
 なお、上図のサンプルは、ほぼ、1.8インチSPI-TFT表示器で1ページに表示可能な文字数(16×20文字)となっています。また、上のサンプル中、壺(=0x9ae2、52区)、憚(=0x9cdd、56区)の二文字が第二水準漢字です。第一水準までのROMデータを使う場合には表示されません。
 ひっくり返すと、この2つの漢字を使わなければ、その他の文字は全て第一水準だけで表示できるのだから、第一水準だけのフォントROMを使っても、それほど大きなビハインドはありません。「壺」は「壷(=0x92d9、36区、第一水準)」で代用しても良いし、「憚る」は「はばかる」でも違和感は無いでしょう。


 Arduino等のMCUボードを使った組み込みシステムで、今回の様な小さな(1.8インチ)表示器であっても、漢字を表示できる利点は大きいです。日本人相手に、英語だのローマ字だので気持ちを伝えようとしても無理があるからです。
 一般的には、「表示器の表示領域が狭い」とか、「日本語フォントROMが大きすぎる」とかの制約があって、組み込みシステムで使うのは難しいのですが、そういう障害を乗り越えた先に存在する日本語表示アプリケーションって、尊いと思いませんか?

 中には、脳による補完を期待した上でも、さすがに判読が厳しい複雑な漢字もありますが、表示させてみて判読できないような漢字は平仮名に変更するとか、読み仮名(よみがな)を付けるとか、表現を変えて難しい漢字自体を回避するとか、調整すれば十分実用に耐え得ると思われます。

応用プログラム

 非同期シリアル通信で受信した文字列データを、そのままSPI-TFT画面に表示する端末ソフトウェアを作ろうと思います。以下、目標仕様です。

目標仕様

 TFTへの文字描画に関しては、「#12-3 DUE+TFTで日本語表示」のプログラム(tft_kprint.ino)が参考になりますし、SPI-TFTをSPI通信で制御する方法については「#18-3 SPI接続TFT表示器」のプログラム(test_st7735r.ino)で試行済みなので、これらをMoscoviumのアセンブラに移植するだけです。

S-JIS文字の判定

 シフトJIS(S-JIS)コードは、7ビットASCIIコードに対して、コード範囲0x80〜0xffの部分に半角カタカナ文字と、マルチバイトコードの拡張を取り込んだ文字セットとなります。

 よって、文字列データから1文字を取り出そうとする場合、まず、1バイト取って来て、このコード範囲がS-JIS第一バイトコード範囲に入っているかどうかを調べます。入っていなかった場合、取って来た1バイトはASCIIコードまたは半角カタカナ文字と見なして処理します(1バイトコード)。
 S-JIS第一バイトコード範囲に入っていた場合、更に次の1バイトを取って来て、2バイトのコードとします。第一バイトが上位、第二バイトが下位となります。

 通常は、この処理をソフトウェアで実行します。しかし、アセンブラでプログラムして見ると意外と面倒です。コード範囲を判定しなければならないので、上限値と下限値に対して2回、比較と分岐を実行する必要があり、更にコード範囲が2つあるので×2倍の手間がかかります。……更に上位・下位バイトに×2倍の、計8回比較しなければならない。

 そこで、FONTJPユニットには、文字コードレジスタfnjpcodに書き込んだコードがS-JISコード範囲に入っているかどうか?の判定フラグ(SJS1,SJS2)がfnjpctlレジスタに用意されています。fnjpcodレジスタの上位バイトがS-JIS第一バイトコード範囲にある場合にはSJS1=1、下位バイトがS-JIS第二バイトコード範囲にある場合にはSJS2=1となります。よって、16ビットのfnjpcodレジスタ値がS-JIS 2バイトコード範囲にある場合、SJS1=SJS2=1です。

 例えば汎用レジスタr0に1バイト目の文字列データを読み込んだ場合、以下の様な手順で1バイト/2バイトコードを判定できます。

  // ASCII or S-JIS code
  lsfti r0,8  // 読み込んだ1バイトを上位側に書き込む
  ldwi r7,fnjpcod
  stw [r7],r0
  ldwi r7,fnjpctl
  ldw r2,[r7]
  andi r2,fnjp_sjs1  // SJS1フラグをチェック
  beq tkp_not_sjis
  // S-JIS code, read 2nd byte
  ldb r2,[r1]  // 2バイト目を読み込んで、下位バイトにセット
  addi r1,1
  add r0,r2
  ldwi r7,fnjpcod
  stw [r7],r0
  tkp_not_sjis:
  // print 1 character
  pushw r1
  jalwr7 tft_kprint_chr


※このサンプルコードでは上位バイトのコード範囲しか判定していません。下位バイトも判定したい場合は各自対応してください。

 判定の過程で、文字コードをfnjpcodレジスタに書き込んでいるので、判定終了後、直ちにフォントデータの読み出しが可能となります。
 以上、プログラム(stft_kprint.asm)の一部抜粋ですので、全体像はソースコードをご確認ください。


 以下に、完成したプログラムをリンクしておきます。

  完成プログラム:stft_kprint.asm

 PCや他のArduino等の機体をホストとして、SPI-TFTへの日本語表示端末(サブシステム)として利用できるようなプログラムです。

デモンストレーション

 前節で完成したプログラム(stft_kprint.asm)は、受動的に動作するソフトウェアですので、ホスト(PC)側からテキストデータを送ってデモンストレーションを実行しようと思います。以下、デモンストレーション内容について検討します。

 完成したスクリプトをリンクしておきます。

  完成スクリプト:fontjp_kpr_demo.olv

 次節の実験で使います。スクリプトを実行するには、Windowsに拙作Olive+のインストールが必要です。

実験の時

 Moscoviumで走らせるプログラム(stft_kprint.asm)をアセンブルしてMIFファイルを作り、日本語フォントFONTJPユニットを搭載したMCOC115JP0408のデザインデータをFPGAボード(Sipeed Lichee Tang Primer)に書き込んでください。I/O制約ファイルはMCOC_full.adcです。

btn_moscovium.png

 デザインデータは上のリンクからダウンロードできます。FPGAボードへの書き込み手順はこちらを参照してください。

 デザインを書き込んだFPGAボードと、USB⇔UART変換モジュール(FTDI)SPI-TFT表示器を以下表の様に結線します。

FTDI 接続 FPGAボード 接続 SPI-TFT
TXD R7(uart_rxd)  
RXD T7(uart_txd)
VCC(ジャンパ:3.3V側) ×  
GND GND GND
LED−
  3.3V VCC
C15(port_out[7]) CS
C16(port_out[6]) SCL
B10(port_out[5]) SDA
C9(port_out[4]) A0
H13(port_out[3]) RESET
下の回路図 LED+

 汎用I/Oポートの出力端子(port_out[ ])が5本必要です。8本ある出力端子の残り3本は、オンボードのRGB LEDに割り当ててある(MCOC_full.adc)ので、すべて使い切ってしまいました。早晩増設しないと足りなくなりますね。

※「#18-7 Moscovium色々拡張」の記事で、I/Oポート数を倍増させる対応としました。


 SPI-TFTのバックライトLED電源は、以下図のような回路に接続してください。

a185_schem.png

 stft_kprint.asm制御コード(0x16)を使って、バックライトLEDの輝度を制御できるようになります。面倒な方は、DUEの時みたく3.3VとGNDに直結でも良いです。3.3V直結だと少し電流値が大きいので、50Ω程の電流制限抵抗を追加しておくのが推奨です(上図R3相当を追加)。バックライトLEDが少し暗くなりますが、表示は十分に視認できます。

 最初、普通にNPNトランジスタを使ってスイッチングする回路(引き込み側にスイッチ)を組んだのですが、どうやらSPI-TFTの基板上でLED−端子がGNDに落ちている様で、うまく制御できませんでした(わざわざGNDと端子を分離しておいて、紛らわしいよ!)。そこで、PNPトランジスタ(手持ちのS8550)を使って、上図の様な回路(注入側にスイッチ)としました。
 PNPトランジスタなので、E16端子=LOWでバックライトLEDが点灯し、E16=HIGHで消灯します。FPGAボードのE16端子は汎用16ビットタイマTIM162ユニットのPWM出力(tmr0_pmwa)となっており、単なるON/OFFだけでなく、中間輝度で光らせることもできます。最後にご覧いただくデモ動画で、その様子もご覧いただけます。


 実験中の様子を示します。

a185_expr.jpg

 シリアル(SPI)接続だと油断していたのだけど、意外にジャンパ線の数が多い……。追加のストローブ信号(D/CX)、リセット信号(RESX)、バックライトLEDの制御信号など、ちょいちょい、増加してるから。でも、許容範囲。


 以下、表示サンプルです。

a185_stft1.jpga185_stft2.jpga123_expr.jpg

 まず、左側の画像から。文字色を変えたり、背景色を変えたりして描画できます。文字の左右・上下反転や回転、倍角表示などはハードウェアのサポートがあるので、ソフトの負担はほとんどありません。
 中央の画像は、ランダムに選択した漢字をグラデーション表示した物です。右側の画像(DUE+TFTシールド)と比較してみてください。一画面に表示されている漢字の数はほぼ同数ですが、SPI-TFT(1.8インチ)の方は8×8ドットフォント、TFTシールド(2.8インチ)の方は16×16ドットフォントです(ランダムなので、表示されている漢字は異なります)。


 以下、動作中の様子を動画にしてみました。



 編集なし(キャプションは追加してます)、撮影したままの動画ですので、描画速度なども実感していただけると思います。
 DUEで試行した時より、少し描画が速い気がします。DUEでは、遅い標準関数(digitalWrite()等)を使ってソフトウェアSPIを実装したのですが、Moscoviumマイコンではアセンブラ+ループアンローリングで実装したので、その分速くなった様です。DUEでも、こちらの例の様に工夫すれば速くなります。
 何気に、「縦書き表示」の描画でも、通常表示の描画と速度が変わらないことに気が付くはずです。フォントの回転にはハードウェアサポートがあるためです!


 だいぶ電流を絞ったのですが、バックライトLEDの明るさも、十分でありましょう?何より、電気の無駄遣いになりますので、電流制限抵抗の追加を推奨します。


btn_arduino.png

btn_prev.png btn_next.png

home