对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
有错误的地方欢迎各位大神指正,谢谢!