はじめに
dlinyj 、
goodic 、および
Hoshiからの投稿を見て、Habrはケーキだと改めて感じました。
最初の投稿は、Linux用HD44780に基づいたキャラクターディスプレイドライバーの作成に関するものです(
dlinyjから
独自のLinuxドライバーを作成する )。 それに対する優れた回答は、グッドハ
ブラウザー (fireを
書か ずにオタクスタイルにおめでとう )と
星 (
新年のラズベリー-HD44780スクリーンをRaspberry Piに固定)の投稿でした 。
また、この人生のお祝いに参加して、ハードウェア
vt52-like
端末を実装したいと考えました。 シンボリックディスプレイはありませんでしたが、本格的な240x320 TFTディスプレイと部分的なドキュメントを備えたARM Cortex-M3に基づいた中国語の開発ボードがありました。
熱意の株があったので、日曜日の午後に目が覚めた(〜17 MSK)、私はこのLCDの組み込みドライバーを書き始めました。
組み込みARMプログラミング、電子機器、または結果だけに興味がある場合は、catの下でお願いします。
鉄
自由に
使えるのは、USB-to-UART
Prolific PL-2303HXハードウェアブリッジを備えた
ST STM32F103RBマイクロコントローラー 、
多数の小さな周辺機器、および未知の接続図を備えた
Ilitek ILI9320コントローラーを備えたTFT LCDに基づくCelestial Empireのシンプルなデバッグボード(約20ドル)です。
インサーキットデバッガおよびプログラマとして、
Olimex JTAG ARM-TINY-USB-Hが使用されました 。 良いデバイスであり、
OpenOCDで問題なく動作し
ます 。
より正確には、最初はどのようなコントローラーがLCDにあるのかさえ知りませんでした。 16ビットバスを介して接続されていることをディスプレイモジュールから学習できるすべてのものには、
nWR
、
nRD
、
BL_EN
、
BL_EN
および
RS
信号があります。
その目的は推測するのが難しくなかった:
nCS
ディスプレイバスのアクティブ化(以降、プレフィックスn
はアクティブな信号レベルが0であることを意味します)BL_EN
バックライト制御nWR
レコードnRD
読み取りRS
レジスタ選択
インターネットの中国セグメントの拡張で見つかったドキュメントのあるアーカイブの1つで、
Ilitek 932xモジュール。
ソフトウェアインターフェース
低レベルインターフェース
RuNetでこのLCDコントローラーを操作することについての説明はあまりないので、おそらく低レベルのインターフェイスについて説明します。
このコントローラーには基本的に4つあります:i80システム(パラレルインターフェイス、従来のメモリ、HD44780インターフェイスに類似)、SPI、VSYNC(システム+
VSYNC
、内部クロック機能付き)およびRGB(
VSYNC
、
HSYNC
、
ENABLE
、外部機能付き)
DOTCLK
タイミング)。 私の場合、i80-systemが利用可能であり、おそらくSPI(チェックしませんでした)。
システムのみを使用したので、その説明を見てみましょう。 記事にあまりロードしないように-スポイラーになります。
電気インターフェイスILI9320電気レベルでは、デジタルテクノロジーの使用は通常、タイミング図で説明されます。 この例では、5つの制御信号と16ビットのデータバスがあります。
nCS
に情報を送信する前に、
nCS
信号でインターフェイスをアクティブにして、0に設定する必要があります。
さらに、0
RS
に設定すると、情報が記録されるレジスタのアドレスが書き込まれます(実際の記録は、
nWR
信号をアクティブにすることによって実行されます
RS
信号は1に戻ります。
その後、実際の読み取りまたは書き込み操作が実行されます(それぞれ
nRD
と
nWR
使用)。
これらのプロセスの図は次のとおりです。
op | |
---|
読む |  |
書きます |  |
GRAMの書き込み/読み取りの際、特殊レジスタ
0x22
ます。 さらに、コントローラーは自動インクリメントを行うことができます
GRAMアドレス。その内容を順番に読み書きできます。
チャート:
op | |
---|
GRAM読み取り |  |
グラム書き込み |  |
操作が完了すると、
nCS
1に戻ります。
タイミング図を描くために、ブラウザで動作する素晴らしい
wavedromプロジェクトを見つけました。
ここでテストし
ます (上の図はここで準備されました)。
電気インターフェイスに基づいて、低レベルの関数が記述されました。
lcd_ll_funcs void _lcd_select(void) { GPIO_ResetBits(GPIOC, GPIO_Pin_9); } void _lcd_deselect(void) { GPIO_SetBits(GPIOC, GPIO_Pin_9); } void _lcd_rs_set(void) { GPIO_SetBits(GPIOC, GPIO_Pin_8); } void _lcd_rs_reset(void) { GPIO_ResetBits(GPIOC, GPIO_Pin_8); } void _lcd_rd_en(void) { GPIO_ResetBits(GPIOC, GPIO_Pin_11); } void _lcd_rd_dis(void) { GPIO_SetBits(GPIOC, GPIO_Pin_11); } void _lcd_wr_en(void) { GPIO_ResetBits(GPIOC, GPIO_Pin_10); } void _lcd_wr_dis(void) { GPIO_SetBits(GPIOC, GPIO_Pin_10); } void _lcd_bl_en(void) { GPIO_SetBits(GPIOC, GPIO_Pin_12); } void _lcd_bl_dis(void) { GPIO_ResetBits(GPIOC, GPIO_Pin_12); }
スピードアップするために、これらの関数をインライン化してマクロに変換することができます(残念ながら、Eclipseはあまりフレンドリーではありません)。
これらの関数に基づいて、レジスターへの書き込み、レジスターからの読み取り、および画像ブリッティングのための関数が実装されています。
高レベルのインターフェース
プログラムの主要部分のLCD機能は、次のAPIを介して利用できます。
u16 lcd_init(void); void lcd_set_cursor(u16 x, u16 y); void lcd_set_window(u16 left, u16 top, u16 right, u16 bottom); void lcd_fill(u32 color); void lcd_rect(u16 left, u16 top, u16 right, u16 bottom); void lcd_put_char_at(u32 data, u16 x, u16 y); u32 lcd_get_fg(void); u32 lcd_get_bg(void); void lcd_set_fg(u32 color); void lcd_set_bg(u32 color);
端末機能は、すべての操作にこのインターフェースを使用します。
最も興味深い部分は、フォントのすべての作業がその背後に隠されているため、シンボルを描画する機能です。 次のようになります。
lcd_put_char_at void lcd_put_char_at(u32 data, u16 x, u16 y) { u8 xsize, ysize; u8 *char_img; lcd_get_char(data, &xsize, &ysize, &char_img); lcd_set_cursor(x, y); lcd_set_window(x, y, x + xsize, y + ysize); _lcd_select(); _lcd_tx_reg(0x22);
ご覧のとおり、シンボルビットマップへのリンクとそのサイズは、シンボルコードによる
lcd_get_char
関数から
lcd_get_char
されます(追加の文字でASCII部分に触れないように32ビットです)。
現在、ASCIIテーブルの下部と「ヘリンボーン」を含むフォントが使用されています。 興味のある方は見つけてみてください)
最もおもしろくなくて(書き込み時間に関して)最も高価なのは、ディスプレイの初期化関数です。
lcd_init:怖がりたい人向け u16 lcd_init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitTypeDef gpio_conf; gpio_conf.GPIO_Speed = GPIO_Speed_50MHz; gpio_conf.GPIO_Mode = GPIO_Mode_Out_PP; gpio_conf.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12; GPIO_Init(GPIOC, &gpio_conf); lcd_gpio_conf(GPIO_Mode_Out_PP);
端末実装
この部分は目立たない。 以前の記事のコードのいくつかを使用して、バッファなしの端末が実装されました。
エスケープシーケンスエスケープシーケンス:
- \ 033 [A =カーソルを1行上に移動
- \ 033 [B =カーソルを1行下に移動
- \ 033 [C =カーソルを1つ右に移動
- \ 033 [D =カーソルを1つ左に移動
- \ 033 [H =カーソルを左上隅に移動-ホーム(位置0,0)
- \ 033 [J =すべてクリア、カーソルをホームに戻さないでください!
- \ 033 [K =行末まで消去します。カーソルをホームに戻しません!
- \ 033 [M =新しい文字マップ-実装されていません
- \ 033 [Y =位置、YXを取る
- \ 033 [X =位置、XYを取る
- \ 033 [R = CGRAMメモリセル選択-CGRAMがないため実装されていません
- \ 033 [V =スクロールが有効-実装されていません
- \ 033 [W =スクロールは無効-実装されていません
- \ 033 [b =バックライトのオン/オフ-実装されていません
その他の便利なコード:
- \ r =復帰(現在の行の位置0にカーソルを戻します!)
- \ n =改行
- \ t =タブ(デフォルトは3文字)
コミュニケーションズ
外の世界と対話するために、
USART1
USB-to-UART
PL-2303HX
を介して非同期モードで使用されます。
Linuxホストの観点からは、これは
/dev/ttyUSBx
です。 残念ながら、
pl2303
のドライバーはかなり不安定であることが判明しました。 しかし、彼らが拾うとすぐに、彼らはきちんと動作します。
メインループ(空のループ)でUARTをポーリングしないようにするために、割り込みを処理します。
ソフトウェアの観点から見ると、これはUSART1を初期化した後、対応する割り込みベクトルを
NVICで設定する必要があることを意味します。
次のようになります。
NVIC_InitTypeDef nvic_conf; nvic_conf.NVIC_IRQChannel = USART1_IRQn; nvic_conf.NVIC_IRQChannelPreemptionPriority = 0; nvic_conf.NVIC_IRQChannelSubPriority = 2; nvic_conf.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&nvic_conf); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
最後のコマンドは、受信レジスタUSART1を埋めるイベントを解決します。
したがって、処理は次のようになります。
void USART1_IRQHandler(void) { u8 data = USART1->DR; uart_write_byte(data); handle_byte(data); }
バイトを返送(エコー)し、ハンドラーを呼び出します。これは単純なステートマシンです。
すべてのコードは
githubリポジトリで公開されます。
PS
この投稿の作成には、ほぼ6時間かかりました。 ハードウェアおよびソフトウェア部品の作成とデバッグ-約13時間。
それを読んだすべての人に感謝します。 すべてのナメクジや他の昆虫については、個人的に書きます。