您的位置:首页 > 其它

STM32学习笔记-FSMC驱动LCD

2018-12-22 11:58 148 查看

文章目录

  • 二、代码部分
  • 一、FSMC原理

    大容量,且引脚数在 100 脚以上的 STM32F103 芯片都带有 FSMC 接口。

    FSMC,即灵活的静态存储控制器,能够与同步或异步存储器和 16 位 PC 存储器卡连接, 接口支持包括 SRAM、 NAND FLASH、 NOR FLASH 和 PSRAM 等存储器。

    1.为什么可以用FSMC驱动LCD?

    外部 SRAM 的控制一般有:地址线(如 A0~A18)、数据线(如 D0~D15)、写信号(WE)、读信号(OE)、片选信号(CS),如果 SRAM 支持字节控制,那么还有 UB/LB 信号。而 TFTLCD包括: RS、 D0~D15、 WR、 RD、 CS、 RST 和 BL 等,其中真正在操作 LCD 的时候需要用到的就只有: RS、 D0~D15、 WR、 RD 和 CS。其操作时序和 SRAM的控制完全类似,唯一不同就是 TFTLCD 有 RS 信号,但是没有地址信号。

    而RS信号是用来控制LCD是写命令还是写数据的,本质上可以理解为一个地址,我们可以将RS信号接在FSMC的地址线上,可以选任意一根地址线,但注意接在不同地址线,地址的值会不同,后面会具体讲到。

    这样数据引脚,地址引脚,写信号(WE)、读信号(OE)、片选信号(CS)都可以和LCD对应脚连接起来,写程序时,这些引脚初始化时,复用FSMC输出即可。LCD中还有RST,BL,接单片机的普通IO口即可。

    2.寻址问题

    FSMC 总共管理 1GB 空间,拥有 4 个存储块(Bank),BANK1是属于NOR/PSRAM,BANK2、BANK3属于NAND,BANK4属于PC卡。

    STM32 的 FSMC 存储块 1(Bank1)被分为 4 个区,每个区管理 64M 字节空间,每个区都有独立的寄存器对所连接的存储器进行配置。 Bank1 的 256M 字节空间由 28 根地址线(HADDR[27:0])寻址。这里 HADDR 是内部 AHB 地址 总线 ,其 中 HADDR[25:0] 来自外部存储器地 址FSMC_A[25:0],而 HADDR[26:27]对 4 个区进行寻址。

    Bank1 所选区 片选信号 地址范围
    第一区 FSMC_NE1 0X6000,0000~63FF,FFFF
    第二区 FSMC_NE2 0X6400,0000~67FF,FFFF
    第三区 FSMC_NE3 0X6800,0000~6BFF,FFFF
    第四区 FSMC_NE4 0X6C00,0000~6FFF,FFFF

    那么为什么是这个地址呢?计算方法也很简单,之前说过,HADDR[27:26]是对4个区进行寻址,显然,00对应第一区,01对应第二区,10对应第三区,11对应第四区,注意是26位和27位。而最高4位为“6”,如果是BANK2便是“7”,BANK3便是8,BANK4,便是9.
    我们要特别注意 HADDR[25:0]的对应关系:
    当 Bank1 接的是 16 位宽度存储器的时候:
    HADDR[25:1]->FSMC_A[24:0]。
    当 Bank1 接的是 8 位宽度存储器的时候: HADDR[25:0]>FSMC_A[25:0]。

    很多TFTLCD使用的是 16 位数据宽度,所以 HADDR[0]并没有用到,只有 HADDR[25:1]是有效的,对应关
    系变为: HADDR[25:1]-> FSMC_A[24:0],相当于右移了一位,这里请大家特别留意。

    3.时序模式

    FSMC 的 NOR FLASH 控制器支持同步和异步突发两种访问方式。选用同步突发访问方式时, FSMC 将 HCLK(系统时钟)分频后,发送给外部存储器作为同步时钟信号 FSMC_CLK。

    对于异步突发访问方式, FSMC 主要设置 3 个时间参数:地址建立时间(ADDSET)、数据建立时间(DATAST)和地址保持时间(ADDHLD)。 FSMC 综合了 SRAM/ROM、 PSRAM 和 NOR Flash 产品的信号特点,定义了 4 种不同的异步时序模型。选用不同的时序模型时,需要设置不同的时序参数

    时序模型 简单描述 时间参数
    Mode1 SRAM/CRAM 时序 DATAST、 ADDSET
    ModeA SRAM/CRAM OE 选通型时序 DATAST、 ADDSET
    Mode2/B NOR FLASH 时序 DATAST、 ADDSET
    ModeC NOR FLASH OE 选通型时序 DATAST、 ADDSET
    ModeD 延长地址保持时间的异步时序 DATAST、 ADDSET、 ADDHLK

    我用的是异步突发模式,模式 A 支持独立的读写时序控制,这个对我们驱动 TFTLCD 来说非常有用,因为 TFTLCD在读的时候,一般比较慢,而在写的时候可以比较快,如果读写用一样的时序,那么只能以读的时序为基准,从而导致写的速度变慢,或者在读数据的时候,重新配置 FSMC 的延时,在读操作完成的时候,再配置回写的时序,这样虽然也不会降低写的速度,但是频繁配置,比较麻烦。而如果有独立的读写时序控制,那么我们只要初始化的时候配置好,之后就不用再配置,既可以满足速度要求,又不需要频繁改配置。
    当然,我也试了一下模式B。

    二、代码部分

    该项目基于STM32F103

    #define Bank1_LCD_D    ((u32)0x6C010000)    //    写数据对应地址
    #define Bank1_LCD_C    ((u32)0x6C000000)	   //  写命令对应地址
    
    #define Set_Rst GPIOA->BSRR = GPIO_Pin_9;
    #define Clr_Rst GPIOA->BRR  = GPIO_Pin_9;
    
    #define Lcd_Light_ON   GPIOB->BSRR = GPIO_Pin_11;
    #define Lcd_Light_OFF  GPIOB->BRR  = GPIO_Pin_11;

    需要说明的是,我的项目选用的是BANK1的NE4,即第四区,LCD的RS引脚接的是PA15,因此地址从0x6C000000开始,而PA15置1为写数据,置0为写命令。注意,PA15对应寄存器D16位。因此写数据对应地址0x6C010000.
    如果LCD的RS引脚接的是PA16,则该引脚对应寄存器的D17位,那么写数据的地址变为0x6C020000,需要换成二进制计算,在此不在赘述。

    /*
    * 函数名:LCD_GPIO_Config
    * 描述  :根据FSMC配置LCD的I/O
    * 输入  :无
    * 输出  :无
    * 调用  :内部调用
    */
    void LCD_GPIO_Config(void)
    {
    GPIO_InitTypeDef GPIO_InitStructure;
    
    /* Enable the FSMC Clock */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);
    
    /* config lcd gpio clock base on FSMC */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC |
    RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE| RCC_APB2Periph_GPIOG , ENABLE);
    
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    
    /* config tft rst gpio */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    /* config tft back_light gpio base on the PT4101 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 ;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    /* config tft data lines base on FSMC
    * data lines,FSMC-D0~D15: PD 14 15 0 1,PE 7 8 9 10 11 12 13 14 15,PD 8 9 10
    */
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_8 | GPIO_Pin_9 |
    GPIO_Pin_10 | GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_Init(GPIOD, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = 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);
    
    /* config tft control lines base on FSMC
    * PD4-FSMC_NOE  :LCD-RD
    * PD5-FSMC_NWE  :LCD-WR
    * PG12-FSMC_NE4  :LCD-CS
    * PG5-FSMC_A15 :LCD-DC
    */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_Init(GPIOD, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_Init(GPIOD, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_Init(GPIOG, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 ;
    GPIO_Init(GPIOG, &GPIO_InitStructure);
    
    /* tft control gpio init */
    
    GPIO_SetBits(GPIOA, GPIO_Pin_9);		 // RST = 1
    GPIO_SetBits(GPIOD, GPIO_Pin_4);		 // RD = 1
    GPIO_SetBits(GPIOD, GPIO_Pin_5);		 // WR = 1
    GPIO_SetBits(GPIOG, GPIO_Pin_12);		 //	CS = 1

    这是引脚初始化代码,FSMC部分数据引脚大部分相同,初始化复用为FSMC模式,读写数据,片选等引脚根据原理图进行配置,也复用为FSMC,特别注意LCD的RS引脚接FSMC的地址线,这个在上面也重点强调了。

    /*
    * 函数名:LCD_FSMC_Config
    * 描述  :LCD  FSMC 模式配置
    * 输入  :无
    * 输出  :无
    * 调用  :内部调用
    */
    static void LCD_FSMC_Config(void)
    {
    FSMC_NORSRAMInitTypeDef  FSMC_NORSRAMInitStructure;
    FSMC_NORSRAMTimingInitTypeDef  p;
    
    p.FSMC_AddressSetupTime = 0x02;	 //地址建立时间
    p.FSMC_AddressHoldTime = 0x00;	 //地址保持时间
    p.FSMC_DataSetupTime = 0x05;		 //数据建立时间
    p.FSMC_BusTurnAroundDuration = 0x00;
    p.FSMC_CLKDivision = 0x00;
    p.FSMC_DataLatency = 0x00;
    //norflash一般用模式B,SRAM一般用模式A,和时序有关
    p.FSMC_AccessMode = FSMC_AccessMode_B;	 // 一般使用模式B来控制LCD
    
    FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM4;  //使用NE4
    FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; //不复用数据地址
    FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_NOR;   //设置为NOR类型
    FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;  //存储器数据宽度为16bit
    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_WaitSign
    1e7dc
    al = FSMC_WaitSignal_Disable;
    FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;    //扩展位不使能,读写使用相同时序
    FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
    FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p;
    FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p;
    
    FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);
    
    /* Enable FSMC Bank1_SRAM Bank */
    FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM4, ENABLE);  //使能BNAK1,NE4
    }

    这是FSMC的配置代码,用的是异步模式B,读写时序相同,具体可以看备注

    以下是使用模式A(参考正点原子代码)

    FSMC_NORSRAMInitTypeDef  FSMC_NORSRAMInitStructure;
    FSMC_NORSRAMTimingInitTypeDef  readWriteTiming;
    FSMC_NORSRAMTimingInitTypeDef  writeTiming;
    
    readWriteTiming.FSMC_AddressSetupTime = 0x01;	 //地址建立时间(ADDSET)为2个HCLK 1/36M=27ns
    readWriteTiming.FSMC_AddressHoldTime = 0x00;	 //地址保持时间(ADDHLD)模式A未用到
    readWriteTiming.FSMC_DataSetupTime = 0x0f;		 // 数据保存时间为16个HCLK,因为液晶驱动IC的读数据的时候,速度不能太快,尤其对1289这个IC。
    readWriteTiming.FSMC_BusTurnAroundDuration = 0x00;
    readWriteTiming.FSMC_CLKDivision = 0x00;
    readWriteTiming.FSMC_DataLatency = 0x00;
    readWriteTiming.FSMC_AccessMode = FSMC_AccessMode_A;	 //模式A
    
    writeTiming.FSMC_AddressSetupTime = 0x00;	 //地址建立时间(ADDSET)为1个HCLK
    writeTiming.FSMC_AddressHoldTime = 0x00;	 //地址保持时间(A
    writeTiming.FSMC_DataSetupTime = 0x03;		 ////数据保存时间为4个HCLK
    writeTiming.FSMC_BusTurnAroundDuration = 0x00;
    writeTiming.FSMC_CLKDivision = 0x00;
    writeTiming.FSMC_DataLatency = 0x00;
    writeTiming.FSMC_AccessMode = FSMC_AccessMode_A;	 //模式A
    
    FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM4;//  这里我们使用NE4 ,也就对应BTCR[6],[7]。
    FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; // 不复用数据地址
    FSMC_NORSRAMInitStructure.FSMC_MemoryType =FSMC_MemoryType_SRAM;// FSMC_MemoryType_SRAM;  //SRAM
    FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;//存储器数据宽度为16bit
    FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode =FSMC_BurstAccessMode_Disable;// FSMC_BurstAccessMode_Disable;
    FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
    FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait=FSMC_AsynchronousWait_Disable;
    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_ExtendedMode = FSMC_ExtendedMode_Enable; // 读写使用不同的时序
    FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
    FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &readWriteTiming; //读写时序
    FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &writeTiming;  //写时序
    
    FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);  //初始化FSMC配置
    
    FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM4, ENABLE);  // 使能BANK1
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: