● 実験テーマ150
「Picoで使用したILI9341_TFT液晶を、PIC24Fで動かす実験」
(3.2"SPI液晶を、使い慣れている、PIC24Fで動かす実験をしてみました)
■ 2023.6.14
・既にこのテーマをやられている先人「趣味の実用電子工作」さんサイトにアップされてた、
zipファイル:GLCD_SD_24F.Xをダウンロード後、解凍。
プロジェクトファイル:GLCD_SD_24F.Xを開くと、
dist- default- prodaction下に、HEXファイル:GLCD_SD_24F.X.prodactionがあるので、
まずは、それをそのままPICに書込んでハードチェックがてら動作を確認してみた。
グラフィックLCD用ライブラリーは、インターネット上で出回っているもの(GFX_Library.c)
を改造して使用されているようで、見慣れた描画デモが展開された。
SDカードへの書込み・読込みテストを含め、ハード(PIC24Fトレーニング基板使用)は問題無いようである。
以下に描画デモの一部を示しました。
・私自身でも少し元のソースをいじって、ILI9341初期化のところだけでも理解しようと思い
全画面を各色で塗潰すテスト、testFillScreen()のみのテストプロジェクトを作成してみることにした。
オリジナルの開発環境は、
MPLAB X IDE(v5.50)
XC16(v1.70) に対し、
私の環境は、ちょっと(だいぶかな・・)古く
MPLAB X IDE v3.05
XC16(v1.25)
アップデートはPCの負荷が重くなるので極力やりたくないので、このままの環境で
ILI9341初期化のところもオリジナル
(手法としては、パラメータ・テーブルの置いてあるアドレス(ポインタ)を指定しインクリメントしながら
パラメータの終わりまで、spi書込みを繰返すようなことをしている。)
のまま記述してみた。
■ 2023.6.28
・昨日までに、SDは除いて、初期化のところまでsimpleなソースを考えてた。
→ 一応でっち上げた。
※ <結果> ↓--- この対象となる変数も多岐にわたる。
「unable to resolve identifier x」エラー多発。コンパイル以前のリンク段階でのエラーで先に進めず。
(識別子 x を解決できません)
この手のエラー多発:ILI9341.cにて
どうもポインターの使い方に問題があるようだが・・・????
それにしても、ILI9341初期化パラメータ・テーブルの数の多い事・・・
■ 2023.6.29
・「mag-tec電子工作」さんの、M5StackのILI9341ディスプレーを動かすソース例では、
せいぜい5〜8個のパラメータを、テーブルでなく、直にwiteCommand()と、witeData()にて
書込んでいる。
これに変えてみる。
void tft_begin(void)関数を書換える。
直接コマンド・データともに与えるので、ILI9341.cの頭にあるパラメータ・マクロテーブルは不要になる。
/***********************************************************
* SPI 経由で ILI9341 に接続し、初期化手順コマンドを送信
************************************************************/
void tft_begin(void) {
delay_ms(100);
/// 100mS幅のリセットパルスを出力
TFT_RST = 1;
delay_ms(5);
TFT_RST = 0;
delay_ms(100);
TFT_RST = 1;
delay_ms(200);
TFT_CS = 0; // start write
TFT_DC = 1; // DCピンをHiにする
witeCommand(0x38); //Idle mode OFF
witeCommand(0x3A); //COLMOD: Pixel Format Set
witeData(0b01010101); //RGB 16 bits / pixel, MCU 16 bits / pixel
witeCommand(0x36); //MADCTL: Memory Access Control
witeData(0b00001000); //D3: BGR(RGB-BGR Order control bit )="1"
witeCommand(0x11); //Sleep OUT
delay_ms(10);
witeData(0x29); //Display ON
TFT_CS = 1; // end write
_width = ILI9341_TFTWIDTH; // #define ILI9341_TFTWIDTH 240 ///< ILI9341 max TFT width
_height = ILI9341_TFTHEIGHT; // #define ILI9341_TFTHEIGHT 320 ///< ILI9341 max TFT height
rotation = 0;
}
・この修正でコンパイル通る。エラー無し。(今回未使用のsdカードポートの3信号に「unable to resolve identifier x」警告マークが
いているが、コンパイルは綺麗に通っている。たぶん宣言だけで実行文がないので出ているマークと思われる。)
・hex書込んで動作確認したが、画面が真っ白のままng
■ 2023.6.30
<デバッグ開始>
@ RESETパルスを確認した。
100mS幅のLoパルスが正常に出力されてる。ok
A ILI9341初期化関数:void tft_begin(void)を見直してみる。
現在適応しているのは「mag-tec電子工作」さんの、M5StackのILI9341ディスプレーを動かすソース例。
「ゆるプロ」さんのを参考にして、これと比較してみるとかなり異なる部分がある。
<「ゆるプロ」さんの初期化例>
void setup() {
SPI.begin(); //SPIを初期化、SCK、MOSI、SSの各ピンの動作は出力、SCK、MOSIはLOW、SSはHIGH
SPI.setClockDivider(SPI_CLOCK_DIV2);
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
// SPI.beginTransaction(settings); // M5StampやRaspberryPi PICOで使う時はコッチの設定でないとコンパイルが通らない
// --- ST3375 INITIAL
pinMode(TFT_CS, OUTPUT);
pinMode(TFT_DC, OUTPUT);
pinMode(TFT_RST, OUTPUT);
// ------ ここから -----------
// --- HARDWARE Reset
digitalWrite(TFT_RST, LOW);
delay(20);
digitalWrite(TFT_RST, HIGH);
delay(20); // このdelayは必要
// --- ILI9341 動作設定
digitalWrite(TFT_CS, LOW); // TFTセレクト
digitalWrite(TFT_DC, LOW); // Command mode
SPI.transfer(0x01); //<< SOFTWARE RESET--------------->> ソフトウエア・リセットも実行している。追加してみる。
delay(150); // ※このdelayはなくても大丈夫かも
SPI.transfer(0x13) ; //<< Normal Display Mode ON
SPI.transfer(0x36) ; //<< Memory Access Control
digitalWrite(TFT_DC, HIGH); // Data mode
SPI.transfer(0x48) ; // MX = ON , GBR = ON (縦画面,左から右に表示)
digitalWrite(TFT_DC, LOW); // Command mode
SPI.transfer(0x3a) ; //<< COLMOD: Pixel Format Set
digitalWrite(TFT_DC, HIGH); // Data mode
SPI.transfer(0x55) ; //<< 16Bits / 1Pixcel
digitalWrite(TFT_DC, LOW); // Command mode
SPI.transfer(0x11) ; //<< Sleep Out
delay(60); // 【重要】このdelayは絶対に必要:電源が不安定な場合は長めに(120ms位に)する
SPI.transfer(0x29) ; //<< Display ON
digitalWrite(TFT_CS, HIGH); // TFT解放
}
<自分の場合・修正後>
/***********************************************************
* SPI 経由で ILI9341 に接続し、初期化手順コマンドを送信
************************************************************/
void tft_begin(void) {
delay_ms(100);
/// 100mS幅のリセットパルスを出力
TFT_RST = 1;
delay_ms(5);
TFT_RST = 0;
delay_ms(100);
TFT_RST = 1;
delay_ms(200);
TFT_CS = 0; // start write
TFT_DC = 1; // DCピンをHiにする
witeCommand(0x01); // SOFTWARE RESET 追加:230630
delay_ms(150); // このdelayはなくても大丈夫かも
witeCommand(0x13); // Normal Display Mode On(全画面表示)追加:230630
// witeCommand(0x38); //Idle mode OFF:削除 230630
witeCommand(0x3A); //COLMOD: Pixel Format Set
witeData(0b01010101); //RGB 16 bits / pixel, MCU 16 bits / pixel
witeCommand(0x36); //MADCTL: Memory Access Control
witeData(0b00001000); //D3: BGR(RGB-BGR Order control bit )="1"
witeCommand(0x11); //Sleep OUT
delay_ms(100); // 【重要】このdelayは絶対に必要:電源が不安定な場合は長めに(120ms位に)する
// 10 -> 100に変更:230630
witeData(0x29); //Display ON
TFT_CS = 1; // end write
_width = ILI9341_TFTWIDTH; // #define ILI9341_TFTWIDTH 240 ///< ILI9341 max TFT width
_height = ILI9341_TFTHEIGHT; // #define ILI9341_TFTHEIGHT 320 ///< ILI9341 max TFT height
rotation = 0;
}
※ これでやってみたが結果は同じng
→ 初期化のパラメータの与え方は、これで良いはずと思う・・・
基本的に、SPI通信が出来ているかタイミングを確認してみたい。
それには、通信速度=16MHzを、100kHz以下に落とさないと、自作ロジアナでは見れない。
<その修正箇所 (デバッグの為の一時的な変更)>
@ PIC24F_GLCD_MSP3217_TEST_1.c
Fcy= 16MHz→ 4MHzにダウン
// CONFIG2
// #pragma config FNOSC = FRCPLL // 内部オシレータでPLL動作させる
#pragma config FNOSC = FRC // 内部オシレータでPLL動作無し
A PIC24F_GLCD_MSP3217_TEST_1.c
SPI2のプライマリプリスケールの分周 1:1 → 1:64に増やす
// SPI2_Init(SPI2_MODE0, SPI2_PPRE_DIV1, 0); //プライマリプリスケールの分周 1:1 (16MHz x 1/1 = 16MHz)
SPI2_Init(SPI2_MODE0, SPI2_PPRE_DIV64, 0); //プライマリプリスケールの分周 1:64 (4MHz x 1/64 = 62.5kHz)
B ILI9341.h
/// クロック周波数定義 ---------------------
// #define CLOCK 16
#define CLOCK 4
・あと上記には関係ないけど、デバッグled(RA3,4)ポートの初期化が、Loになっていて点灯しているので
ここだけHiにしておく。
そしてプログラムの最後(while(1))の前で、RA3(赤)LEDを点灯させることにする。
----------------------------------------------------------------------------------------------------------------
<修正後の動作確認結果>
@ 以下のチャンネル設定で自作ロジアナにてSPIタイミングを確認したところ、CS/の立下りから
witeCommand(0x11); //Sleep OUTまで問題無いことが確認出来た。
※-> いや良くタイミングをみたら、何故かCS/が立ち下がってから上がりまでの時間が極短い??-
---> 230701に気付く!!
しかしこの時は、この事が、画面が真っ白なまま・・の原因だとは、何故か思わなかった。
A それと今更ながら設定ソースに誤りのある事が発覚。
writeData(0x29); //Display ON -> writeCommand(0x29); //Display ON が正しい
※ ここまでの修正をしたが未だ症状変わらず。真っ白表示のまま??
何か設定が足りないのか???
■ 2023.7.1
・setAddrWindow()のところのcs/からのタイミングが上手く取れた。
この部分のspiタイミングは問題無いと言って良いと考える。
■ 2023.7.4
・setAddrWindow(x, y, w, h);で、writeCommand(ILI9341_RAMWR); // Write to RAMまでは確認出来ているので、
全画面(320 x 240= 76800画素)を赤:0xF800で埋め尽くす関数のところのタイミングを観測してみる。
自作ロジアナはトリガ用の信号が無いと厳しい。
led_on(RA3)信号をトリガにしてみる。
そこがlowになったら、そのルーチンが実行される。
void fillRect(int x, int y, int w, int h, unsigned int color) {
unsigned long px;
/// 16bitカラーコードを上位8bit/ 下位8bitに変換(RGB565変換)
unsigned char hi,lo;
hi = (unsigned char)((color >> 8) & 0x00FF);
lo = (unsigned char)(color & 0x00FF);
if( (x < _width) && (y < _height) && w && h) { // 塗り潰し範囲が範囲内か?(ゼロ以外の幅と高さになっているか?)
if((x + w - 1) >= _width) w = _width - x;
if((y + h - 1) >= _height) h = _height - y;
TFT_CS = 0; // start write
setAddrWindow(x, y, w, h);
px = (unsigned long)(w * h); // 塗り潰し範囲内の画素総数
PORTAbits.RA3=0; // RED LED ON(デバッグ・ロジアナトリガ用)230704
/// 塗り潰し範囲内の画素総数だけSPI書込みし指定色で塗潰す
while (px--) {
writeData(hi);
writeData(lo);
}
TFT_CS = 1; // end write
}
}
-----------------------------------------------------------------------------------------------------------
<main>
//--------------------------
// グラフィック表示例の処理
//--------------------------
testFillScreen();
PORTAbits.RA3=1; // RED LED OFF
while(1);
}
/***********************************************************
* グラフィック表示例用の関数群
* 初回バージョンは、全面を各色指定で塗り潰す関数のみテスト
************************************************************/
void testFillScreen() {
// fillRect(0, 0, _width, _height, ILI9341_BLACK);
fillRect(0, 0, _width, _height, ILI9341_RED);
// fillRect(0, 0, _width, _height, ILI9341_GREEN);
// fillRect(0, 0, _width, _height, ILI9341_BLUE);
// fillRect(0, 0, _width, _height, ILI9341_BLACK);
}
※ 320 x 240= 76800画素分書込むので、
自作ロジアナのバッファには全部収まり切れない。
5121byte分が上限
途中の取得データで評価可能
<評価結果>
・赤のRGB565コード:0xF800
これを、上位8bit:0xF8と、下位8bit:0x00に分けて正常に、2byte転送されていた。
■ 2023.8.17
・ここ5Wほど、SPIのタイミング設定等、色々試したが、どうしても「画面真っ白」のまま変わらず。
初期化のspiタイミングも良さそうだし。
初期化の内容も良さそうなのに????
大元プロジェクト「GLCD_SD_24F.X」(趣味の電子工作さん)のhexでは動いているのに・・・・
そのままのソースでコンパイルすると、私の使っている古いMPLAB IDE X v.3.05では、ポインタ変数の所
で大量のエラーが出てコンパイル不能になる。
どうも迷走状態にはまり込んでしまったようで、このプロジェクトは暫く保留にすことにした。
気が向いたら再開予定にする。
■ 2023.10.4
・ずいぶんと間が空いてしまったが、ちょっとやる気が出たので再開することに。
まずは、これまで、MPLAB X IDEでデバッグを進めてきたが、やにWIN10_PCへの負荷が重く、
特に、MPLAB X IDE起動時、完全に立上るまでに、時間が掛かり過ぎて非効率。
(前々から、MPLAB_X_IDEの立上り時間が異常に長いのが気になっている。
「Back ground scanning....」とは何をやってんだか? )
そこで、負荷が軽くて常用している、MPLAB IDE v8.60に適合するようソースを変更して
この先、進めることにした。
コンパイルokだが、白画面のまま変わらず。
■ 2023.10.5
・spiのclkとdataのタイミングが気になっている。再度転送速度を、62.5kHzに落として確認
-> タイミングは問題ない模様
ちゃんと、clkの立上りで、dataを読込んでいる。
■ 2023.10.6
・TFT初期化の冒頭で、CSをアクティブLoにするが、一瞬Loになってから直ぐにHiに戻ってしまう事を再確認した。
-> CSをアクティブLo後、DCをHiにしているが、DCレベルの初期化はmain頭で既に済んでいるので
ダブル処理になる。ここを削除したら、TFT初期化ルーチンを実行の間、CSはアクティブLo
をキープするようになり初めて塗潰し動作を確認出来た。
ただし未だおかしい。横方向は良いのだが、縦方向が上部の一部しか塗潰さない・・
しかし何故、この処理をしたら良くなったかはよく判らない。(ダブル処理だが問題無いはず)
CSとDCの微妙なタイミングの問題が改善されたのかな・・・
まあ長い間ここで悩んでいたのが解決したので良しとする。
(TFT初期化の間、CSがノンアクティブHiの為、設定が全て無効になっていたので当然な話である)
-> fillRect関数内で以下修正した
(1) 340- -> 320 (塗潰し範囲オーバー判断の箇所)
(2) px=(unsigned long)(w * h);が思い通リ動いていないようで
直に、320x240=76800なので、px= 76800としたら、全画面塗潰しはokになる。
■ 2023.10.7
・px = (long)w * h;としたら、変数対応の塗潰しokになる。
■ 2023.10.8
・中央付近に小さな塗潰し四角形を描画を追加
■ 2023.10.13
・新たなプロジェクトを作成し、塗潰し四角形描画の他、各種の描画デモを追加した。
詳細は、末尾にアップしたソース類を参照してください。
<最終回路図>
・こちらから、どうぞ→ 「PIC24F_3.2"SPI_GLCD実験回路図」
<最終ソース及び、ヘッダーファイル>
(1) mainソース
@ PIC24F_GLCD_ILI9341_TEST_SIMPLE.c(四角形を各色で塗潰すのみのテスト)
A PIC24F_GLCD_ILI9341_TEST.c
(各種描画デモ)
(2)
各種ライブラリ・ヘッダファイル
・ILI9341.c
・ILI9341.h
・skSPIlib.c
・skSPIlib.h
・ASCII12dot(12*12_フォントデータ: 後閑氏が作成された、アスキー文字データ ・ 後から私自身で数点キャラクタを追加してます)
・ImageData.h
← 実験テーマ1に戻る TOP PAGEに戻る 実験テーマ151へ →