- Smart LCD 接続では、フレームバッファを用意して、定期的に 出力するような制御は不要になり、PORT を叩くだけで制御できる。
- そのかわり、どのようなコントローラが載っていてどのようにコマンドを発行するのかという情報が必要になる。
- Smart LCD なら、Linux でデバッグする前に、単純なプログラムで試してみることが出来るし、そうするほうが開発効率が良い。
... というわけで USBBOOT で動かせるプログラムとして LCDを制御するようなものを作ってみようと思う。
ピンのアサインについて
LCD が どのように GPIO に割り付けられるのか? .. これを知らないといけないわけだが、SLCD コントローラを使う前提になるから、だいたいは決まってしまうのだ。
LCD_DAT0-LCD_DAT17 (LCD の DB0-DB15(+ DB16,DB17) に接続)
LCD_VSYNC( = SLCD_CS) LCD の WR
LCD_HSYNC( = SLCD_RS) LCD の RS
LCD の CS/RD を使う場合は別途 GPIOを(PORTD から)割り当てる。
- A-41 では RD は 固定 (read しない/できない)
Linux のコードだと PIN_CS_N / PIN_RESET_N が GPIO として定義されることになっている。RESET も GPIO かも知れない。
追記:
A-41 は、
LCD RESET = 102 PD23 LCD_SPL(LCD)
LCD CS = 103 PD22 LCD_CLS(LCD)
だということが分かった。
コントローラについて
- A-41 では、ILI9325 が有力だが、違うかも知れない。
FPC-TLN240T36A1 というのが載っているのだが、
"FPC-TLN240T36A5 9325"でググるとなにやら沢山ヒットする。 - A-33 は 400x240 なので、320x240 用の LCD コントローラは使っていない。ILI9326 か?
ちなみに、ILI9325/ILI3926 では アプリケーションノートの PDF もあり、初期化例が載っている。
そもそもこれがなにか分からない。だから試行錯誤しなければならないのだ。
解析方法について
- CSとRESET のピンアサインだけは、探す必要がある。CS(RESET) を プルダウンしてみて、GPIO を読めばたぶん分かる。
- まずは、解析などせず ILI9325 だと思ってプログラムを作成し動かしてみる。全然だめなら解析する。
- 解析は、ロジアナを使うつもりだが、16ch なので、16bit + RS/WR を一度には取れない。まずは、RS/WR + 下位8bit 分。
これで、インデックス レジスタの設定を見て どういうレジスタを使っているかを知る。 - それであたりが付けられなかったら RS/WR + 上位 8bit も取る。同じシーケンスのはず(RD がないから状態によってシーケンスが変わらない)だから、全部が分かるはず。
- でも、まずは 解析の練習を フォトフレーム KDPDK24 でやるつもり。
- オリジナルのファームウェアを消す段階になったら、8bit タイプの LCD に交換するのも良いかも知れない。なぜなら 8bit 分GPIO が空く。多分 GPIO の空きは 0 だから貴重。 - 問題は、テストピン。外れたりすると面倒だから 配線をハンダ付けしてしまうかも。配線材は、ピンヘッダ用接続ケーブル[CB-PH10P-250] を切って使うつもり。
- PDPDK24 の 20pin の空きパターン(1.0mm ピッチ)でハンダ付けしているのだが、線が太すぎてなかなか難しい。
- ちょっと反則だが、
これを切ってテストピン代わりに付けるか。
- 強度が足りなかった。プローブ付けたらもげてしまった。
- やはり ハンダ付けか。
追記:
PDPDK24の分析練習は終了。ST7785 か そのあたりのコントローラのようだ。2Ah(CASET), 2Bh(RASET), 2Ch(RAMWR) の繰り返しで画面を更新している。
picfun: 2.4/2.8インチ QVGA液晶表示器の制御 に、ILI9325 のライブラリがある。LCD が使えるかどうかのテストならこれを参考にしたほうが分かりやすい。
バスについて
ILI9325 で 16bit アクセスをする場合、DB17-10 が上位 8bit / DB8-1 が下位 8 bit 。ちなみに、8bit アクセスする場合 DB17-10 に接続し、上位→下位の順で 2 回 Write する。(8bit 用のコードを参考にするのに必要な情報)
16bit アクセスすると 決め打ちしているが、IPU が使える条件は、32bit (R8G8B8) か 16bit(R5G6B5) しかない。IPU を使わないと 動画性能が落ちるのでかならず使っているはず。
追記:実際のコードを組んでみる。
RESET と CS は判ったので、コードを組みはじめることはできそうだ。(確認したのは、A-33 だが、A-41 も同じだと思う。)
で、A-41 は ILI9325 だと思うので、これ用のコードを検討する。
まずは、ILI9325AN -- アプリケーションノートにあるコードを見てみると ... いくつかのパネルに対してのコードが別々になっていた。
コードを比較してみると ..
- 初期化の電圧設定 と ガンマ曲線の設定のみが違う。
- 違うパネルのデータを使っても 表示だけはできそう。 - ついでに ILI9326AN を見てみると、ILI9325 と手順はほぼ同じものの、レジスタのアドレスと値が違う。各パネルの違いは、ILI9325 と同じような感じ。
とりあえず、アプリケーションノートにあるコードを元にして picfun のコードを参考に プログラムを作成しようと思う。
ちょっといくつか ILI93xx の コマンドリファレンスを 切りだして 画像にしてみた。描画エリアと 描画方向を指定して データを連続で送る ... ということは出来ると思うのだが .. コマンド体系は同じように見えるが、それぞれコマンド自体は違うようだ。
- 0x20 : Horizontal GRAM Address Set
- 0x21 : Vertical GRAM Address Set
- 0x22 : Write DATA to GRAM
に相当している。
ILI9326/ILI9328 も同じだが、ILI9327 は、2A/2B/2C で ST7785 と同じ。
picfun のコード(ILI9325)だと、
ST7785 での、2Ah(CASET), 2Bh(RASET), 2Ch(RAMWR)がそれぞれ
これだけで描画するというのもひとつの手だ。ただのテストなのだから 凝ったことをする必要はない。
GPIO のアクセス方法
- GPIO 関係の レジスタは、3 つ 1組みになっている。Read-only の xxx というレジスタに対して、Write-only の xxxS/xxxC というレジスタがある。機能は、該当ビットを 1 にする (xxxS) / 0 にする (xxxC)。-- 以下 xxxS/xxxC については省略して説明。
- 複数bit の 値を 1 オペレーションで設定することはできない。 - xxx は PAyy,PByy,PCyy .. とネーミングされているが、マクロは PXyy となっていて統一的に扱う。以下の説明でも PXyy を使う。
- PXIN -- 入力に設定されたとき ピンの値が読める。
- PXDAT -- 出力に設定されたときの GPIO の値。
- PXFUN / PXSEL -- この 2 つで GPIO として使う設定になる。0/0 が GPIO 。
- PXDIR -- GPIO の方向。1 で 出力。
- PXPE -- pull-up または pull-down (PIN によって決まっている) の設定。0 で pull-up/pull-down。
まとめ - 出力設定 PXFUN = 0 , PXSEL = 0 , PXDIR = 1
- 入力設定 PXFUN = 0 , PXSEL = 0 , PXDIR = 0
- 出力 H: PXDAT = 1 / L PXDAT = 0
bit 単位の set/clear 関数はマクロにあるのだが、まとめてアクセスする関数は定義されていない。どのようにアクセスするものなのかまずはチェック
delay について
コードには、delayms など ms 単位での待ちをいれている。これをちゃんと実装しないと、まずそうだ。
また、GPIO のアクセスで WR のパルス幅をコントロールしないといけない。適当に作ると 早すぎて コントローラの条件を満たさないかも知れない。
USBBOOT では 228 MHz が デフォルトになっている。1 clock 4ns ぐらい。
Linux のコードを参考にして、__delay(loops) と mdelay(ms) を作ろうと思う。具体的には、
#define CPUCLOCK 228000000
static inline void __delay(unsigned int loops)
{
__asm__ __volatile__ (
" .set noreorder \n"
" .align 3 \n"
"1: bnez %0, 1b \n"
" subu %0, 1 \n"
" .set reorder \n"
: "=r" (loops)
: "0" (loops));
}
static inline void mdelay(unsigned int ms)
{
int i;
for (i=0; i<ms; i++) {
__delay(CPUCLOCK / 2000);
}
}
これ。__delay の 1 loop は 2clock のようだ。

A-41 の LCD に表示できた。
- WK11: usbboot-wk11.tar.gz
- 16bit の ILI9325 用のコードで画面クリアが出来た。
- 青、緑、赤で 全面の塗りつぶしも OK で、予想通り R5G6B5。 - ただし、最初は安定しなかった。時々画面が白のままになる。
- delay を増やすことで、正しくクリアできるようにはなった。- CS/RS/データの確定後 10ns 待って WR を ↓。
- 50ns 以上(500ns 以下)待って WR を ↑
- 40ns 以上待って 次のステップ。
タイミングのチェック:
- 追記: ILI_93XX_Reset() が適当だったので安定しないことがわかった。
普通に clear/set するようにしたら 安定した。 - CS/RS/データの確定後 10ns 待って WR を ↓。
- フォントの描画コードも入れている。
- 表示はできているが、現状は色がおかしい。
→ バグがわかった。
- デバッグに利用できるのももうすぐ。
→ スクロール機能が必須。 - ILI9326 用のコードも作ったので、A-33 でもやってみたいが、予備が届くまでおあづけかな。
- バッテリー充電機能が不明なので、いちいちバッテリーを外している。これが面倒。
- だが使えることを確認して安心したい。
A-33 も動いた。
- WK12: usbboot-wk12.tar.gz
結局、制御できるかどうか安心したくて、やってみることにした。 - ILI9326 16bit インターフェイス用のコードが動くことが確認できた。初期化のコードは、アプリケーションノートから取ってきたものだが、他は、ILI9325 用のコードをベースに レジスタ番号を ILI9326 に合わせただけ。あっさり動作した。
- 画面サイズは、横 240 x 縦 432 だった。(A-41 は 横 240 x 縦 320)
これで一安心。
Linux 移植でのデバッグでも 情報を画面に 残せるようなる。これをベースにして jz_ubcomm ドライバ に組み込む予定。(正規の SLCD ドライバは別途考える)
A-41 から I2Cを引き出して LED を点灯できるようになったのだが、ほとんど使わないうちに いらなくなりそうだ。
Neo Slim 3000 の方は、Smart LCD 接続でなく RGB インターフェイス。こうなると、A-41/A-33 で進めたほうが 良さそうだ。
ところで、予備を everbuying で 2 つ 買っているのだが、売り切れで 1 つしか入手できないという連絡があった。結局差額を支払って A-32 にチェンジ。A-33 とだいたい同じ兄弟機のはずだし、中を見たいし、A-33 ほど安っぽくはないし .. まぁいいか。
これで LCD制御はひとまず完了。- Linux で主に使うのは、フレームバッファの転送だけなので 凝った機能を使わない。SleepMode に入る/出る という機能もあるが、アプリケーションノートそのままだし。
- いずれ P5-5 にも 手を付けると思うが、先のはなし。
おまけ: ILI9325 メモ- R03h : Entry Mode
(9326 では、R03h = R003h)
D15/D14 : TRI/DFM = 00 → 65K mode
D12 : BGR = 1 → swap R and R (??)
D5/D4 : I/D = 11 → incliment/decliment:
V inc , H inc
D3 : AM = 0 → update direction = Horizontal
例:
ILI93XX_CtrlWrite(0x03, 0x1030);
TRI/DFM の設定で、16bit モードでも 256K Color の書き込みができる。ただし、2 回の書き込みが必要。(8bit モードでは、3回)
BGR=1 と下記の REV=1 で、RGB データを逆順にできる。何故か逆順が 普通に R5G6B5 としてアクセスできる設定。
重要なのが、I/D と AM 。データを書き込む方向を指定するもので、これを使えば画面を回転させられる。 - R61h : Gate Scan Control
(9326 では、R61h = R401h,R6Ah = R404h)
D2 : NDL = 0 → Non-Display Area = black ?
D1 : VLE = 0 → virtial scrolling = disabled
D0 : REV = 1 → change endian
例:
ILI93XX_CtrlWrite(0x61, 0x0003);
ILI93XX_CtrlWrite(0x6A, vscroll_base);
NDL は、表示外エリアが白か黒かを指定するもの。
REV は、それぞれ R,G,B の MSB の指定。
VLE は、縦スクロールの許可。これを使えば長辺方向にスクロールできる。Linux の本来のドライバは、フレームバッファから転送するので必要ないが、デバッグでコンソールもどきにするとき欲しい機能。
とりあえず Pixel 描画以外に、これだけ知っているだけで十分使える。
あとガンマ曲線の設定を理解できれば、好みの色調に出来て嬉しいかも。
それ以外で気になるのは... - R2BHh : Frame Rate
(9326 では、R20Bh だが値の意味が違う)
デフォルト 96 Hz だが、40 Hz まで落とせる。(9326 では、デフォルト 80 Hz / 最小 30 Hz)
ひょっとして、フレームレートを下げると液晶本体の消費電力もかなり減ったりしないのだろうか? 一度調査してみたい。
ちょっと修正。- WK13: usbboot-wk13.tar.gz
上記の RESET の操作を修正。
あと、exec コマンドを追加。0x80600000 にロードして go する簡易コマンド。
まだ動いていないが、MinGW で動くように気がついたらコードを修正している。
- Linux で主に使うのは、フレームバッファの転送だけなので 凝った機能を使わない。SleepMode に入る/出る という機能もあるが、アプリケーションノートそのままだし。