はじめに
MachiKaniaがサポートしている液晶ディスプレイはILI9341搭載QVGA(320x240)またはILI9488搭載480x320でSPI接続のものなのでそれ以外の制御チップを使用しているディスプレイは接続できないとが試しにST7789搭載の液晶ディスプレイを接続したらグラフィックsなど表示できたがファイル選択などの画面は表示しない部分やひょじじたいがおかしくなってしまった。そこでST7789搭載の液晶ディスプレイを利用するプログラムの作成を試みた。
検証環境
以下の環境でプログラムの作成と検証を行ないました。
- macOS : Tahoe 26.0.1
- PicoCalc : Raspberry Pi Pico
- MachiKania : Phyllosoma 1.6.0
使用部品
下記の部品を使用しました。
- ディスプレイ:ST7789SPI接続液晶ディスプレイ。Amazonで購入したが執筆時点で商品ページ(XiangCai(よく考える) 2.0インチTFTディスプレイOLEDLCDドライブICST7789V240RGBx320ドットマトリックスSPIインターフェイスArduioフルカラーLCDディスプレイ用黒プリント基板, 11JJ402611_huaiyan)はなくなっていた。
配線
Raspberry Pi PicoとST7789搭載液晶ディスプレイはSPI1で接続し、各端子は次のように配線しました。Picoの()内の数値はRaspberry Pi Picoの物理ピン番号です。
| ST7789 | Pico |
|---|---|
| GND | GND(38) |
| VCC | 3V3(36) |
| SCL | GP10(14) |
| SDA | GP11(15) |
| RST | GP21(27) |
| DC | GP22(29) |
| CS | GP5(7) |
配線図を以下に示します。
MachiKaniaのSPIピン設定
MachiKaniaはSPI出使用するRaspberry Pi Picoのピン番号を設定ファイルMACHIKAP.INIに記述しておく。上記の敗戦にあわせて下記の設定をしました。
SPIMISO=8
SPIMOSI=11
SPICLK=10
ST7789搭載液晶ディスプレイを利用する流れ
ST7789を搭載した液晶ディスプレイを使用するまでの流れは次のとおりです。
- SPIのチャンネルを開く
- ST7789の初期化
- 描画の実行
SPIのチャンネルを開く
MachiKaniaではSPIで使用するピンをファイルMACHIKAP.INIに記載しているのでBASICのコードではSPIの動作周波数、転送データ幅、SPIモード、CSピンを指定するだけでよい。今回は周波数20MHz、データ幅8ビット、モード2、物理ピン5(GP3)をCSとしました。また、液晶ディスプレイのRESETピン、CSピンをハイレベルに設定します。コードは次のとおりです。
WAIT 120
SPI 20000, 8, 2, 5
DELAYMS 300
OUT 11, 1 : OUT 12, 1
ST7789初期化
以前、Raspberry Pi PicoでPicoMite(MMBasic)を使う〜CSなしST7789 LCDを動かすで使用したコードをKM-BASICのコードに変換し、さらにフレームレートなどの設定を追加しました。下記がそのコードで、サブルーチンINITとして定義しています。その他のサブルーチンについては後述します。
LABEL INIT
REM ハードリセット
OUT 11, 1 : DELAYMS 10
OUT 11, 0 : DELAYMS 10
OUT 11, 1 : DELAYMS 120
GOSUB SCMD, $01 : REM SWRESET
DELAYMS 150
GOSUB SCMD, $11 : REM SLPOUT
DELAYMS 120
REM 16bitカラー ,RGB565
GOSUB SCMD, $3A : GOSUB SDATA, $55
REM MADCTL : ポートレートモードに
GOSUB SCMD, $36 : GOSUB SDATA, $00
REM フレームレート等の設定
GOSUB SCMD, $B2
POKE BUF, $0C : POKE BUF+ 1, $0C
POKE BUF+ 2, $00 : POKE BUF+ 3, $33
POKE BUF+ 4, $33
GOSUB SDBLK, BUF, 5
GOSUB SCMD, $B7 : GOSUB SDATA, $35
GOSUB SCMD, $BB : GOSUB SDATA, $19
GOSUB SCMD, $C0 : GOSUB SDATA, $2C
GOSUB SCMD, $C2 : GOSUB SDATA, $01
GOSUB SCMD, $C3 : GOSUB SDATA, $12
GOSUB SCMD, $C4 : GOSUB SDATA, $20
GOSUB SCMD, $C6 : GOSUB SDATA, $0F
GOSUB SCMD, $D0 : GOSUB SDATA, $A4 : GOSUB SDATA, $A1
REM ディスプレイをオンに
GOSUB SCMD, $29
DELAYMS 100
RETURN
コマンド送信サブルーチン SCMD
ST7789にコマンドを1バイトのコマンドを送信するサブルーチンSCMDを次のように定義しました。CSをローレベルにして、SPIWRITE命令で引数のデータを送信します。
LABEL SCMD
VAR C
C = ARGS(1)
OUT 12, 0 : REM CSをローに
SPIWRITE C
RETURN
データ送信サブルーチン SDATA
ST7789にコマンド送信後に1バイトのデータを送信するサブルーチンSDATAを次のように定義しました。CSをハイレベルにして、SPIWRITE命令でサブルーチンの引数のデータを送信します。
LABEL SDATA
VAR D
OUT 12, 1 : REM CSをハイに
D = ARGS(1)
SPIWRITE D
RETURN
データのバルク送信サブルーチン SDBLK
ST7789にコマンド送信後に複数個のデータを送信するサブルーチンSDBLKを次のように定義しました。CSをハイレベルにして、SPIWRTIEDATA命令でサブルーチンの最初の引数のバッファアドレスから二番目の引数の個数分のデータを送信します。
LABEL SDBLK
VAR B,N
B = ARGS(1) : N = ARGS(2)
OUT 12, 1
SPIWRITEDATA B, N
RETURN
データ転送先領域指定サブルーチン SAWIN
ST7789ではデータ転送先領域の横方向の範囲をコマンド2AH、縦方向の範囲をコマンド2BHを送信後に始点・終点の順にまとめて送信しておきます。
この範囲指定後に指定領域分の描画データをまとめて送信するとディスプレイに表示されます。
LABEL SAWIN
VAR X0,X1,Y0,Y1
X0 = ARGS(1) : Y0 = ARGS(2)
X1 = ARGS(3) : Y1 = ARGS(4)
GOSUB SCMD, $2A
POKE AWB, X0 /256 : POKE AWB + 1, X0 % 256
POKE AWB + 2, X1 /256 : POKE AWB + 3, X1 % 256
GOSUB SDBLK, AWB, 4
GOSUB SCMD, $2B
POKE AWB, Y0 /256 : POKE AWB + 1, Y0 % 256
POKE AWB + 2, Y1 /256 : POKE AWB + 3, Y1 % 256
GOSUB SDBLK, AWB, 4
GOSUB SCMD, $2C
RETURN
描画機能
ST7789の初期化が完了したら文字などを描画できるようになります。今回は下記の機能をサブルーチンで作成しました。多くはChatGPTの力を借りて作成しています。
| 機能 | サブルーチン名 | 引数 |
|---|---|---|
| 16ビットカラー生成 | RGB565 | RGBの各階調 |
| 一文字 | DCHR | 表示開始座標、文字、前景色、背景色 |
| 文字列 | DSTR | 表示開始座標、文字列、前景色、背景色 |
| 1ピクセル描画 | DPXL | 表示座標、色 |
| 直線 | DLINE | 始点と終点座標、色 |
| 長方形 | RECT | 描画開始座標、幅、高さ、線幅、色、塗りつぶしの有無 |
| 水平線 | HLINE | 表示開始座標、長さ、色 |
| 垂直線 | VLINE | 表示開始座標、長さ、色 |
| 円 | DCIRCLE | 中心座標、半径、線幅、色、塗りつぶしの有無 |
| 楕円 | ELLIPSE | 中心座標、縦径、横径、線幅、色、塗りつぶしの有無 |
16ビットカラー値算出サブルーチン RGB565
3つの引数に与えてRGBの8ビットの値から16ビットカーラを計算し、返すサブルーチン。ST7789が反転表示してしまうためRGBの値を255から引いて計算している。
LABEL RGB565
VAR R,G,B,C
R = ARGS(1) : G = ARGS(2) : B = ARGS(3)
C = ((255 - R >> 3) << 11) OR ((255 - G >> 2) << 5) OR (255 - B >> 3)
RETURN C
一文字描画サブルーチン DCHR
引数で指定した座標を表示する文字の左上座標として指定した前景色と背景色で描くサブルーチン。
文字データはMachiKaniaのシステムフォントのデータを一文字分読み取って前景色、背景色データをバッファに保管してまとめ、サブルーチンSAWINでバッファのデータを転送領域を指定し、サブルーチンSDBLKでまとめて転送します。MachiKaniaのIL9325.BASのprtメソッドのコードを利用しました。
ディスプレイの
ABEL DCHR
VAR PX,PY,CH,FG,BG
VAR A,I,P,D
VAR ROW,PIX
VAR FGH,FGL,BGH,BGL
VAR COL
REM 引数の値をローカル変数に代入
PX = ARGS(1) : PY = ARGS(2) : CH$ = ARGS$(3)
FG = ARGS(4) : BG = ARGS(5)
REM 前景色、背景色を上位8ビット下位8ビットに分ける
FGH = FG / 256 : FGL = FG % 256
BGH = BG / 256 : BGL = BG % 256
A = PEEK(CH) : IF A=0 THEN RETURN : REM 文字データを読み取り、
P = SYSTEM(103) + A * 8 : REM フォントデータのアドレスを取得
I = 0
FOR ROW = 0 TO 7 : REM 行
D = PEEK(P) : REM フォンとデータの取得
FOR PIX = 0 TO 7 : REM 1ドットごとの前景、背景の判断
IF D AND $80 THEN
POKE CBUF + I * 2, FGH : POKE CBUF + I * 2 + 1, FGL
ELSE
POKE CBUF + I * 2, BGH : POKE CBUF + I * 2 + 1, BGL
ENDIF
D=D<<1 : REM 次のドットを先頭にシフト
I=I+1
NEXT
P=P+1 : REM 次の行へ
NEXT
REM フォンとデータの転送領域の指定
GOSUB SAWIN, PX, PY, PX + 7, PY + 7
GOSUB SCMD, $2C : REM メモリへの書き込み開始
GOSUB SDBLK, CBUF, 8*2*8 : REM 書き込みデータをバルク転送
RETURN
文字列描画サブルーチン DSTR
文字描画サブルーチンDCHRを使って文字列を描画するサブルーチン。引数に与えられた文字列から一文字ずつ取り出して文字描画サブルーチンDCHRで描きます。
KM-BASICには他のBASICにあるMID$関数がないが文字列変数$(取り出す位置,取り出す文字数)で同様の機能を実現できる。
LABEL DSTR
VAR PX,PY,TXT,FG,BG
VAR K
REM 引数の取得と格納
PX=ARGS(1) : PY=ARGS(2) : TXT$=ARGS$(3)
FG=ARGS(4) : BG=ARGS(5)
REM 文字列の先頭から一文字ずつとり出し、文字描画サブルーチンDCHRで描画
FOR K=0 TO LEN(TXT$)-1
GOSUB DCHR, PX, PY, TXT$(K, 1), FG, BG
PX = PX + 8
NEXT
RETURN
1ピクセル描画サブルーチン DPXL
引数で指定した座標のピクセルに、引数で指定した色のデータを書き込むサブルーチン。
LABEL DPXL
VAR X,Y,C
REM 引数の取得と格納
X = ARGS(1) : Y = ARGS(2) : C = ARGS(3)
REM 色データを8ビットごとに分割
POKE BUF, C / 256 : POKE BUF + 1, C % 256
REM データ転送先の指定
GOSUB SAWIN, X, Y, X, Y
GOSUB SDBLK, BUF, 2 : REM 色データを転送
RETURN
直線描画サブルーチン DLINE
引数で指定した開始、終了座標間に指定した色の直線を描くサブルーチン。ChatGPTの力を借りて作りました。
1ピクセル描画サブルーチン DPXLを使って始点座標から終点座標に一つずつ点を描画することで直線を描いています。
LABEL DLINE
VAR X0,X1,Y0,Y1,COL
VAR SX,SY,ERR,E2
REM 引数の取得と格納
X0 = ARGS(1) : Y0 = ARGS(2)
X1 = ARGS(3) : Y1 = ARGS(4)
COL = ARGS(5)
DX = ABS(X1 - X0) : DY = ABS(Y1 - Y0)
IF X0 < X1 THEN SX = 1 ELSE SX = -1
IF Y0 < Y1 THEN SY = 1 ELSE SY = -1
IF DX > DY THEN
ERR = DX / 2
ELSE
ERR = DY / 2
ENDIF
REM 1ピクセルずつ描画
DO
GOSUB DPXL, X0, Y0, COL
IF X0 = X1 AND Y0 = Y1 THEN BREAK
E2 = ERR
IF E2 > -DX THEN ERR = ERR - DY : X0 = X0 + SX
IF E2 < DY THEN ERR = ERR + Dx : Y0 = Y0 + SY
LOOP
RETURN
長方形描画サブルーチン RECT
引数で指定した長方形の左上の座標から引数で指定した幅と高さの長方形を指定され線幅で描きます。塗りつぶし指定があると塗りつぶしの長方形が描かれます。このコードもChatGPTの力を借りました。
長方形の描画は水平線描がサブルーチンHLINEと垂直線描がサブルーチンVLINEを使用しています。
LABEL RECT
VAR X0,Y0,X1,Y1
VAR W,H,T,COL,FILL
VAR I
REM 引数の取得と格納
X0 = ARGS(1) : Y0 = ARGS(2)
W = ARGS(3) : H = ARGS(4)
T = ARGS(5) : COL = ARGS(6) : FILL = ARGS(7)
REM 終点の算出
X1 = X0 + W - 1 : Y1 = Y0 + H - 1
REM 塗りつぶし指定が有る場合は水平線描サブルーチンHLINEで描く
IF FILL != 0 THEN
FOR I = Y0 + T TO Y1 - T
GOSUB HLINE, X0+T, I, W-2*T, COL
NEXT
ENDIF
REM 上下の枠の描画
FOR I = 0 TO T - 1
GOSUB HLINE, X0, Y0+I, W, COL
GOSUB HLINE, X0, Y1-I, W, COL
NEXT
REM 左右の枠の指定
FOR I = 0 TO T - 1
GOSUB VLINE, X0+I, Y0, H, COL
GOSUB VLINE, X1-I, Y0, H, COL
NEXT
RETURN
水平線描画サブルーチン HLINE
水平線を描くサブルーチンです。
描画するデータをバッファにまとめて格納し、指定した領域にバルク転送します。
LABEL HLINE
VAR X,Y,L,COL
VAR HI,LO
VAR I
REM 引数の取得と格納
X = ARGS(1) : Y = ARGS(2) : L = ARGS(3) : COL = ARGS(4)
HI = COL / 256 : LO = COL % 256 : REM 色データの分離
REM 色データをバッファに格納
FOR I=0 TO L
POKE BUF + 2 * I, HI
POKE BUF + 2 * I + 1, LO
NEXT
REM データ転送領域を指定し、水平線データを転送
GOSUB SAWIN, X, Y, X+L-1, Y
GOSUB SCMD, $2C
GOSUB SDBLK, BUF, L * 2
RETURN
垂直線描画サブルーチン VLINE
垂直線を描くサブルーチンです。水平線と同様に描画するデータをバッファにまとめて格納し、指定領域にバルク転送しています。
LABEL VLINE
VAR X,Y,L,COL
VAR HI,LO
VAR I
REM 引数の取得と格納
X = ARGS(1) : Y = ARGS(2) : L = ARGS(3) : COL = ARGS(4)
REM 色データをバッファに格納
HI = COL / 256 : LO = COL % 256
FOR I=0 TO L - 1
POKE BUF + 2 * I, HI
POKE BUF + 2 * I + 1, LO
NEXT
REM データ転送領域を指定し、水平線データを転送
GOSUB SAWIN, X, Y, X, Y+L-1
GOSUB SCMD, $2C
GOSUB SDBLK, BUF, L * 2
RETURN
円描画サブルーチン DCIRCLE
引数で指定した中心座標、半径、線幅、色の円あるいは塗りつぶし円を描きます。
LABEL DCIRCLE
VAR CX,CY,R,T,COL,FILL
VAR Y,XOUT,XIN,RIN
REM 引数の取得と格納
CX = ARGS(1) : CY = ARGS(2)
R = ARGS(3) : T = ARGS(4)
COL= ARGS(5) : FILL=ARGS(6)
IF T < 1 THEN T = 1
IF R-T+1 > 0 THEN RIN=R-T+1 ELSE RIN=0
FOR Y = -R TO R
XOUT = INT(SQRT#(FLOAT#(R*R - Y*Y)) + 0.5)
IF FILL=1 THEN
GOSUB HLINE, CX-XOUT, CY+Y, 2*XOUT+1, COL
ELSE
GOSUB DPXL, CX-XOUT, CY+Y, COL
GOSUB DPXL, CX+XOUT, CY+Y, COL
ENDIF
IF NOT(FILL) AND RIN > 0 THEN
IF ABS(Y) < RIN THEN
XIN = INT(SQRT#(FLOAT#(RIN * RIN - Y*Y)) + 0.5)
ENDIF
ENDIF
NEXT
RETURN
楕円描画サブルーチン ELLIPSE
引数で指定した中心座標、横径、縦径、線幅、色の楕円あるいは塗りつぶし楕円を描きます。
LABEL ELLIPSE
VAR CX,CY,HDIAM,VDIAM,T,COL,FILL
VAR INNERRX,INNERRY
VAR Y,XOUT,XIN,FRAC,RX,RY
REM 引数の取得と格納
CX = ARGS(1) : CY = ARGS(2)
VDIAM = ARGS(3) : HDIAM = ARGS(4)
T = ARGS(5) : COL = ARGS(6)
FILL = ARGS(7)
IF T < 1 THEN T = 1
RX = HDIAM / 2
RY = VDIAM / 2
IF RX <= 0 OR RY <= 0 THEN RETURN
IF RX - T + 1 > 0 THEN INNERRX = RX -T + 1 ELSE INNERRX = 0
IF RY - T + 1 > 0 THEN INNERRY = RY -T + 1 ELSE INNERRY = 0
FOR Y = -RY TO RY
FRAC# = 1.0 - FLOAT#(Y * Y) / FLOAT#(RY * RY)
IF FRAC# < 0 THEN FRAC# = 0
XOUT = INT(FLOAT#(RX) * SQRT#(FRAC#) + 0.5)
IF FILL = 1 THEN
GOSUB HLINE,CX-XOUT, CY+Y, 2*XOUT+1, COL
ELSE
IF INNERRX=0 OR INNERRY=0 THEN
GOSUB DPXL, CX-XOUT, CY+Y, COL
GOSUB DPXL, CX+XOUT, CY+y, COL
ELSE
FRAC# = 1.0 - FLOAT#(Y*Y)/FLOAT#(INNERRY*INNERRY)
IF FRAC# < 0 THEN
XIN = -1
ELSE
XIN = INT(FLOAT#(INNERRX) * SQRT#(FRAC#) + 0.5)
ENDIF
IF XIN < 0 THEN
GOSUB HLINE, CX-XOUT, CY+Y, 2*XOUT+1, COL
ELSEIF XOUT > XIN THEN
GOSUB HLINE, CX-XOUT, CY+Y, XOUT-XIN, COL
GOSUB HLINE, CX+XIN+1, CY+Y, XOUT-XIN, COL
ENDIF
ENDIF
ENDIF
NEXT
RETURN
画面クリアサブルーチン CLSC
画面を指定した色でクリアするサブルーチンです。
画面の上から一行ずつの指定した色データをまとめて転送して画面をクリアしています。
LABEL CLSC
VAR COL,I,Y
COL = ARGS(1)
FOR I = 0 TO 239
POKE BUF + I * 2, COL / 256
POKE BUF + I * 2 + 1, COL % 256
NEXT
GOSUB SAWIN, 0, 0, 239, 319
FOR Y = 0 TO D319
GOSUB SDBLK, BUF, 480
NEXT
RETURN
すべてのコード
下記が上記のサブルーチンを含んだ文字列、図形の描画のコードです。
REM ST7789用の機能を作成
USETIMER 100
USEVAR COL
USEVAR X0, X1, Y0, Y1
USEVAR ERR, E2
USEVAR DX, DY, SX, SY
USEVAR FILL, HI, LO
USEVAR CH, FG, BG, TXT
USEVAR FGH, FGL, BGH, BGL
USEVAR ROW, PIX, MASK, BUF
USEVAR CBUF : REM 1文字分のバッファ
USEVAR AWB : REM アドレスウィンドウ用バッファ
USEVAR PX, PY
USEVAR CC
USEVAR CX, CY, XOUT,XIN
USEVAR INNERRX, INNERRY, FRAC
USEVAR HDIAM, VDIAM
USEVAR RX, RY,RIN
REM バッファ
DIM BUF(480/4)
DIM CBUF(8*2*8/4)
DIM AWB(4)
USEGRAPHIC
Dim CC(10) : REM COLOR
REM 色定義
CC(0) = GOSUB(RGB565( 0, 0, 0) : REM Black
CC(1) = GOSUB(RGB565( 0, 0, 255) : REM Blue
CC(2) = GOSUB(RGB565( 0, 255, 0) : REM Green
CC(3) = GOSUB(RGB565( 0, 161, 233) : REM Cyan
CC(4) = GOSUB(RGB565(255, 0, 0) : REM Red
CC(5) = GOSUB(RGB565(228, 0, 127) : REM Magenta
CC(6) = GOSUB(RGB565(255, 255, 0) : REM Yellow
CC(7) = GOSUB(RGB565(128, 128, 128) : REM Gray
CC(8) = GOSUB(RGB565(165, 42, 42) : REM Brown
CC(9) = GOSUB(RGB565(255, 165, 0) : REM Orange
CC(10) = GOSUB(RGB565(255, 255, 255) : REM White
REM Open SPI
WAIT 120
SPI 20000, 8, 2, 5
DELAYMS 300
REM Set DC & Reset pin to HIGH
OUT 11, 1 : OUT 12, 1
GOSUB INIT,0 : REM ST7789の初期化
GOSUB CLSC, CC(0) : REM 画面を黒でクリア
REM 文字列描画
GOSUB DSTR, 10, 0, "Hello ST7789", CC(10), CC(0)
GOSUB DSTR, 10, 10, "RED red", CC(4), CC(0)
GOSUB DSTR, 10, 20, "GREEN green", CC(2), CC(0)
GOSUB DSTR, 10, 30, "BLUE blue", CC(1), CC(0)
USEVAR XX1, XX2, YY1, YY2
XX1 = 0 : XX2 = 0
YY1 = 0 : YY2 = 50
REM ASCIIテーブルの表示
FOR I = $20 TO $7E
GOSUB DCHR, XX2, YY2, CHR$(I), CC(10), CC(0)
XX1 = XX1 + 16
XX2 = XX2 + 8
IF (I -16) % 16 = 15 THEN
XX1 = 0 : XX2 = 0
YY1 = YY1 + 24 : YY2 = YY2 + 12
ENDIF
NEXT
REM 直線描が
FOR I= 0 TO 10
GOSUB DLINE, 130, I * 4, 239, I * 4, CC(I)
NEXT
REM 長方形描画
FOR I=1 TO 10
GOSUB RECT, 130, 50, I*10, I* 3, 2, CC(I), 0
NEXT
REM 塗りつぶし長方形
GOSUB RECT, 130, 110, 100, 50, 1, CC(2), 1
REM 同心円描画
FOR R=1 TO 10
GOSUB DCIRCLE, 40, 160, R*3, 3, CC(R), 0
NEXT
REM 塗りつぶし円描画
GOSUB DCIRCLE, 110, 160, 30, 1, CC(4), 1
REM 楕円描画
GOSUB Ellipse, 80, 240, 50, 80, 3, CC(5), 0
GOSUB Ellipse, 180, 240 ,60, 90, 1, CC(6), 1
END
REM === 以下サブルーチン郡 ===
LABEL SCMD
VAR C
C = ARGS(1)
OUT 12, 0
SPIWRITE C
RETURN
REM --------------------------------
LABEL SDATA
VAR D
OUT 12, 1
D = ARGS(1)
SPIWRITE D
RETURN
REM --------------------------------
LABEL SDBLK
VAR B,N
B = ARGS(1) : N = ARGS(2)
OUT 12, 1
SPIWRITEDATA B, N
RETURN
REM --------------------------------
REM アドレスウィンドウ
LABEL SAWIN
VAR X0,X1,Y0,Y1
X0 = ARGS(1) : Y0 = ARGS(2)
X1 = ARGS(3) : Y1 = ARGS(4)
GOSUB SCMD, $2A
POKE AWB, X0 /256 : POKE AWB + 1, X0 % 256
POKE AWB + 2, X1 /256 : POKE AWB + 3, X1 % 256
GOSUB SDBLK, AWB, 4
GOSUB SCMD, $2B
POKE AWB, Y0 /256 : POKE AWB + 1, Y0 % 256
POKE AWB + 2, Y1 /256 : POKE AWB + 3, Y1 % 256
GOSUB SDBLK, AWB, 4
GOSUB SCMD, $2C
RETURN
REM --------------------------------
REM Initialize
LABEL INIT
VAR M : REM 0=Portrait,1=Landscape
M = ARGS(1)
REM Hard reset
OUT 11, 1 : DELAYMS 10
OUT 11, 0 : DELAYMS 10
OUT 11, 1 : DELAYMS 120
GOSUB SCMD, $01 : REM SWRESET
DELAYMS 150
GOSUB SCMD, $11 : REM SLPOUT
DELAYMS 120
REM Color : 16bit,565
GOSUB SCMD, $3A : GOSUB SDATA, $55
REM MADCTL : Portrait
GOSUB SCMD, $36 : GOSUB SDATA, $00
ENDIF
GOSUB SCMD, $B2
POKE BUF, $0C : POKE BUF+ 1, $0C
POKE BUF+ 2, $00 : POKE BUF+ 3, $33
POKE BUF+ 4, $33
GOSUB SDBLK, BUF, 5
GOSUB SCMD, $B7 : GOSUB SDATA, $35
GOSUB SCMD, $BB : GOSUB SDATA, $19
GOSUB SCMD, $C0 : GOSUB SDATA, $2C
GOSUB SCMD, $C2 : GOSUB SDATA, $01
GOSUB SCMD, $C3 : GOSUB SDATA, $12
GOSUB SCMD, $C4 : GOSUB SDATA, $20
GOSUB SCMD, $C6 : GOSUB SDATA, $0F
GOSUB SCMD, $D0 : GOSUB SDATA, $A4 : GOSUB SDATA, $A1
GOSUB SCMD, $29
DELAYMS 100
RETURN
REM --------------------------------
LABEL RGB565
VAR R,G,B,C
R = ARGS(1) : G = ARGS(2) : B = ARGS(3)
C = ((255 - R >> 3) << 11) OR ((255 - G >> 2) << 5) OR (255 - B >> 3)
RETURN C
REM --------------------------------
LABEL DPXL
VAR X,Y,C
X = ARGS(1) : Y = ARGS(2) : C = ARGS(3)
GOSUB SAWIN, X, Y, X, Y
POKE BUF, C / 256 : POKE BUF + 1, C % 256
GOSUB SDBLK, BUF, 2
RETURN
REM --- LINE(X0, Y0, X1, Y1, COL)
LABEL DLINE
VAR X0,X1,Y0,Y1,COL
VAR SX,SY,ERR,E2
X0 = ARGS(1) : Y0 = ARGS(2)
X1 = ARGS(3) : Y1 = ARGS(4)
COL = ARGS(5)
DX = ABS(X1 - X0) : DY = ABS(Y1 - Y0)
IF X0 < X1 THEN SX = 1 ELSE SX = -1
IF Y0 < Y1 THEN SY = 1 ELSE SY = -1
IF DX > DY THEN
ERR = DX / 2
ELSE
ERR = DY / 2
ENDIF
DO
GOSUB DPXL, X0, Y0, COL
IF X0 = X1 AND Y0 = Y1 THEN BREAK
E2 = ERR
IF E2 > -DX THEN ERR = ERR - DY : X0 = X0 + SX
IF E2 < DY THEN ERR = ERR + Dx : Y0 = Y0 + SY
LOOP
RETURN
REM --- RECT x0,y0,w,h,t,col,fill
LABEL RECT
VAR X0,Y0,X1,Y1
VAR W,H,T,COL,FILL
VAR I
X0 = ARGS(1) : Y0 = ARGS(2)
W = ARGS(3) : H = ARGS(4)
T = ARGS(5) : COL = ARGS(6) : FILL = ARGS(7)
X1 = X0 + W - 1 : Y1 = Y0 + H - 1
IF FILL != 0 THEN
FOR I = Y0 + T TO Y1 - T
GOSUB HLINE, X0+T, I, W-2*T, COL
NEXT
ENDIF
FOR I = 0 TO T - 1
GOSUB HLINE, X0, Y0+I, W, COL
GOSUB HLINE, X0, Y1-I, W, COL
NEXT
FOR I = 0 TO T - 1
GOSUB VLINE, X0+I, Y0, H, COL
GOSUB VLINE, X1-I, Y0, H, COL
NEXT
RETURN
REM --- HLINE X,Y,L,COL--------------------------
LABEL HLINE
VAR X,Y,L,COL
VAR HI,LO
VAR I
X = ARGS(1) : Y = ARGS(2) : L = ARGS(3) : COL = ARGS(4)
HI = COL / 256 : LO = COL % 256
FOR I=0 TO L
POKE BUF + 2*I, HI
POKE BUF + 2*I + 1, LO
NEXT
GOSUB SAWIN, X, Y, X+L-1, Y
GOSUB SCMD, $2C
GOSUB SDBLK, BUF, L * 2
RETURN
REM --- VLINE x,y,l,col
LABEL VLINE
VAR X,Y,L,COL
VAR HI,LO
VAR ROW
X = ARGS(1) : Y = ARGS(2) : L = ARGS(3) : COL = ARGS(4)
HI = COL / 256 : LO = COL % 256
FOR ROW=0 TO L - 1
POKE BUF + 2 * ROW, HI
POKE BUF + 2 * ROW + 1, LO
NEXT
GOSUB SAWIN, X, Y, X, Y+L-1
GOSUB SCMD, $2C
GOSUB SDBLK, BUF, L * 2
RETURN
REM --- Circle cx,cy,r,t,col,fill
LABEL DCIRCLE
VAR CX,CY,R,T,COL,FILL
VAR Y,XOUT,XIN,RIN
CX = ARGS(1) : CY = ARGS(2)
R = ARGS(3) : T = ARGS(4)
COL= ARGS(5) : FILL=ARGS(6)
IF T < 1 THEN T = 1
IF R-T+1 > 0 THEN RIN=R-T+1 ELSE RIN=0
FOR Y = -R TO R
XOUT = INT(SQRT#(FLOAT#(R*R - Y*Y)) + 0.5)
IF FILL=1 THEN
GOSUB HLINE, CX-XOUT, CY+Y, 2*XOUT+1, COL
ELSE
GOSUB DPXL, CX-XOUT, CY+Y, COL
GOSUB DPXL, CX+XOUT, CY+Y, COL
ENDIF
IF NOT(FILL) AND RIN > 0 THEN
IF ABS(Y) < RIN THEN
XIN = INT(SQRT#(FLOAT#(RIN * RIN - Y*Y)) + 0.5)
ENDIF
ENDIF
NEXT
RETURN
REM ---- ELLIPSE cx,cy,vD,hD,t,col,fill
LABEL ELLIPSE
VAR CX,CY,HDIAM,VDIAM,T,COL,FILL
VAR INNERRX,INNERRY
VAR Y,XOUT,XIN,FRAC,RX,RY
CX = ARGS(1) : CY = ARGS(2)
VDIAM = ARGS(3) : HDIAM = ARGS(4)
T = ARGS(5) : COL = ARGS(6)
FILL = ARGS(7)
IF T < 1 THEN T = 1
RX = HDIAM / 2
RY = VDIAM / 2
IF RX <= 0 OR RY <= 0 THEN RETURN
IF RX - T + 1 > 0 THEN INNERRX = RX -T + 1 ELSE INNERRX = 0
IF RY - T + 1 > 0 THEN INNERRY = RY -T + 1 ELSE INNERRY = 0
FOR Y = -RY TO RY
FRAC# = 1.0 - FLOAT#(Y * Y) / FLOAT#(RY * RY)
IF FRAC# < 0 THEN FRAC# = 0
XOUT = INT(FLOAT#(RX) * SQRT#(FRAC#) + 0.5)
IF FILL = 1 THEN
GOSUB HLINE,CX-XOUT, CY+Y, 2*XOUT+1, COL
ELSE
IF INNERRX=0 OR INNERRY=0 THEN
GOSUB DPXL, CX-XOUT, CY+Y, COL
GOSUB DPXL, CX+XOUT, CY+y, COL
ELSE
FRAC# = 1.0 - FLOAT#(Y*Y)/FLOAT#(INNERRY*INNERRY)
IF FRAC# < 0 THEN
XIN = -1
ELSE
XIN = INT(FLOAT#(INNERRX) * SQRT#(FRAC#) + 0.5)
ENDIF
IF XIN < 0 THEN
GOSUB HLINE, CX-XOUT, CY+Y, 2*XOUT+1, COL
ELSEIF XOUT > XIN THEN
GOSUB HLINE, CX-XOUT, CY+Y, XOUT-XIN, COL
GOSUB HLINE, CX+XIN+1, CY+Y, XOUT-XIN, COL
ENDIF
ENDIF
ENDIF
NEXT
RETURN
REM --- DrawChar(px%, py%, ch$, fg%, bg%)
REM 一文字の描画
LABEL DCHR
VAR PX,PY,CH,FG,BG
VAR A,I,P,D
VAR ROW,PIX
VAR FGH,FGL,BGH,BGL
VAR COL
PX = ARGS(1) : PY = ARGS(2) : CH$ = ARGS$(3)
FG = ARGS(4) : BG = ARGS(5)
FGH = FG / 256 : FGL = FG % 256
BGH = BG / 256 : BGL = BG % 256
A = PEEK(CH) : IF A=0 THEN RETURN
P = SYSTEM(103) + A * 8 : REM System font area
I = 0
FOR ROW = 0 TO 7
D = PEEK(P)
FOR PIX = 0 TO 7
IF D AND $80 THEN
POKE CBUF + I * 2, FGH : POKE CBUF + I * 2 + 1, FGL
ELSE
POKE CBUF + I * 2, BGH : POKE CBUF + I * 2 + 1, BGL
ENDIF
D=D<<1 : I=I+1
NEXT
P=P+1
NEXT
GOSUB SAWIN, PX, PY, PX + 7, PY + 7
GOSUB SCMD, $2C
GOSUB SDBLK, CBUF, 8*2*8
RETURN
REM --- DrawString(px%, py%, txt$, fg%, bg%)
LABEL DSTR
VAR PX,PY,TXT,FG,BG
VAR K
PX=ARGS(1) : PY=ARGS(2) : TXT$=ARGS$(3)
FG=ARGS(4) : BG=ARGS(5)
FOR K=0 TO LEN(TXT$)-1
GOSUB DCHR, PX, PY, TXT$(K, 1), FG, BG
PX = PX + 8
NEXT
RETURN
REM --------------------------------
LABEL CLSC
VAR COL,I,Y
COL = ARGS(1)
FOR I = 0 TO 239
POKE BUF + I * 2, COL / 256
POKE BUF + I * 2 + 1, COL % 256
NEXT
GOSUB SAWIN, 0, 0, 239, 319
FOR Y = 0 TO 319
GOSUB SDBLK, BUF, 480
NEXT
RETURN
上記プログラムの実行結果です。
さいごに
ST7789を使った液晶ディスプレイに文字列、図形を表示できるようになりました。次のステップとしてクラスファイルにして汎用的に使えるように試しましたが何も描画されない状態で手詰まり状態です。何とかクラス化して使用できるようにしたいと思っています。

