stm32 FSMC LCD

本文深入解析FSMC(静态存储器控制器)的工作原理及其在STM32微控制器中的应用。介绍了如何通过FSMC控制器实现NOR闪存、PSRAM及LCD等外部设备的驱动配置,并详细解释了地址线、数据线及控制线的分配方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

FSMC全称“静态存储器控制器”。 

使用FSMC控制器后,可以把FSMC提供的FSMC_A[25:0]作为地址线,而把FSMC提供的FSMC_D[15:0]作为数据总线。 

(1)当存储数据设为8位时,(FSMC_NANDInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_8b) 地址各位对应FSMC_A[25:0],数据位对应FSMC_D[7:0]

 (2)当存储数据设为16位时,(FSMC_NANDInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b) 地址各位对应FSMC_A[24:0],数据位对应FSMC_D[15:0] FSMC 包括4个模块: 

(1)AHB接口(包括FSMC配置寄存器) 

(2)NOR闪存和PSRAM控制器(驱动LCD的时候LCD就好像一个PSRAM的里面只有2个16位的存储空间,一个是DATA RAM 一个是CMD RAM) 

(3)NAND闪存和PC卡控制器 

(4)外部设备接口 注:FSMC可以请求AHB进行数据宽度的操作。如果AHB操作的数据宽度大于外部设备(NOR或NAND或LCD)的宽度,此时FSMC将AHB操作分割成几个连续的较小的数据宽度,以适应外部设备的数据宽度。 FSMC对外部设备的地址映像从0x6000 0000开始,到0x9FFF FFFF结束,共分4个地址块,每个地址块256M字节。可以看出,每个地址块又分为4个分地址块,大小64M。对NOR的地址映像来说,我们可以通过选择HADDR[27:26]来确定当前使用的是哪个64M的分地址块,如下页表格。而这四个分存储块的片选,则使用NE[4:1]来选择。数据线/地址线/控制线是共享的。

NE1 ->Bank1 NE2->Bank2 NE3->Bank3 NE4->Bank4 

若 NE1 连接,则 每小块NOR/PSRAM 64M 

第一块:6000 0000h--63ff ffffh (DATA长度为8位情况下,由地址线FSMC_A[25:0]决定;DATA长度为16位情况下,由地址线FSMC_A[24:0]决定)

 第二块:6400 0000h--67ff ffffh 第二块:6800 0000h--6bff ffffh 

第三块:6c00 0000h--6fff ffffh 

注:这里的HADDR是需要转换到外部设备的内部AHB地址线,每个地址对应一个字节单元。因此,若外部设备的地址宽度是8位的,则HADDR[25:0]与STM32的CPU引脚FSMC_A[25:0]一一对应,最大可以访问64M字节的空间。若外部设备的地址宽度是16位的,则是HADDR[25:1]与STM32的CPU引脚FSMC_A[24:0]一一对应。在应用的时候,可以将FSMC_A总线连接到存储器或其他外设的地址总线引脚上。

例:STM32F10XX FCMS控制LCD的驱动 

FSMC提供了所有的LCD控制器的信号:

 FSMC_D[16:0]  16bit的数据总线 

FSMC NEx:分配给NOR的256M,再分为4个区,每个区用来分配一个外设,这四个外设的片选分为是NE1-NE4,对应的引脚为:PD7—NE1,PG9—NE2,PG10-NE3,PG12—NE4 

FSMC NOE:输出使能,连接LCD的RD脚。

 FSMC NWE:写使能,连接LCD的RW脚。

 FSMC Ax:用在LCD显示RAM和寄存器之间进行选择的地址线,即该线用于选择LCD的RS脚,该线可用地址线的任意一根线,范围:FSMC_A[25:0]。

 注:RS = 0时,表示读写寄存器;RS = 1表示读写数据RAM。

 举例1:选择NOR的第一个存储区,并且使用FSMC_A16来控制LCD的RS引脚,则我们访问LCD显示RAM的基址为0x6002 0000,访问LCD寄存器的地址为:0x6000 0000。因为数据长度为16bit ,所以FSMC_A[24:0]对应HADDR[25:1] 所以显示RAM的基址=0x60000000+2^16*2=0x60000000+0x2 0000=0x60020000 

举例2:选择NOR的第四个存储区,使用FSMC_A0控制LCD的RS脚,则访问LCD显示RAM的基址为0x6c00 0002,访问LCD寄存器的地址为:0x6c00 0000。 

例:

 FSMC_D[15:0],连16bit数据线;FSMC_NE1,连片选:只有bank1可用 FSMC NOE:输出使能 FSMC NEW:FSMC写使能 FSMC Ax:连接RS,可用范围FSMC_A[24:0] 一般使用模式B来做LCD的接口控制,不适用外扩模式。并且读写操作的时序一样。此种情况下,我们需要使用三个参数:ADDSET,DATAST,ADDHOLD。这三个参数在位域FSMC_TCRx中设置。 当HCLK的频率是72MHZ,使用模式B,则有如下时序: 地址建立时间:0x1 地址保持时间:0x0 数据建立时间:0x2 注:这里地址建立地址保持数据建立三个时间不知道怎么设出来的。。。。。我是根据别人的经验来设定的。高手知道这个设置不同有什么区别的话,请指教,谢谢:)

void LCD_CtrlLinesConfig(void)

{
  GPIO_InitTypeDef GPIO_InitStructure;


  /* Enable GPIOD, GPIOE, GPIOF, GPIOG and AFIO clocks */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOG | RCC_AHB1Periph_GPIOE |
                         RCC_AHB1Periph_GPIOF, ENABLE);


/*-- GPIO Configuration ------------------------------------------------------*/
  /* SRAM Data lines,  NOE and NWE configuration */
  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_Pin_4 |GPIO_Pin_5;;
  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_NOPULL;


  GPIO_Init(GPIOD, &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_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);


  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);


  /* SRAM Address lines configuration */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_Init(GPIOF, &GPIO_InitStructure);  
  GPIO_PinAFConfig(GPIOF, GPIO_PinSource0, GPIO_AF_FSMC);   


  /* NE3 configuration */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; 


  GPIO_Init(GPIOG, &GPIO_InitStructure);
  GPIO_PinAFConfig(GPIOG, GPIO_PinSource10, GPIO_AF_FSMC);

}

void LCD_FSMCConfig(void)
{
  FSMC_NORSRAMInitTypeDef  FSMC_NORSRAMInitStructure;
  FSMC_NORSRAMTimingInitTypeDef  p;
   
  /* Enable FSMC clock */
  RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC, ENABLE);
  
/*-- FSMC Configuration ------------------------------------------------------*/
/*----------------------- SRAM Bank 3 ----------------------------------------*/
  /* FSMC_Bank1_NORSRAM4 configuration */
  p.FSMC_AddressSetupTime = 3;
  p.FSMC_AddressHoldTime = 0;
  p.FSMC_DataSetupTime = 9;
  p.FSMC_BusTurnAroundDuration = 0;
  p.FSMC_CLKDivision = 0;
  p.FSMC_DataLatency = 0;
  p.FSMC_AccessMode = FSMC_AccessMode_A;
  /* Color LCD configuration ------------------------------------
     LCD configured as follow:
        - Data/Address MUX = Disable
        - Memory Type = SRAM
        - Data Width = 16bit
        - Write Operation = Enable
        - Extended Mode = Enable
        - Asynchronous Wait = Disable */


  FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM3;
  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_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 = &p;
  FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p;


  FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);   


  /* Enable FSMC NOR/SRAM Bank3 */
  FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM3, ENABLE);
}

<think>好的,我现在要解决的问题是如何在STM32中通过FSMC驱动LCD显示。首先,我需要了解FSMC的基本概念和它在STM32中的作用。根据提供的引用资料,FSMC是灵活的静态存储控制器,可以连接多种存储器,比如SRAM、NAND FLASH等。但用户提到的是用FSMC来控制8080并口的LCD,这让我有点困惑,因为通常FSMC用于存储器,但显然这里被用来驱动LCD。需要理解为什么FSMC可以用于LCD驱动。 接下来,我需要回顾引用中的内容。引用[2]提到,FSMC一般是用来连接存储设备的,但可以用来控制8080并口的LCD。这说明8080接口的LCD可能被当作存储器设备来访问,这样FSMC就能通过类似存储器读写的方式操作LCD的控制信号。这可能涉及到将LCD的寄存器映射到某个内存地址,通过写入该地址来发送命令或数据。 然后,我需要考虑如何配置FSMC模块。根据引用[3],STM32F4的FSMC支持多种存储器类型,而LCD可能被配置为类似SRAM的接口。需要确定FSMC的初始化参数,比如时序配置、地址映射等。此外,HAL库的使用也是关键,用户提到了使用CUBEMX配置,所以可能需要通过图形化界面选择FSMC参数,生成初始化代码。 接下来是具体的步骤。首先在CubeMX中启用FSMC,并选择对应的接口类型为LCD或8080。然后配置地址线、数据线、控制信号(如读/写、片选等)的引脚。根据LCD的数据手册,设置正确的时序参数,比如建立时间、保持时间等。接着生成代码,并在HAL库中调用相应的函数进行初始化。 然后是LCD的初始化和显示驱动部分。需要按照LCD的规格书,通过FSMC发送初始化命令序列,设置显示模式、分辨率等。之后,可以通过内存写入的方式向LCD的显存地址写入像素数据,实现图像显示。可能还需要处理不同的颜色格式,比如RGB565或RGB888,并转换为LCD支持的格式。 在代码实现方面,可能需要定义LCD的基地址,将命令和数据写入特定的地址偏移。例如,写入命令时访问基地址+0,写入数据时访问基地址+1,或者类似的结构。这取决于LCD的8080接口的具体设计。 此外,还需要注意FSMC的bank选择,不同的存储区域可能对应不同的片选信号,需要根据硬件连接选择正确的bank和片选引脚。同时,确保GPIO的配置正确,特别是复用功能是否正确设置为FSMC相关信号。 在调试过程中,可能会遇到时序不匹配导致LCD无法正常工作的问题。这时需要检查FSMC的时序配置是否符合LCD的要求,可能需要调整建立时间和保持时间的参数。使用逻辑分析仪或示波器观察控制信号的波形,确认时序是否符合预期。 最后,综合以上步骤,整理出一个清晰的配置流程,包括CubeMX设置、FSMC初始化、LCD初始化命令发送、以及像素数据写入的方法。同时,需要参考具体的LCD数据手册,因为不同型号的LCD可能有不同的命令和初始化序列。 可能还需要考虑性能优化,比如使用DMA传输数据以提高刷新率,或者利用FSMC的突发传输模式。不过对于基础应用,可能不需要这些高级功能,但了解这些选项对于后续优化有帮助。 总结来说,关键步骤包括:理解FSMCLCD的接口原理、CubeMX配置FSMC参数、硬件连接检查、时序配置、初始化代码生成、LCD命令发送、以及像素数据写入的实现。需要结合参考资料中的信息,特别是引用[1]和[2]提到的具体配置教程,来确保每一步的正确性。</think>### STM32 FSMC驱动LCD显示配置教程 #### **1. FSMCLCD接口原理** FSMC(Flexible Static Memory Controller)通过模拟存储器接口控制8080并口LCDLCD的寄存器被映射到特定内存地址,写入数据时,FSMC自动生成控制信号(如读/写、片选)[^3]。例如,向地址`0x60000000`写入数据时,FSMC会触发LCD的写使能信号(WR)和数据传输。 #### **2. CubeMX配置步骤** 1. **启用FSMC模块** - 在CubeMX中打开`Connectivity > FSMC`,选择`LCD Interface`或`NOR Flash/PSRAM`模式(根据LCD类型)。 - 配置数据宽度(通常为16位,对应RGB565格式)和存储类型(如SRAM)[^2]。 2. **引脚配置** - **数据线**:连接`D0-D15`至LCD的`DB0-DB15`。 - **控制信号**: - `NOE`(读使能) → LCD的RD引脚 - `NWE`(写使能) → LCD的WR引脚 - `NE1`(片选) → LCD的CS引脚 - **地址线**:如使用A0控制命令/数据选择(RS信号),连接`A0`至LCD的RS引脚[^1]。 3. **时序配置** - 根据LCD数据手册设置`Address Setup Time`、`Data Setup Time`等参数。 - 示例(针对通用TFT-LCD): ```c FSMC_NORSRAM_TimingTypeDef Timing; Timing.AddressSetupTime = 1; // 地址建立时间(单位:HCLK周期) Timing.DataSetupTime = 2; // 数据建立时间 Timing.BusTurnAroundDuration = 0; ``` 生成代码后,HAL库会自动应用时序。 #### **3. LCD初始化与驱动代码** 1. **定义LCD基地址** 假设使用FSMC的Bank1(NE1),基地址为`0x60000000`,则: - **命令地址**:`0x60000000`(A0=0) - **数据地址**:`0x60000001`(A0=1) ```c #define LCD_CMD_ADDR (*(volatile uint16_t *)0x60000000) #define LCD_DATA_ADDR (*(volatile uint16_t *)0x60000001) ``` 2. **发送初始化命令序列** ```c void LCD_WriteCmd(uint16_t cmd) { LCD_CMD_ADDR = cmd; } void LCD_WriteData(uint16_t data) { LCD_DATA_ADDR = data; } // 示例:设置显示方向 void LCD_SetOrientation() { LCD_WriteCmd(0x36); // 命令:存储访问控制 LCD_WriteData(0x48); // 参数:竖屏模式,BGR顺序 } ``` 3. **填充像素数据** ```c void LCD_Fill(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color) { LCD_WriteCmd(0x2A); // 列地址设置 LCD_WriteData(x >> 8); LCD_WriteData(x & 0xFF); LCD_WriteData((x + width - 1) >> 8); LCD_WriteData((x + width - 1) & 0xFF); LCD_WriteCmd(0x2B); // 行地址设置 LCD_WriteData(y >> 8); LCD_WriteData(y & 0xFF); LCD_WriteData((y + height - 1) >> 8); LCD_WriteData((y + height - 1) & 0xFF); LCD_WriteCmd(0x2C); // 写入显存 for (uint32_t i = 0; i < width * height; i++) { LCD_DATA_ADDR = color; } } ``` #### **4. 调试与优化** - **时序问题**:若显示异常,检查FSMC时序是否匹配LCD要求,必要时增大`DataSetupTime`。 - **DMA加速**:使用DMA传输像素数据可提升刷新率,需配置FSMC的`Memory Burst`模式[^3]。 #### **示例电路连接(STM32F4与LCD)** | STM32引脚 | LCD引脚 | 功能 | |-----------|----------|------------| | PD7 | DB15 | 数据线高位 | | ... | ... | ... | | PD0 | DB0 | 数据线低位 | | PE1 | A0 | RS信号 | | PD4 | NOE | RD信号 | | PD5 | NWE | WR信号 | | PG12 | NE1 | CS片选 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值