显示器简介
显示器属于计算机的 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 了。