基于正点原子的FTFLCD原理阐述

基于正点原子的FTFLCD原理阐述

STM32操作FTFLCD模块的流程图

任何 LCD,使用流程都可以简单的用以上流程图表示。其中硬复位和初始化序列,只需要 执行一次即可。而画点流程就是:设置坐标→写 GRAM 指令→写入颜色数据,然后在 LCD 上 面,我们就可以看到对应的点显示我们写入的颜色了。读点流程为:设置坐标→读 GRAM 指令 →读取颜色数据,这样就可以获取到对应点的颜色数据了。

TFTFLCD的数据端口简介

ILI9341 液晶控制器自带显存,其显存总大小为 172800(240*320*18/8),即 18 位模式(26 万色)下的显存量。在 16 位模式下,ILI9341 采用 RGB565 格式存储颜色数据,此时 ILI9341 的 18 位数据线与 MCU 的 16 位数据线以及 LCD GRAM 的对应关系如图 18.1.1.4 所示:

从图中可以看出,ILI9341在16位模式下面,数据线有用的是:D17~D13 和 D11~D1,D0 和D12没有用到,实际上在我们LCD模块里面,ILI9341的D0和D12压根就没有引出来,这样,ILI9341的D17~D13 和D11~D1对应MCU的D15~D0。

FSMC是什么?FSMC与IO口操作的区别?

最早CPU要访问外部RAM需要三条总线:地址总线、数据总线(以16条地址线8位存储器为例)和控制总线:

地址总线:A0到A15共计16根地址线

数据总线:D0到D7共计8根数据线

控制总线:至少包括读写控制等控制线

CPU要访问外部RAM,就得靠这些线来进行控制,

首先在这16根地址线上呈现地址值,指示要访问的目标地址,使得外部RAM可以定位到存储单元;

接着,要让控制总线上呈现是读还是要写,好让外部RAM做好准备;

最后,如果是读,则外部RAM就把指定地址存储器的值8位呈现在D0到D7上,由CPU取走。

如果是写,则CPU自己把8位值输出呈现在D0到D7上,由外部RAM接收后改写存储器的值。

这整个过程都是由硬件来实现的,完全没有任何一句用户代码来参与的,是CPU设计之初就定义实现好的,这个过程的时间关系就叫做时序。一定要记住一点,总线是硬件实现的,有严格的规定好的时序。

可以看到,这种对引脚要求是比较多的,16条地址线加8条数据线再加控制线必须有25根线以上,所以8051为了省线,将8条数据线和地址线的低8位进行了时分复用(称为AD0到AD7),这样就可以省掉8根线,但代价是必须由外部增加锁存器来锁存地址的低8位(现在的外部RAM可以理解为将锁存器做到了芯片中)。但过程仍是上述描述的内容。即使这样,仍需要引脚近20根,如果存储量大,地址线更多,这些线就是STM32的FSMC,FSMC即灵活的静态存储器控制器,就是用来驱动外部总线,做上面所描述的工作的。为什么说是灵活的,我想主要是因为它可以通过事先对一些时间等参数进行设置调整,可以适应不同厂家参数有差异的SRAM或者像LCD、OLED等类似外设。但这些参数设定一次之后,整个控制时序关系就固定了,总线在具体工作的时候就不再需要用户来操心了,这就是硬件实现的优点,速度快且不占用CPU的计算资源。

至于IO,我想就不用解释了,就是CPU的输入输出端口,可以由CPU控制读写的一个个外部引脚,既然可以控制,就有人仿造总线的时序,用多个IO来通过软件控制的方式来模拟外部总线,比如8051没有SPI接口,就可以用至少三个IO口来分别模拟SCLK时钟,MOSI和MISO数据线。事实上,你也可以用二十几个IO来模拟上面所说的三条总线,但每一次的读写你都得按照时间顺序来控制这二十几个IO端口,你可以把它编好后写成函数,但仍然是占用CPU大量资源的,这就是软件实现的弊端,速度慢且占用CPU的计算资源。

STM32向外提供了灵活的总线访问接口即FSMC,无须你用IO来模拟,就如同8051的地址数据总线一样以硬件的方式来自动工作。不仅如此,如果你的系统用不到FSMC接口,STM32还可以把预备FSMC使用的端口让出来,使它可以当成普通IO一样来使用,从而节省宝贵的外部引脚空间。

为何FTFLCD可以被当作SRAM被FSMC控制?

首先我们了解下外部SRAM的连接,外部SRAM的控制一般有:地址线(如 A0~A18)、数据线(如 D0~D15)、写信号(WE)、 读信号(OE)、片选信号(CS),如果 SRAM 支持字节控制,那么还有 UB/LB 信号。而TFTLCD的信号包括:RS、D0~D15、WR、RD、CS、RST和BL等,其中真正在操作LCD的时候需要用到的就只有:RS、D0~D15、WR、RD 和 CS。其操作时序和SRAM的控制完全类似,唯一不同就是TFTLCD有RS信号,但是没有地址信号。

TFTLCD 通过RS信号来决定传送的数据是数据还是命令,本质上可以理解为一个地址信号,比如我们把RS接在A0上面,那么当FSMC控制器写地址0的时候,会使得A0变为0,对TFTLCD来说,就是写命令。而FSMC写地址1的时候,A0 将会变为1,对TFTLCD来说,就是写数据了。这样,就把数据和命令区分开了,他们其实就是对应SRAM 操作的两个连续地址。当然RS也可以接在其他地址线上,我们这里将RS接在了战舰STM32开发板的A10上面。

FSMC如何操作SRAM?

选择存储块

我要将FTFLCD的GRAM作为SRAM来使用,因此我选择将设备与Bank1相连接。

SRAM寻址操作

STM32的FSMC存储块1(Bank1)被分为4个区,每个区管理64M字节空间,每个区都 有独立的寄存器对所连接的存储器进行配置。Bank1的256M字节空间由28根地址线 (HADDR[27:0])寻址。

这里HADDR 是内部AHB地址总线,其中HADDR[25:0]来自外部存储器地址FSMC_A[25:0],而HADDR[26:27]对4个区进行寻址。

我们要特别注意 HADDR[25:0]的对应关系:

当Bank1接的是16位宽度存储器的时候:HADDR[25:1]→ FSMC_A[24:0];

当Bank1接的是8位宽度存储器的时候:HADDR[25:0]→ FSMC_A[25:0]。

FSMC为何需要26根地址线?

 

首先,我们要明白我们是在字节寻址并不是位寻址,字节寻址与位寻址的区别如下:

地址对应的元素大小不同,就比如一个数组中装的元素不同,字节寻址是“地址对应的元素是字节”,位寻址是“地址对应的元素是位”。

其次,我们要知道26根地址线访问的最大元素个数为(0——2^27-1=0——134,217,727)共134,217,728个字节元素,而块1到块4中1GB的内存对应的“字节byte(不是位bit)”个数为134,217,728,因此26根地址线可以访问FSMC的外部存储的所有字节元素。

HADDR与FSMC的对应关系

对于16位的数据线来说,一个地址对应了两个字节,因此此时26根地址线可以访问的字节元素个数变为了原来的1/2,但是一个数据的宽度变为了原来的2倍。因此才出现了当数据传输线的宽度为16位时,我们要将HADDR右移一位以对应FSMC_A[24:0]。以此类推,可以得出32位数据线的HADDR与FSMC_A的对应关系。

FSMC中寄存器的功能

FSMC的读写时序逻辑图

从模式A的读写时序图,我们可以看出,读操作还存在额外的 2 个HCLK周期,用于数据 存储,所以同样的配置读操作一般比写操作会慢一点。

时序参数介绍

对于异步突发访问方式,FSMC主要设置3个时间参数:地址建立时间(ADDSET)、数据建立时间(DATAST)和地址保持时间(ADDHLD)。FSMC综合了SRAM/ROM、PSRAM和NOR Flash产品的信号特点,定义了4种不同的异步时序模型。选用不同的时序模型时,需要设置不 同的时序参数:

寄存器的配置

控制寄存器

EXTMOD

扩展模式使能位,也就是是否允许读写不同的时序,很明显,我们本章需要读写不同的时序,故该位需要设置为 1。只有此位被设置才可以配置“写操作时序寄存器”

WREN

写使能位。我们需要向 TFTLCD 写数据,故该位必须设置为 1

MWID[1:0]

存储器数据总线宽度。00,表示 8 位数据模式;01 表示 16 位数据模式;10 和 11 保留。我们的 TFTLCD 是 16 位数据线,所以设置 WMID[1:0]=01

MTYP[1:0]

存储器类型。00 表示 SRAM、ROM;01 表示 PSRAM;10 表示 NOR FLASH;11 保留。前面提到,我们把 TFTLCD 当成 SRAM 用,所以需要设置 MTYP[1:0]=00

MBKEN

存储块使能位。这个容易理解,我们需要用到该存储块控制 TFTLCD,当然要 使能这个存储块了

时序寄存器 

这个寄存器包含了每个存储器块的控制信息,可以用于 SRAM、ROM 和 NOR 闪存存储器。 如果 FSMC_BCRx 寄存器中设置了 EXTMOD 位,则有两个时序寄存器分别对应读操作(本寄存器) 和写操作(FSMC_BWTRx 寄存器)。因为我们要求读写分开时序控制,所以 EXTMOD 是使能了的,也就是本寄存器是读操作时序寄存器,控制读操作的相关时序。本章我们要用到的设置有: ACCMOD、DATAST 和 ADDSET 这三个设置。

ACCMOD[1:0]

访问模式。00表示访问模式 A;01表示访问模式B;10表示访问模式 C; 11表示访问模式D,本章我们用到模式A,故设置为00

DATAST[7:0]

数据保持时间。0 为保留设置,其他设置则代表保持时间为: DATAST 个 HCLK 时钟周期,最大为 255 个 HCLK 周期。对 ILI9341 来说,其实就是 RD 低电平持续时间,一般为355ns,而一个HCLK时钟周期为13.8ns 左右(72Mhz),为了兼容其他屏,我们这里设置DATAST为15,也就是16个HCLK 周期,时间大约是 234ns(未计算数据存储的2个HCLK 时间,对9341来说超频了,但是实际上是可以正常使用的)

ADDSET[3:0]

地址建立时间。其建立时间为:ADDSET 个 HCLK 周期,最大为 15 个 HCLK 周期。对 ILI9341 来说,这里相当于 RD 高电平持续时间,为 90ns,本来这里我们应该设置和 DATAST 一样,但是由于 STM32F103 FSMC 的性能问题,就算设置 ADDSET为0,RD的高电平持续时间也达到了190ns以上,所有,我们这里可以设置ADDSET为较小的值,本章我们设置ADDSET为1,即2个HCLK 周期,实际RD高电平大于200ns

写操作时序寄存器

该寄存器在本章用作写操作时序控制寄存器,需要用到的设置同样是:ACCMOD、DATAST 和 ADDSET 这三个设置。这三个设置的方法同 FSMC_BTRx 一模一样,只是这里对应的是写 操作的时序,ACCMOD 设置同FSMC_BTRx一模一样,同样是选择模式A,另外 DATAST 和ADDSET则对应低电平和高电平持续时间,对 ILI9341 来说,这两个时间只需要 15ns 就够了,比读操作快得多。所以我们这里设置DATAST为3,即 4 个 HCLK 周期,时间约为 55ns(因为9320等控制器,这个时间要求比较长,要 50ns)。然后ADDSET(也存在性能问题)设置为 0, 即1个HCLK周期,实际WR高电平时间大于100ns。

库函数的配置

FSMC_BCRx和FSMC_BTRx,组合成BTCR[8]寄存器组,他们的对应关系如下:

注意:FSMC_BTRx与FSMC_BCRx的长度为32bits。

为何选择模式A?

模式A支持独立的读写时序控制,这个对我们驱动 TFTLCD 来说非常有用,因为TFTLCD 在读的时候,一般比较慢,而在写的时候可以比较快,如果读写用一样的时序,那么只能以读的时序为基准,从而导致写的速度变慢,或者在读数据的时候,重新配置FSMC的延时,在读 操作完成的时候,再配置回写的时序,这样虽然也不会降低写的速度,但是频繁配置,比较麻烦。而如果有独立的读写时序控制,那么我们只要初始化的时候配置好,之后就不用再配置,既可以满足速度要求,又不需要频繁改配置。

为何需要设置时序?

支持同时扩展多种存储器。FSMC的映射地址空间中,不同的BANK是独立的,可用于扩展不同类型的存储器。当系统中扩展和使用多个外部存储器时,FSMC会通过总线悬空延迟时间参数的设置,防止各存储器对总线的访问冲突。

FTFLCD对应的库函数简介

u16 LCD_BGR2RGB(u16 c)

颜色格式转换函数(当我们用读点函数读取出的点的颜色为BGR格式,但是我们写入某一点的颜色时使用的是RGB格式)

u16 LCD_ReadPoint(u16 x,u16 y)

读点函数(返回该点的颜色)

void LCD_DisplayOn(void)

LCD开显示

void LCD_DisplayOff(void)

LCD关显示

void LCD_SetCursor(u16 Xpos, u16 Ypos)

设置LCD的光标位置

void LCD_Scan_Dir(u8 dir)

扫描方向设置函数

void LCD_DrawPoint(u16 x,u16 y)

将POINT_COLOR(代表颜色)写入对应的(x,y)坐标的位置

void LCD_Fast_DrawPoint(u16 x,u16 y,u16 color)

将(x,y)点的颜色修改成color颜色(与上面功能相同)

void LCD_SSD_BackLightSet(u8 pwm)

调节屏幕亮度的函数

void LCD_Display_Dir(u8 dir)

屏幕是竖向显示还是横向显示

void LCD_Set_Window(u16 sx,u16 sy,u16 width,u16 height)

在屏幕上开个显示窗(屏幕开窗函数)

void LCD_Init(void)

TFTLCD初始化函数(调用之前必须先初始化串口x)

void LCD_Clear(u16 color)

清屏并且进行颜色填充

void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color)

矩形区域填充函数(使用POINT_COLOR规定的的颜色)

void LCD_Color_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color)

LCD矩形填充函数(使用color规定的颜色)

void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2)

LCD划线函数

void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2)

矩形区域填充函数

void LCD_Draw_Circle(u16 x0,u16 y0,u8 r)

画圆函数

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

字符显示函数

void LCD_ShowNum(u16 x,u16 y,u32 num,u8 len,u8 size)

数值显示函数

void LCD_ShowxNum(u16 x,u16 y,u32 num,u8 len,u8 size,u8 mode)

带有显示模式设置的数值显示函数

void LCD_ShowString(u16 x,u16 y,u16 width,u16 height,u8 size,u8 *p)

字符串显示函数

 

猜你喜欢

转载自blog.csdn.net/weixin_45590473/article/details/108597921