无码专区 中文字幕,在线亚洲中文精品第1页,亚洲无码在线观看视屏,欧美日韩国产综合第一区,国产成a人片在线观看视频下载,精品人妻中文字幕1区

歡迎來(lái)到廣東TFT屏幕廠家官方網(wǎng)站!
contact us

聯(lián)系我們

廣東TFT屏幕廠家 > 新聞資訊 > ALIENTEK 阿波羅 STM32F767 開(kāi)發(fā)板資料連載第十八章 TFTLCD實(shí)驗(yàn)

ALIENTEK 阿波羅 STM32F767 開(kāi)發(fā)板資料連載第十八章 TFTLCD實(shí)驗(yàn)

編輯 :

廣東TFT屏幕

時(shí)間 : 2021-12-22 15:27 瀏覽量 : 64

1)試驗(yàn)服務(wù)平臺(tái):alientek 阿波羅 STM32F767 單片機(jī)開(kāi)發(fā)板2)節(jié)選自《STM32F7 開(kāi)發(fā)設(shè)計(jì)指引(HAL 庫(kù)版)》關(guān)心官微號(hào)微信公眾號(hào),獲得大量材料:正點(diǎn)原子



第十八章 TFTLCD(MCU 屏)試驗(yàn)

在第 16 章大家詳細(xì)介紹了 OLED 模塊以及顯示,可是該模塊只有顯示純色/兩色,不可以顯示彩

色,并且規(guī)格也較小。此章大家將詳細(xì)介紹 ALIENTEK 的 TFT LCD 模塊(MCU 屏),該模塊選用

TFTLCD 控制面板,可以顯示 16 位色的真彩照片。在這章中,大家將應(yīng)用阿波羅 STM32F767 開(kāi)發(fā)設(shè)計(jì)

板底版上的 TFTLCD 插口(僅適用 MCU 屏,此章僅詳細(xì)介紹 MCU 屏的應(yīng)用),來(lái)照亮 TFTLCD,

并完成 ASCII 標(biāo)識(shí)符和彩色的顯示等作用,并在串口通信打印出 LCD 控制板 ID,與此同時(shí)在 LCD 上邊顯示。

此章分成如下所示一些一部分:

18.1 TFTLCD&FMC 介紹

18.2 硬件開(kāi)發(fā)

18.3 軟件開(kāi)發(fā)

18.4 在線下載認(rèn)證

18.5 STM32CubeMX 配備 FMC(SRAM)

18.1 TFTLCD&FMC 介紹

此章大家將根據(jù) STM32F767的 FMC 插口來(lái)操縱TFTLCD 的顯示,因此這節(jié)分成2個(gè)一部分,

各自詳細(xì)介紹 TFTLCD 和 FMC。

18.1.1 TFTLCD 介紹

TFT-LCD 即塑料薄膜晶體三極管液晶顯示器。其英語(yǔ)全稱(chēng)之為:Thin Film Transistor-Liquid Crystal

Display。TFT-LCD 與微波感應(yīng)器 TN-LCD、STN-LCD 的簡(jiǎn)易引流矩陣不一樣,它在液晶顯示屏的每一個(gè)象

素上面設(shè)定有一個(gè)塑料薄膜晶體三極管(TFT),可合理地?cái)[脫非選通時(shí)的串?dāng)_,使顯示液晶顯示屏的靜態(tài)數(shù)據(jù)特

性與掃描線數(shù)不相干,因而進(jìn)一步提高了圖象品質(zhì)。TFT-LCD 也被稱(chēng)為真彩液晶顯示器。

上一章詳細(xì)介紹了 OLED 模塊,此章,大家給各位詳細(xì)介紹 ALIENTEK TFTLCD 模塊(MCU 插口),

該模塊有以下特性:

1,2.8’/3.5’/4.3’/7’等 4 種尺寸的顯示屏可選。

2,320×240 的屏幕分辨率(3.5’屏幕分辨率為:320*480,4.3’和 7’屏幕分辨率為:800*480)。

3,16 位真彩顯示。

4,內(nèi)置觸摸顯示屏,可以拿來(lái)做為操縱鍵入。

此章,大家以 2.8 寸(別的 3.5 寸/4.3 寸等 LCD 方式相近,請(qǐng)參照 2.8 的就可以)的 ALIENTEK

TFTLCD 模塊為例子詳細(xì)介紹,該模塊適用 65K 色顯示,顯示屏幕分辨率為 320×240,插口為 16 位的 80

并口,內(nèi)置觸摸顯示屏。

該模塊的外型圖如下圖 18.1.1.1 所顯示

圖 18.1.1.1 ALIENTEK 2.8 寸 TFTLCD 外型圖


模塊電路原理圖如下圖 18.1.1.2 所顯示:

圖 18.1.1.2 ALIENTEK 2.8 寸 TFTLCD 模塊電路原理圖


TFTLCD 模塊選用 2*17 的 2.54 公排針與外界聯(lián)接,接口定義如下圖 18.1.1.3 所顯示:

圖 18.1.1.3 ALIENTEK 2.8 寸 TFTLCD 模塊插口圖


從圖 18.1.1.3 可以看得出,ALIENTEK TFTLCD 模塊選用 16 位的并方法與外界聯(lián)接,往往

不選用 8 位的方法,是由于顯示屏的信息量較為大,特別是在在顯示照片的情況下,假如用 8 位手機(jī)充電線,

便會(huì)比 16 位方法慢一倍以上,大家自然期待速率越是快就越好,因此大家挑選 16 位的插口。圖

18.1.1.3 還列舉了觸摸顯示屏集成ic的插口,有關(guān)觸摸顯示屏此章大家很少詳細(xì)介紹,后邊的章節(jié)目錄會(huì)出現(xiàn)詳盡的介

紹。該模塊的 80 并口有以下一些電源線:

CS:TFTLCD 片選數(shù)據(jù)信號(hào)。

WR:向 TFTLCD 載入數(shù)據(jù)信息。

RD:從 TFTLCD 接收數(shù)據(jù)。

D[15:0]:16 位雙重手機(jī)充電線。

RST:硬校準(zhǔn) TFTLCD。

RS:指令/數(shù)據(jù)信息標(biāo)示(0,讀寫(xiě)能力指令;1,讀寫(xiě)能力數(shù)據(jù)信息)。

80 并口在上一節(jié)大家早已有完整的講解了,這兒大家就不會(huì)再詳細(xì)介紹,必須表明的是,TFTLCD

模塊的 RST 電源線是立即收到 STM32F767 的校準(zhǔn)腳底,并不由自主APP操縱,那樣可以省出來(lái)一

個(gè) IO 口。此外大家還要一個(gè)led背光控線來(lái)操縱 TFTLCD 的led背光。因此,大家一共必須的 IO

口數(shù)額為 21 個(gè)。這兒還要留意,大家標(biāo)明的 DB1~DB8,DB10~DB17,是相比于 LCD 操縱

IC 標(biāo)明的,事實(shí)上大伙兒可以把她們就相當(dāng)于 D0~D15,那樣解釋起來(lái)就相對(duì)簡(jiǎn)單一點(diǎn)。

ALIENTEK給予 2.8/3.5/4.3/7 寸等 4種不一樣規(guī)格和分辯率的TFTLCD 模塊,其推動(dòng)集成ic為:

ILI9341/NT35310/NT35510/SSD1963 等(實(shí)際的型號(hào)規(guī)格,大伙兒可以根據(jù)在線下載此章試驗(yàn)編碼,根據(jù)串

口或是 LCD 顯示查詢),這兒大家僅以 ILI9341 控制板為例子開(kāi)展詳細(xì)介紹,別的的操縱基本上都相近,

大家也不詳盡論述了。

ILI9341 液晶控制板內(nèi)置獨(dú)顯存儲(chǔ),其獨(dú)顯存儲(chǔ)總尺寸為 172800(240*320*18/8),即 18 位方式(26

萬(wàn)色)下的顯總量。在 16 位方式下,ILI9341 選用 RGB565 文件格式儲(chǔ)存色調(diào)數(shù)據(jù)信息,這時(shí) ILI9341

的 18 位手機(jī)充電線與 MCU 的 16 位手機(jī)充電線及其 LCD GRAM 的對(duì)應(yīng)關(guān)系如下圖 18.1.1.4 所顯示:

圖 18.1.1.4 16 位數(shù)據(jù)信息與獨(dú)顯存儲(chǔ)對(duì)應(yīng)關(guān)系圖

從圖內(nèi)可以看得出,ILI9341 在 16 位方式下邊,手機(jī)充電線有效的是:D17~D13 和 D11~D1,D0

和 D12 沒(méi)有使用,事實(shí)上在大家 LCD 模塊里邊,ILI9341 的 D0 和 D12 根本就沒(méi)有引過(guò)來(lái),這

樣,ILI9341 的 D17~D13 和 D11~D1 相匹配 MCU 的 D15~D0。

那樣 MCU 的 16 位數(shù)據(jù)信息,最少 5 位意味著深藍(lán)色,正中間 6 位為翠綠色,最大 5 位為鮮紅色。標(biāo)值越

大,表明該色調(diào)越重。此外,需注意 ILI9341 全部的命令全是 8 位的(高 8 位失效),且主要參數(shù)

除開(kāi)讀寫(xiě)能力 GRAM 的那時(shí)候是 16 位,別的實(shí)際操作主要參數(shù),全是 8 位的。

下面,大家介紹一下 ILI9341 的一些關(guān)鍵指令,由于 ILI9341 的指令許多,大家這兒就

不所有詳細(xì)介紹了,有感興趣的各位可以尋找 ILI9341 的 datasheet 看一下。里邊對(duì)這種指令有完整的介

紹。大家將詳細(xì)介紹:0XD3,0X36,0X2A,0X2B,0X2C,0X2E 等 6 條命令。

最先看來(lái)命令:0XD3,這個(gè)是讀 ID4 命令,用以載入 LCD 控制板的 ID,該命令如表 18.1.1.1

所顯示:

表 18.1.1.1 0XD3 命令敘述


從以上可以看得出,0XD3 命令后邊跟了 4 個(gè)主要參數(shù),最終 2 個(gè)主要參數(shù),讀出是 0X93 和 0X41,

恰好是大家控制板 ILI9341 的小數(shù)一部分,進(jìn)而,根據(jù)該命令,就可以辨別常用的 LCD 控制器是什

么型號(hào)規(guī)格,那樣,大家的編碼,就可以依據(jù)控制板的型號(hào)規(guī)格去實(shí)行相匹配推動(dòng) IC 的復(fù)位編碼,進(jìn)而

兼容不一樣推動(dòng) IC 的屏,促使一個(gè)編碼適用幾款 LCD。

下面看命令:0X36,這也是儲(chǔ)存瀏覽程序控制,可以操縱 ILI9341 儲(chǔ)存器的讀寫(xiě)能力方位,簡(jiǎn)

單的說(shuō),便是在持續(xù)寫(xiě) GRAM 的情況下,可以操縱 GRAM 表針的提高方位,進(jìn)而操縱顯示方法

(讀 GRAM 也是一樣)。該命令如表 18.1.1.2 所顯示:

表 18.1.1.2 0X36 命令敘述


從以上可以看得出,0X36 命令后邊,緊隨一個(gè)主要參數(shù),這兒大家關(guān)鍵關(guān)心:MY、MX、MV

這三個(gè)位,根據(jù)這三個(gè)位的設(shè)定,我們可以操縱全部 ILI9341 的所有掃描儀方位,如表 18.1.1.3

所顯示:



表 18.1.1.3 MY、MX、MV 設(shè)定與 LCD 掃描儀方位關(guān)系表


那樣,我們?cè)谶\(yùn)用 ILI9341 顯示內(nèi)容的情況下,就會(huì)有非常大靈敏性了,例如顯示 BMP 照片,

BMP 編解碼數(shù)據(jù)信息,就是以照片的左下方逐漸,漸漸地顯示到右上方,假如設(shè)定 LCD 掃描儀方位為從

左到右,從下向上,那麼大家只必須設(shè)定一次座標(biāo),隨后就不斷的往 LCD 填充顏色數(shù)據(jù)信息就可以,

那樣可以進(jìn)一步提高顯示速率。

下面看命令:0X2A,這也是列詳細(xì)地址設(shè)定命令,在從左往右,自上而下的掃描儀方法(默認(rèn)設(shè)置)

下邊,該命令用以設(shè)定橫坐標(biāo)軸(x 座標(biāo)),該命令如表 18.1.1.4 所顯示:

表 18.1.1.4 0X2A 命令敘述

在默認(rèn)設(shè)置掃描儀方法時(shí),該命令用以設(shè)定 x 座標(biāo),該命令含有 4 個(gè)主要參數(shù),事實(shí)上是 2 個(gè)平面坐標(biāo):

SC 和 EC,即列詳細(xì)地址的起始值和完畢值,SC 務(wù)必不大于 EC,且 0≤SC/EC≤239。一般在設(shè)

置 x 座標(biāo)的情況下,大家只必須帶 2 個(gè)主要參數(shù)就可以,也就是設(shè)定 SC 就可以,由于假如 EC 沒(méi)有轉(zhuǎn)變,

大家只必須設(shè)定一次就可以(在復(fù)位 ILI9341 的過(guò)程中設(shè)定),進(jìn)而提高速度。

與 0X2A 命令相近,命令:0X2B,是頁(yè)詳細(xì)地址設(shè)定命令,在從左往右,自上而下的掃描儀方法

(默認(rèn)設(shè)置)下邊,該命令用以設(shè)定縱軸(y 座標(biāo))。該命令如表 18.1.1.5 所顯示:

表 18.1.1.5 0X2B 命令敘述


在默認(rèn)設(shè)置掃描儀方法時(shí),該命令用以設(shè)定 y 座標(biāo),該命令含有 4 個(gè)主要參數(shù),事實(shí)上是 2 個(gè)平面坐標(biāo):

SP 和 EP,即頁(yè)詳細(xì)地址的起始值和完畢值,SP 務(wù)必不大于 EP,且 0≤SP/EP≤319。一般在設(shè)定

y 座標(biāo)的情況下,大家只必須帶 2 個(gè)主要參數(shù)就可以,也就是設(shè)定 SP 就可以,由于假如 EP 沒(méi)有轉(zhuǎn)變,我

們只必須設(shè)定一次就可以(在復(fù)位 ILI9341 的過(guò)程中設(shè)定),進(jìn)而提高速度。

下面看命令:0X2C,該命令是寫(xiě) GRAM 命令,在推送該命令以后,大家便可以往 LCD

的 GRAM 里邊載入色調(diào)數(shù)據(jù)信息了,該命令適用持續(xù)寫(xiě),命令敘述如表 18.1.1.6 所顯示:


表 18.1.1.6 0X2C 命令敘述



從以上得知,在接到命令 0X2C 以后,數(shù)據(jù)信息合理位寬變成 16 位,我們可以持續(xù)載入 LCD

GRAM 值,而 GRAM 的詳細(xì)地址將依據(jù) MY/MX/MV 設(shè)定的掃描儀方位開(kāi)展自增。比如:假定設(shè)定

的是從左往右,自上而下的掃描儀方法,那麼設(shè)定好起止座標(biāo)(根據(jù) SC,SP 設(shè)定)后,每載入

一個(gè)顏色值,GRAM 詳細(xì)地址可能全自動(dòng)自增 1(SC  ),假如遇到 EC,則返回 SC,與此同時(shí) SP  ,一

直到座標(biāo):EC,EP 完畢,期間不用再度設(shè)定的座標(biāo),進(jìn)而進(jìn)一步提高載入速率。

最終,一起來(lái)看看命令:0X2E,該命令是讀 GRAM 命令,用以載入 ILI9341 的獨(dú)顯存儲(chǔ)(GRAM),

該命令在 ILI9341 的數(shù)據(jù)信息指南上邊的敘述是不正確的,真正的導(dǎo)出狀況如表 18.1.1.7 所顯示:


表 18.1.1.7 0X2E 命令敘述


該命令用以載入 GRAM,如表 18.1.1.7 所顯示,ILI9341 在得到該命令后,第一次導(dǎo)出的是

dummy 數(shù)據(jù)信息,也就是失效的數(shù)據(jù)信息,第二次逐漸,載入到的才算是合理的 GRAM 數(shù)據(jù)信息(從座標(biāo):

SC,SP 逐漸),導(dǎo)出規(guī)律性為:每一個(gè)色調(diào)份量占 8 個(gè)位數(shù),一次導(dǎo)出 2 個(gè)色調(diào)份量。例如:第一次

導(dǎo)出是 R1G1,接著的規(guī)律性為:B1R2?G2B2?R3G3?B3R4?G4B4?R5G5... 依此類(lèi)推。假如

大家只必須載入一個(gè)點(diǎn)的顏色值,那麼只必須接受到主要參數(shù) 3 就可以,假如要持續(xù)載入(運(yùn)用 GRAM

詳細(xì)地址自增,方式跟上面一樣),那麼就依照以上規(guī)律性去接受色調(diào)數(shù)據(jù)信息。

以上,便是實(shí)際操作 ILI9341 常見(jiàn)的好多個(gè)命令,根據(jù)這好多個(gè)命令,大家便可以不錯(cuò)的操縱 ILI9341

顯示大家所要顯示的內(nèi)容了。

一般 TFTLCD 模塊的應(yīng)用步驟如下圖 18.1.1.5:

圖 18.1.1.5 TFTLCD 應(yīng)用步驟


一切 LCD,應(yīng)用步驟都能夠簡(jiǎn)易的用以上流程表表明。在其中硬校準(zhǔn)和復(fù)位編碼序列,只必須

實(shí)行一次就可以。而畫(huà)點(diǎn)步驟便是:設(shè)定座標(biāo)?寫(xiě) GRAM 命令?載入色調(diào)數(shù)據(jù)信息,隨后在 LCD 上

面,大家就可以見(jiàn)到相應(yīng)的點(diǎn)顯示大家載入的色調(diào)了。讀點(diǎn)步驟為:設(shè)定座標(biāo)?讀 GRAM 命令

?載入色調(diào)數(shù)據(jù)信息,那樣就可以獲得到對(duì)應(yīng)的點(diǎn)的色調(diào)數(shù)據(jù)信息了。

以上僅僅非常簡(jiǎn)單的實(shí)際操作,也是最常見(jiàn)的實(shí)際操作,擁有這種實(shí)際操作,一般就可以正常的應(yīng)用 TFTLCD

了。下面人們將該模塊用于來(lái)顯示標(biāo)識(shí)符和數(shù)據(jù),根據(jù)以上詳細(xì)介紹,我們可以得到 TFTLCD 顯示

必須的有關(guān)設(shè)定流程如下所示:

1)設(shè)定 STM32F767 與 TFTLCD 模塊相連接的 IO。

這一步,先將我們與 TFTLCD 模塊相連的 IO 口進(jìn)行初始化,以便驅(qū)動(dòng) LCD。這里我們用

到的是 FMC,F(xiàn)MC 將在 18.1.2 節(jié)向大家詳細(xì)介紹。

2)初始化 TFTLCD 模塊。

即圖 18.1.1.5 的初始化序列,這里我們沒(méi)有硬復(fù)位 LCD,因?yàn)榘⒉_ STM32F767 開(kāi)發(fā)板

的 LCD 接口,將 TFTLCD 的 RST 同 STM32F767 的 RESET 連接在一起了,只要按下開(kāi)發(fā)板的

RESET 鍵,就會(huì)對(duì) LCD 進(jìn)行硬復(fù)位。初始化序列,就是向 LCD 控制器寫(xiě)入一系列的設(shè)置值(比

如伽馬校準(zhǔn)),這些初始化序列一般 LCD 供應(yīng)商會(huì)提供給客戶,我們直接使用這些序列即可,

不需要深入研究。在初始化之后,LCD 才可以正常使用。

3)通過(guò)函數(shù)將字符和數(shù)字顯示到 TFTLCD 模塊上。

這一步則通過(guò)圖 18.1.1.5 左側(cè)的流程,即:設(shè)置坐標(biāo)?寫(xiě) GRAM 指令?寫(xiě) GRAM 來(lái)實(shí)現(xiàn),

但是這個(gè)步驟,只是一個(gè)點(diǎn)的處理,我們要顯示字符/數(shù)字,就必須要多次使用這個(gè)步驟,從而

達(dá)到顯示字符/數(shù)字的目的,所以需要設(shè)計(jì)一個(gè)函數(shù)來(lái)實(shí)現(xiàn)數(shù)字/字符的顯示,之后調(diào)用該函數(shù),

就可以實(shí)現(xiàn)數(shù)字/字符的顯示了。

STM32F767xx 系列芯片都帶有 FMC 接口,即可變存儲(chǔ)存儲(chǔ)控制器,能夠與同步或異步存

儲(chǔ)器、SDRAM 存儲(chǔ)器和 NAND FLASH 等連接,STM32F767 的 FMC 接口支持包括 SRAM、

SDRAM、NAND FLASH、NOR FLASH 和 PSRAM 等存儲(chǔ)器。FMC 的框圖如圖 18.1.2.1 所示:

圖 18.1.2.1 FMC 框圖


從上圖我們可以看出,STM32F767 的 FMC 將外部設(shè)備分為 3 類(lèi):NOR/PSRAM 設(shè)備、NAND

設(shè)備和 SDRAM 設(shè)備。他們共用地址數(shù)據(jù)總線等信號(hào),他們具有不同的 CS 以區(qū)分不同的設(shè)備,

比如本章我們用到的 TFTLCD 就是用的 FMC_NE1 做片選,其實(shí)就是將 TFTLCD 當(dāng)成 SRAM

來(lái)控制。

這里我們介紹下為什么可以把 TFTLCD 當(dāng)成 SRAM 設(shè)備用:首先我們了解下外部 SRAM

的連接,外部 SRAM 的控制一般有:地址線(如 A0~A18)、數(shù)據(jù)線(如 D0~D15)、寫(xiě)信號(hào)(WE)、

讀信號(hào)(OE)、片選信號(hào)(CS),如果 SRAM 支持字節(jié)控制,那么還有 UB/LB 信號(hào)。而 TFTLCD

的信號(hào)我們?cè)?18.1.1 節(jié)有介紹,包括:RS、D0~D15、WR、RD、CS、RST 和 BL 等,其中真

正在操作 LCD 的時(shí)候需要用到的就只有:RS、D0~D15、WR、RD 和 CS。其操作時(shí)序和 SRAM

的控制完全類(lèi)似,唯一不同就是 TFTLCD 有 RS 信號(hào),但是沒(méi)有地址信號(hào)。

TFTLCD 通過(guò) RS 信號(hào)來(lái)決定傳送的數(shù)據(jù)是數(shù)據(jù)還是命令,本質(zhì)上可以理解為一個(gè)地址信

號(hào),比如我們把 RS 接在 A0 上面,那么當(dāng) FMC 控制器寫(xiě)地址 0 的時(shí)候,會(huì)使得 A0 變?yōu)?0,

對(duì) TFTLCD 來(lái)說(shuō),就是寫(xiě)命令。而 FMC 寫(xiě)地址 1 的時(shí)候,A0 將會(huì)變?yōu)?1,對(duì) TFTLCD 來(lái)說(shuō),

就是寫(xiě)數(shù)據(jù)了。這樣,就把數(shù)據(jù)和命令區(qū)分開(kāi)了,他們其實(shí)就是對(duì)應(yīng) SRAM 操作的兩個(gè)連續(xù)地

址。當(dāng)然 RS 也可以接在其他地址線上,阿波羅 STM32F767 開(kāi)發(fā)板是把 RS 連接在 A18 上面的。

STM32F767 的 FMC 支持 8/16/32 位數(shù)據(jù)寬度,我們這里用到的 LCD 是 16 位寬度的,所

以在設(shè)置的時(shí)候,選擇 16 位寬就 OK 了。我們?cè)賮?lái)看看 FMC 的外部設(shè)備地址映像,STM32F767

的 FMC 將外部存儲(chǔ)器劃分為 6 個(gè)固定大小為 256M 字節(jié)的存儲(chǔ)區(qū)域,如圖 18.1.2.2 所示:

圖 18.1.2.2 FMC 存儲(chǔ)塊地址映像


從上圖可以看出,F(xiàn)MC 總共管理 1.5GB 空間,擁有 6 個(gè)存儲(chǔ)塊(Bank),本章,我們用到

的是塊 1,所以在本章我們僅討論塊 1 的相關(guān)配置,其他塊的配置,請(qǐng)參考《STM32F7 中文參

考手冊(cè)》第 13 章(286 頁(yè))的相關(guān)介紹。

STM32F767 的 FMC 存儲(chǔ)塊 1(Bank1)被分為 4 個(gè)區(qū),每個(gè)區(qū)管理  ** M 字節(jié)空間,每個(gè)

區(qū)都有獨(dú)立的寄存器對(duì)所連接的存儲(chǔ)器進(jìn)行配置。Bank1 的 256M 字節(jié)空間由 28 根地址線

(HADDR[27:0])尋址。

這里 HADDR 是內(nèi)部AHB地址總線,其中HADDR[25:0]來(lái)自外部存儲(chǔ)器地址 FMC_A[25:0],

而 HADDR[26:27]對(duì) 4 個(gè)區(qū)進(jìn)行尋址。如表 18.1.2.1 所示:

表 18.1.2.1 Bank1 存儲(chǔ)區(qū)選擇表

HADDR[25:0]位包含外部存儲(chǔ)器的地址,由于 HADDR 為字節(jié)地址,而存儲(chǔ)器按字尋址,

所以,根據(jù)存儲(chǔ)器數(shù)據(jù)寬度的不同,實(shí)際上向存儲(chǔ)器發(fā)送的地址也有所不同,如表 18.1.2.2 所

示:

表 18.1.2.2 NOR/PSRAM 外部存儲(chǔ)器地址


因此,F(xiàn)MC 內(nèi)部 HADDR 與存儲(chǔ)器尋址地址的實(shí)際對(duì)應(yīng)關(guān)系就是:

當(dāng)接的是 32 位寬度存儲(chǔ)器的時(shí)候:HADDR[25:2]? FMC_A [23:0]。

當(dāng)接的是 16 位寬度存儲(chǔ)器的時(shí)候:HADDR[25:1]? FMC_A [24:0]。

當(dāng)接的是 8 位寬度存儲(chǔ)器的時(shí)候:HADDR[25:0]? FMC_A [25:0]。

不論外部接 8 位/16 位/32 位寬設(shè)備,F(xiàn)MC_A[0]永遠(yuǎn)接在外部設(shè)備地址 A[0]。 這里,

TFTLCD 使用的是 16 位數(shù)據(jù)寬度,所以 HADDR[0]并沒(méi)有用到,只有 HADDR[25:1]是有效的,

對(duì)應(yīng)關(guān)系變?yōu)椋篐ADDR[25:1]? FMC_A[24:0],相當(dāng)于右移了一位,這里請(qǐng)大家特別留意。另

外,HADDR[27:26]的設(shè)置,是不需要我們干預(yù)的,比如:當(dāng)你選擇使用 Bank1 的第一個(gè)區(qū),

即使用 FMC_NE1 來(lái)連接外部設(shè)備的時(shí)候,即對(duì)應(yīng)了 HADDR[27:26]=00,我們要做的就是配置

對(duì)應(yīng)第 1 區(qū)的寄存器組,來(lái)適應(yīng)外部設(shè)備即可。STM32F767 的 FMC 各 Bank 配置寄存器如表

18.1.2.3 所示:

表 18.1.2.3 FMC 各 Bank 配置寄存器表


對(duì)于 NOR FLASH 控制器,主要是通過(guò) FMC_BCRx、FMC_BTRx 和 FMC_BWTRx 寄存器

設(shè)置(其中 x=1~4,對(duì)應(yīng) 4 個(gè)區(qū))。通過(guò)這 3 個(gè)寄存器,可以設(shè)置 FMC 訪問(wèn)外部存儲(chǔ)器的時(shí)序

參數(shù),拓寬了可選用的外部存儲(chǔ)器的速度范圍。FMC 的 NOR FLASH 控制器支持同步和異步突

發(fā)兩種訪問(wèn)方式。選用同步突發(fā)訪問(wèn)方式時(shí),F(xiàn)MC 將 HCLK(系統(tǒng)時(shí)鐘)分頻后,發(fā)送給外部存

儲(chǔ)器作為同步時(shí)鐘信號(hào) FMC_CLK。此時(shí)需要的設(shè)置的時(shí)間參數(shù)有 2 個(gè):

1,HCLK 與 FMC_CLK 的分頻系數(shù)(CLKDIV),可以為 2~16 分頻;

2,同步突發(fā)訪問(wèn)中獲得第 1 個(gè)數(shù)據(jù)所需要的等待延遲(DATLAT)。

對(duì)于異步突發(fā)訪問(wèn)方式,F(xiàn)MC 主要設(shè)置 3 個(gè)時(shí)間參數(shù):地址建立時(shí)間(ADDSET)、數(shù)據(jù)建

立時(shí)間(DATAST)和地址保持時(shí)間(ADDHLD)。FMC 綜合了 SRAM、PSRAM 和 NOR Flash 產(chǎn)品

的信號(hào)特點(diǎn),定義了 4 種不同的異步時(shí)序模型。選用不同的時(shí)序模型時(shí),需要設(shè)置不同的時(shí)序

參數(shù),如表 18.1.2.4 所列:

表 18.1.2.4 NOR FLASH/PSRAM 控制器支持的時(shí)序模型


在實(shí)際擴(kuò)展時(shí),根據(jù)選用存儲(chǔ)器的特征確定時(shí)序模型,從而確定各時(shí)間參數(shù)與存儲(chǔ)器讀/

寫(xiě)周期參數(shù)指標(biāo)之間的計(jì)算關(guān)系;利用該計(jì)算關(guān)系和存儲(chǔ)芯片數(shù)據(jù)手冊(cè)中給定的參數(shù)指標(biāo),可

計(jì)算出 FMC 所需要的各時(shí)間參數(shù),從而對(duì)時(shí)間參數(shù)寄存器進(jìn)行合理的配置。

本章,我們使用異步模式 A(ModeA)方式來(lái)控制 TFTLCD,模式 A 的讀操作時(shí)序如圖

18.1.2.3 所示:

圖 18.1.2.3 模式 A 讀操作時(shí)序圖


模式 A 支持獨(dú)立的讀寫(xiě)時(shí)序控制,這個(gè)對(duì)我們驅(qū)動(dòng) TFTLCD 來(lái)說(shuō)非常有用,因?yàn)?TFTLCD

在讀的時(shí)候,一般比較慢,而在寫(xiě)的時(shí)候可以比較快,如果讀寫(xiě)用一樣的時(shí)序,那么只能以讀

的時(shí)序?yàn)榛鶞?zhǔn),從而導(dǎo)致寫(xiě)的速度變慢,或者在讀數(shù)據(jù)的時(shí)候,重新配置 FMC 的延時(shí),在讀

操作完成的時(shí)候,再配置回寫(xiě)的時(shí)序,這樣雖然也不會(huì)降低寫(xiě)的速度,但是頻繁配置,比較麻

煩。而如果有獨(dú)立的讀寫(xiě)時(shí)序控制,那么我們只要初始化的時(shí)候配置好,之后就不用再配置,

既可以滿足速度要求,又不需要頻繁改配置。

模式 A 的寫(xiě)操作時(shí)序如圖 18.1.2.4 所示:


圖 18.1.2.4 模式 A 寫(xiě)操作時(shí)序

圖 18.1.2.3 和圖 18.1.2.4 中的 ADDSET 與 DATAST,是通過(guò)不同的寄存器設(shè)置的,接下來(lái)

我們講解一下 Bank1 的幾個(gè)控制寄存器

首先,我們介紹 SRAM/NOR 閃存片選控制寄存器:FMC_BCRx(x=1~4),該寄存器各位

描述如圖 18.1.2.5 所示:

圖 18.1.2.5 FMC_BCRx 寄存器各位描述


該寄存器我們?cè)诒菊掠玫降脑O(shè)置有:EXTMOD、WREN、MWID、MTYP 和 MBKEN 這幾

個(gè)設(shè)置,我們將逐個(gè)介紹。

EXTMOD:擴(kuò)展模式使能位,也就是是否允許讀寫(xiě)不同的時(shí)序,很明顯,我們本章需要讀

寫(xiě)不同的時(shí)序,故該位需要設(shè)置為 1。

WREN:寫(xiě)使能位。我們需要向 TFTLCD 寫(xiě)數(shù)據(jù),故該位必須設(shè)置為 1。

MWID[1:0]:存儲(chǔ)器數(shù)據(jù)總線寬度。00,表示 8 位數(shù)據(jù)模式;01 表示 16 位數(shù)據(jù)模式;10

表示 32 位數(shù)據(jù)模式;11 保留。我們的 TFTLCD 是 16 位數(shù)據(jù)線,所以設(shè)置 WMID[1:0]=01。

MTYP[1:0]:存儲(chǔ)器類(lèi)型。00 表示 SRAM;01 表示 PSRAM;10 表示 NOR FLASH/OneNAND

FLASH;11 保留。前面提到,我們把 TFTLCD 當(dāng)成 SRAM 用,所以需要設(shè)置 MTYP[1:0]=00。

MBKEN:存儲(chǔ)塊使能位。這個(gè)容易理解,我們需要用到該存儲(chǔ)塊控制 TFTLCD,當(dāng)然要

使能這個(gè)存儲(chǔ)塊了。

接下來(lái),我們看看 SRAM/NOR 閃存片選時(shí)序寄存器:FMC_BTRx(x=1~4),該寄存器各

位描述如圖 18.1.2.6 所示:

圖 18.1.2.6 FMC_BTRx 寄存器各位描述


這個(gè)寄存器包含了每個(gè)存儲(chǔ)器塊的控制信息,可以用于 SRAM 和 NOR 閃存存儲(chǔ)器等。如

果 FMC_BCRx 寄存器中設(shè)置了 EXTMOD 位,則有兩個(gè)時(shí)序寄存器分別對(duì)應(yīng)讀(本寄存器)和寫(xiě)

操作(FMC_BWTRx 寄存器)。因?yàn)槲覀円笞x寫(xiě)分開(kāi)時(shí)序控制,所以 EXTMOD 是使能了的,

也就是本寄存器是讀操作時(shí)序寄存器,控制讀操作的相關(guān)時(shí)序。本章我們要用到的設(shè)置有:

ACCMOD、DATAST 和 ADDSET 這三個(gè)設(shè)置。

ACCMOD[1:0]:訪問(wèn)模式。00 表示訪問(wèn)模式 A;01 表示訪問(wèn)模式 B;10 表示訪問(wèn)模式 C;

11 表示訪問(wèn)模式 D,本章我們用到模式 A,故設(shè)置為 00。

DATAST[7:0]:數(shù)據(jù)保持時(shí)間。0 為保留設(shè)置,其他設(shè)置則代表保持時(shí)間為: DATAST 個(gè)

HCLK 時(shí)鐘周期,最大為 255 個(gè) HCLK 周期。對(duì) ILI9341 來(lái)說(shuō),其實(shí)就是 RD 低電平持續(xù)時(shí)間,

一般為 355ns。而一個(gè) HCLK 時(shí)鐘周期為 4.6ns 左右(1/216Mhz),為了兼容其他屏,我們這里

設(shè)置 DATAST 為 80,也就是 80 個(gè) HCLK 周期,時(shí)間大約是 368ns。

ADDSET[3:0]:地址建立時(shí)間。其建立時(shí)間為:ADDSET 個(gè) HCLK 周期,最大為 15 個(gè) HCLK

周期。對(duì) ILI9341 來(lái)說(shuō),這里相當(dāng)于 RD 高電平持續(xù)時(shí)間,為 90ns,我們?cè)O(shè)置 ADDSET 為最大

15,即 15*4.6=69ns(略超)。

最后,我們?cè)賮?lái)看看 SRAM/NOR 閃寫(xiě)時(shí)序寄存器:FMC_BWTRx(x=1~4),該寄存器各

位描述如圖 18.1.2.7 所示:

圖 18.1.2.7 FMC_BWTRx 寄存器各位描述


該寄存器在本章用作寫(xiě)操作時(shí)序控制寄存器,需要用到的設(shè)置同樣是:ACCMOD、DATAST

和 ADDSET 這三個(gè)設(shè)置。這三個(gè)設(shè)置的方法同 FMC_BTRx 一模一樣,只是這里對(duì)應(yīng)的是寫(xiě)操

作的時(shí)序,ACCMOD 設(shè)置同 FMC_BTRx 一模一樣,同樣是選擇模式 A,另外 DATAST 和

ADDSET 則對(duì)應(yīng)低電平和高電平持續(xù)時(shí)間,對(duì) ILI9341 來(lái)說(shuō),這兩個(gè)時(shí)間只需要 15ns 就夠了,

比讀操作快得多。所以我們這里設(shè)置 DATAST 為 4,即 4 個(gè) HCLK 周期,時(shí)間約為 18.4ns。然

后 ADDSET 設(shè)置為 4,即 4 個(gè) HCLK 周期,時(shí)間為 18.4ns。

至此,我們對(duì) STM32F767 的 FMC 介紹就差不多了,關(guān)于 FMC 的詳細(xì)介紹,請(qǐng)大家參考

《STM32F7 中文參考手冊(cè)》第 13 章。通過(guò)以上兩個(gè)小節(jié)的了解,我們可以開(kāi)始寫(xiě) LCD 的驅(qū)動(dòng)

代碼了。不過(guò),這里還要給大家做下科普,在 MDK 的寄存器定義里面,并沒(méi)有定義 FMC_BCRx、

FMC_BTRx、FMC_BWTRx 等這個(gè)單獨(dú)的寄存器,而是將他們進(jìn)行了一些組合。

FMC_BCRx 和 FMC_BTRx,組合成 BTCR[8]寄存器組,他們的對(duì)應(yīng)關(guān)系如下:

BTCR[0]對(duì)應(yīng) FMC_BCR1,BTCR[1]對(duì)應(yīng) FMC_BTR1

BTCR[2]對(duì)應(yīng) FMC_BCR2,BTCR[3]對(duì)應(yīng) FMC_BTR2

BTCR[4]對(duì)應(yīng) FMC_BCR3,BTCR[5]對(duì)應(yīng) FMC_BTR3

BTCR[6]對(duì)應(yīng) FMC_BCR4,BTCR[7]對(duì)應(yīng) FMC_BTR4

FMC_BWTRx 則組合成 BWTR[7],他們的對(duì)應(yīng)關(guān)系如下:

BWTR[0]對(duì)應(yīng) FMC_BWTR1,BWTR[2]對(duì)應(yīng) FMC_BWTR2,

BWTR[4]對(duì)應(yīng) FMC_BWTR3,BWTR[6]對(duì)應(yīng) FMC_BWTR4,

BWTR[1]、BWTR[3]和 BWTR[5]保留,沒(méi)有用到。

通過(guò)上面的講解,通過(guò)對(duì) FSC 相關(guān)的寄存器的描述,大家對(duì) FMC 的原理有了一個(gè)初步的

認(rèn)識(shí),如果還不熟悉的朋友,請(qǐng)一定要搜索網(wǎng)絡(luò)資料理解 FMC 的原理。只有理解了原理,使

用庫(kù)函數(shù)才可以得心應(yīng)手。那么在庫(kù)函數(shù)中是怎么實(shí)現(xiàn) FMC 的配置的呢?FMC_BCRx,

FMC_BTRx 寄存器在庫(kù)函數(shù)是通過(guò)什么函數(shù)來(lái)配置的呢?下面我們來(lái)講解一下使用 FMC 接口

驅(qū)動(dòng) LCD(SRAM)相關(guān)的庫(kù)函數(shù)操作過(guò)程。與 SRAM 和 FMC 相關(guān)的庫(kù)函數(shù)定義和聲明在源

文件 stm32f7xx_hal_fmc.c/stm32f7xx_hal_sram.c 以及頭文件

stm32f7xx_hal_fmc.h/stm32f7xx_hal_sram.h 中。

1) 使能 FMC 和 GPIO 時(shí)鐘,初始化 IO 口配置,設(shè)置映射關(guān)系

這個(gè)步驟在前面實(shí)驗(yàn)已多次講解。這里我們主要列出 FMC 時(shí)鐘使能方法:

__HAL_RCC_FMC_CLK_ENABLE ();

//使能 FMC 時(shí)鐘

對(duì)于 IO 配置,調(diào)用函數(shù) HAL_GPIO_Init 配置即可,具體 請(qǐng)參考實(shí)驗(yàn)源碼。

2) 初始化 FMC 接口讀寫(xiě)時(shí)序參數(shù),初始化 LCD(SRAM)控制接口

根據(jù)前面的講解,我們把 LCD 當(dāng) SRAM 使用,連接在 FMC 接口之上,所以我們要初始化

FMC 讀寫(xiě)時(shí)序參數(shù)以及 LCD 數(shù)據(jù)接口,也就是初始化三個(gè)寄存器 FMC_BCRx,F(xiàn)MC_BTRx

和 FMC_BWTRx。HAL 庫(kù)提供了 SRAM 初始化函數(shù) HAL_SRAM_Init,該函數(shù)聲明如下:

HAL_StatusTypeDef HAL_SRAM_Init(SRAM_HandleTypeDef *hsram,

FMC_NORSRAM_TimingTypeDef *Timing,

FMC_NORSRAM_TimingTypeDef *ExtTiming);

該函數(shù)有三個(gè)入口參數(shù),首先我們來(lái)看看第一個(gè)入口參數(shù) hsram,它是

SRAM_HandleTypeDef 結(jié)構(gòu)體指針類(lèi)型,該參數(shù)用來(lái)初始化當(dāng) FMC 接口當(dāng) SRAM 使用時(shí)的控

制接口參數(shù)。結(jié)構(gòu)體 SRAM_HandleTypeDef 定義如下:

typedef struct

{

FMC_NORSRAM_TypeDef

*Instance;

FMC_NORSRAM_EXTENDED_TypeDef

*Extended;

FMC_NORSRAM_InitTypeDef

Init;

HAL_LockTypeDef

Lock;

__IO HAL_SRAM_StateTypeDef

State;

DMA_HandleTypeDef

*hd ** ;

}SRAM_HandleTypeDef;

成員變量 Instance 和成員變量 Extended 實(shí)際上是用來(lái)在指定的時(shí)序模型下,寄存器基地址

和擴(kuò)展模式寄存器基地址。這個(gè)怎么理解呢,本實(shí)驗(yàn)我們使用異步模式 A(ModeA)方式來(lái)控

制 TFTLCD,使用的存儲(chǔ)塊是 Bank1,所以寄存器基地址 Instance 我們直接寫(xiě) FMC_Bank1 即可,

當(dāng)然,HAL 庫(kù)定義好了宏定義 FMC_NORSRAM_DEVICE,也就是如果是 SRAM 設(shè)備,直接

填寫(xiě)這個(gè)宏定義標(biāo)識(shí)符即可。因?yàn)槲覀円渲玫淖x寫(xiě)時(shí)序是不一樣的,也就是我們前面講解的

FMC_BCRx 寄存器的 EXTMOD 位我們會(huì)配置為 1 允許讀寫(xiě)不同的時(shí)序,所以我們這里還要指

定寫(xiě)操作時(shí)序寄存器地址,也就是通過(guò)參數(shù) Extended 來(lái)指定的,這里我們?cè)O(shè)置為 FMC_Bank1E

即可,同樣 MDK 定義好了宏定義標(biāo)識(shí)符 FMC_NORSRAM_EXTENDED_DEVICE,所以這里

我們填寫(xiě)這個(gè)宏定義標(biāo)識(shí)符也是一樣的。對(duì)于寫(xiě)時(shí)序參數(shù)配置,是在函數(shù) HAL_SRAM_Init 的

第三個(gè)參數(shù) ExtTiming 來(lái)配置的,這個(gè)我們后面會(huì)講解。

成員變量 Init 是 FMC_NORSRAM_InitTypeDef 結(jié)構(gòu)體指針類(lèi)型,改變量才是真正用來(lái)設(shè)置

SRAM 控制接口參數(shù)的。我們接下來(lái)看看這個(gè)結(jié)構(gòu)體定義:

typedef struct

{

uint32_t NSBank;

//存儲(chǔ)區(qū)塊號(hào)

uint32_t DataAddressMux;

//地址/數(shù)據(jù)復(fù)用使能

uint32_t MemoryType;

//存儲(chǔ)器類(lèi)型

uint32_t MemoryDataWidth; //存儲(chǔ)器數(shù)據(jù)寬度

uint32_t BurstAccessMode;

uint32_t WaitSignalPolarity;

uint32_t WaitSignalActive;

uint32_t WriteOperation;

//存儲(chǔ)器寫(xiě)使能

uint32_t WaitSignal;

uint32_t ExtendedMode;

//是否使能擴(kuò)展模式

uint32_t AsynchronousWait;

uint32_t WriteBurst;

uint32_t ContinuousClock;

//啟用/禁止 FMC 時(shí)鐘輸出到外部存儲(chǔ)設(shè)備

uint32_t WriteFifo;

uint32_t PageSize;

}FMC_NORSRAM_InitTypeDef;

NSBank 用來(lái)指定使用到的存儲(chǔ)塊區(qū)號(hào),前面講過(guò),我們是使用的存儲(chǔ)塊區(qū)號(hào) 1,所以選擇

值為 FMC_NORSRAM_BANK1。DataAddressMux 用來(lái)設(shè)置是否使能地址/數(shù)據(jù)復(fù)用,該變量?jī)H對(duì)

NOR/PSRAM 有 效 , 所 以 這 里 我 們 選 擇 不 使 能 地 址 / 數(shù)據(jù)復(fù)用值

FMC_DATA_ADDRESS_MUX_DISABLE 即可。MemoryType 用來(lái)設(shè)置存儲(chǔ)器類(lèi)型,這里我們

把 LCD 當(dāng) SRAM 使用,所以設(shè)置為 FMC_MEMORY_TYPE_SRAM 即可。MemoryDataWidth

用來(lái)設(shè)置存儲(chǔ)器數(shù)據(jù)總線寬度,可選 8 位還是 16 位,這里我們選擇 16 位數(shù)據(jù)寬度

FMC_NORSRAM_MEM_BUS_WIDTH_16。WriteOperation 用來(lái)設(shè)置存儲(chǔ)器寫(xiě)使能,也就是是

否允許寫(xiě)入。毫無(wú)疑問(wèn)我們會(huì)進(jìn)行存儲(chǔ)器寫(xiě)操作,所以這里設(shè)置為

FMC_WRITE_OPERATION_ENABLE。ExtendedMode 用來(lái)設(shè)置是否使能擴(kuò)展模式,也就是是

否允許讀寫(xiě)使用不同時(shí)序,前面講解過(guò)本實(shí)驗(yàn)讀寫(xiě)采用不同時(shí)序,所以設(shè)置值為使能值

FMC_EXTENDED_MODE_ENABLE。ContinuousClock 用來(lái)設(shè)置啟用/禁止 FMC 時(shí)鐘輸出到外

部存儲(chǔ)設(shè)備 ,這里 僅 當(dāng) 使 用 FMC_BCR1 寄 存 器 的 時(shí) 候 需 要 啟 用 , 啟 用 值 為

FMC_CONTINUOUS_CLOCK_SYNC_ASYNC 。 其 他 參 數(shù) WriteBurst , BurstAccessMode ,

WaitSignalPolarity,WaitSignalActive,WaitSignal,AsynchronousWait 等是用在突發(fā)訪問(wèn)和異步

時(shí)序情況下,這里我們不做過(guò)多講解。

成員變量 Lock 和 State 是 HAL 庫(kù)處理狀態(tài)標(biāo)識(shí)變量。這里就不做過(guò)多講解。

成員變量 hd **  在使用 DMA 時(shí)候才使用,這里就先不講解了。

函數(shù) HAL_SRAM_Init 的第一個(gè)入口參數(shù)就給大家講解到這里。

接下來(lái)看看后面 2 個(gè)參數(shù) Timing 和 ExtTiming,它們都是 FMC_NORSRAM_TimingTypeDef

結(jié)構(gòu)體指針類(lèi)型,分別用來(lái)設(shè)置 FMC 接口讀和寫(xiě)時(shí)序,主要涉及地址建立保持時(shí)間,數(shù)據(jù)建

立時(shí)間等等配置,對(duì)于我們的實(shí)驗(yàn)中,讀寫(xiě)時(shí)序不一樣,讀寫(xiě)速度要求不一樣,所以對(duì)于參數(shù)

Timing 和 ExtTiming 設(shè)置了不同的值。

FMC_NORSRAM_TimingTypeDef 結(jié)構(gòu)體定義如下:

typedef struct

{

uint32_t AddressSetupTime;

//地址建立時(shí)間

uint32_t AddressHoldTime;

//地址保持時(shí)間

uint32_t DataSetupTime;

//數(shù)據(jù)簡(jiǎn)歷時(shí)間

uint32_t BusTurnAroundDuration; //總線周轉(zhuǎn)階段的持續(xù)時(shí)間

uint32_t CLKDivision;

//CLK 時(shí)鐘輸出信號(hào)的周期

uint32_t DataLatency;

//同步突發(fā) NOR FLASH 的數(shù)據(jù)延遲

uint32_t AccessMode;

//異步模式配置

}FMC_NORSRAM_TimingTypeDef;

成員變量 AddressSetupTime 用來(lái)設(shè)置地址建立時(shí)間。AddressHoldTime 用來(lái)設(shè)置地址保持

時(shí)間。DataSetupTime 用來(lái)設(shè)置數(shù)據(jù)建立時(shí)間。BusTurnAroundDuration 用來(lái)配置總線周轉(zhuǎn)階段

的持續(xù)時(shí)間。CLKDivision 用來(lái)配置 CLK 時(shí)鐘輸出信號(hào)的周期,以 HCLK 周期數(shù)表示。

DataLatency 用來(lái)設(shè)置同步突發(fā) NOR FLASH 的數(shù)據(jù)延遲。AccessMode 用來(lái)設(shè)置異步模式,取

值范圍為 FMC_ACCESS_MODE_A,F(xiàn)MC_ACCESS_MODE_B, FMC_ACCESS_MODE_C 和

FMC_ACCESS_MODE_D,這里我們用是異步模式 A,所以取值為 FMC_ACCESS_MODE_A。

HAL_SRAM_Init 函數(shù)各個(gè)入口參數(shù)含義和配置就給大家講解到這里。

和其他外設(shè)一樣,HAL 庫(kù)也提供了 SRAM 的初始化 MSP 回調(diào)函數(shù),函數(shù)聲明如下:

void HAL_SRAM_MspInit(SRAM_HandleTypeDef *hsram) ;

關(guān)于 MSP 函數(shù)的使用方法相信大家已經(jīng)非常熟悉。該函數(shù)內(nèi)部一般用來(lái)使能時(shí)鐘以及初

始化 IO 口這些與 MCU 相關(guān)的步驟。

前面我們講解過(guò),F(xiàn)MC 接口支持多種存儲(chǔ)器,包括 SDRAM,NOR,NAND 和 PC CARD

等。HAL 庫(kù)為每種支持的存儲(chǔ)器類(lèi)型都定義了一個(gè)獨(dú)立的 HAL 庫(kù)文件,并且在文件中定義了

獨(dú)立的初始化函數(shù)。這里以 SDRAM 為例,HAL 提供庫(kù)支持文件 stm32f7xx_hal_sdram.c 和頭文

件 stm32f7xx_hal_sdram.h,同時(shí)還提供了獨(dú)立的初始化函數(shù) HAL_SDRAM_Init,這里我們就列

出幾種存儲(chǔ)器的初始化函數(shù):

HAL_SDRAM_Init();//SDRAM 初始化函數(shù),省略入口參數(shù)

HAL_NOR_Init();//NOR 初始化函數(shù),省略入口參數(shù)

HAL_NAND_Init();//NAND 初始化函數(shù),省略入口參數(shù)

3)存儲(chǔ)區(qū)使能

實(shí)際上,當(dāng)我們調(diào)用了存儲(chǔ)器初始化函數(shù)之后,相應(yīng)的使用到的存儲(chǔ)區(qū)就已經(jīng)被使能。

SRAM 存儲(chǔ)區(qū)使能方法為:

__FMC_NORSRAM_ENABLE(FMC_Bank1,F(xiàn)MC_NORSRAM_BANK1);

18.2 硬件設(shè)計(jì)

本實(shí)驗(yàn)用到的硬件資源有:

1) 指示燈 DS0

2) TFTLCD 模塊

TFTLCD 模塊的電路見(jiàn)圖 18.1.1.2,這里我們介紹 TFTLCD 模塊與 ALIETEK 阿波羅

STM32F767 開(kāi)發(fā)板的連接,阿波羅 STM32F767 開(kāi)發(fā)板底板的 LCD 接口和 ALIENTEK TFTLCD

模塊直接可以對(duì)插,連接關(guān)系如圖 18.2.1 所示:

圖 18.2.1 TFTLCD 與開(kāi)發(fā)板連接示意圖


圖 18.2.1 中圈出來(lái)的部分就是連接 TFTLCD 模塊的接口,液晶模塊直接插上去即可。

在硬件上,TFTLCD 模塊與阿波羅 STM32F767 開(kāi)發(fā)板的 IO 口對(duì)應(yīng)關(guān)系如下:

LCD_BL(背光控制)對(duì)應(yīng) PB5;

LCD_CS 對(duì)應(yīng) PD7 即 FMC_NE1;

LCD _RS 對(duì)應(yīng) PD13 即 FMC_A18;

LCD _WR 對(duì)應(yīng) PD5 即 FMC_NWE;

LCD _RD 對(duì)應(yīng) PD4 即 FMC_NOE;

LCD _D[15:0]則直接連接在 FMC_D15~FMC_D0;

這些線的連接,阿波羅 STM32F767 開(kāi)發(fā)板的內(nèi)部已經(jīng)連接好了,我們只需要將 TFTLCD

模塊插上去就好了。實(shí)物連接(4.3 寸 TFTLCD 模塊)如圖 18.2.2 所示:

圖 18.2.2 TFTLCD 與開(kāi)發(fā)板連接實(shí)物圖


18.3 軟件設(shè)計(jì)

打開(kāi)我們光盤(pán)的實(shí)驗(yàn) 13 TFTLCD(MCU 屏)工程可以看到我們添加了兩個(gè)文件 lcd.c 和頭

文 件 lcd.h 。 同 時(shí) , FMC 和 SRAM 相 關(guān) 的 庫(kù) 函 數(shù) 和 聲 明 定 義 在 源 文 件

stm32f7xx_hal_fmc.c/stm32f7xx_hal_sdram.c 和頭文件 stm32f7xx_hal_fmc.h

/stm32f7xx_hal_sram.h 中。

在 lcd.c 里面要輸入的代碼比較多,我們這里就不貼出來(lái)了,只針對(duì)幾個(gè)重要的函數(shù)進(jìn)行講

解。完整版的代碼見(jiàn)光盤(pán)?4,程序源碼?標(biāo)準(zhǔn)例程-寄存器版本?實(shí)驗(yàn) 13 TFTLCD(MCU 屏)

實(shí)驗(yàn) 的 lcd.c 文件。

本實(shí)驗(yàn),我們用到 FMC 驅(qū)動(dòng) LCD,通過(guò)前面的介紹,我們知道 TFTLCD 的 RS 接在 FMC

的 A18 上面,CS 接在 FMC_NE1 上,并且是 16 位數(shù)據(jù)總線。即我們使用的是 FMC 存儲(chǔ)器 1

的第 1 區(qū),我們定義如下 LCD 操作結(jié)構(gòu)體(在 lcd.h 里面定義):

//LCD 地址結(jié)構(gòu)體

typedef struct

{

vu16 LCD_REG;

vu16 LCD_RAM;

} LCD_TypeDef;

//使用 NOR/SRAM 的 Bank1.sector1,地址位 HADDR[27,26]=00 A18 作為數(shù)據(jù)命令區(qū)分線

//注意設(shè)置時(shí) STM32 內(nèi)部會(huì)右移一位對(duì)其!

#define LCD_BASE ((u32)(0x | 0x0007FFFE))

#define LCD ((LCD_TypeDef *) LCD_BASE)

其中 LCD_BASE,必須根據(jù)我們外部電路的連接來(lái)確定,我們使用 Bank1.sector1 就是從

地址 0X 開(kāi)始,而 0x0007FFFE,則是 A18 的偏移量,這里很多朋友不理解這個(gè)偏移量

的概念,簡(jiǎn)單說(shuō)明下:以 A18 為例,0x0007FFFE 轉(zhuǎn)換成二進(jìn)制就是:0111 1111 1111 1111 1110,

而 16 位數(shù)據(jù)時(shí),地址右移一位對(duì)齊,那么實(shí)際對(duì)應(yīng)到地址引腳的時(shí)候,就是:A18:A0=011 1111

1111 1111 1111,此時(shí) A18 是 0,但是如果 16 位地址再加 1(注意:對(duì)應(yīng)到 8 位地址是加 2,即

0x0007FFFE +0X02),那么:A18:A0=100 0000 0000 0000 0000,時(shí) A18 就是 1 了,即實(shí)現(xiàn)了對(duì)

RS 的 0 和 1 的控制。

我們將這個(gè)地址強(qiáng)制轉(zhuǎn)換為 LCD_TypeDef 結(jié)構(gòu)體地址,那么可以得到 LCD->LCD_REG 的

地址就是 0X6007,FFFE,對(duì)應(yīng) A18 的狀態(tài)為 0(即 RS=0),而 LCD->LCD_RAM 的地址就是

0X6008,0000(結(jié)構(gòu)體地址自增),對(duì)應(yīng) A18 的狀態(tài)為 1(即 RS=1)。

所以,有了這個(gè)定義,當(dāng)我們要往 LCD 寫(xiě)命令/數(shù)據(jù)的時(shí)候,可以這樣寫(xiě):

LCD->LCD_REG=CMD; //寫(xiě)命令

LCD->LCD_RAM=DATA; //寫(xiě)數(shù)據(jù)

而讀的時(shí)候反過(guò)來(lái)操作就可以了,如下所示:

CMD= LCD->LCD_REG; //讀 LCD 寄存器

DATA = LCD->LCD_RAM; //讀 LCD 數(shù)據(jù)

這其中,CS、WR、RD 和 IO 口方向都是由 FMC 硬件自動(dòng)控制,不需要我們手動(dòng)設(shè)置了。

接下來(lái),我們先介紹一下 lcd.h 里面的另一個(gè)重要結(jié)構(gòu)體:

//LCD 重要參數(shù)集

typedef struct

{

u16 width;

//LCD 寬度

u16 height;

//LCD 高度

u16 id;

//LCD ID

u8 dir;

//橫屏還是豎屏控制:0,豎屏;1,橫屏。

u16 wramcmd;

//開(kāi)始寫(xiě) gram 指令

u16 setxcmd;

//設(shè)置 x 坐標(biāo)指令

u16 setycmd;

//設(shè)置 y 坐標(biāo)指令

}_lcd_dev;

//LCD 參數(shù)

extern _lcd_dev lcddev; //管理 LCD 重要參數(shù)

該結(jié)構(gòu)體用于保存一些 LCD 重要參數(shù)信息,比如 LCD 的長(zhǎng)寬、LCD ID(驅(qū)動(dòng) IC 型號(hào))、

LCD 橫豎屏狀態(tài)等,這個(gè)結(jié)構(gòu)體雖然占用了十幾個(gè)字節(jié)的內(nèi)存,但是卻可以讓我們的驅(qū)動(dòng)函數(shù)

支持不同尺寸的 LCD,同時(shí)可以實(shí)現(xiàn) LCD 橫豎屏切換等重要功能,所以還是利大于弊的。有

了以上了解,下面我們開(kāi)始介紹 lcd.c 里面的一些重要函數(shù)。

先看 7 個(gè)簡(jiǎn)單,但是很重要的函數(shù):

//寫(xiě)寄存器函數(shù)

//regval:寄存器值

void LCD_WR_REG(vu16 regval)

{

regval=regval;

//使用-O2 優(yōu)化的時(shí)候,必須插入的延時(shí)

LCD->LCD_REG=regval;//寫(xiě)入要寫(xiě)的寄存器序號(hào)

}

//寫(xiě) LCD 數(shù)據(jù)

//data:要寫(xiě)入的值

void LCD_WR_DATA(vu16 data)

{

data=data;

//使用-O2 優(yōu)化的時(shí)候,必須插入的延時(shí)

LCD->LCD_RAM=data;

}

//讀 LCD 數(shù)據(jù)

//返回值:讀到的值

u16 LCD_RD_DATA(void)

{

vu16 ram;

//防止被優(yōu)化

ram=LCD->LCD_RAM;

return ram;

}

//寫(xiě)寄存器

//LCD_Reg:寄存器地址

//LCD_RegValue:要寫(xiě)入的數(shù)據(jù)

void LCD_WriteReg(u16 LCD_Reg, u16 LCD_RegValue)

{

LCD->LCD_REG = LCD_Reg;

//寫(xiě)入要寫(xiě)的寄存器序號(hào)

LCD->LCD_RAM = LCD_RegValue; //寫(xiě)入數(shù)據(jù)

}

//讀寄存器

//LCD_Reg:寄存器地址

//返回值:讀到的數(shù)據(jù)

u16 LCD_ReadReg(u16 LCD_Reg)

{

LCD_WR_REG(LCD_Reg);

//寫(xiě)入要讀的寄存器序號(hào)

delay_us(5);

return LCD_RD_DATA();

//返回讀到的值

}

//開(kāi)始寫(xiě) GRAM

void LCD_WriteRAM_Prepare(void)

{

LCD->LCD_REG=lcddev.wramcmd;

}

//LCD 寫(xiě) GRAM

//RGB_Code:顏色值

void LCD_WriteRAM(u16 RGB_Code)

{

LCD->LCD_RAM = RGB_Code;//寫(xiě)十六位 GRAM

}

因?yàn)?FMC 自動(dòng)控制了 WR/RD/CS 等這些信號(hào),所以這 7 個(gè)函數(shù)實(shí)現(xiàn)起來(lái)都非常簡(jiǎn)單,我

們就不多說(shuō),注意,上面有幾個(gè)函數(shù),我們添加了一些對(duì) MDK –O2 優(yōu)化的支持,去掉的話,

在-O2 優(yōu)化的時(shí)候會(huì)出問(wèn)題。這些函數(shù)實(shí)現(xiàn)功能見(jiàn)函數(shù)前面的備注,通過(guò)這幾個(gè)簡(jiǎn)單函數(shù)的組

合,我們就可以對(duì) LCD 進(jìn)行各種操作了。

第七個(gè)要介紹的函數(shù)是坐標(biāo)設(shè)置函數(shù),該函數(shù)代碼如下:

//設(shè)置光標(biāo)位置

//Xpos:橫坐標(biāo)

//Ypos:縱坐標(biāo)

void LCD_SetCursor(u16 Xpos, u16 Ypos)

{

if(lcddev.id==0X9341||lcddev.id==0X5310)

{

LCD_WR_REG(lcddev.setxcmd);

LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);

LCD_WR_REG(lcddev.setycmd);

LCD_WR_DATA(Ypos>>8);LCD_WR_DATA(Ypos&0XFF);

}else if(lcddev.id==0X1963)

{

if(lcddev.dir==0)//x 坐標(biāo)需要變換

{

Xpos=lcddev.width-1-Xpos;

LCD_WR_REG(lcddev.setxcmd);

LCD_WR_DATA(0);LCD_WR_DATA(0);

LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);

}else

{

LCD_WR_REG(lcddev.setxcmd);

LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);

LCD_WR_DATA((lcddev.width-1)>>8);

LCD_WR_DATA((lcddev.width-1)&0XFF);

}

LCD_WR_REG(lcddev.setycmd);

LCD_WR_DATA(Ypos>>8);LCD_WR_DATA(Ypos&0XFF);

LCD_WR_DATA((lcddev.height-1)>>8);LCD_WR_DATA((lcddev.height-1)&0XFF);

}else if(lcddev.id==0X5510)

{

LCD_WR_REG(lcddev.setxcmd);LCD_WR_DATA(Xpos>>8);

LCD_WR_REG(lcddev.setxcmd+1);LCD_WR_DATA(Xpos&0XFF);

LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(Ypos>>8);

LCD_WR_REG(lcddev.setycmd+1);LCD_WR_DATA(Ypos&0XFF);

}

}

該函數(shù)實(shí)現(xiàn)將 LCD 的當(dāng)前操作點(diǎn)設(shè)置到指定坐標(biāo)(x,y)。因?yàn)?9341/5310/1963/5510 等的設(shè)

置有些不太一樣,所以進(jìn)行了區(qū)別對(duì)待。

接下來(lái)我們介紹第八個(gè)函數(shù):畫(huà)點(diǎn)函數(shù)。該函數(shù)實(shí)現(xiàn)代碼如下:

//畫(huà)點(diǎn)

//x,y:坐標(biāo)

//POINT_COLOR:此點(diǎn)的顏色

void LCD_DrawPoint(u16 x,u16 y)

{

LCD_SetCursor(x,y);

//設(shè)置光標(biāo)位置

LCD_WriteRAM_Prepare(); //開(kāi)始寫(xiě)入 GRAM

LCD->LCD_RAM=POINT_COLOR;

}

該函數(shù)實(shí)現(xiàn)比較簡(jiǎn)單,就是先設(shè)置坐標(biāo),然后往坐標(biāo)寫(xiě)顏色。其中 POINT_COLOR 是我們

定義的一個(gè)全局變量,用于存放畫(huà)筆顏色,順帶介紹一下另外一個(gè)全局變量:BACK_COLOR,

該變量代表 LCD 的背景色。LCD_DrawPoint 函數(shù)雖然簡(jiǎn)單,但是至關(guān)重要,其他幾乎所有上

層函數(shù),都是通過(guò)調(diào)用這個(gè)函數(shù)實(shí)現(xiàn)的。

有了畫(huà)點(diǎn),當(dāng)然還需要有讀點(diǎn)的函數(shù),第九個(gè)介紹的函數(shù)就是讀點(diǎn)函數(shù),用于讀取 LCD

的 GRAM,這里說(shuō)明一下,為什么 OLED 模塊沒(méi)做讀 GRAM 的函數(shù),而這里做了。因?yàn)?OLED

模塊是單色的,所需要全部 GRAM 也就 1K 個(gè)字節(jié),而 TFTLCD 模塊為彩色的,點(diǎn)數(shù)也比 OLED

模塊多很多,以 16 位色計(jì)算,一款 320×240 的液晶,需要 320×240×2 個(gè)字節(jié)來(lái)存儲(chǔ)顏色值,

也就是也需要 150K 字節(jié),這對(duì)任何一款單片機(jī)來(lái)說(shuō),都不是一個(gè)小數(shù)目了。而且我們?cè)趫D形

疊加的時(shí)候,可以先讀回原來(lái)的值,然后寫(xiě)入新的值,在完成疊加后,我們又恢復(fù)原來(lái)的值。

這樣在做一些簡(jiǎn)單菜單的時(shí)候,是很有用的。這里我們讀取 TFTLCD 模塊數(shù)據(jù)的函數(shù)為

LCD_ReadPoint,該函數(shù)直接返回讀到的 GRAM 值。該函數(shù)使用之前要先設(shè)置讀取的 GRAM

地址,通過(guò) LCD_SetCursor 函數(shù)來(lái)實(shí)現(xiàn)。LCD_ReadPoint 的代碼如下:

//讀取個(gè)某點(diǎn)的顏色值

//x,y:坐標(biāo)

//返回值:此點(diǎn)的顏色

u16 LCD_ReadPoint(u16 x,u16 y)

{

u16 r=0,g=0,b=0;

if(x>=lcddev.width||y>=lcddev.height)return 0; //超過(guò)了范圍,直接返回

LCD_SetCursor(x,y);

if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X1963)

LCD_WR_REG(0X2E);//9341/3510/1963 發(fā)送讀 GRAM 指令

else if(lcddev.id==0X5510)LCD_WR_REG(0X2E00);//5510 發(fā)送讀 GRAM 指令

r=LCD_RD_DATA();

//dummy Read

if(lcddev.id==0X1963)return r;

//1963 直接讀就可以

opt_delay(2);

r=LCD_RD_DATA();

//實(shí)際坐標(biāo)顏色

//9341/NT35310/NT35510 要分 2 次讀出

opt_delay(2);

b=LCD_RD_DATA();

g=r&0XFF; //對(duì)于 9341/5310/5510,第一次讀取的是 RG 的值,R 在前,G 在后,各占 8 位

g<<=8;

return (((r>>11)<<11)|((g>>10)<<5)|(b>>11));

//需要公式轉(zhuǎn)換一下

}

在 LCD_ReadPoint 函數(shù)中,因?yàn)槲覀兊拇a不止支持一種 LCD 驅(qū)動(dòng)器,所以,我們根據(jù)

不同的 LCD 驅(qū)動(dòng)器((lcddev.id)型號(hào),執(zhí)行不同的操作,以實(shí)現(xiàn)對(duì)各個(gè)驅(qū)動(dòng)器兼容,提高函數(shù)

的通用性。

第十個(gè)要介紹的是字符顯示函數(shù) LCD_ShowChar,該函數(shù)同前面 OLED 模塊的字符顯示函

數(shù)差不多,但是這里的字符顯示函數(shù)多了 1 個(gè)功能,就是可以以疊加方式顯示,或者以非疊加

方式顯示。疊加方式顯示多用于在顯示的圖片上再顯示字符。非疊加方式一般用于普通的顯示。

該函數(shù)實(shí)現(xiàn)代碼如下:

//在指定位置顯示一個(gè)字符

//x,y:起始坐標(biāo)

//num:要顯示的字符:" "--->"~"

//size:字體大小 12/16/24/32

//mode:疊加方式(1)還是非疊加方式(0)

void LCD_ShowChar(u16 x,u16 y,u8 num,u8 size,u8 mode)

{

u8 temp,t1,t;

u16 y0=y;

u8 csize=(size/8+((size%8)?1:0))*(size/2);//得到字體一個(gè)字符對(duì)應(yīng)點(diǎn)陣集所占的字節(jié)數(shù)

num=num-' ';//ASCII 字庫(kù)是從空格開(kāi)始取模,所以-' '就是對(duì)應(yīng)字符的字庫(kù)

for(t=0;t<csize;t++)

{

if(size==12)temp=asc2_1206[num][t];

//調(diào)用 1206 字體

else if(size==16)temp=asc2_1608[num][t]; //調(diào)用 1608 字體

else if(size==24)temp=asc2_2412[num][t]; //調(diào)用 2412 字體

else if(size==32)temp=asc2_3216[num][t]; //調(diào)用 3216 字體

else return;

//沒(méi)有的字庫(kù)

for(t1=0;t1<8;t1++)

{

if(temp&0x80)LCD_Fast_DrawPoint(x,y,POINT_COLOR);

else if(mode==0)LCD_Fast_DrawPoint(x,y,BACK_COLOR);

temp<<=1;

y++;

if(y>=lcddev.height)return;

//超區(qū)域了

if((y-y0)==size)

{

y=y0;

x++;

if(x>=lcddev.width)return; //超區(qū)域了

break;

}

}

}

}

在 LCD_ShowChar 函數(shù)里面,我們采用快速畫(huà)點(diǎn)函數(shù) LCD_Fast_DrawPoint 來(lái)畫(huà)點(diǎn)顯示字

符,該函數(shù)同 LCD_DrawPoint 一樣,只是帶了顏色參數(shù),且減少了函數(shù)調(diào)用的時(shí)間,詳見(jiàn)本例

程源碼。該代碼中我們用到了四個(gè)字符集點(diǎn)陣數(shù)據(jù)數(shù)組 asc2_3216、asc2_2412、asc2_1206 和

asc2_1608,這幾個(gè)字符集的點(diǎn)陣數(shù)據(jù)的提取方式,同十六章介紹的提取方法是一模一樣的。詳

細(xì)請(qǐng)參考第十六章。

最后,我們?cè)俳榻B一下 TFTLCD 模塊的初始化函數(shù) LCD_Init,該函數(shù)先配置 FMC 控制器,

然后讀取 LCD 控制器的型號(hào),根據(jù)控制 IC 的型號(hào)執(zhí)行不同的初始化代碼,其簡(jiǎn)化代碼如下:

//初始化 lcd

//該初始化函數(shù)可以初始化各種型號(hào)的 LCD(詳見(jiàn)本.c 文件最前面的描述)

void LCD_Init(void)

{

GPIO_InitTypeDef GPIO_Initure;

FMC_NORSRAM_TimingTypeDef FMC_ReadWriteTim;

FMC_NORSRAM_TimingTypeDef FMC_WriteTim;

__HAL_RCC_GPIOB_CLK_ENABLE();

//開(kāi)啟 GPIOB 時(shí)鐘

GPIO_Initure.Pin=GPIO_PIN_5;

//PB5,背光控制

GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽輸出

GPIO_Initure.Pull=GPIO_PULLUP;

//上拉

GPIO_Initure.Speed=GPIO_SPEED_HIGH;

//高速

HAL_GPIO_Init(GPIOB,&GPIO_Initure);

LCD_MPU_Config(); //使能 MPU 保護(hù) LCD 區(qū)域

SRAM_Handler.Instance= FMC_NORSRAM_DEVICE;

//SRAM BANK1

SRAM_Handler.Extended= FMC_NORSRAM_EXTENDED_DEVICE;

SRAM_Handler.Init.NSBank=FMC_NORSRAM_BANK1;

//使用 NE1

SRAM_Handler.Init.DataAddressMux=FMC_DATA_ADDRESS_MUX_DISABLE;

//地址/數(shù)據(jù)線不復(fù)用

SRAM_Handler.Init.MemoryType=FMC_MEMORY_TYPE_SRAM; //SRAM

SRAM_Handler.Init.MemoryDataWidth=FMC_NORSRAM_MEM_BUS_WIDTH_16;

//16 位數(shù)據(jù)寬度

SRAM_Handler.Init.BurstAccessMode=FMC_BURST_ACCESS_MODE_DISABLE;

//是否使能突發(fā)訪問(wèn),僅對(duì)同步突發(fā)存儲(chǔ)器有效,此處未用到

SRAM_Handler.Init.WaitSignalPolarity=FMC_WAIT_SIGNAL_POLARITY_LOW;

//等待信號(hào)的極性,僅在突發(fā)模式訪問(wèn)下有用

SRAM_Handler.Init.WaitSignalActive=FMC_WAIT_TIMING_BEFORE_WS;

//存儲(chǔ)器是在等待周期之前的一個(gè)時(shí)鐘周期還是等待周期期間使能 NWAIT

SRAM_Handler.Init.WriteOperation=FMC_WRITE_OPERATION_ENABLE;

//存儲(chǔ)器寫(xiě)使能

SRAM_Handler.Init.WaitSignal=FMC_WAIT_SIGNAL_DISABLE;

//等待使能位,此處未用到

SRAM_Handler.Init.ExtendedMode=FMC_EXTENDED_MODE_ENABLE;

//讀寫(xiě)使用不同的時(shí)序

SRAM_Handler.Init.AsynchronousWait=FMC_ASYNCHRONOUS_WAIT_DISABLE;

//是否使能同步傳輸模式下的等待信號(hào),此處未用到

SRAM_Handler.Init.WriteBurst=FMC_WRITE_BURST_DISABLE;

//禁止突發(fā)寫(xiě)

SRAM_Handler.Init.ContinuousClock=FMC_CONTINUOUS_CLOCK_SYNC_ASYNC;

//FMC 讀時(shí)序控制寄存器

FMC_ReadWriteTim.AddressSetupTime=0x011; //地址建立時(shí)間為 17 個(gè) HCLK

FMC_ReadWriteTim.AddressHoldTime=0x00;

FMC_ReadWriteTim.DataSetupTime=0x55; //數(shù)據(jù)保存時(shí)間(DATAST)為 85 個(gè) HCLK

FMC_ReadWriteTim.AccessMode=FMC_ACCESS_MODE_A; //模式 A

//FMC 寫(xiě)時(shí)序控制寄存器

FMC_WriteTim.AddressSetupTime=0x15; //地址建立時(shí)間(ADDSET)為 21 個(gè) HCLK

FMC_WriteTim.AddressHoldTime=0x00;

FMC_WriteTim.DataSetupTime=0x015; //數(shù)據(jù)保存時(shí)間(DATAST)為 21 個(gè) HCLK

FMC_WriteTim.AccessMode=FMC_ACCESS_MODE_A; //模式 A

HAL_SRAM_Init(&SRAM_Handler,&FMC_ReadWriteTim,&FMC_WriteTim);

delay_ms(50); // delay 50 ms

//嘗試 9341 ID 的讀取

LCD_WR_REG(0XD3);

lcddev.id=LCD_RD_DATA(); //dummy read

lcddev.id=LCD_RD_DATA(); //讀到 0X00

lcddev.id=LCD_RD_DATA();

//讀取 93

lcddev.id<<=8;

lcddev.id|=LCD_RD_DATA();

//讀取 41

if(lcddev.id!=0X9341)

//非 9341,嘗試看看是不是 NT35310

{

LCD_WR_REG(0XD4);

lcddev.id=LCD_RD_DATA();//dummy read

lcddev.id=LCD_RD_DATA();//讀回 0X01

lcddev.id=LCD_RD_DATA();//讀回 0X53

lcddev.id<<=8;

lcddev.id|=LCD_RD_DATA();

//這里讀回 0X10

if(lcddev.id!=0X5310)

//也不是 NT35310,嘗試看看是不是 NT35510

{

LCD_WR_REG(0XDA00);

lcddev.id=LCD_RD_DATA();

//讀回 0X00

LCD_WR_REG(0XDB00);

lcddev.id=LCD_RD_DATA();

//讀回 0X80

lcddev.id<<=8;

LCD_WR_REG(0XDC00);

lcddev.id|=LCD_RD_DATA();

//讀回 0X00

if(lcddev.id==0x8000)lcddev.id=0x5510;

//NT35510 讀回的 ID 是 8000H,為方便區(qū)分,我們強(qiáng)制設(shè)置為 5510

if(lcddev.id!=0X5510)

//也不是 NT5510,嘗試看看是不是 SSD1963

{

LCD_WR_REG(0XA1);

lcddev.id=LCD_RD_DATA();

lcddev.id=LCD_RD_DATA();

//讀回 0X57

lcddev.id<<=8;

lcddev.id|=LCD_RD_DATA();

//讀回 0X61

if(lcddev.id==0X5761)lcddev.id=0X1963;

//SSD1963 讀回的 ID 是 5761H,為方便區(qū)分,我們強(qiáng)制設(shè)置為 1963

}

}

}

printf(" LCD ID:%x",lcddev.id); //打印 LCD ID

if(lcddev.id==0X9341)

//9341 初始化

{

……//9341 初始化代碼

}else if(lcddev.id==0xXXXX) //其他 LCD 初始化代碼

{

……//其他 LCD 驅(qū)動(dòng) IC,初始化代碼

}

//初始化完成以后,提速

if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X5510||lcddev.id==0X1963)

{

//重新配置寫(xiě)時(shí)序控制寄存器的時(shí)序

FMC_Bank1E->BWTR[0]&=~(0XF<<0);

//地址建立時(shí)間(ADDSET)清零

FMC_Bank1E->BWTR[0]&=~(0XF<<8);

//數(shù)據(jù)保存時(shí)間清零

FMC_Bank1E->BWTR[0]|=5<<0; //地址建立時(shí)間(ADDSET)為 5 個(gè) HCLK =21ns

FMC_Bank1E->BWTR[0]|=5<<8;//數(shù)據(jù)保存時(shí)間(DATAST) 為 21ns

}

LCD_Display_Dir(0);

//默認(rèn)為豎屏顯示

LCD_LED(1);

//點(diǎn)亮背光

LCD_Clear(WHITE);

}

該函數(shù)先對(duì) FMC 相關(guān) IO 進(jìn)行初始化,然后是 FMC 的初始化,這個(gè)我們?cè)谇懊娑加薪榻B,

最后根據(jù)讀到的 LCD ID,對(duì)不同的驅(qū)動(dòng)器執(zhí)行不同的初始化代碼,從上面的代碼可以看出,

這個(gè)初始化函數(shù)針對(duì)多款不同的驅(qū)動(dòng) IC 執(zhí)行初始化操作,這樣提高了整個(gè)程序的通用性。大家

在以后的學(xué)習(xí)中應(yīng)該多使用這樣的方式,以提高程序的通用性、兼容性。

這里還要提醒大家,在 LCD_Init 函數(shù)中有如下一行代碼:

LCD_MPU_Config(); //使能 MPU 保護(hù) LCD 區(qū)域

這行代碼的作用是調(diào)用函數(shù) LCD_MPU_Config 使能 MPU 保護(hù) LCD 區(qū)域,而函數(shù)

LCD_MPU_Config 定義的內(nèi)容實(shí)際上是我們上一章給大家講解的使能 MPU 保護(hù) LCD 區(qū)域。這

里我們之所以直接在 LCD 程序中加入 MPU 保護(hù),是因?yàn)榉奖愦蠹以谝浦?LCD 相關(guān)代碼到自

己的工程中的時(shí)候不會(huì)因?yàn)闆](méi)有引入 MPU 相關(guān)配置而導(dǎo)致 LCD 無(wú) ** 常工作。

特別注意:本函數(shù)使用了 printf 來(lái)打印 LCD ID,所以,如果你在主函數(shù)里面沒(méi)有初始化串

口,那么將導(dǎo)致程序死在 printf 里面!!如果不想用 printf,那么請(qǐng)注釋掉它。

SRAM 初始化 MSP 回調(diào)函數(shù) HAL_SRAM_MspInit 內(nèi)容比較簡(jiǎn)單,主要是進(jìn)行時(shí)鐘使能以

及 IO 口映射配置,這里就不做過(guò)多講解。

LCD 驅(qū)動(dòng)相關(guān)的函數(shù)就給大家講解到這里。接下來(lái),我們看看主函數(shù)代碼如下:

int  ** in(void)

{

u8 x=0;

u8 lcd_id[12];

Cache_Enable(); //打開(kāi) L1-Cache

HAL_Init();

//初始化 HAL 庫(kù)

Stm32_Clock_Init(432,25,2,9); //設(shè)置時(shí)鐘,216Mhz

delay_init(216); //延時(shí)初始化

uart_init(115200);

//串口初始化

LED_Init(); //初始化 LED

LCD_Init(); //初始化 LCD

POINT_COLOR=RED;

sprintf((char*)lcd_id,"LCD ID:%04X",lcddev.id);//將 LCD ID 打印到 lcd_id 數(shù)組。

while(1)

{

switch(x)

{

case 0:LCD_Clear(WHITE);break;

……//此處省略部分代碼

case 11:LCD_Clear(BROWN);break;

}

POINT_COLOR=RED;

LCD_ShowString(10,40,260,32,32,"Apollo STM32F4/F7");

LCD_ShowString(10,80,240,24,24,"TFTLCD TEST");

LCD_ShowString(10,110,240,16,16,"ATOM@ALIENTEK");

LCD_ShowString(10,130,240,16,16,lcd_id);

//顯示 LCD ID

LCD_ShowString(10,150,240,12,12,"2016/7/11");

x++;

if(x==12)x=0;

LED0_Toggle;

delay_ms(1000);

}

}

該部分代碼將顯示一些固定的字符,字體大小包括 32*16、24*12、16*8 和 12*6 等四種,

同時(shí)顯示 LCD 驅(qū)動(dòng) IC 的型號(hào),然后不停的切換背景顏色,每 1s 切換一次。而 LED0 也會(huì)不停

的閃爍,指示程序已經(jīng)在運(yùn)行了。其中我們用到一個(gè) sprintf 的函數(shù),該函數(shù)用法同 printf,只

是 sprintf 把打印內(nèi)容輸出到指定的內(nèi)存區(qū)間上,sprintf 的詳細(xì)用法,請(qǐng)百度學(xué)習(xí)。

另外特別注意:uart_init 函數(shù),不能去掉,因?yàn)樵?LCD_Init 函數(shù)里面調(diào)用了 printf,所以

一旦你去掉這個(gè)初始化,就會(huì)死機(jī)了!實(shí)際上,只要你的代碼有用到 printf,就必須初始化串口,

否則都會(huì)死機(jī),即停在 usart.c 里面的 fputc 函數(shù),出不來(lái)。

在編譯通過(guò)之后,我們開(kāi)始下載驗(yàn)證代碼。

18.4 下載驗(yàn)證

將程序下載到阿波羅 STM32 后,可以看到 DS0 不停的閃爍,提示程序已經(jīng)在運(yùn)行了。同

時(shí)可以看到 TFTLCD 模塊的顯示如圖 18.4.1 所示:

圖 18.4.1 TFTLCD 顯示效果圖


我們可以看到屏幕的背景是不停切換的,同時(shí) DS0 不停的閃爍,證明我們的代碼被正確的

執(zhí)行了,達(dá)到了我們預(yù)期的目的。

18.5 STM32CubeMX 配置 FMC(SRAM)

當(dāng)大家了解了 FMC 的基本工作原理,那么使用 STM32CubeMX 配置 FMC 相關(guān)參數(shù)就會(huì)非

常簡(jiǎn)單。如果大家對(duì) FMC 沒(méi)有理解,請(qǐng)仔細(xì)看教程學(xué)習(xí)。這里我們們不再詳細(xì)講解每個(gè)配置

項(xiàng)的含義。使用 STM32CubeMX 配置 FMC 的一般步驟為:

① 進(jìn)入 Pinout->FMC 配置欄,配置 FMC 基本參數(shù)。根據(jù)前面的講解,這里我們使用的是

BANK1 的第一個(gè)分區(qū) NE1,同時(shí)吧 LCD 作為 SRAM 使用,19 位地址線,16 位數(shù)據(jù)線。

配置參數(shù)如下圖 18.5.1 所示:

圖 18.5.1 FMC 配置參數(shù)


② 點(diǎn)擊 Configuration->FMC 進(jìn)入 FMC 配置界面,在 NOR/SRAM 1 選項(xiàng)卡之下配置相關(guān)參

數(shù)。這些參數(shù)的含義這里我們不累贅,在 18.1 小節(jié)講解 HAL_SRAM_Init 函數(shù)的時(shí)候都

有講解。配置方法如下圖 18.5.2 所示:

圖 18.5.2 FMC Configuration 配置界面 NOR/PSRAM1 選項(xiàng)卡


在該配置界面,點(diǎn)擊右邊的 GPIO Settigns 選項(xiàng)卡,還可以配置相關(guān) IO 口的信息。

經(jīng)過(guò)上面配置步驟,我們就可以生成相應(yīng)的初始化代碼,大家生成后和本章實(shí)驗(yàn)工

程對(duì)比學(xué)習(xí)。

熱門(mén)推薦:

cache
Processed in 0.012968 Second.