顯示器簡介
顯示器屬於計算機的 I/O 設備,即輸入輸出設備。它是一種將特定電子信息輸出到屏幕上再反射到人眼的顯示工具。常見的有 CRT 顯示器、液晶顯示器、LED 點陣顯示器及OLED 顯示器
本章講解的內容涉及對 FSMC 的控制,若您不了解 FSMC 外設,可以先學習前面的《FSMC—擴展外部 SRAM》章節。
液晶顯示器
液晶顯示器,簡稱 LCD(Liquid Crystal Display),相對於上一代 CRT 顯示器(陰極射線管顯示器),LCD 顯示器具有功耗低、體積小、承載的信息量大及不傷眼的優點,因而它成為了現在的主流電子顯示設備,其中包括電視、電腦顯示器、手機屏幕及各種嵌入式設備的顯示器。圖 27-1 是液晶電視與 CRT 電視的外觀對比,很明顯液晶電視更薄,“時尚”是液晶電視給人的第一印象,而 CRT 電視則感覺很“笨重”。

液晶是一種介於固體和液體之間的特殊物質,它是一種有機化合物,常態下呈液態,但是它的分子排列卻和固體晶體一樣非常規則,因此取名液晶。如果給液晶施加電場,會改變它的分子排列,從而改變光線的傳播方向,配合偏振光片,它就具有控制光線透過率的作用,再配合彩色濾光片,改變加給液晶電壓大小,就能改變某一顏色透光量的多少,圖 27-2 中的就是綠色顯示結構。利用這種原理,做出可控紅、綠、藍光輸出強度的顯示結構,把三種顯示結構組成一個顯示單位,通過控制紅綠藍的強度,可以使該單位混合輸出不同的色彩,這樣的一個顯示單位被稱為像素。
注意液晶本身是不發光的,所以需要有一個背光燈提供光源,光線經過一系列處理過程才到輸出,所以輸出的光線強度是要比光源的強度低很多的,比較浪費能源(當然,比CRT 顯示器還是節能多了)。而且這些處理過程會導致顯示方向比較窄,也就是它的視角小,從側面看屏幕會看不清它的顯示內容。另外,輸出的色彩變換時,液晶分子轉動也需要消耗一定的時間,導致屏幕的響應速度低
LED 和 OLED 顯示器
LED 點陣顯示器不存在以上液晶顯示器的問題,LED 點陣彩色顯示器的單個像素點內包含紅綠藍三色 LED 燈,顯示原理類似我們實驗板上的 LED 彩燈,通過控制紅綠藍顏色的強度進行混色,實現全彩顏色輸出,多個像素點構成一個屏幕。由於每個像素點都是LED 燈自發光的,所以在戶外白天也顯示得非常清晰,但由於 LED 燈體積較大,導致屏幕的像素密度低,所以它一般只適合用於廣場上的巨型顯示器。相對來說,單色的 LED 點陣顯示器應用得更廣泛,如公交車上的信息展示牌、店招等,見圖 27-3。

新一代的 OLED 顯示器與 LED 點陣彩色顯示器的原理類似,但由於它采用的像素單元是“有機發光二極管”(Organic Light Emitting Diode),所以像素密度比普通 LED 點陣顯示器高得多,見圖 27-5。
OLED 顯示器不需要背光源、對比度高、輕薄、視角廣及響應速度快等優點。待到生產工藝更加成熟時,必將取代現在液晶顯示器的地位,見圖 27-5。
顯示器的基本參數
不管是哪一種顯示器,都有一定的參數用於描述它們的特性,各個參數介紹如下:
(1) 像素
像素是組成圖像的最基本單元要素,顯示器的像素指它成像最小的點,即前面講解液晶原理中提到的一個顯示單元。
(1) 分辨率
一些嵌入式設備的顯示器常常以“行像素值 x 列像素值”表示屏幕的分辨率。如分辨率 800x480 表示該顯示器的每一行有 800 個像素點,每一列有 480 個像素點,也可理解為有 800 列,480 行。
(2) 色彩深度
色彩深度指顯示器的每個像素點能表示多少種顏色,一般用“位”(bit)來表示。如單色屏的每個像素點能表示亮或滅兩種狀態(即實際上能顯示 2 種顏色),用 1 個數據位就可以表示像素點的所有狀態,所以它的色彩深度為 1bit,其它常見的顯示屏色深為16bit、24bit。
(3) 顯示器尺寸
顯示器的大小一般以英寸表示,如 5 英寸、21 英寸、24 英寸等,這個長度是指屏幕對角線的長度, 通過顯示器的對角線長度及長寬比可確定顯示器的實際長寬尺寸。
(4) 點距
點距指兩個相鄰像素點之間的距離,它會影響畫質的細膩度及觀看距離,相同尺寸的屏幕,若分辨率越高,則點距越小,畫質越細膩。如現在有些手機的屏幕分辨率比電腦顯示器的還大,這是手機屏幕點距小的原因;LED 點陣顯示屏的點距一般都比較大,所以適合遠距離觀看。
液晶控制原理
圖 27-6 是兩種適合於 STM32 芯片使用的顯示屏,我們以它為例講解控制液晶屏的基本原理
這個完整的顯示屏由液晶顯示面板、電容觸摸面板以及 PCB 底板構成。圖中的觸摸面板帶有觸摸控制芯片,該芯片處理觸摸信號並通過引出的信號線與外部器件通訊,觸摸面板中間是透明的,它貼在液晶面板上面,一起構成屏幕的主體,觸摸面板與液晶面板引出的排線連接到 PCB 底板上,根據實際需要,PCB 底板上可能會帶有“液晶控制器芯片”,圖中右側的液晶屏 PCB 上帶有 RA8875 液晶控制器。因為控制液晶面板需要比較多的資源,所以大部分低級微控制器都不能直接控制液晶面板,需要額外配套一個專用液晶控制器來處理顯示過程,外部微控制器只要把它希望顯示的數據直接交給液晶控制器即可。而不帶液晶控制器的 PCB 底板 ,只有小部分的電源管理電路,液晶面板的信號線與外部微控制器相連,直接控制。STM32F429 系列的芯片不需要額外的液晶控制器,也就是說它把專用液晶控制器的功能集成到 STM32F429 芯片內部了,可以理解為電腦的 CPU 集成顯卡,它節約了額外的控制器成本。而 STM32F1 系列的芯片由於沒有集成液晶控制器到芯片內部,所以它只能驅動自帶控制器的屏幕,可以理解為電腦的外置顯卡。總的來說,這兩類屏幕的控制框圖如圖 27-7 所示。
液晶面板的控制信號
本章我們主要講解如何控制液晶面板,液晶面板的控制信號線即圖 27-6 中液晶面板引出的 FPC 排線,其說明見表 27-1,液晶面板通過這些信號線與液晶控制器通訊,使用這種通訊信號的被稱為 RGB 接口(RGB Interface)。

(1) RGB 信號線
RGB 信號線各有 8 根,分別用於表示液晶屏一個像素點的紅、綠、藍顏色分量。使用紅綠藍顏色分量來表示顏色是一種通用的做法,打開 Windows 系統自帶的畫板調色工具,可看到顏色的紅綠藍分量值,見圖 27-8。常見的顏色表示會在“RGB”后面附帶各個顏色分量值的數據位數,如 RGB565 表示紅綠藍的數據線數分別為 5、6、5 根,一共為 16 個數據位,可表示 2 16 種顏色;而這個液晶屏的種顏色分量的數據線都有 8根,所以它支持 RGB888 格式,一共 24 位數據線,可表示的顏色為 2 24種。
(2) 同步時鍾信號 CLK
液晶屏與外部使用同步通訊方式,以 CLK 信號作為同步時鍾,在同步時鍾的驅動下,每個時鍾傳輸一個像素點數據。
(3) 水平同步信號 HSYNC
水平同步信號 HSYNC(Horizontal Sync)用於表示液晶屏一行像素數據的傳輸結束,每傳輸完成液晶屏的一行像素數據時,HSYNC 會發生電平跳變,如分辨率為 800x480 的顯示屏(800 列,480 行),傳輸一幀的圖像 HSYNC 的電平會跳變 480 次。
(4) 垂直同步信號 VSYNC
垂直同步信號 VSYNC(Vertical Sync)用於表示液晶屏一幀像素數據的傳輸結束,每傳輸完成一幀像素數據時,VSYNC 會發生電平跳變。其中“幀”是圖像的單位,一幅
圖像稱為一幀,在液晶屏中,一幀指一個完整屏液晶像素點。人們常常用“幀/秒”來表示液晶屏的刷新特性,即液晶屏每秒可以顯示多少幀圖像,如液晶屏以 60 幀/秒的速率運行時,VSYNC 每秒鍾電平會跳變 60 次。
(5) 數據使能信號 DE
數據使能信號 DE(Data Enable)用於表示數據的有效性,當 DE 信號線為高電平時,RGB 信號線表示的數據有效。
液晶數據傳輸時序
通過上述信號線向液晶屏傳輸像素數據時,各信號線的時序見圖 27-9。圖中表示的是向液晶屏傳輸一幀圖像數據的時序,中間省略了多行及多個像素點。
液晶屏顯示的圖像可看作一個矩形,結合圖 27-10 來理解。液晶屏有一個顯示指針,它指向將要顯示的像素。顯示指針的掃描方向方向從左到右、從上到下,一個像素點一個像素點地描繪圖形。這些像素點的數據通過 RGB 數據線傳輸至液晶屏,它們在同步時鍾CLK 的驅動下一個一個地傳輸到液晶屏中,交給顯示指針,傳輸完成一行時,水平同步信號 HSYNC 電平跳變一次,而傳輸完一幀時 VSYNC 電平跳變一次。
但是,液晶顯示指針在行與行之間,幀與幀之間切換時需要延時,而且 HSYNC 及VSYNC 信號本身也有寬度,這些時間參數說明見表 27-2。
在這些時間參數控制的區域,數據使能信號線“DE”都為低電平,RGB 數據線的信號無效,當“DE”為高電平時,表示的數據有效,傳輸的數據會直接影響液晶屏的顯示區域。
顯存
液晶屏中的每個像素點都是數據,在實際應用中需要把每個像素點的數據緩存起來,再傳輸給液晶屏,一般會使用 SRAM 或 SDRAM 性質的存儲器,而這些專門用於存儲顯示數據的存儲器,則被稱為顯存。顯存一般至少要能存儲液晶屏的一幀顯示數據,如分辨率為 800x480 的 液 晶 屏 , 使 用 RGB888 格 式 顯 示 , 它 的 一 幀 顯 示 數 據 大 小 為 :3x800x480=1152000 字 節 ; 若 使 用 RGB565 格 式 顯 示 , 一 幀 顯 示 數 據 大 小 為 :2x800x480=768000 字節。一般來說,外置的液晶控制器會自帶顯存,而像 STM32F429 等集成液晶控制器的芯片可使用內部 SRAM 或外擴 SDRAM 用於顯存空間。
電阻觸摸屏實物
上面講解的屏幕其液晶控制器與液晶屏是完全分離的,且具有帶控制器和不帶控制器的版本,易於理解,下面我們再來分析實驗板標配的分辨率為 320*240 的 3.2 寸電阻觸摸液晶屏,見圖 27-11。
圖中的標號3部分是液晶屏幕的整體,通過引出的排針接入到實驗板上可對它進行控制,它分為標號1的液晶觸摸面板和標號2的 PCB 底板兩部分。
標號1處的液晶觸摸面板由液晶屏和觸摸屏組成,屏幕表面的灰色線框即為電阻觸摸屏的信號線,觸摸屏的下方即為液晶面板,在它的內部包含了一個型號為 ILI9341 的液晶控制器芯片(由於集成度高,所以圖中無法看見),該液晶控制器使用 8080 接口與單片機通訊,圖中液晶面板引出的 FPC 信號線即 8080 接口(RGB 接口已在內部直接與 ILI9341 相連),且控制器中包含有顯存,單片機把要顯示的數據通過引出的 8080 接口發送到液晶控制器,這些數據會被存儲到它內部的顯存中,然后液晶控制器不斷把顯存的內容刷新到液晶面板,顯示內容。
標號2處的是 PCB 底板,它主要包含了一個電阻觸摸屏的控制器 XPT2046,電阻觸摸屏控制器實質上是一個 ADC 芯片,通過檢測電壓值來計算觸摸坐標。PCB 底板與液晶觸摸面板通過 FPC 排線座連接,然后引出到排針,方便與實驗板的排母連接。
本章我們就以 3.0 寸的 TFTLCD 模塊為例來介紹(其他尺寸的彩屏和驅動芯片使用方法類似),該模塊驅動芯片型號是 R61509V3,分辨率為 240*400,接口為 16 位的 80 並口,自帶觸摸功能。該模塊的外觀圖如圖 38.1.1 所示:
TFTLCD 模塊采用 2*17 的 2.54 公排針與外部連接,從圖 38.1.2 可以看出,此 TFTLCD 模塊采用 16 位的並口方式與外部連接,之所以不采用 8 位的方式,是因為彩屏的數據量比較大,尤其在顯示圖片的時候,如果用 8 位數據線,就會比 16 位方式慢一倍以上,我們當然希望速度越快越好,所以選擇 16 位的接口,當然不同 TFTLCD 數據位數不一樣,如果彩屏是 8 位的同樣也是接在 16位的對應高 8 位或者低 8 位上,接口使用 16 位是方便兼容其他彩屏。圖 38.1.2還列出了觸摸屏芯片的接口,關於觸摸屏本章我們不多介紹,在后面的章節會有詳細的介紹。該模塊的 80 並口有如下一些信號線:
CS: TFTLCD 片選信號。
WR:向 TFTLCD 寫入數據控制。
RD:從 TFTLCD 讀取數據控制。
RS:命令/數據選擇( 0,讀寫命令; 1,讀寫數據)。
DB[15:0]:16 位雙向數據線。
RST:TFTLCD 復位。
80 並口的通信時序前面已經介紹,這里需要說明的是,TFTLCD 模塊的 RST信號線是直接接到 STM32F1 的復位腳上,並不由軟件控制,這樣可以節省一個IO 口。所以要控制 TFTLCD 模塊顯示,總共需要 20 個 IO 口(除觸摸功能管腳)。
這些信號線即 8080 通訊接口,STM32 通過該接口與 控制芯片進行通訊,實現對液晶屏的控制。通訊的內容主要包括命令和顯存數據,顯存數據即各個像素點的 RGB565 內容;命令是指對控制芯片的控制指令,MCU 可通過 8080 接口發送命令編碼控制 控制芯片 的工作方式,例如復位指令、設置光標指令、睡眠模式指令等等,具體的指令在相應控制芯片數據手冊均有詳細說明。寫命令時序圖見圖 27-14。

知道了模塊的管腳功能及通信時序,接下來我們就來介紹下如何讓液晶模塊顯示。通常按照以下幾步即可實現 TFT 液晶顯示:
(1)設置 STM32F1 與 TFTLCD 模塊相連接的 IO
要讓 TFTLCD 模塊顯示,首先得初始化 TFTLCD 模塊與 STM32F1 相連的 IO口,以便控制 TFTLCD。這里我們用使用的是 STM32F1 的 FSMC,FSMC 將在 38.1.2節向大家詳細介紹。
(2)初始化 TFTLCD 模塊(寫入一系列設置值)
初始化 IO 口,接着就是對 TFTLCD 進行配置,首先就是要復位下 LCD,由於模塊的復位引腳是接在 STM32F1 復位上的,所以直接按下開發板復位鍵即可,然后就是初始化序列,即向 LCD 控制器寫入一系列的設置值(比如 RGB 格式、LCD顯示方向、伽馬校准等),這部分代碼一般 LCD 廠商會提供,我們直接使用這些初始化序列即可,無需深入研究。關於這些設置值可以在你所使用的彩屏模塊驅動芯片數據手冊內查找到,只不過這些數據手冊全是英文的,其實也不是很難,我們用到的只是幾個設置值而已,不認識的可以百度翻譯下。初始化完成之后,LCD 就可以正常使用了。
(3)將要顯示的內容寫到 TFTLCD 模塊內
這一步需要按照:設置坐標→寫 GRAM 指令→寫 GRAM 來實現,但是這個步驟,只是一個點的處理,如果我們想要顯示字符或數字,就必須要多次使用這個步驟,從而達到顯示字符或數字的目的,一般我們會設計一個函數來封裝這些過程(實現字符或數字的顯示),之后只需調用該函數,就可以實現字符或數字的顯示了。
這一部分內容等到我們后面編寫程序的時候大家就可以看到,其實還是比較簡單的。接下來我們就來揭開 STM32F1 的 FSMC 的神秘面紗
使用 STM32 的 FSMC 模擬 8080 接口時序
R61509V3 控制芯片的 8080 通訊接口時序可以由 STM32 使用普通 I/O 接口進行模擬,但這樣效率太低,STM32 提供了一種特別的控制方法——使用 FSMC 接口實現 8080 時序。
FSMC 簡介
STM32F1 系列芯片使用 FSMC 外設來管理擴展的存儲器,FSMC 是 Flexible StaticMemory Controller 的縮寫,譯為靈活的靜態存儲控制器。它可以用於驅動包括 SRAM、NOR FLASH 以及 NAND FLSAH 類型的存儲器,不能驅動如 SDRAM 這種動態的存儲器而在 STM32F429 系列的控制器中,它具有 FMC 外設,支持控制 SDRAM 存儲器。
由於 FSMC 外設可以用於控制擴展的外部存儲器,而 MCU 對液晶屏的操作實際上就是把顯示數據寫入到顯存中,與控制存儲器非常類似,且 8080 接口的通訊時序完全可以使用 FSMC 外設產生,因而非常適合使用 FSMC 控制液晶屏。
FSMC 外設的結構見圖 27-15。
1. 通訊引腳
在框圖的右側是 FSMC 外設相關的控制引腳,由於控制不同類型存儲器的時候會有一些不同的引腳,看起來有非常多,其中地址線 FSMC_A 和數據線 FSMC_D 是所有控制器都共用的。這些 FSMC 引腳具體對應的 GPIO 端口及引腳號可在《STM32F103 規格書》中搜索查找到,不在此列出。
STM32F1 的 FSMC 將外部設備分為 2 類: NOR/PSRAM 設備、NAND/PC 卡設備。他們共用地址數據總線等信號,但具有不同的 CS 以區分不同的設備。本章實驗我們使用的是 FSMC 的 NOR/PSRAM 存儲器控制器部分,即把 TFTLCD當成 SRAM 設備使用。為什么可以把 TFTLCD 當成 SRAM 設備用,這個首先要了解 NOR/PSRAM 存儲器控制器的接口信號,其接口信號功能如下:

從上圖中可以看出外部 SRAM 的控制一般有:地址線(如 A0~A25)、雙向數據線(如 D0~D15)、寫信號( NWE)、讀信號( NOE)、片選信(NE[x]),如果 SRAM 支持字節控制,那么還有 UB/LB 信號。而 TFTLCD 的信號我們在上一節有介紹,包括: RS、DB0-DB15、 WR、 RD、 CS、 RST 等,其中真正在操作 LCD 的時候需要用到的就只有:RS、 DB0-DB15、 WR、 RD、 CS。這樣一來它們的操作接口信號完全類似,唯一不同就是 TFTLCD 有 RS 信號,但是沒有地址信號。
TFTLCD 通過 RS 信號來決定傳送的數據是數據還是命令,本質上可以理解為一個地址信號,比如我們把 RS 接在 A0 上面,那么當 FSMC 控制器寫地址 0的時候,會使得 A0 變為 0,對 TFTLCD 來說,就是寫命令。而 FSMC 寫地址 1的時候, A0 將會變為 1,對 TFTLCD 來說,就是寫數據了。這樣,就把數據和命令區分開了,他們其實就是對應 SRAM 操作的兩個連續地址。當然 RS 也可以接在其他地址線上,我們 STM32F1 開發板是把 RS 連接在 A10 上面的。
知道了可以將 TFTLCD 當做 SRAM 設備用,下面我們就來看下 FSMC 的外部設備地址映射,從 FSMC 的角度,外部存儲器被划分為 4 個固定大小的存儲區域(Bank),每個存儲區域的大小為 256 MB,共 1GB 空間。如圖 38.1.2.2 所示:
本章實驗使用到的是 Bank1,所以我們只講解這塊存儲區域,其他的區域大家可參考《STM32F10x 中文參考手冊》-19 靈活的靜態存儲控制器(FSMC)章節內容。
存儲區域 1 可連接多達 4 個 NOR Flash 或 PSRAM 存儲器器件。此存儲區域被划分為 4 個 NOR/PSRAM 區域,帶 4 個專用片選信號。存儲區域 2 和 3 用於連接NAND Flash 器件(每個存儲區域一個器件)。存儲區域 4 用於連接 PC卡設備。對於每個存儲區域,所要使用的存儲器類型由用戶在配置寄存器中定義。STM32F1 的 FSMC 各 Bank 配置寄存器如圖 38.1.2.3 所示:
STM32F1 的 FSMC 存儲塊 1( Bank1)又被分為 4 個區,每個區管理 64M 字 節空間,每個區都有獨立的寄存器對所連接的存儲器進行配置。 Bank1 的 256M字節空間由 28 根地址線(HADDR[27:0])尋址。這里 HADDR 是內部 AHB 地址 總線,其 中 HADDR[25:0] 來自外部存儲器地 址 FSMC_A[25:0],而 HADDR[26:27]對 4 個區進行尋址。如圖 38.1.2.4 所示:
本章實驗我們使用的是 Bank1 的第 4 區,即起始地址為 0X6C000000。這里要特別注意 HADDR[25:0], HADDR[25:0]包含外部存儲器地址。由於 HADDR 為字節地址,而存儲器不都是按字節尋址,所以根據存儲器數據寬度不同,實際向存儲器發送的地址也將有所不同,如下圖所示:
(1) 對於16位寬度的外部存儲器,FSMC將在內部使用HADDR[25:1]產生外部存儲器的地址FSMC_A[24:0]。不論外部存儲器的寬度是多少(16位或8位),FSMC_A[0]始終應該連到外部存儲器的地址線A[0]。
如果外部存儲器的寬度為 8 位, FSMC 將使用內部的 HADDR[25:0] 地址來作為對外部存儲器的尋址地址 FSMC_A[25:0]。
這里請大家特別留意,如果外部存儲器的寬度為 16 位, FSMC 將使用內部的 HADDR[25:1] 地址來作為對外部存儲器的尋址地址 FSMC_A[24:0],相當於右移了一位,在后面我們設置 A10 地址的時候就要使用到。無論外部存儲器的寬度為 16 位還是 8 位, FSMC_A[0] 都應連接到外部存儲器地址 A[0]。
另外,HADDR[27:26]的設置,是不需要我們干預的,比如:當你選擇使用Bank1 的第三個區,即使用 FSMC_NE3 來連接外部設備的時候,即對應了HADDR[27:26]=10,我們要做的就是配置對應第 3 區的寄存器組,來適應外部設備即可。FSMC 的各 Bank 配置寄存器在上圖 38.1.2.3 以列出。
對於 NOR FLASH 控制器,主要是通過 FSMC_BCRx、 FSMC_BTRx 和FSMC_BWTRx 寄存器設置(其中 x=1~4,對應 4 個區)。通過這 3 個寄存器, 可以設置 FSMC 訪問外部存儲器的時序參數,拓寬了可選用的外部存儲器的速度范圍。
FSMC 的 NOR FLASH 控制器支持同步和異步突發兩種訪問方式。選用同步突發訪問方式時, FSMC 將 HCLK(系統時鍾)分頻后,發送給外部存儲器作為同步時鍾信號 FSMC_CLK。此時需要的設置的時間參數有 2 個:①HCLK 與 FSMC_CLK 的分頻系數(CLKDIV),可以為 2~16 分頻;②同步突發訪問中獲得第 1 個數據所需要的等待延遲(DATLAT)。對於異步突發訪問方式, FSMC 主要設置 3 個時間參數:地址建立時間(ADDSET)、數據建立時間(DATAST)和地址保持時間(ADDHLD)。FSMC 綜合了 SRAM/ROM、 PSRAM 和 NORFlash 產品的信號特點,定義了 4 種不同的異步時序模型。選用不同的時序模型時,需要設置不同的時序參數,如圖 38.1.2.5 所列:

在實際擴展時,根據選用存儲器的特征確定時序模型,從而確定各時間參數與存儲器讀/寫周期參數指標之間的計算關系;利用該計算關系和存儲芯片數據手冊中給定的參數指標,可計算出 FSMC 所需要的各時間參數,從而對時間參數寄存器進行合理的配置。本章實驗我們使用異步模式 A( ModeA)方式來控制 TFTLCD,模式 A 的讀操作時序如圖 38.1.2.6 所示:
模式 A 支持獨立的讀寫時序控制,這個對我們驅動 TFTLCD 來說非常有用,因為 TFTLCD 在讀的時候,一般比較慢,而在寫的時候可以比較快,如果讀寫用一樣的時序,那么只能以讀的時序為基准,從而導致寫的速度變慢,或者在讀數據的時候,重新配置 FSMC 的延時,在讀操作完成的時候,再配置回寫的時序,這樣雖然也不會降低寫的速度,但是頻繁配置,比較麻煩。而如果有獨立的讀寫時序控制,那么我們只要初始化的時候配置好,之后就不用再配置,既可以滿足速度要求,又不需要頻繁改配置。模式 A 的寫操作時序如圖 38.1.2.7 所示:
模式 A 讀寫時序中的 ADDSET 與 DATAST,是通過不同的寄存器設置的。由於篇幅限制,本章並沒有對 FSMC 相關寄存器進行介紹,大家可以參考《STM32F10x中文參考手冊》-19 靈活的靜態存儲控制器(FSMC)章節寄存器內容,里面有詳細的講解。不過,這里還要給大家做下科普,在標准庫的寄存器定義里面,並沒有定義 FSMC_BCRx、 FSMC_BTRx、 FSMC_BWTRx 等這個單獨的寄存器,而是將他們進行了一些組合。
FSMC_BCRx 和 FSMC_BTRx,組合成 BTCR[8]寄存器組,他們的對應關系如下:
BTCR[0]對應 FSMC_BCR1, BTCR[1]對應 FSMC_BTR1
BTCR[2]對應 FSMC_BCR2, BTCR[3]對應 FSMC_BTR2
BTCR[4]對應 FSMC_BCR3, BTCR[5]對應 FSMC_BTR3
BTCR[6]對應 FSMC_BCR4, BTCR[7]對應 FSMC_BTR4
FSMC_BWTRx 則組合成 BWTR[7],他們的對應關系如下:
BWTR[0]對應 FSMC_BWTR1, BWTR[2]對應 FSMC_BWTR2,
BWTR[4]對應 FSMC_BWTR3, BWTR[6]對應 FSMC_BWTR4,
BWTR[1]、 BWTR[3]和 BWTR[5]保留,沒有用到。
FSMC 內部還是比較復雜的,如果看不懂的可以暫時放下,因為我們使用的是庫函數開發,只需簡單配置下即可使用。
FSMC 配置步驟
接下來我們介紹下如何使用庫函數對 FSMC 進行配置。這個也是在編寫程序中必須要了解的。具體步驟如下:(FSMC 相關庫函數在 stm32f10x_fsmc.c 和
stm32f10x_fsmc.h 文件中)
(1)FSMC 初始化
FSMC 的初始化主要是配置 FSMC_BCRx, FSMC_BTRx,FSMC_BWTRx 這三個寄存器,固件庫內提供了 3 個初始化函數對這些寄存器配置。FSMC 初始化庫函數
如下:
FSMC_NORSRAMInit();
FSMC_NANDInit();
FSMC_PCCARDInit();
這三個函數分別用來初始化 4 種類型存儲器。這里根據名字就很好判斷對應關系。用來初始化 NOR 和 SRAM 使用同一個函數 FSMC_NORSRAMInit()。所以我們之后使用的 FSMC 初始化函數為 FSMC_NORSRAMInit()。該初始化函數原型是:
void FSMC_NORSRAMInit(FSMC_NORSRAMInitTypeDef* FSMC_NORSRAMInitStruct);
這 個 函 數 只 有 一 個 參 數 , 是 一 個 結 構 體 指 針 變 量 , 結 構 體 類 型是FSMC_NORSRAMInitTypeDef,其內成員變量非常多,因為 FSMC 相關的配置項非常多。下面我們簡單介紹下它的成員:
typedef struct
{
uint32_t FSMC_Bank;
uint32_t FSMC_DataAddressMux;
uint32_t FSMC_MemoryType;
uint32_t FSMC_MemoryDataWidth;
uint32_t FSMC_BurstAccessMode;
uint32_t FSMC_AsynchronousWait;
uint32_t FSMC_WaitSignalPolarity;
uint32_t FSMC_WrapMode;
uint32_t FSMC_WaitSignalActive;
uint32_t FSMC_WriteOperation;
uint32_t FSMC_WaitSignal;
uint32_t FSMC_ExtendedMode;
uint32_t FSMC_WriteBurst;
FSMC_NORSRAMTimingInitTypeDef* FSMC_ReadWriteTimingStruct;
FSMC_NORSRAMTimingInitTypeDef* FSMC_WriteTimingStruct;
}FSMC_NORSRAMInitTypeDef;
從這個結構體我們可以看出,前面有 13 個基本類型( unit32_t)的成員變量,這 13 個參數是用來配置片選控制寄存器 FSMC_BCRx。最后面還有兩個
FSMC_NORSRAMTimingInitTypeDef 指針類型的成員變量。前面我們講到,FSMC 有讀時序和寫時序之分,所以這里就是用來設置讀時序和寫時序的參數了,也就是說,這兩個參數是用來配置寄存器 FSMC_BTRx 和 FSMC_BWTRx,后面我們會講解到。下面我們就來看看這些成員:
FSMC_Bank:用來設置使用到的存儲塊標號和區號,本章實驗我們是使用的存儲塊 1 區號 4,所以選擇值為 FSMC_Bank1_NORSRAM4。
FSMC_DataAddressMux:用於配置 FSMC 的數據線與地址線是否復用。FSMC支持數據與地址線復用或非復用兩種模式。在非復用模式下 16 位數據線及 26位地址線分開始用;復用模式則低 16 位數據/地址線復用,僅對 NOR 和 PSRAM有效。在復用模式下,推薦使用地址鎖存器以區分數據與地址。本實驗使用 FSMC模擬8080 時序,僅使用一根地址線 A10 提供 8080 的 RS 信號,所以不需要復用,即設置為 FSMC_DataAddressMux_Disable。
FSMC_MemoryType:用來設置 FSMC 外接的存儲器類型,可選類型為 NOR FLASH模式、PSARM 模式及 SRAM 模式。我們這里把 TFTLCD 當做 SRAM 使用,所以選擇值為 FSMC_MemoryType_SRAM。
FSMC_MemoryDataWidth:用來設置 FSMC 接口的數據寬度,可選擇 8 位還是16 位,這里我們是 16 位數據寬度,所以選擇值為 FSMC_MemoryDataWidth_16b。
FSMC_WriteOperation:用於配置寫操作使能,如果禁止了寫操作,FSMC 不會產生寫時序,但仍可從存儲器中讀出數據。本實驗需要向 TFTLCD 內寫數據,所以要寫使能,配置為 FSMC_WriteOperation_Enable(寫使能)。
FSMC_ExtendedMode:用於配置是否使用擴展模式,在擴展模式下,讀時序和寫時序可以使用獨立時序模式。如讀時序使用模式 A,寫時序使用模式 B,這些 A、B、C、D 模式實際上差別不大,主要是在使用數據/地址線復用的情況下,FSMC 信號產生的時序不一樣。
FSMC_BurstAccessMode:用於配置訪問模式。FSMC 對存儲器的訪問分為異步模式和突發模式(同步模式)。在異步模式下,每次傳送數據都需要產生一個確定的地址,而突發模式可以在開始時提供一個地址之后,把數據成組地連續寫入。本實驗使用異步模式 FSMC_BurstAccessMode_Disable。
FSMC_WaitSignalPolarity(配置等待信號極性)、FSMC_WrapMode(配置是否使用非對齊方式)、FSMC_WaitSignalActive(配置等待信號什么時期產生)、
FSMC_WaitSignal(配置是否使用等待信號)、FSMC_WriteBurst(配置是否允許突發寫操作),這些成員均需要在突發模式開啟后配置才有效。本實驗使用的是異步模式,所以這些成員的參數沒有意義。
FSMC_ReadWriteTimingStruct 和 FSMC_WriteTimingStruct:用於設置讀寫時序。這兩個變量都是 FSMC_NORSRAMTimingInitTypeDef 結構體指針類型。這兩個參數在初始化的時候分別用來初始化片選控制寄存器 FSMC_BTRx 和寫操作時序控制寄存器 FSMC_BWTRx。FSMC_NORSRAMTimingInitTypeDef 結構體如下:
typedef struct
{
uint32_t FSMC_AddressSetupTime;//地址建立時間
uint32_t FSMC_AddressHoldTime;//地址保持時間
uint32_t FSMC_DataSetupTime;//數據建立時間
uint32_t FSMC_BusTurnAroundDuration;//總線恢復時間
uint32_t FSMC_CLKDivision;//時鍾分頻
uint32_t FSMC_DataLatency;//數據保持時間
uint32_t FSMC_AccessMode;//訪問模式
}FSMC_NORSRAMTimingInitTypeDef;
這些成員主要用於設計地址建立保持時間,數據建立時間等配置,這些時間是由 HCLK 經過成員時鍾分頻得來的,該分頻值在成員 FSMC_CLKDivision(時鍾分頻)中設置,其中 FSMC_AccessMode(訪問模式)成員的設置只在開啟了擴展模式才有效,而且開啟了擴展模式后,讀時序和寫時序的設置可以是獨立的。本實驗 中 我 們 需 要 讀 寫 速 度 不 一 樣 , 所 以 開 啟 了 擴 展 模 式 並 且 對 於 參 數FSMC_DataSetupTime 設置了不同的值。此結構體其實就是對 FSMC_BTRx 和FSMC_BWTRx 寄存器操作,大家可以查看中文參考手冊寄存器說明。
本實驗中的時序設置是根據 R61509V3 的數據手冊設置的,調試的時候可以先把這些值設置得大一些,然后慢慢靠近數據手冊要求的最小值,這樣會取得比較好的效果。時序的參數設置對 LCD 的顯示效果有一定的影響。
了解結構體成員功能后,就可以進行配置,本章實驗配置代碼如下:
FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;
FSMC_NORSRAMTimingInitTypeDef FSMC_ReadNORSRAMTiming;
FSMC_NORSRAMTimingInitTypeDef FSMC_WriteNORSRAMTiming;
FSMC_ReadTimingInitStructure.FSMC_AddressSetupTime = 0x01;// 地址建立時間(ADDSET)為 2 個 HCLK 1/36M=27ns
FSMC_ReadTimingInitStructure.FSMC_AddressHoldTime = 0x00;// 地址保持時間(ADDHLD)模式 A 未用到
FSMC_ReadTimingInitStructure.FSMC_DataSetupTime = 0x0f;// 數據保存時間為 16 個 HCLK,因為液晶驅動 IC 的讀數據的時候,速度不能太快,尤其對 1289 這個 IC。
FSMC_ReadTimingInitStructure.FSMC_BusTurnAroundDuration = 0x00;
FSMC_ReadNORSRAMTiming.FSMC_CLKDivision = 0x00;
FSMC_ReadNORSRAMTiming.FSMC_DataLatency = 0x00;
FSMC_ReadNORSRAMTiming.FSMC_AccessMode = FSMC_AccessMode_A;//模式 A
FSMC_WriteNORSRAMTiming.FSMC_AddressSetupTime =0x00;//地址建立時間(ADDSET)為 1 個 HCLK
FSMC_WriteNORSRAMTiming.FSMC_AddressHoldTime = 0x00;//地址保持時間(A
FSMC_WriteNORSRAMTiming.FSMC_DataSetupTime = 0X03;//數據保存時間為 4 個 HCLK
FSMC_WriteNORSRAMTiming.FSMC_BusTurnAroundDuration = 0x00;
FSMC_WriteNORSRAMTiming.FSMC_CLKDivision = 0x00;
FSMC_WriteNORSRAMTiming.FSMC_DataLatency = 0x00;
FSMC_WriteNORSRAMTiming.FSMC_AccessMode = FSMC_AccessMode_A;//模式 A
FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM4;// 這里我們使用 NE4 ,也就對應 BTCR[6],[7]。
FSMC_NORSRAMInitStructure.FSMC_DataAddressMux=FSMC_DataAddressMux_Disable; // 不復用數據地址
FSMC_NORSRAMInitStructure.FSMC_MemoryType=FSMC_MemoryType_SRAM;// FSMC_MemoryType_SRAM; //SRAM
FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth=FSMC_MemoryDataWidth_16b;//存儲器數據寬度為 16bit
FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode=FSMC_BurstAccessMode_Disable;// FSMC_BurstAccessMode_Disable;
FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity=FSMC_WaitSignalPolarity_Low;
FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait=FSMC_AsynchronousWait_Disable;
FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive=FSMC_WaitSignalActive_BeforeWaitState;
FSMC_NORSRAMInitStructure.FSMC_WriteOperation=FSMC_WriteOperation_Enable; // 存儲器寫使能
FSMC_NORSRAMInitStructure.FSMC_WaitSignal=FSMC_WaitSignal_Disable;
FSMC_NORSRAMInitStructure.FSMC_ExtendedMode=FSMC_ExtendedMode_Enable; // 讀寫使用不同的時序
FSMC_NORSRAMInitStructure.FSMC_WriteBurst=FSMC_WriteBurst_Disable;
FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct=&FSMC_ReadNORSRAMTiming; //讀寫時序
FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct=&FSMC_WriteNORSRAMTiming; //寫時序
FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); //初始化 FSMC 配置
(2)使能(開啟)FSMC
固件庫提供了不同的庫函數來初始化各種存儲器,同樣也提供了不同類型的存儲器使能函數,如下:
void FSMC_NORSRAMCmd(uint32_t FSMC_Bank, FunctionalState NewState);
void FSMC_NANDCmd(uint32_t FSMC_Bank, FunctionalState NewState);
void FSMC_PCCARDCmd(FunctionalState NewState);
這 3 個函數支持不同種類的存儲器,從函數名來看也非常好理解。我們把TFTLCD 當作 SRAM 使用,即使用第一個函數。該函數第一個參數用來選擇存儲器的區域,第二個參數用來使能或者失能。將以上幾步全部配置好后,我們就可以使用 STM32F1 的 FSMC 了。