GU3000Graphicクラス(VFDクラス)は, 描画機能を提供するFrameBufferクラスと,ハードウェア(GPIO)を制御するGU3000GPIOクラスを継承して作られています. VFDクラスはGU3000Graphicクラスと同一のもの(typedefで定義)です. 本マニュアルでは,それぞれのクラスとそれらの関数(メソッド)について説明します.
class GU3000Graphic : public FrameBuffer, private GU3000GPIO
typedef GU3000Graphic VFD;
グラフィックDMAモードの詳細についてはVFDモジュールの仕様書「基本機能ソフトウェア仕様書 5章 グラフィックDMAモード」を参照して下さい.
git clone https://github.com/ryomuk/gu3000.git
cd gu3000/src
make
これで,静的ライブラリ gu3000.a が出来ます.
gu3000graphic.hをインクルードして下さい.
プログラム例 hello.cpp
#include <gu3000graphic.h>
int main(){
VFD vfd;
vfd.puts("Hello World!");
vfd.show();
}
wiringPi,およびgu3000.aをリンクして下さい. 直接コンパイルのコマンドを入力する場合は,下記の例のようにします.
cd gu3000/src/examples/hello
g++ -c hello.cpp -I../..
g++ -o hello hello.o ../../gu3000.a -lwiringPi -I../..
ライブラリやinclude用のパスは,Makefile等で適宜設定して下さい.
描画はFrameBufferのbuf上に行われます. buf[]はshow()メソッドによってVFDの表示メモリ(display_memory[])に転送されます. VFDに送られた内容はm_buf[]にもコピーされます.
graphicDMAモードにおいてもVFDへの転送はそれなりに時間がかかるので, 差分が含まれるエリア(差分が開始したところから終了したところまで)を転送します.
+-------------------------------
|GU3000Graphic(= VFD)
| (typedef GU3000Graphic VFD)
|+-------------------+
|| FrameBuffer |
||buf[WIDTH*HEIGHT] |
|+-------------------+
|
|m_buf[WIDTH*HEIGHT*面数]
|
|+-------------------+
|| GU3000GPIO |
|| RDY WR D0-D7 |
|+-------------------+
+--------------------------------
↑ ↓ ↓
+--------------------------------
RDY WR D0-D7
| VFDモジュール
| display_memory[WIDTH*HEIGHT*面数]
+--------------------------------
- gu3000gpio.h
- gu3000gpio.cpp
GPIOのピンを下記デフォルト値で設定します. データバスはData0から8bitの連番に設定されます.
#define VFD_RDY 18 // RDY信号ピン番号
#define VFD_WR 19 // WR信号(負論理)ピン番号
#define VFD_Data0 20 // Data0ピン番号
void GU3000GPIO::init(int rdy, int wr, int d0, int d1, int d2, int d3, int d4, int d5, int d6, int d7)
GPIOのピンを引数に従って設定します.
VFDモジュールのピクセルの並びは下記のようになっています. (「ディスプレイモジュール3900Bシリーズ"基本機能"ソフトウェア仕様書」 5章 グラフィックDMAモード, 5.2節 表示メモリ 参照)
アドレスは上から下に増加しますが,1バイト(8ピクセル)中は,MSBが上,LSBが下です.
VFD hardware pixel mapping is MSB first (why??)
See software manual (section 5.2(page 63))
x
y 0 1 2 3 4 5... 255
0 D7
D6
D5
D4
D3
D2
D1
D0
1 D7
D6
D5
D4
.
.
好みの問題かもしれませんが,これは若干気持が悪いので,FrameBufferクラスではLSBが上,MSBが下として描画処理を実装しています. ビットマップ画像もこの格納方法に従います.
GU3000GPIO::writeByteImage()でVFDへに画像(bitmapimage)の書き込む際に, プライベート変数m_bitmaporderの値によって, D0〜D7の順かD7〜D0の順かを切り替えています. デフォルトの設定はLSB firstです.
//
// Bit Order of Image Data for writeByteImage()
//
#define VFD_MSBFIRST 0
#define VFD_LSBFIRST 1
#define VFD_DEFAULT_BITMAPORDER VFD_LSBFIRST
GPIO経由で1バイト書き込む.
GPIO経由で1バイトのbitmapイメージ(縦8bitx横1bit)を書き込む. データがMSB first(上がMSB)かLSB first(上がLSB)かは, m_bitmaporder(デフォルト値はLSB first)で設定しておく.
VFD側は上がMSBなので,デフォルトの設定では イメージデータはテレコになって書き込まれる.
GPIO経由で1ワード(2バイト)書き込む.
RDY信号(入力)のGPIOピン番号です.
WR信号(出力, 負論理)のGPIOピン番号です.
Data0〜Data7(出力)のGPIOピン番号です.
ビットマップがLSB firstかMSB firstかを指定するための変数です.
VFDモジュールからのRDY信号がアクティブになるのを待ちます. 通常の待ち時間はマイクロ秒レベルなので, 割り込み等ではなくひたすらポーリングするループです. VFDからインターフェースボードへの入力はプルアップされていますが, インターフェースボード自体が無いとここで止まってしまうので, その場合はVFD_DEGUB_IGNORE_RDYを#defineしてコンパイルします. GPIOのRDYをプルアップに設定しておけばいいかと思いましたが、 Raspbery Pi 4ではプルアップできるピンが限定されているようなので、 こうなっています.
inline void waitRDY(){
#ifndef VFD_DEGUB_IGNORE_RDY
while(!digitalRead(m_rdy)){
}
#endif
簡易的な描画機能を提供するクラスです.
- framebuffer.h
- framebuffer.cpp
- font.h
- font.cpp
- fonts/*.h
左上が原点です.回転は実装していません.
(0, 0) ... (WIDTH-1, 0)
.
.
.
(0, HEIGHT-1) (WIDTH-1, HEIGHT-1)
フレームバッファのメモリです.1bit/1ピクセル. MycroPythonのframebufで言う,'MONO_VLSB'です.
VFDモジュールにあわせて,垂直方向にアドレスが並ぶようになっています. VFDモジュールの表示メモリはMSBが上(座標が小さい側, MSB first)ですが, 普通はLSB firstだと思うので,LSB firstで実装しています. MycroPythonのframebufにも'MONO_VMSB'は無かったので. でもなぜかffmpegのrawvideoはMSB firstのようです.
フレームバッファの幅.
フレームバッファの高さ.
WIDTH * HEIGHT / 8 です.ループで出てくることが多い値なので,個別の変数にしています.
文字描画用のカーソル位置(x座標).
文字描画用のカーソル位置(y座標).
文字描画用のフォント.
ライブラリ内蔵フォントのリスト.
WIDTH = x, HEIGHT = yで初期化.bufを確保します. フォントをデフォルト(g_DefaultFont)に設定します.
buf[0..bufsize]をcで埋めます.
bufをゼロクリアして,カーソル位置を(0,0)にします. GU3000Graphicクラスでは,clearFrameBuffer() で呼びます. (参考: GU3000Graphic::clear()はフレームバッファのクリアに加えて, VFDモジュールの表示メモリもクリアします.)
(x, y)にピクセルを描画します. 高速にするために,定義域のエラーチェックをしていないことに注意.
(x, y)のピクセルを消します. 高速にするために,定義域のエラーチェックをしていないことに注意.
(x, y)のピクセル値を返します. ピクセルが無ければ0, ピクセルがあれば,(1<<(y&7))を返します. (x, y)がフレームバッファの範囲外の場合は0を返します.
各バイトがMSB first(MSBが上)の場合の(x, y)のピクセル値を返します. ピクセルが無ければ0, ピクセルがあれば,(1<<(7-(y&7)))を返します. (x, y)がフレームバッファの範囲外の場合は0を返します.
(x, y)のピクセルを描画/消去します.(pen!=0: 描画, pen==0: 消去) (x, y)がフレームバッファの範囲外の場合は何もしません.
(x0, y0)から(x1, y1)までの線を描画/消去します.(pen!=0: 描画, pen==0: 消去) 水平線はwriteFastHline,垂直線はwriteFastVline, それ以外はwriteLineにディスパッチしています.
四角形(辺だけ)を描画,消去します.(pen!=0: 描画, pen==0: 消去)
四角形(内部塗りつぶし)を描画,消去します.(pen!=0: 描画, pen==0: 消去)
座標(x, y)から(x+width-1, y+height-1)を対角線とする矩形エリアに, 幅width, 高さheightのビットマップ画像を描画します.
現カーソル位置に文字を描画してカーソルを進めます. 描画スペースが無い場合はスクロールします.
現カーソル位置に文字列を描画してカーソルを進めます. 描画スペースが無い場合はスクロールします.
座標(x, y)に文字を描画します.カーソル位置は変えません.
文字描画用のカーソル位置(文字の左上)を(x, y)に設定します.
1バイト(8ピクセル)分,上にスクロールします.
タブストップの位置をnの倍数文字目に設定します.
文字描画用のフォントをフォントデータへのポインタで設定する. フォントデータの実体はfonts/*.hに記載されており, font.cppがインクルードし,Font *型のグローバル変数(定数)になっています.
文字描画用のフォントをフォント名で設定する.
フォント名を引数とし,フォントデータへのポインタを返します.
デフォルトのフォントを描画用に設定します.下記と等価です.
setFontByName(FONT_DEFAULT_FONTNAME)
デフォルト値は下記の通りです.(font.hに記載)
#define FONT_DEFAULT_FONTNAME "Noritake6x8"
現在設定されているフォントを元に, プロポーショナルフォントで描画するため のフォントビットマップテーブル(*m_pfont_bitmap_ptr[])と, 文字幅のテーブル(m_pfont_width[])を作成します.
文字描画を固定幅フォントで描画するように設定します.
setBitmapOrder(VFD_MSBFIRST)に設定した場合の文字描画用にフォントデータを変換します.
水平方向でLSB firstのビットマップ画像をbufに読み込みます.
BMPファイル形式のコンテンツのビットマップ画像をbufに読み込みます.
1byte/pixelのビットマップ画像をbufに読み込みます.
m_ybytes = HEIGHT / 8 です.出現頻度が多いので,専用の変数にしています.
現在のフォントのビットマップデータへのポインタです.
現在のフォントの幅です.
現在のフォントの高さです.
フォント描画時のx方向の余白です.
フォント描画時のy方向の余白です.
現在のフォントの先頭コードの値です.
現在のフォントの末尾コードの値です.
フォントのbitmapの1文字あたりのバイト数です.
文字の描画をプロポーショナルにするか固定幅にするかのフラグです. (false: 固定幅, true: プロポーショナル)
setFontPropotional()が生成する, プロポーショナルフォント用のビットマップデータのテーブルです.
setFontPropotional()が生成する, プロポーショナルフォントの各文字の幅のテーブルです.
(x0, y0)から(x1, y1)までの線を描画します. drawLineから呼ばれます.
(x, y)から長さvlengthの垂直線を描画します.
(x, y)から長さhlengthの水平線を描画します.
ビットマップ画像の空白ではない部分の幅を返します. setFontProportional()で,プロポーショナルフォントの文字幅テーブルを作成するための関数です.
ビットマップ画像の空白ではない部分のy座標(最左が0)を返します. setFontProportional()で,プロポーショナルフォントのビットマップデータテーブルを作成するための関数です.
typedef struct {
const byte *bitmap; // VLSB(垂直方向, LSB first)のビットマップデータ
const char *name; // getFontByName(), setFontByName() で使われる名前
int width; // 文字の幅
int height; // 文字の高さ
int xspace; // x方向の余白
int yspace; // y方向の余白
int firstcode; // 最初の文字コード
int lastcode; // 最後の文字コード
} Font;
フォントデータのリストです.font.cppで, fonts/*.h に記述されたフォントデータの実体を列挙して定義されます.
GU3000Graphicクラスは, FrameBufferクラスをpublicで,GU3000GPIOクラスをprivateで継承したクラスです. グラフィックDMAモードのVFDにFrameBufferの内容を表示する機能を実装しています.
- gu3000graphic.h
- gu3000graphic.cpp
VFDモジュールのx方向(横)のドット数です.
VFDモジュールのy方向(縦)のドット数です.
デフォルト値で初期化します.
init(VFD_Xdots, VFD_Ydots, VFD_DispMemSize, VFD_DAD_BROADCAST);
引数に従って初期化します.
- x: x方向(横)ドット数
- y: y方向(縦)ドット数
- memsize: VFDモジュールの総バッファサイズ(表示エリア+非表示エリア)
- DAD: VFDモジュールのアドレス(マニュアルでDADと呼ばれているもの)
VFDモジュールのアドレス(マニュアルでDADと呼ばれているもの)を設定します. ブロードキャストの場合は0xffです.
GU3000GPIO::setBitmapOrder() と同じものです.
指定されたVFD表示メモリのアドレスにビットイメージデータを書き込みます. VFDモジュールのコマンド(ビットイメージ書き込み, 5.4.1.1節)に対応します.
指定されたエリアにビットイメージを書き込みます. VFDモジュールのコマンド(エリアビットイメージ書き込み, 5.4.1.2節)に対応します.
表示スタートアドレスを指定します. VFDモジュールのコマンド(表示スタートアドレス指定, 5.4.1.3節)に対応します.
このコマンドの後に書き込まれたコマンドは,内部表示リフレッシュに同期して動作します. VFDモジュールのコマンド(リフレッシュ同期表示指定, 5.4.1.4節)に対応します.
輝度を設定します. VFDモジュールのコマンド(表示輝度指定5.4.1.5節)に対応します.
show()メソッドで転送する先のVFDの表示メモリのアドレス (描画用アドレス)を設定します.
転送先アドレスが複数面ある場合にローテートします. 非表示エリアに描画するような場合に使用します.
描画用アドレスの値を,VFDの表示アドレスに設定します. 非表示面に描画した後に表示開始するような場合に使用します.
フレームバッファのクリア,VFD表示メモリのクリアを行います. VFDの表示開始アドレスと描画用アドレスを0に設定します.
フレームバッファ(buf[])をクリアし,カーソル位置を(0,0)にします. FrameBuffer::clear()と等価です.
buf[]の内容をVFDに転送します. 転送先の先頭アドレスは描画用アドレス(m_drawing_addr)です. VFDに送られた内容はm_buf[]にもコピーされます.
graphicDMAモードにおいてもVFDへの転送はそれなりに時間がかかるので, 差分が含まれるエリア(差分が開始したところから終了したところまで)を転送します.
描画用アドレスをローテートした後に描画します.
VFDの内部表示リフレッシュに同期してshow()のバッファ転送を行います.
描画用アドレスをローテートした後に描画し, VFDの内部表示リフレッシュに同期して表示アドレスを更新します.
buf[]全体を(差分転送ではなく)VFDの表示メモリに転送します.
VFDの表示メモリに転送した内容を保持するためのバッファです. 差分転送用に使用します.
1回目のshow()処理であることを示すフラグです.
- true: buf[]全体をVFDに転送します.
- false: 差分転送を行います.
VFDモジュールの総バッファサイズ(byte数)(表示エリア+非表示エリア)です.
VFDモジュールの表示エリアのサイズ(byte数)です.
show()が転送する先の表示メモリのアドレスです.
VFDモジュールのアドレス(マニュアルでDADと呼ばれているもの)です.
コマンドの強制中断等によって, writeBitImage()等の処理が途中で中断されている可能性があるため, VFD初期化時に, VFDに対して表示メモリサイズ分のダミーデータを送ります.
VFDモジュールのコマンドを起動します. 「基本機能ソフトウェア仕様書 5.4節」参照.
https://www.noritake-itron.jp/products/module/gu-3000
- 「ディスプレイモジュールハードウェア仕様書」DS-1604-000-04, 2015年6月1日改訂
- 「ディスプレイモジュール3900Bシリーズ"基本機能"ソフトウェア仕様書」DS-1600-0007-00, 2010年11月29日制定
- 「蛍光表示管モジュール「GU-3000 シリーズ モジュール」アプリケーションノート」 APF300 R1.72