使用FSMC驱动TFT,肯定是最快的,但是,我们的板子就那么点IO资源,QFP100又不是很厉害的芯片,所以,驱动TFT这事,是能省就省,但还是好好学学FSMC,有用的.16位并口就不说了,就说说8位并口.RST引脚接MCU RST即可.
八位接线方法:
/* PD14 - FSMC_D0 - DB0 PD15 - FSMC_D1 - DB1 PD0 - FSMC_D2 - DB2 PD1 - FSMC_D3 - DB3 PE7 - FSMC_D4 - DB4 PE8 - FSMC_D5 - DB5 PE9 - FSMC_D6 - DB6 PE10 - FSMC_D7 - DB7 PD7 - FSMC_NE1 - CS PD11 - FSMC_RS - RS PD5 - FSMC_NEW - WR PD4 - FSMC_NOE - RD */
的然后配置IO,FSMC模式,以及FSMC时序.影响到整个TFT配置的时序部分有FSMC_DataSetupTime和FSMC_AddressSetupTime.这个需要根据你的屏幕设置,一般来说,按照我如下配置,一般可以初始化FSMC以及时序,如果不行,就加大这个值,一般TFT手册上也有,但是相对保守,我们自己可以设置得小一些,提高效率.剩下肯定是送各种寄存器,初始化数据啊.
GPIO_InitTypeDef GPIO_InitStructure; FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure; FSMC_NORSRAMTimingInitTypeDef FSMC_NORSRAMTimingInitStructure; /* Enable GPIOs clock */ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE , ENABLE); /* Enable FSMC clock */ RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC, ENABLE); /* Set PD.00(D2), PD.01(D3), PD.04(NOE), PD.05(NWE), PD.08(D13), PD.09(D14), PD.10(D15), PD.11(A16), PD.14(D0), PD.15(D1) as alternate function push pull */ 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_PinSource7, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOD, GPIO_PinSource11, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_FSMC); GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_FSMC); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_7 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_11 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOD, &GPIO_InitStructure); /* Set PE.07(D4), PE.08(D5), PE.09(D6), PE.10(D7), PE.11(D8), PE.12(D9), PE.13(D10), PE.14(D11), PE.15(D12) as alternate function push pull */ /* GPIOE configuration */ 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_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 ; GPIO_Init(GPIOE, &GPIO_InitStructure); FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM1; FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_SRAM; FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b; FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable; FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low; 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_AsynchronousWait = FSMC_AsynchronousWait_Disable; FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable; FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable; FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &FSMC_NORSRAMTimingInitStructure; // FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); /* FSMC写速度设置 */ FSMC_NORSRAMTimingInitStructure.FSMC_AddressSetupTime = 0x02;//1; /* 地址建立时间 */ FSMC_NORSRAMTimingInitStructure.FSMC_AddressHoldTime = 0X00; FSMC_NORSRAMTimingInitStructure.FSMC_DataSetupTime = 0x03;//1; /* 数据建立时间 */ FSMC_NORSRAMTimingInitStructure.FSMC_BusTurnAroundDuration = 0x00; FSMC_NORSRAMTimingInitStructure.FSMC_CLKDivision = 0x00; FSMC_NORSRAMTimingInitStructure.FSMC_DataLatency = 0x00; FSMC_NORSRAMTimingInitStructure.FSMC_AccessMode = FSMC_AccessMode_A; /* FSMC 访问模式 */ FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &FSMC_NORSRAMTimingInitStructure; FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); /* Enable FSMC Bank4_SRAM Bank */ FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE);
为什么初始化时候,写的总线宽度还是16位呢,如果高位是0x00,低位是0xAA,传输0x00AA结果是不是就是8位,这样如果16位RAM也在一起,更好处理呢,当然,先这么将就看看,等下详解.然后需要计算出A16[16Bit模式从A0 - 1开始算]所在的地址:
/* Private define ------------------------------------------------------------*/ #define LCD_REG (*((volatile unsigned short *) 0x60000000)) /* RS = 0 */ #define LCD_RAM (*((volatile unsigned short *) 0x60020000)) /* RS = 1 */
我们可以接入到逻辑分析仪,来观察时序,测试代码:
while(1){ LCD_WriteIndex(0XAA); LCD_WriteData(0x55); LCD_WriteData(0xA5); LCD_WriteIndex(0x1F); LCD_WriteData(0xFE); }
看图:
那来验证一个问题,设置成8Bit,然后LCD_RAM的地址变成0x60010000 [8Bit模式从A0开始算],看看:
系统已经自作聪明的,帮我们先送高位,再送低位了,真是十足坑爹啊.所以,还是用16Bit好,只要不打开那个IO复用[复用成其他功能可能也可以,但是没测试过.]就可以了.接下来,要注意LCD的数据写入读出方式:
void LCD_WriteIndex(uint8_t data) { LCD_REG = data; //写入要写的寄存器序号 } void LCD_WriteData(uint8_t data) { LCD_RAM = data; } void LCD_DrawPoint_16Bit(uint16_t color) { LCD_RAM = color >> 8; LCD_RAM = color; } void LCD_WriteReg(uint8_t LCD_Reg, uint8_t LCD_RegValue) { LCD_REG = LCD_Reg; //写入要写的寄存器序号 LCD_RAM = LCD_RegValue;//写入数据 }
的其他就根据LCD进行设置了,附件里面提供一个,我基于4.0寸,ILI9486,8Bit的屏幕驱动.这个驱动就是不断刷屏,看调试截图:
拍照图,因为屏幕亮度本身比较高,条件也不好,然后拍出来,闪光灯一下子打在屏幕上了,所以...将就看看:
程序源码: