Stm32FSMC及TFTLED屏笔记(开始于2021-07-23)

Stm32FSMC及TFTLED屏笔记

截图的图片出自正点原子的参考手册和网络资料,如有侵权,请联系我删除(因为没怎么写过博客,有注明出处,但对版权的具体细节不清楚)

1.FSMC*(Flexiable Static Memory Controler)*

1)FSMC的应用:

在这里插入图片描述

  • 以上是STM32官方手册的内容,可以认为,FSMC,是芯片内部专门可以用于读取外部接入的(SRAM,PC卡等)需要并口协议读写的存储器的一个控制器,起到一个连接器(或者是桥)的作用。

    只要我们按芯片要求将外部SRAM等于GPIO连接好,并配置好FSMC的相关配置,就可以给这些SRAM配置一个向内部寄存器那样的地址,就可以直接向SRAM的具体地址写入数据(软件上和寄存器操作一样,直接给对应地址赋值,但实际是通过并口数据线将数据写入)这样就可以是我们对外部SRAM的使用效率提升,而不用再使用GPIO去模拟对应的时序*(可以直接向内部寄存器一样赋值)*。

在这里插入图片描述

  • 从上面的框图也可以看出,因为并口信号线FSMC[15:0]是公用的,所以一次只能同时外接一个SRAM类的存储器。

在这里插入图片描述

  • 如上图,实际上,是内部连接的AHB将FSMC可控制的寄存器区域划分为以下这四个,其中NOR/PSRAM内再划分为Block1-4四块。FSMC在这片区域寻址(这片区域的地址在配置完成后,将会称为外设的地址 即把外设地址命名为这些地址)时,使用HADDR地址线(共有28位[27:0]),HADDR[27:26]两位决定NOR/PSRAM内部的的Block1-4(00-1;01-2;10-3;11-4)。

2)NOR/SRAM:

(1)映象部分:

在这里插入图片描述

  • 值得注意的是在外部SRAM连接的FSMC_A在存储器位数不同时,地址线的对齐方式不同。

    因为在内部AHB的地址里(即HADDR[25:0])是以字节为单位的,即一个地址可以写8位数据;

    当外部是以半字(16位)为单位时,这时候每当在外部地址写完一次(16位数据)的过程中,内部AHB对应的地址应该是移动两位的(2*8位);所以为了使用方便,这儿有一个很巧妙(也很常用)的方法就是将HADDR[25:0]左移一位与FSMC_A对齐;

    • 举例如下:当在外设FSMC_A的第……0001*(地址为bit0 = 1处的地址,前面的0省略)写数据时,HADDR中对应是第……001 _(地址为bit1 = 1处的地址,下划线表示:因左移一位对齐而失效的HADDR [0] )*; 这样在外设写……0001;这移位时,内部HADDR 实际上走了……0010,和0011两个8位数据

    • 所以这样的对齐方式,使FSMC_A的一位会对应HADDR的两位:

      FSMC_A(16位单位外设地址)HADDR(实际内部的8位单位地址)
      00000 0 和 00 1(下划线表示因左移而失效的HADDR[0])
      00101 0 和 01 1
      01010 0 和 10 1
  • 可以看出刚好是左移一位对齐,而且000 位仍有对应 000位地址,即起始地址仍一样。

(2)信号线及8080并口协议:

在这里插入图片描述

  • 以下将SRAM常用的8080并口协议的连接线与FSMC的输出信号做些整理

    参考博文,如侵权请联系

    SRAM*(以IS62WV51216为例)*FSMC说明
    CSNE[x]片选,低电平表示选中。
    OENOE输出使能,即(对主机MCU来说)读使能
    WENWE写使能
    UB/LBNBL[1]/NBL[0]高位/地位数据掩码(是否允许访问高8位/低8位数据,低电平允许)
    A0-A18A[25:0]地址总线
    I/O0-7;I/O8-15D[15:0]双向数据线(可选8位或16位)
  • 8080并口协议时序:(这里只做简单介绍)

    在CS选中后,地址线发送对应地址信息表示该地址;(结束时拉高CS)

    • 读时;NWE拉高,禁止写;后拉低NOE写使能,SRAM数据放于数据口上,NOE拉高,上升沿数据读出;

    • 写时;NOE拉高,禁止读;后拉低NWE写使能,主机MCU数据放于数据口上,NWE拉高,上升沿数据写入;

    • 当只需要高8位/低8位用于数据传输时,可使用地址掩码,NBL[1:0]进行控制,低电平表示允许访问。

  • 而在FMSC内当我们按照要求连接好硬件电路后,可以直接向写读内部寄存器一样,直接写 ”xxxx*(地址)* = 0xyyyyy (数据) “ 即可。FSMC会自动帮我们完成上述对各种信号线的操作;

(3)硬件连接:

(FSMC只有大容量,多引脚封装的stm32有,我用的是STM32ZET6)具体的引脚连接可参照下图、下表,或者上面的参考博客

在这里插入图片描述

在这里插入图片描述

(4)寄存器:

主要有FSMC_BCRx*(片选控制寄存器),FSMC_BTRx(读时序控制寄存器),FSMC——BWTRx(写时序控制寄存器)*

按如下组合进行访问:

在这里插入图片描述

(5)库函数使用:(见如下代码及注释,参考正点原子)
void FSMC_NORSRAMInit(FSMC_NORSRAMInitTypeDef* FSMC_NORSRAMInitStruct)//需要填入一个结构体的NORSRAM初始化;
typedef struct
{
 uint32_t FSMC_Bank; //来设置使用到的存储块标号和区号,
 //如NOR/PSRAM是块1;我们用其中(有4块)的块4 FSMC_Bank1_NORSRAM4。
 uint32_t FSMC_DataAddressMux;
 // 地址/数据复用使能,若设置为使能,那么地址的低 16位和数据将共用数据总线,
 uint32_t FSMC_MemoryType; // 来设置存储器类型,如SRAM FSMC_MemoryType_SRAM。
 uint32_t FSMC_MemoryDataWidth;//用来设置数据宽度,如16位FSMC_MemoryDataWidth_16b
 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;

关于读写时序的结构体参数如下*(即上面结构体的最后两个成员变量)*:

typedef struct
{
//主要是设置地址及数据的建立时间,根据所接外设SRAM的不同而设置;
 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; //访问模式有四种,ABCD,异步访问SRAM用模式A
}FSMC_NORSRAMTimingInitTypeDef;

FSMC的使能函数如下:(较简单)

void FSMC_NORSRAMCmd(uint32_t FSMC_Bank, FunctionalState NewState);
void FSMC_NANDCmd(uint32_t FSMC_Bank, FunctionalState NewState);
void FSMC_PCCARDCmd(FunctionalState NewState);

2.TFTLED屏(ILI9341驱动)

1)ILI9341驱动:

(1)接口时序:8080并口:
接口线作用简介
CS片选
WR写使能
RD读使能·
D[15:0]16位双向数据线
RST硬件复位线
RS/DCX数据1*(写入9341的SRAM)/命令0(写入9341的寄存器)* 控制线

在接线上,原子用的方法比较巧妙;

  • 将RST复位接在系统的复位上;

  • 将RS线接在FSMC的任意一个地址线上(A10上)如下:

    typedef struct
    {
    	vu16 LCD_REG;
    	vu16 LCD_RAM;
    } LCD_TypeDef;
    //使用NOR/SRAM的 Bank1.sector4,地址位HADDR[27,26]=11 A10作为数据命令区分线 
    //注意设置时STM32内部会右移一位对其! 			    
    #define LCD_BASE        ((u32)(0x6C000000 | 0x000007FE))
    #define LCD             ((LCD_TypeDef *) LCD_BASE)
    
  • 利用结构体地址自增的特性:

    将LCD这个结构体定义做LCD_BASE*(A10)的地址*;***(注意:16位数据传输时,将外设地址右移一对齐位,所以实际是 HADDR[11] 位)***,这样:

    LCD_REG == 0x6C0007FE ,A10位为0(7为0111);

    LCD_RAM == 0x6C000800,A10位为1(8为1000)这里的A10均指外设的A10即FSMC_A[10].

    如此在,对地址LCD_REG = 0xyyyy*(数据)时就是,写入命令(写道9341的寄存器中)(因为此时,RS=0)*;

    同理,对地址LCD_RAM = 0xyyyy*(数据)时就是,写入数据(写到9341的SRAM上)(因为此时,RS=1)*。

2)ILI9341的部分命令:

  • 0xD3:读ID.

    在这里插入图片描述

  • 0x36:控制GRAM的指针增长方向。

    在这里插入图片描述

  • 0x2A:设置列坐标,(即x轴横坐标)

    0x2B:与2A一样,设置的是行坐标(即y轴纵坐标)

    注:以下的SC可以理解为 Start Column;EC可以理解为Ending Column.

    在这里插入图片描述

  • 0x2C:填入颜色数据(RGB565格式)

    在这里插入图片描述

    RGB565格式如下:

    在这里插入图片描述

    同时,我们从高亮那部分可以得知,为什么我们之前法横纵坐标的数据的时候,每个坐标(如SC)必须用16位(为了兼容足够大的屏幕),却被拆成两个8位来发的原因。

  • 0x2E:读GRAM,即读处对应点的颜色:

    在这里插入图片描述

3)原子代码使用:

原子帮我们将许多底层的代码都封装好了,但在使用时有一些注意事项:

  • 使用时,需先执行LCD_Init();函数进行初始化;

  • **因为LCD_Init()函数里默认将芯片信号printf到串口1输出;所以在执行LCD_Init()初始化函数前,需先执行串口初始化uart_init();或者直接将LCD_Init()内的printf();注释掉,否则程序会卡死在printf中 **

  • 将原子的LCD.h中可以调用的函数整理在这儿,方便自己查找:

    void LCD_Init(void);													   	//初始化
    void LCD_DisplayOn(void);													//开显示
    void LCD_DisplayOff(void);													//关显示
    void LCD_Clear(u16 Color);	 												//清屏
    void LCD_SetCursor(u16 Xpos, u16 Ypos);										//设置光标
    void LCD_DrawPoint(u16 x,u16 y);											//画点
    void LCD_Fast_DrawPoint(u16 x,u16 y,u16 color);								//快速画点
    u16  LCD_ReadPoint(u16 x,u16 y); 											//读点 
    void LCD_Draw_Circle(u16 x0,u16 y0,u8 r);						 			//画圆
    void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2);							//画线
    void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2);		   				//画矩形
    void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color);		   				//填充单色
    void LCD_Color_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color);				//填充指定颜色
    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);				//显示 数字(高位用0补充)
    void LCD_ShowString(u16 x,u16 y,u16 width,u16 height,u8 size,u8 *p);		//显示一个字符串,12/16/24字体,若想字符串不覆盖显示,将其中的Showchar(mode=1)即可
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值