先日、日本橋のシリコンハウスで購入したTFT液晶ディスプレイ「FG040346DSSWBG03-DJK」を
液晶コントローラを使わずSTM32F4DISCOVERY単体で駆動しました。
480×272bit 24bitカラー リフレッシュレート75Hz
外付けのSRAM,ROMは使っていません。
背面にあるのはロジアナのLAP-Cです。
今回は前回の秋月300円液晶での反省点を活かして駆動方法を工夫しました。
まず液晶の仕様を紹介した後で、STM32F4による駆動方法を説明します。
○液晶の仕様
共立液晶はいわゆる秋月3000円とほぼ同じ仕様の液晶です。
またPSPの液晶に近い仕様になっていますが電源電圧やピン配置はPSP液晶と異なるため
互換性はありません。
秋月液晶との違いは秋月液晶の画面がノングレアであるのに対し、
共立液晶はグレアタイプで光沢があります。
個人的にはグレアタイプの方が色が鮮やかに見えるので好みです。
ピン配置です。
画素データ以外の信号はクロックのPCLKとデータのゲート信号のDEのみで
水平と垂直の同期信号は使用せずにNCとしても良い事になっています。
どうやって同期を取っているのかというと次のような仕組みになっています。
ブランキング期間の記載はデータシートに無かった為、シャープのPSP液晶を参考にしました。
表示期間中にDEをHIGHレベルにして、
その間のPCLKの立下りクロックごとに1pixelを取り込むようになっています。
水平ブランキング期間は45PCLK以上,垂直期間中は14H以上の間 DEをLOWレベルにします。
DEのHIGH期間で画像の表示タイミングを同期できるのでLCDコントローラの付いていない
液晶の中では比較的簡単で使いやすいと思います。
○回路
1.STM32F4DISCOVERY
LCDとの接続は上記の表どおりですが、
私の使っているボードはピンを自由に使うためにボード上の加速度センサ以外の部品を取り除いています。
2.昇圧・定電流回路
このLCDはLEDバックライト用に24Vの電圧と20mAの電流を必要とします。
これを5Vから生成する為に、MC34063を使った昇圧 + 定電流回路を組みました。
定電流にしたのはDCDCのリプル電圧でバックライトがチラつかない様にする為です。
C3までが昇圧回路でそこから右側が定電流回路です。
右端の2つのピンにLEDアレイをつなぐと、21mAの定電流が流れます。
この時入力には160mAの電流が流れたので出力から見た効率は63%です。
MC34063は安い割に昇降圧どちらにも使えるので手元にあると便利ですね。
3.FPCコネクタ
前回、秋月300円液晶で散々接続に苦労したので今回は最初からaitendoにて
40pinのFPCコネクタを購入しました。
接続は下接点です(一度間違ってしまいました)。
○STM32F4による駆動
○前回の反省点
前回、秋月300円液晶を駆動した時の反省点は下記のとおりです。
①DMAのソフトウェア制御
DMAで内臓SRAM→GPIOへデータを転送していたが、ブランキング期間にDMAリクエストを止める
必要があり、ソフトで制御していた為にタイミングの調整が非常にシビアで大変だった。
②不正確な1フレーム
内臓SRAMの容量が一画面に足りないので小刻みに画像データを送り出していた。
1フレーム(30FPSなら1秒に30フレーム)に画像一枚を対応させる必要があるので1フレームの期間が正確に1/30秒になっていないと動画を再生する際に、本来の再生時間とずれてしまう。
しかし液晶の1クロック単位の長さをソフトでうまく調整する事が出来なかった。
○分析
結局、数MHzの周期で動き続けているDMAデータ転送やクロックを、
無理にソフトウェアで止めたりタイミングを調整していた事が主な原因でした。
CORTEX-M3は割り込みルーチンに入るまでに12クロック掛かるので
とめたいLCDクロックを先読みしてルーチンに入り、ルーチンの中でもタイミングの微調整が必要で苦労しました。根性で動かしていましたがw
○タイマ最高
そういう訳で今回はタイミングの制御は一切ペリフェラルに任せられるようにしました。
結果、正確なタイミングで転送できるようになり、ソフトはサーキュラーバッファに画像データを供給すれば良いだけになりました。
STM32F4は高機能なタイマが合計10個もあるので非常に応用の幅が広く便利です。
FPS=60の場合を例にとり説明します。
1.使用タイマの概要
今回は以下のようにTIMを5つ使用しました。全てPWMモードで駆動しています。
●用語
タイマのゲート機能について
ゲート機能においてマスターとなったタイマはスレイブのタイマにゲート信号を送ります。
そしてゲート信号がHighレベルの間のみ、スレイブにclock(今回はAPBクロック)が供給されます。
タイマのリセット機能について
マスターはスレイブにリセット信号を送ります。
スレイブのカウンタはリセット信号の立ち上がりエッジで、カウントをリセットします。
DMAリクエストについて
DMAはDMAリクエスト毎にメモリ上のデータをペリフェラルに転送できます。
今回はタイマのPWM立ち上がりエッジのタイミングでサーキュラーバッファのデータをGPIOの出力レジスタに転送し、LCDへ1画素分の信号を送っています。
サーキュラーバッファの半分もしくは完全にデータを転送した時点で割り込みが起こり、
CPUにデータのプッシュを要求します。
2.信号の全体像
これは内臓クロック84MHzからPCLKの1周期を作ると分解能が足らず端数が出てしまう為です。
例: 1PCLKに対する内臓クロック = 84MHz ÷ (480 + 45) ÷ (272 + 14) ÷ 60fps = 9.32
端数は切り捨てになるので、切り捨てた分の誤差をブランキング期間で調整しています。
5つのタイマーの中で実際にLCDに信号を送るのはTIM2の水平ゲートとTIM3のPCLKのみであり、
他は同期とDMAリクエスト用のタイマとなっています。
水平ゲートは画素の送出を制御し、垂直ゲートは水平ゲートを制御しています。
また、垂直ゲート用タイマはPCLKを画素の出力タイミングと同期させる役割もあります。
3.水平ゲートの説明
以下はロジックアナライザで測定した水平ゲートの立ち上がり,画素表示の開始部分の波形です。水平ゲートの立ち上がり後にDMAリクエスト用タイマのPWM波形が現れているのが分かります。
TIM3は常にLCDにPCLKを供給し続けますが、DMAリクエスト用タイマは水平ゲートがHighの間のみ画素をLCDに送ります。
そして水平ゲートがLowの間、水平ブランキング期間を作ります。
LCDはPCLKの立下りエッジで画素を取り込むので、それまでにGPIOにデータをセットアップしなければなりません。(厳密にはLCD側に信号取り込みのセットアップ時間が必要なのでそれより12nsec早く)
PCLKの立下りまでの時間を稼ぐために、DMAリクエストのタイミングをPCLKの立ち上がりより早くなるよう周期をずらしています。
横向きの矢印がDMAリクエストからGPIOの出力までの期間を示していますが、PCLKの立下りよりも十分早く出力されています。
明らかにDMAの反応がSTM32F1より早くなっています。
GPIOがAHBバスに直結されて、APBバスを経由するレイテンシが無くなったおかげですね。
4.垂直ゲートの説明
以下は垂直ゲートの立ち上がり,1フレームの開始部分の波形です。
垂直ゲートはLCDに信号を送っていませんが重要な役割を担っています。
垂直ゲートがLowの間、水平ゲートのクロックが停止し垂直ブランキング期間を作ります。
また、1フレームを正確に1秒/FPSの期間に調整しています。
1フレームをTIMクロック単位で調整すれば水晶振動子の精度で正確な1フレームが作れます。
ただし、PCLKはクロックと同期しているわけでは無いので、1フレームごとに調整しなければ
ゲートやDMAリクエストのタイマ周期とずれを起こしてしまいます。
そこで垂直ゲートの立ち上がり時にPCLKにリセット信号を送って同期を取っています。
リセット信号から実際のリセットが起こるまでは矢印で表されるように数クロック分の遅延があります。
垂直ゲートがLowの間、水平ゲートのクロックが停止し垂直ブランキング期間を作ります。
また、1フレームを正確に1秒/FPSの期間に調整しています。
1フレームをTIMクロック単位で調整すれば水晶振動子の精度で正確な1フレームが作れます。
ただし、PCLKはクロックと同期しているわけでは無いので、1フレームごとに調整しなければ
ゲートやDMAリクエストのタイマ周期とずれを起こしてしまいます。
そこで垂直ゲートの立ち上がり時にPCLKにリセット信号を送って同期を取っています。
リセット信号から実際のリセットが起こるまでは矢印で表されるように数クロック分の遅延があります。
○ハマったポイント
TIM1とTIM8はSTM32の中でも高機能タイマに分類され、
モータ制御用に使用されるBREAK入力機能がついているのですが、ここでハマりました。
このBREAK機能の中でoutputの有効化という機能があるのですが、これがデフォルトの設定では
タイマー出力ごとにoutputが無効になるように設定されていてPWM信号を止めてしまうのです。
他の汎用タイマのようにPWMを設定するとここでハマると思います。
解決策ですがタイマごとに下記のように設定して
タイマの更新イベントごとにoutputが自動的に再有効となるようにします。
//These settings are needed for continuous PWM cycle.
TIM_BDTRInitTypeDef bdtr;
TIM_BDTRStructInit(&bdtr);
bdtr.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
TIM_BDTRConfig(TIM1, &bdtr);
○小技
☆DMAでGPIOの上位bitのみ操作する方法
今回GPIOBポートのB8 - B15までを8bitカラーに割り当てています。
STM32F4はGPIOがAHBに直結しているのでB0 - B7 に影響を与えずに
上位bitにアクセスする事が出来ます。
具体的にはDMAの設定時に下記の通りペリフェラルアドレスを設定してバイト転送を行います。
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) ((uint8_t *) &(GPIOB->ODR) + 1);
なお、STM32F1はGPIOがAPBブリッジを経由している為、ワード未満のアクセスはワードに拡張されるので上記のようなアクセスは出来ないと思われます。(未確認)
○画質は?
今までに扱ってきた液晶の中で一番綺麗でした!
ただ、写真に撮るとどうしても画質が劣化してしまうのが残念です。
肉眼で見るともっと綺麗なのですが。
画像データは無圧縮でSTM32F4の内臓ROMに収められ、1枚 480 * 272 * 3 = 391680byteです。
秋月液晶のときは16bitカラーで駆動したので 400 * 96 * 2 = 76800byteだったので5倍以上ですねw
これほど大量のデータを処理できるSTM32F4の能力は素晴らしいと思います。
それでは次は動画の再生にチャレンジします!
参考にさせて頂いたページ:
Chanさん :秋月3000円液晶モジュールの試食
charanori さん:RX62Nで秋月3000円液晶 ATM0430D5の味見
Coocox forum :PWM STM32F4