STM32F4-DISCO 学习之 FSMC 驱动TFT

/ 0评 / 2

使用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);
}

看图:

QQ截图20150906113337那来验证一个问题,设置成8Bit,然后LCD_RAM的地址变成0x60010000 [8Bit模式从A0开始算],看看:

QQ截图20150906113742

系统已经自作聪明的,帮我们先送高位,再送低位了,真是十足坑爹啊.所以,还是用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的屏幕驱动.这个驱动就是不断刷屏,看调试截图:

QQ截图20150905230008

拍照图,因为屏幕亮度本身比较高,条件也不好,然后拍出来,闪光灯一下子打在屏幕上了,所以...将就看看:

QQ图片20150906114322

程序源码: 

4)并口驱动TFT实验[ILI9486-8Bit]

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注