• [021] [STM32] FSMC外设详解及模拟驱动LCD编程


    STM32
    Contents
    STM32的FSMC
    性及架构
    外部存储器地址映射
    NOR Flash/PSRAM
    控制器
    STM32的FSMC
    配置结构体
    NOR/SRAM时序
    初始化结构体
    NOR/SRAM初始
    化配置结构体
    FSMC驱动LCD
    LCD控制原理
    使用FSMC模
    拟8080时序
    FSMC驱动LCD实验

    1 STM32的FSMC特性及架构

    FSMC(Flexible Static Memeoy Controller)灵活的静态存储控制器,它可以用于驱动包括SRAM、NOR FLASH以及NAND FLSAH类型的存储器,不能驱动如SDRAM这种动态的存储器。FMC外设支持控制SDRAM存储器。硬件框架如下图所示:

    image-20220715104003614

    FSMC支持8/16/32位数据宽度(32位宽数据将被划分成多个连续的16或8位访问),并将外部存储器划分为固定大小为256(4 * 64)MB的四个存储块:

    image-20220715092448839

    1.1 外部存储器地址映射

    1.1.1 NOR Flash/PSRAM 地址映射

    Bank1被用于驱动NOR Flash/SRAM/PSRAM,被分为4个区,每个区为64MB。FSMC_NE[1:4]片选引脚对应的不同的Bank所选区,并且有唯一确定的HADDR[27:26]值与之对应,如下表所示:

    image-20220715102822282

    HADDR 是 AHB 内部地址线,但也会参与对外部存储器的寻址。

    以下图为例,LCD的CS片选引脚拉低时,会将与之相连的FSMC_NE3拉低,即选择Bank1的第3区。因此,一般地址与器件挂载的片选引脚相关,当不同的FSMC_NE引脚连接不同的外部存储器时,访问的存储区域不一样,达到控制多块存储器的目的。

    image-20220715095831787

    注意:Bank1每个存储区域片选信号NE[4:1]是唯一的,其它信号(地址、数据和控制)均为共享信号。

    根据存储器数据宽度不同,实际向存储器发送的地址也将有所不同,如下表所示:

    image-20220715113425616

    当Bank1接16位宽度存储器时:HADDR[25:1] --> FSMC_A[24:0]
    当Bank1接8位宽度存储器时: HADDR[25:0] --> FSMC_A[25:0]

    即当存储器数据宽度为16位时,FSMC将使用内部的HADDR[25:1] 地址来作为对外部存储器的寻址地址,因此实际向存储器写入的地址会向右移1位。下面举例说明:

     *(volatile uint16_t*)(0x60000468UL)=0xABCD; 
    
    • 1

    向0x60000468(Bank1的第1区)写入0xABCD,观察写入时的时序图(先阅读后面的接口信号&通讯时序章节后再来看此处分析):

    image-20220715152244042

    数据总线上先产生0x234(0x468 >> 1),然后NE1被拉低,在NADV下降沿瞬间,数据被锁存在地址锁存器上(A0~A15)和A16~A25(实验暂未使用,若使用会在NE1下降沿同时送出)组合成完整的地址信号。

    注意不论外接8位/16位宽设备,FSMC_A[0]永远接在外部设备地址A[0]。

    1.1.2 NAND/PC卡地址映射

    在此情况下,有三个存储区域:

    image-20220715161854109

    对于NAND Flash存储器,通用区和特性区存储空间分为三个部分,均位于低位256KB中:

    image-20220715162119245

    软件通过操作这3个区域访问NAND Flash的流程:

    • 向NAND Flash发送读写等操作命令:软件可向命令区任何地址写入命令值
    • 向NAND Flash发送将要读/写的地址:软件可向地址区任何地址写入地址值。(对于4字节长度的地址,需向地址区执行多次连续写操作)
    • 从NAND Flash读写数据:软件从数据区任何地址写入/读出数据。

    由于 NAND Flash 存储器会自动递增地址,所以在访问连续存储器位置时,无需递增数据区域的地址。

    1.2 NOR Flash/PSRAM控制器

    1.2.1 外部存储器接口信号

    对于NOR Flash/PSRAM,对于是否将FSMC的地址与数据线复用时的接口信号不一样,注意前缀“N”表示相关的信号为低电平有效。

    • NOR Flash,非复用
    FSMC信号名称I/O说明
    CLKO时钟(用于同步突发)
    A[25:0]O地址总线
    D[15:0]I/O双向数据总线
    NE[1:4]O片选信号
    NOEO输出使能(读使能)
    NWEO写入使能
    NL(NADV)O锁存使能
    NWAITIFSMC 的 NOR Flash 等待输入信号

    A[25:0] 26根地址线一共可以表示226=64MB行存储单元,可访问的空间大小与数据宽度有关。

    • NOR Flash,复用
    FSMC信号名称I/O说明
    CLKO时钟(用于同步突发)
    A[25:16]O地址总线
    AD[15:0]I/O16位复用双向地址/数据总线
    NE[1:4]O片选信号
    NOEO输出使能(读使能)
    NWEO写入使能
    NL(NADV)O锁存使能
    NWAITIFSMC 的 NOR Flash 等待输入信号
    • PSRAM/SRAM,非复用
    FSMC信号名称I/O说明
    CLKO时钟(用于同步突发)
    A[25:0]O地址总线
    D[15:0]I/O双向数据总线
    NE[1:4]O片选信号
    NOEO输出使能(读使能)
    NWEO写入使能
    NL(NADV)O仅用于PSRAM输入的地址有效信号
    NWAITIFSMC 的 NOR Flash 等待输入信号
    NBL[1]O高字节使能
    NBL[0]O低字节使能

    NBL[1:0] 在进行读取访问时为低电平

    • PSRAM/SRAM,复用
    FSMC信号名称I/O说明
    CLKO时钟(用于同步突发)
    A[25:16]O地址总线
    AD[15:0]I/O16位复用双向地址/数据总线
    NE[1:4]O片选信号
    NOEO输出使能(读使能)
    NWEO写入使能
    NL(NADV)O仅用于PSRAM输入的地址有效信号
    NWAITIFSMC 的 NOR Flash 等待输入信号
    NBL[1]O高字节使能
    NBL[0]O低字节使能

    1.2.2 通讯时序

    • 当出现FSMC_CLK时钟的下降沿时,NOEL/NWEL/NEL/NADVL/NADVH/NBLL/地址有效输出可发生变化。
    • 当出现FSMC_CLK时钟的上升沿时,NOEH/NWEH/NEH/NOEH/NBLH/地址有效输出可发生变化。

    FSMC模式

    • 如果使能扩展模式(FSMC_BCRx寄存器中的EXTMOD位置1),则最多可提供四种扩展模式(A、B、C和D)。可混合使用A、B、C和D模式来进行读取和写入操作(例如,可以在模式A下执行读取操作,而在模式B下执行写入操作)。
    • 如果禁用扩展模式(FSMC_BCRx寄存器中的EXTMOD位置0),则FSMC可以在模
      式1或模式2下运行:
      • 当选择SRAM/CRAM存储器类型时,模式1为默认模式(FSMC_BCRx寄存器中
        MTYP=0x0或0x01)。
      • 当选择NOR存储器类型时,模式2为默认模式(FSMC_BCRx寄存器中MTYP=
        0x10)。

    驱动SRAM时一般使用模式1或者模式A。

    下面分析模式A(SRAM/PSRAM)的读/写时序:

    读时序

    image-20220715161402752

    存储器操作周期由地址建立周期(ADDSET)、**数据建立周期(**DATAST)组成。在地址建立周期中,地址线发出要访问的地址,NBL[1:0] 在进行读取访问时为低电平,片选信号使能存储器芯片;地址建立周期结束后读使能信号线发出读使能信号,接着存储器通过数据信号线把目标数据传输给FSMC,FSMC把它交给内核。

    写时序

    image-20220715161517570

    写时序类似,区别是在数据建立周期期间写使能信号线发出写信号。

    注意:STM32F1与F4的D[15:0]时序有些差异,详见各自手册。

    对于NOR FLASH/PSRAM控制器(存储块1),通过FSMC_BCRx、FSMC_BTRx和FSMC_BWTRx寄存器(其中x=1~4,对应bank的4个区)设置FSMC访问外部存储器的时序参数,拓宽了可选用的外部存储器的速度范围。模式A下的寄存器配置参数如下图所示:

    FSMC_BCRx寄存器:

    image-20220715164033741

    FSMC_BTRx寄存器:

    image-20220715164100581

    FSMC_BWTRx寄存器:

    image-20220715164248619

    若没有设置FSMC_BCRx的EXTMOD位,则读写共用FSMC_BTRx寄存器

    若设置了EXTMOD位,则FSMC_BTRx将和FSMC_BWTRx配合来配置写入和读取的时序参数。即FSMC_BTRx用于配置读取访问,FSMC_BWTRx用于配置写入访问

    2 STM32的FSMC配置结构体

    在ST官方库提供的的寄存器定义里面,并没有定义FSMC_BCRx、FSMC_BTRx、FSMC_BWTRx等这个单独的寄存器,而是将他们进行了一些组合。规律如下:

    • FSMC_BCRx和FSMC_BTRx,组合成BTCR[8]寄存器组,他们的对应关系如下:

      BTCR数组偶数位(从0开始)对应FSMC_BCRx(从1开始),BTCR数组奇数位则对应FSMC_BTRx

    • FSMC_BWTRx则组合成BWTR[7],他们的对应关系如下:
      BWTR[0]对应FSMC_BWTR1,BWTR[2]对应FSMC_BWTR2,
      BWTR[4]对应FSMC_BWTR3,BWTR[6]对应FSMC_BWTR4,
      BWTR[1]、BWTR[3]和BWTR[5]保留。

    2.1 NOR/SRAM时序初始化结构体

    typedef struct
    {
      /*!< 地址建立时间,0-0xF个HCLK周期 @note 此参数与同步NOR Flash无关 */
      uint32_t FSMC_AddressSetupTime;       
      /*!< 地址保持时间,0-0xF个HCLK周期 @note 此参数与同步NOR Flash无关 */
      uint32_t FSMC_AddressHoldTime;        
      /*!< 数据建立时间,0-0xF个HCLK周期 @note 此参数用于SRAM, ROM 和 异步复用NOR Flash */
      uint32_t FSMC_DataSetupTime; 
      /*!< 总线转换周期,0-0xF个HCLK周期。在复用NOR FLASH存储器中,地址线与数据线可分时复用,总线转换周期就是指总线在这两种状态间切换需要的延时,防止冲突。控制其它存储器时这个参数无效,配置为0即可。*/
      uint32_t FSMC_BusTurnAroundDuration;  
      /*!< 时钟分频因子,范围1-0xF,@note 此参数与异步存储器无关*/  
      uint32_t FSMC_CLKDivision;    
      /*!< 数据保持时间 @note 此参数与异步存储器无关*/ 	
      uint32_t FSMC_DataLatency;      
      /*!< 存储器访问模式,控制LCD时一般使用B模式 */ 
      uint32_t FSMC_AccessMode;          
    }FSMC_NORSRAMTimingInitTypeDef;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    LCD通信时的地址&数据建立周期

    2.2 NOR/SRAM初始化配置结构体

    typedef struct
    {
      /*!< 设置要控制的Bank区域(BANK1的分区) value of @ref FSMC_NORSRAM_Bank */   
      uint32_t FSMC_Bank;        
      /*!< 设置地址总线与数据总线是否复用,在控制NOR FLASH时,可以地址总线与数据总线可以分时复用,以减少使用STM32信号线的数量,但通信速度会下降 */     
      uint32_t FSMC_DataAddressMux;
      /*!< 设置要控制的存储器类型 */   
      uint32_t FSMC_MemoryType; 
      /*!< 设置要控制的存储器的数据宽度 */   
      uint32_t FSMC_MemoryDataWidth;
      /*!< 设置是否使用突发访问模式 */ 
      uint32_t FSMC_BurstAccessMode;
      /*!< 设置是否使能在同步传输时使用的等待信号,在控制同步类型的NOR或PSRAM时,存储器可以使用FSMC_NWAIT引脚通知STM32需要等待。 */ 
      uint32_t FSMC_AsynchronousWait;                                    
      /*!< 设置等待信号的有效极性,即要求等待时,使用高电平还是低电平 */ 
      uint32_t FSMC_WaitSignalPolarity;
      /*!< 设置是否支持把非对齐(如访问奇数地址)的AHB突发操作分割成2次线性操作(FSMC_WrapMode_Enable/Disable),该配置仅在突发模式下有效 */ 
      uint32_t FSMC_WrapMode; 
      /*!< 配置在突发传输模式时,决定存储器是在等待状态之前的一个数据周期有效还是在等待状态期间有效 */ 
      uint32_t FSMC_WaitSignalActive;
      /*!< 设置是否写使能,禁止写使能的话FSMC只能从存储器中读取数据 */     
      uint32_t FSMC_WriteOperation;
      /*!< 设置当存储器牌突发传输模式时,是否允许通过NWAIT信号引脚插入等待状态 */ 
      uint32_t FSMC_WaitSignal;
      /*!< 是否使用扩展模式 */ 
      uint32_t FSMC_ExtendedMode;
      /*!< 是否使能写突发操作 */ 
      uint32_t FSMC_WriteBurst;
      /*!< 写时序初始化结构体 */ 
      FSMC_NORSRAMTimingInitTypeDef* FSMC_ReadWriteTimingStruct;  
      /*!< 读时序初始化结构体 */ 
      FSMC_NORSRAMTimingInitTypeDef* FSMC_WriteTimingStruct;    
    }FSMC_NORSRAMInitTypeDef;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    突发访问模式:指发送一个地址后连续访问多个数据(存储器地址自增),非突发模式下每访问一个数据都需要输入一个地址,仅在控制同步类型的存储器时才能使用突发模式。(LCD每次访问固定地址,因此配置为非突发模式)

    • 非扩展模式下,对存储器读写的时序都只使用FSMC_BCR寄存器中的配置,即FSMC_ReadWriteTimingStruct结构体成员;
    • 扩展模式下,对存储器的读写时序可以分开配置,读时序使用FSMC_BCR寄存器,写时序使用FSMC_BWTR寄存器的配置,即下面的FSMC_WriteTimingStruct结构体。

    控制LCD需要关注的配置(黄色mark部分):

    image-20220715175443600

    3 FSMC驱动LCD

    3.1 LCD控制原理

    LCD分为带控制器与不带控制器的,本文主要分析带有ILI9806G液晶控制器芯片的LCD,其内部结构如下图所示:

    image-20220718090926863

    1. LI9806G的主要控制信号线和配置引脚,根据其不同状态设置可以使芯片工作在不同的模式,如每个像素点的位数是8、16还是24位;可配置使用SPI接口、8080接口还是RGB接口与MCU进行通讯,从而访问它的控制寄存器(CR)、地址计数器(AC)、及GRAM。
    2. GRAM(Graphics RAM)为LCD的显存,GRAM中每个存储单元都对应着液晶面板的一个像素点。它右侧的各种模块共同把GRAM中的数据转化成液晶面板的控制信号,使像素点呈现特定的颜色,而像素点组合起来则成为一幅完整的图像。
    3. Source Driver:LCD显示驱动电路由一个480输出源驱动(S1-S1440)组成。当输入480RGB像素的数据时,将锁存显示模式数据,电压根据锁存数据从源驱动器输出。
    4. CABC(content adaptive brightness control):自适应亮度控制,控制LCD的背光
    5. Charge-Pump Power Circuit:电荷泵电路,产生驱动面板的电压等级,电压水平根据寄存器设置进行调整。

    3.1.1 液晶屏的信号线及8080时序

    image-20220718094711749

    ▲ IM[3:0]信号线配置

    image-20220718095333580

    ▲ DBI[2:0]寄存器RGB接口格式配置

    ILI9806G控制器根据自身的IM[3:0]信号线电平决定它与MCU的通讯方式,DBI[2:0]配置RGB格式,本文使用的LCD被配置8080接口通讯,且使用16根数据线的RGB565格式。引出的排针信号线如下图:

    image-20220718092902963

    信号线ILI9806G对应的信号线说明
    LCD_DB[15:0]D[15:0]数据信号
    LCD_RDRDX数据信号,电平有效
    LCD_RSD/CX数据/命令信号,电平时,D[15:0]表示的是数据(RGB像素数据或命令数据),电平时D[15:0]表示控制命令
    LCD_RESETRESX复位信号,电平有效
    LCD_WRWRX数据信号,电平有效
    LCD_CSCSX片选信号,电平有效
    LCD_BK-背光信号,电平点亮
    GPIO23-空引脚,不需要连接
    RST与触摸IC相连触摸IC的复位引脚
    INT与触摸IC相连触摸IC的中断信号引脚
    SCL与触摸IC相连触摸IC的IIC总线的时钟信号
    SDA与触摸IC相连触摸IC的IIC总线的数据信号

    带X的表示低电平有效

    向ILI9806写命令的时序图(8080接口写命令时序):

    image-20220718093834179

    CSX拉低,片选使能,可写入数据。

    • 写命令:D/CX拉低传输命令,WRX拉低且RDX拉高表示方向为写入,显示模块在WRX上升沿捕获数据线D[23:0]输出的命令地址
    • 写数据:D/CX拉高传输数据,WRX拉低且RDX拉高表示方向为写入,显示模块在WRX上升沿捕获数据线D[23:0]输出的数据。

    格式为RGB565的一个像素数据传输过程:

    image-20220718095930505

    MSB = DB15, LSB = DB0

    3.2 使用FSMC模拟8080时序

    控制LCD时,控制LCD时使用与NOR FLASH一样的模式B,NOR FLASH控制信号线:

    FSMC信号名称信号方向功能
    CLK输出时钟(同步突发模式使用)
    A[25:0]输出地址总线
    D[15:0]输入/输出双向数据总线
    NE[x]输出片选,x = 1…4
    NOE输出输出使能
    NWE输出写使能
    NWAIT输入NOR闪存要求FSMC等待的信号
    NADV输出地址、数据线复用时作锁存信号

    表中高亮部分为控制LCD需要用到的引脚,因采用异步模式控制,因此无需同步时钟CLK。

    FSMC模式B时序与8080时序/引脚对比

    image-20220718101756084

    FSMC-NOR信号线功能8080信号线功能
    NEx片选信号CSX片选信号
    NWE写使能WRX写使能
    NOE读使能RDX读使能
    D[15:0]数据信号D[15:0]数据信号
    A[25:0]地址信号D/CX数据/命令选择

    通过对比发现区别看起来较大的即为A[25:0]地址信号与LCD控制器的D/C数据/命令选择信号。因此,为模拟8080时序,可将D/CX与A0(其他地址引脚也可以)连接,当A0拉低时表示传输的信号为命令,拉高则表示数据。即当使用FSMC向奇数地址写入数据时表示传数据,偶数地址表示传命令:

    地址地址的二进制值**(仅列出低四位)**A0(D/CX)的电平控制ILI9341时的意义
    0x6xxx xxx100011高电平D数值
    0x6xxx xxx300111高电平D数值
    0x6xxx xxx000000低电平C命令
    0x6xxx xxx200100低电平C命令

    3.3 FSMC驱动LCD实验

    1. 初始化FSMC控制相关的引脚

    image-20220718105313421

    注意:开发板中LCD与SRAM共用同一个FSMC,但是在不同时刻下操作的片选引脚不一样,SRAM为NE4,因此向LCD写入时会拉低NE3片选,选择bank1的第3区,不会干扰到SRAM。

    D0~D15、CS、RD、WE、RS(命令/数据选择)全部初始化为复用推挽输出。BL、RST初始化为普通推挽输出。

    1. 初始化FSMC为异步NOR FLASH驱动模式
    static void FSMC_LCD_Init(void)
    {
        FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;
        FSMC_NORSRAMTimingInitTypeDef readWriteTiming;
    
        /*使能FSMC外设时钟*/
        RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC, ENABLE);
    
        //地址建立时间(ADDSET)为5个HCLK, 5/168M = 30ns
        readWriteTiming.FSMC_AddressSetupTime = 0x04;
    
        //地址保持时间(ADDHLD)模式B未用到
        readWriteTiming.FSMC_AddressHoldTime = 0x00;
    
        //数据建立时间(DATAST)+ 1个HCLK = 5/168M=30ns
        readWriteTiming.FSMC_DataSetupTime = 0x04;
    
        //设置总线转换周期,仅用于复用模式的NOR操作
        readWriteTiming.FSMC_BusTurnAroundDuration = 0x00;
    
        //设置时钟分频,仅用于同步类型的存储器
        readWriteTiming.FSMC_CLKDivision = 0x00;
    
        //数据保持时间,仅用于同步型的NOR
        readWriteTiming.FSMC_DataLatency = 0x00;
    
        //选择匹配为异步NOR FLASH的模式(模拟8080)
        readWriteTiming.FSMC_AccessMode = FSMC_AccessMode_B;
    
        // 选择FSMC映射的存储区域: Bank1 sram3
        FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM3;
    
        //设置地址总线与数据总线是否复用,仅用于NOR
        FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
    
        //设置要控制的存储器类型:NOR FLASH类型
        FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_NOR;
    
        //存储器数据宽度:16位
        FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
    
        //设置是否使用突发访问模式,仅用于同步类型的存储器
        FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
    
        //设置是否使能等待信号,仅用于同步类型的存储器
        FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait = FSMC_AsynchronousWait_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_ExtendedMode = FSMC_ExtendedMode_Disable;
    
        //突发写操作
        FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
    
        //读写时序配置
        FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &readWriteTiming;
    
        //读写同样时序,使用扩展模式时这个配置才有效
        FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &readWriteTiming;
    
        FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); //初始化FSMC配置
    
        FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM3, ENABLE); // 使能BANK
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    其中,地址建立时间ADDSET和数据建立时间DATAST需要参考ILI9806G手册时序图计算:

    image-20220718135632203

    • tast:地址建立时间
    • twc:写数据周期(建立数据)
    • trcs/trcsfm:trcs为读帧缓存周期、trcsfm为读ID数据周期

    image-20220718135957934

    对于STM32F4其HCLK频率为168M,即1个HCLK为6ns,但是根据模式B的时序图实际写入的ADDSET和DATAST均会+1。同时,由于读数据比写数据慢许多,一般需要使能扩展模式,即读写使用不同的时序。However, 本文使用的「野火」LCD屏幕经过他们测试ADDSET和DATAST都设为30ns,且读写使用相同时序(不用扩展模式),即可正常通信。

    1. 编写向液晶屏读写数据及写入命令的函数

    BANK1第3区的基地址为0x68000000,使用A0地址信号控制LCD的D/C信号,即向HADDR的0x68000000 | (1 << 0)表示传输数据,而0x68000000 & ~(1 << 0)表示传输命令。

    不过经前文分析,当存储器数据宽度为16位时,FSMC使用HADDR[25:1] 地址来作为对外部存储器的寻址地址,即HADDR1对应A0,实际向存储器写入的地址会向右移1位。因此,要先让A0左移1位,即0x68000000 | (1 << 1)表示传输数据,而0x68000000 & ~(1 << 1)表示传输命令。

    注意:对于其他地址引脚,如传输命令,第0位需置0,其他小于该引脚对应的位需置1。如配置A17位地址引脚,则写数据地址为0x68000000 + (1<<18) = 0x68040000,则写命令地址为0x6803FFFE

    #define Bank1_NOR_SRAM3_ADDR    ((uint32_t)(0x68000000))	
    //使用A0连接到D/CX引脚
    #define FSMC_Addr_ILI9806G_DATA    ((uint32_t)(Bank1_NOR_SRAM3_ADDR |  (1 << (0 + 1))))	 //0x68000002
    #define FSMC_Addr_ILI9806G_CMD     ((uint32_t)(Bank1_NOR_SRAM3_ADDR & ~(1 << (0 + 1))))	 //0x68000000
    
    /**
      * @brief  向ILI9806G写入命令
      * @param  usCmd :要写入的命令(表寄存器地址)
      * @retval 无
      */	
    __inline void ILI9806G_Write_Cmd ( uint16_t usCmd )
    {
    	* ( __IO uint16_t * ) ( FSMC_Addr_ILI9806G_CMD ) = usCmd;
    	
    }
    
    /**
      * @brief  向ILI9806G写入数据
      * @param  usData :要写入的数据
      * @retval 无
      */	
    __inline void ILI9806G_Write_Data ( uint16_t usData )
    {
    	* ( __IO uint16_t * ) ( FSMC_Addr_ILI9806G_DATA ) = usData;
    	
    }
    
    /**
      * @brief  从ILI9806G读取数据
      * @param  无
      * @retval 读取到的数据
      */	
    __inline uint16_t ILI9806G_Read_Data ( void )
    {
    	return ( * ( __IO uint16_t * ) ( FSMC_Addr_ILI9806G_DATA ) );
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    读取LCD控制芯片ID:

    image-20220718145444038

    需要先复位LCD

    //读取液晶ID
    uint16_t LCD_GetID(void)
    {
        uint16_t id = 0;
        uint16_t dummy;
    
        LCD_ReadReg(0xD3, &dummy);
        dummy = LCD_RD_DATA();		// 实测需要空读三次才行
        dummy = LCD_RD_DATA();
    
        id |= (uint16_t)(LCD_RD_DATA() << 8);
        id |= LCD_RD_DATA();
    
        return id;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    1. 向液晶屏发送寄存器配置

    寄存器配置由厂家提供,我们只需将写数据函数、写命令函数、延时函数均换成自己封装好的FSMC读写函数和延时函数即可。

    1. 控制液晶屏显示图形,进行测试

    液晶扫描方向设置

    image-20220718153521206

    image-20220830162149023

    void ILI9806G_GramScan(uint8_t ucOption)
    {
        //参数检查,只可输入0-7
        if (ucOption > 7)
            return;
    
        //根据模式更新LCD_SCAN_MODE的值,主要用于触摸屏选择计算参数
        LCD_SCAN_MODE = ucOption;
    
        //根据模式更新XY方向的像素宽度
        if (ucOption % 2 == 0)
        {
            // 0 2 4 6模式下X方向像素宽度为480,Y方向为854
            LCD_X_LENGTH = ILI9806G_LESS_PIXEL;
            LCD_Y_LENGTH = ILI9806G_MORE_PIXEL;
        }
        else
        {
            // 1 3 5 7模式下X方向像素宽度为854,Y方向为480
            LCD_X_LENGTH = ILI9806G_MORE_PIXEL;
            LCD_Y_LENGTH = ILI9806G_LESS_PIXEL;
        }
    
        // 0x36命令参数的高3位可用于设置GRAM扫描方向
        ILI9806G_Write_Cmd(0x36);
        ILI9806G_Write_Data(0x00 | (ucOption << 5)); //根据ucOption的值设置LCD参数,共0-7种模式
        ILI9806G_Write_Cmd(CMD_SetCoordinateX);
        ILI9806G_Write_Data(0x00);                             /* x 起始坐标高8位 */
        ILI9806G_Write_Data(0x00);                             /* x 起始坐标低8位 */
        ILI9806G_Write_Data(((LCD_X_LENGTH - 1) >> 8) & 0xFF); /* x 结束坐标高8位 */
        ILI9806G_Write_Data((LCD_X_LENGTH - 1) & 0xFF);        /* x 结束坐标低8位 */
    
        ILI9806G_Write_Cmd(CMD_SetCoordinateY);
        ILI9806G_Write_Data(0x00);                             /* y 起始坐标高8位 */
        ILI9806G_Write_Data(0x00);                             /* y 起始坐标低8位 */
        ILI9806G_Write_Data(((LCD_Y_LENGTH - 1) >> 8) & 0xFF); /* y 结束坐标高8位 */
        ILI9806G_Write_Data((LCD_Y_LENGTH - 1) & 0xFF);        /* y 结束坐标低8位 */
    
        /* write gram start */
        ILI9806G_Write_Cmd(CMD_SetPixel);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    注意0x36寄存器bit3是配置数据为RGB还是BGR,若实际使用过程中R与B颜色错位,则需将此位置1,即使用ILI9806G_Write_Data(0x0f | (ucOption << 5));

    image-20220909161743166

    绘制矩形

    绘制矩形步骤:

    image-20220718150753050

    //绘制矩形 RGB565
    void LCD_Draw_Rect(uint16_t x0, uint16_t x1, uint16_t y0, uint16_t y1, uint16_t color)
    {
        ILI9806G_Write_Cmd(0x2a);
        ILI9806G_Write_Data((x0 >> 8) & 0xFF); // x0高8位
        ILI9806G_Write_Data(x0 & 0xFF);
        ILI9806G_Write_Data((x1 >> 8) & 0xFF); // x1高8位
        ILI9806G_Write_Data(x1 & 0xFF);
    
        ILI9806G_Write_Cmd(0x2b);
        ILI9806G_Write_Data((y0 >> 8) & 0xFF); // y0高8位
        ILI9806G_Write_Data(y0 & 0xFF);
        ILI9806G_Write_Data((y1 >> 8) & 0xFF); // y1高8位
        ILI9806G_Write_Data(y1 & 0xFF);
    
        ILI9806G_Write_Cmd(0x2c); // 写入像素命令(往定义的矩形框内按扫描方向进行写入)
        for (uint32_t i = 0; i < (x1 - x0 + 1) * (y1 - y0 + 1); i++){
            ILI9806G_Write_Data(color);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    References

    • STM32的FSMC详解
    • STM32F4XX中文参考手册.pdf
    • ILI9806G-Data Sheet for all customers(V100)_20140417.pdf
    • STM32 库开发实战指南.pdf

    END

  • 相关阅读:
    sandman_nc_2016
    (免费分享)基于springboot医药进销存系统
    束搜索-binsearch
    NLP入门——语言结构/语言建模
    数字信号处理-8-自相关
    过滤和分页源码、接口文档、jwt介绍和构成、base64编码、drf-jwt使用
    [山东科技大学OJ]2301 Problem G: 车牌限行
    基于LangChain的LLM应用开发3——记忆
    【数据架构】数据网格与 Data Fabric:了解差异
    WEB应用
  • 原文地址:https://blog.csdn.net/kouxi1/article/details/126787134