基于STM32F407的FSMC功能实现对TFT的控制

本文详细介绍了如何使用STM32的FSMC(灵活静态存储控制器)来驱动TFT液晶屏,包括FSMC的基本概念、接口配置、时序匹配以及具体的代码实现。通过对FSMC寄存器的配置,实现了将MCU的引脚连接到TFT接口,并通过FSMC的配置适应TFT的独特时序,如复用地址总线为数据总线并利用额外的控制信号。文章还提供了完整的配置代码示例,以及TFT初始化的步骤,为读者提供了实际操作的参考。
摘要由CSDN通过智能技术生成

对FSMC的理解

1.FSMC即灵活的静态存储控制器,能够连接同步、异步存储器和 16 位 PC 存储卡。专业讲解可以看STM32F4xx中文参考手册。

2.个人理解:

其实它就是为了扩展存储做了一种接口时许,因为想尽量多的兼容各个存储,所以他需要灵活配置,比如说配置成SRAM接口时序,NAND FLASH接口时序,NOR FLASH接口时序,PSRAM接口时序,等等。

通过看这些存储的接口时序,会发现他们有共性比如说肯定有地址总线,数据总线和OE,WE,NWAIT控制信号,那区别就是不同的存储可能会增加一些自己独特的控制信号。参考官方的这张图:

 

我们的目的就是通过配置FSMC的寄存器,让他匹配上这些存储以及有类似接口的一些设备,比如本文要实现的TFT控制就有类似接口时序。

TFT的接口时序:

 从图可以看到TFT的时序有:

数据总线(对应FSMC的D0-D15),

WR写信号(FSMC的NWE),

RD读信号(FSMC的NOE),

CS片选信号(对应FSMC_NEx),

唯一的区别是 :

1.TFT有RS信号,作用是表示写命令还是写数据。

2. TFT时序没有地址总线

细品一下,没有地址总线光用数据总线的话,那怎么知道数据写的是什么数据呢?其实它是把地址总线和数据总线复用成一个了,然后通过RS信号来区分是地址总线还是数据总线,只是学名叫成了写命令和写数据。

借用这个思想,那我们随便找地址总线中的一条地址线作为RS,通过这条地址线的高低来等同RS的作用,即区分是写命令还是写数据,比如我们用第19条即FSMC_A19,那么写命令就是往第20位地址是0的时候写,写数据就是往第20位是1的地址里写。

原理明白后,把TFT的pin和MCU的pin连接起来即可,剩余RST随便找个IO控制一下。

MCU pin----FSMC复用            //LCD pin
PD0 -----------FSMC_D2       //DB2
PD1 -----------FSMC_D3       //DB3
PD4 -----------FSMC_NOE        //RD
PD5 -----------FSMC_NWE        //WR    
PD8 -----------FSMC_D13
PD9 -----------FSMC_D14
PD10-----------FSMC_D15
PD14-----------FSMC_D0  
PD15-----------FSMC_D1                        
PE7 -----------FSMC_D4 
PE8 -----------FSMC_D5 
PE9 -----------FSMC_D6 
PE10-----------FSMC_D7 
PE11-----------FSMC_D8 
PE12-----------FSMC_D9 
PE13-----------FSMC_D10
PE14-----------FSMC_D11
PE15-----------FSMC_D12
PE3------------FSMC_A19        //RS
PD7------------FSMC_NE4        //CS

下面是FSMC的配置程序:

  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_GPIOE, ENABLE);
  RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_14|GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOD, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;	
  GPIO_Init(GPIOE, &GPIO_InitStructure);
	
	GPIO_PinAFConfig(GPIOD,GPIO_PinSource0,GPIO_AF_FSMC);
	GPIO_PinAFConfig(GPIOD,GPIO_PinSource1,GPIO_AF_FSMC);
	GPIO_PinAFConfig(GPIOD,GPIO_PinSource4,GPIO_AF_FSMC);
	GPIO_PinAFConfig(GPIOD,GPIO_PinSource5,GPIO_AF_FSMC);
	GPIO_PinAFConfig(GPIOD,GPIO_PinSource8,GPIO_AF_FSMC);
	GPIO_PinAFConfig(GPIOD,GPIO_PinSource9,GPIO_AF_FSMC);
	GPIO_PinAFConfig(GPIOD,GPIO_PinSource10,GPIO_AF_FSMC);
	GPIO_PinAFConfig(GPIOD,GPIO_PinSource14,GPIO_AF_FSMC);
	GPIO_PinAFConfig(GPIOD,GPIO_PinSource15,GPIO_AF_FSMC);
	GPIO_PinAFConfig(GPIOD,GPIO_PinSource7,GPIO_AF_FSMC);

	GPIO_PinAFConfig(GPIOE,GPIO_PinSource3,GPIO_AF_FSMC);
	GPIO_PinAFConfig(GPIOE,GPIO_PinSource7,GPIO_AF_FSMC);
	GPIO_PinAFConfig(GPIOE,GPIO_PinSource8,GPIO_AF_FSMC);
	GPIO_PinAFConfig(GPIOE,GPIO_PinSource9,GPIO_AF_FSMC);
	GPIO_PinAFConfig(GPIOE,GPIO_PinSource10,GPIO_AF_FSMC);
	GPIO_PinAFConfig(GPIOE,GPIO_PinSource11,GPIO_AF_FSMC);
	GPIO_PinAFConfig(GPIOE,GPIO_PinSource12,GPIO_AF_FSMC);
	GPIO_PinAFConfig(GPIOE,GPIO_PinSource13,GPIO_AF_FSMC);
	GPIO_PinAFConfig(GPIOE,GPIO_PinSource14,GPIO_AF_FSMC);
	GPIO_PinAFConfig(GPIOE,GPIO_PinSource15,GPIO_AF_FSMC);	 
		    
	FSMC_Bank1->BTCR[0]=0X00000000;
	FSMC_Bank1->BTCR[1]=0X00000000;
	FSMC_Bank1E->BWTR[0]=0X00000000;
	FSMC_Bank1->BTCR[0]|=1<<12;	
	FSMC_Bank1->BTCR[0]|=1<<14;	
	FSMC_Bank1->BTCR[0]|=1<<4;    
						    
	FSMC_Bank1->BTCR[1]|=0<<28;	  	 
	FSMC_Bank1->BTCR[1]|=0XF<<0;
	FSMC_Bank1->BTCR[1]|=60<<8;   
	FSMC_Bank1E->BWTR[0]|=0<<28; 						    
	FSMC_Bank1E->BWTR[0]|=9<<0;	
	FSMC_Bank1E->BWTR[0]|=8<<8;
	FSMC_Bank1->BTCR[0]|=1<<0;	

配置完之后就直接用

typedef struct
{
	vu16 LCD_REG;
	vu16 LCD_RAM;
} LCD_TypeDef;

#define LCD_BASE        ((u32)(0x60000000 | 0x000ffffE))//根据上面讲的细品一下为什么是这个地址!
#define LCD             ((LCD_TypeDef *) LCD_BASE)

void LCD_WR_REG(vu16 regval)
{   
	LCD->LCD_REG=regval;	 
}

void LCD_WR_DATA(vu16 data)
{	  
	LCD->LCD_RAM=data;		 
}

TFT配置

		LCD_WR_REG(0xCF);  
		LCD_WR_DATA(0x00); 
		LCD_WR_DATA(0xC1); 
		LCD_WR_DATA(0X30); 
		LCD_WR_REG(0xED);  
		LCD_WR_DATA(0x64); 
		LCD_WR_DATA(0x03); 
		LCD_WR_DATA(0X12); 
		LCD_WR_DATA(0X81); 
		LCD_WR_REG(0xE8);  
		LCD_WR_DATA(0x85); 
		LCD_WR_DATA(0x10); 
		LCD_WR_DATA(0x7A); 
		LCD_WR_REG(0xCB);  
		LCD_WR_DATA(0x39); 
		LCD_WR_DATA(0x2C); 
		LCD_WR_DATA(0x00); 
		LCD_WR_DATA(0x34); 
		LCD_WR_DATA(0x02); 
		LCD_WR_REG(0xF7);  
		LCD_WR_DATA(0x20); 
		LCD_WR_REG(0xEA);  
		LCD_WR_DATA(0x00); 
		LCD_WR_DATA(0x00); 
		LCD_WR_REG(0xC0);    //Power control 
		LCD_WR_DATA(0x1B);   //VRH[5:0] 
		LCD_WR_REG(0xC1);    //Power control 
		LCD_WR_DATA(0x01);   //SAP[2:0];BT[3:0] 
		LCD_WR_REG(0xC5);    //VCM control 
		LCD_WR_DATA(0x30); 	 //3F
		LCD_WR_DATA(0x30); 	 //3C
		LCD_WR_REG(0xC7);    //VCM control2 
		LCD_WR_DATA(0XB7); 
		LCD_WR_REG(0x36);    // Memory Access Control 
		LCD_WR_DATA(0x48); 
		LCD_WR_REG(0x3A);   
		LCD_WR_DATA(0x55); 
		LCD_WR_REG(0xB1);   
		LCD_WR_DATA(0x00);   
		LCD_WR_DATA(0x1A); 
		LCD_WR_REG(0xB6);    // Display Function Control 
		LCD_WR_DATA(0x0A); 
		LCD_WR_DATA(0xA2); 
		LCD_WR_REG(0xF2);    // 3Gamma Function Disable 
		LCD_WR_DATA(0x00); 
		LCD_WR_REG(0x26);    //Gamma curve selected 
		LCD_WR_DATA(0x01); 
		LCD_WR_REG(0xE0);    //Set Gamma 
		LCD_WR_DATA(0x0F); 
		LCD_WR_DATA(0x2A); 
		LCD_WR_DATA(0x28); 
		LCD_WR_DATA(0x08); 
		LCD_WR_DATA(0x0E); 
		LCD_WR_DATA(0x08); 
		LCD_WR_DATA(0x54); 
		LCD_WR_DATA(0XA9); 
		LCD_WR_DATA(0x43); 
		LCD_WR_DATA(0x0A); 
		LCD_WR_DATA(0x0F); 
		LCD_WR_DATA(0x00); 
		LCD_WR_DATA(0x00); 
		LCD_WR_DATA(0x00); 
		LCD_WR_DATA(0x00); 		 
		LCD_WR_REG(0XE1);    //Set Gamma 
		LCD_WR_DATA(0x00); 
		LCD_WR_DATA(0x15); 
		LCD_WR_DATA(0x17); 
		LCD_WR_DATA(0x07); 
		LCD_WR_DATA(0x11); 
		LCD_WR_DATA(0x06); 
		LCD_WR_DATA(0x2B); 
		LCD_WR_DATA(0x56); 
		LCD_WR_DATA(0x3C); 
		LCD_WR_DATA(0x05); 
		LCD_WR_DATA(0x10); 
		LCD_WR_DATA(0x0F); 
		LCD_WR_DATA(0x3F); 
		LCD_WR_DATA(0x3F); 
		LCD_WR_DATA(0x0F); 
		LCD_WR_REG(0x2B); 
		LCD_WR_DATA(0x00);
		LCD_WR_DATA(0x00);
		LCD_WR_DATA(0x01);
		LCD_WR_DATA(0x3f);
		LCD_WR_REG(0x2A); 
		LCD_WR_DATA(0x00);
		LCD_WR_DATA(0x00);
		LCD_WR_DATA(0x00);
		LCD_WR_DATA(0xef);	 
		LCD_WR_REG(0x11); 
		delay_ms(120);
		LCD_WR_REG(0x29); //display on

最后就是自己写一些GUI函数实现对TFT的显示输出。

完整工程下载:

https://download.csdn.net/download/lengxuemo/86403838

有错误的地方欢迎各位大神指正,谢谢!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值