单片机FSMC模拟8080接口时序,驱动液晶屏
LCD并口时序图
某34pinLCD引脚图,内部驱动为S6B33B2
通过对比可以看到8080时序除了RS线其它的和FSMC很像。
FSMC-NOR flash和8080信号线按照下面方式对接
FSMC-NOR信号线 | 功能 | 8080信号线 | 功能 |
---|---|---|---|
NEx | 片选信号 | CS片选 | 片选信号 |
NWE | 写使能 | WR | 写使能 |
NOE | 读使能 | RD | 读使能 |
D[15:0] | 数据信号 | D[15:0] | 数据信号 |
A0 | 地址信号0 | RS | 数据/命令选择 |
8080接口的RS可以和FSMC任何一个地址线A连接,这样高电平时数据线D就会被数据成数值,低电平时就会被处理成命令。
如何让A0为确定的电平呢,只需向FSMC的地址线上发送奇数,A0就是高电平。向FSMC地址线上发送偶数,A0就是低电平。
寄存器配置
在stm32CubeMX里直接选择内存类型为LCD接口,需要配置的寄存器选项已经列出来了,不需要配置的寄存器是灰色的。
如果启用了扩展模式下面将有模式A和模式D可选
配置三个保持时间
- AddressSetupTime 地址建立时间 0-15 个 HCLK 周期
- DataSetupTime 数据建立时间 1-255 个 HCLK 周期
- BusTurnAround 总线转换周期 0-15个 HCLK 周期
生成代码如下:
SRAM_HandleTypeDef hsram1;
/* FSMC initialization function */
void MX_FSMC_Init(void)
{
/* USER CODE BEGIN FSMC_Init 0 */
/* USER CODE END FSMC_Init 0 */
FSMC_NORSRAM_TimingTypeDef Timing = {0};
/* USER CODE BEGIN FSMC_Init 1 */
/* USER CODE END FSMC_Init 1 */
/** Perform the SRAM1 memory initialization sequence
*/
hsram1.Instance = FSMC_NORSRAM_DEVICE;
hsram1.Extended = FSMC_NORSRAM_EXTENDED_DEVICE;
/* hsram1.Init */
hsram1.Init.NSBank = FSMC_NORSRAM_BANK1; //bank内部区域的第一个小块, 选择NE1
hsram1.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE;//地址/数据不复用
hsram1.Init.MemoryType = FSMC_MEMORY_TYPE_SRAM;//存储器类型SRAM
hsram1.Init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16;//16位数据位宽
hsram1.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE;//是否突发,仅对同步突发存储器有用
hsram1.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW;//等待信号的极性, 仅在突发模式访问下有用
hsram1.Init.WrapMode = FSMC_WRAP_MODE_DISABLE;//关闭突发模式
hsram1.Init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS;//在SRAM向fsmc发出数据脉冲时的前一个时钟周期,发出等待信号
hsram1.Init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE;//存储器写使能
hsram1.Init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE;//等待使能位,未用到
hsram1.Init.ExtendedMode = FSMC_EXTENDED_MODE_DISABLE;//读写使用相同的时序
hsram1.Init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE;//同步传输模式等待信号, 未用到
hsram1.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE;//禁止突发写
hsram1.Init.PageSize = FSMC_PAGE_SIZE_NONE; //指定页的大小,操作CRAM用*/
/* Timing */
Timing.AddressSetupTime = 0xf;
Timing.AddressHoldTime = 15;
Timing.DataSetupTime = 0xff;
Timing.BusTurnAroundDuration = 0xf;
Timing.CLKDivision = 16;
Timing.DataLatency = 17;
Timing.AccessMode = FSMC_ACCESS_MODE_A;
/* ExtTiming */
if (HAL_SRAM_Init(&hsram1, &Timing, NULL) != HAL_OK)
{
Error_Handler( );
}
/* USER CODE BEGIN FSMC_Init 2 */
/* USER CODE END FSMC_Init 2 */
}
初始化FSMC用了两个类型的结构体 **SRAM_HandleTypeDef ** 和 FSMC_NORSRAM_TimingTypeDef
1 第一个SRAM_HandleTypeDef 结构体
第一个类型结构体是配置存储器寄存器的,只到里面的前三个成员。
1.1 FSMC的基地址,因为FSMC的第一个寄存器是FSMC_BCR1,所以这里初始化也是FSMC_BCR1寄存器的地址。
FMC_NORSRAM_TypeDef *Instance;
#define FSMC_R_BASE 0xA0000000UL /*!< FSMC registers base address */
1. 2 扩展寄存器地址
FMC_NORSRAM_EXTENDED_TypeDef *Extended;
1.3 第三个成员也是结构体类型用来配置SRAM寄存器的结构体:
FMC_NORSRAM_InitTypeDef Init;
typedef struct
{
uint32_t NSBank; /*!< /*设置要控制的 Bank 区域 参数定义参考 @ref FMC_NORSRAM_Bank*/
uint32_t DataAddressMux; /*!< 设置地址总线与数据总线是否复用 参数定义参考 @ref FMC_Data_Address_Bus_Multiplexing*/
uint32_t MemoryType; /*!< 设置存储器的类型 参数定义参考 @ref FMC_Memory_Type*/
uint32_t MemoryDataWidth; /*!< 设置存储器的数据宽度 参数定义参考 @ref FMC_NORSRAM_Data_Width */
uint32_t BurstAccessMode; /*!< 设置是否支持突发访问模式,只支持同步类型 ,对异步不起作用 参数定义参考 @ref FMC_Burst_Access_Mode*/
uint32_t WaitSignalPolarity; /*!< 设置等待信号的极性 参数定义参考 @ref FMC_Wait_Signal_Polarity */
uint32_t WrapMode; /*!< 设置是否支持对齐的突发模式 参数定义参考 @ref FMC_Wrap_Mode */
uint32_t WaitSignalActive; /*!< 配置等待信号在等待前有效还是等待期间有效 参数定义参考 @ref FMC_Wait_Timing */
uint32_t WriteOperation; /*!< 设置使能或者禁止写保护 参数定义参考 @ref FMC_Write_Operation */
uint32_t WaitSignal; /*!< 设置是否使能等待状态插入 参数定义参考 @ref FMC_Wait_Signal */
uint32_t ExtendedMode; /*!< 设置是否使能扩展模式 参数定义参考 @ref FMC_Extended_Mode */
uint32_t AsynchronousWait; /*!< 设置是否使能等待信号 参数定义参考 @ref FMC_AsynchronousWait */
uint32_t WriteBurst; /*!< 设置是否使能写突发操作 参数定义参考 @ref FMC_Write_Burst */
uint32_t ContinuousClock; /*!< 启用或禁用FMC时钟输出到外部存储器设备 参数定义参考 @ref FMC_Continous_Clock */
uint32_t WriteFifo; /*!< 启用或禁用FMC控制器使用的写FIFO功能。通过FMC_BCR1寄存器启用 参数定义参考 @ref FMC_Write_FIFO */
uint32_t PageSize; /*!< 指定页的大小 参数定义参考 @ref FMC_Page_Size */
} FMC_NORSRAM_InitTypeDef;
2 第二个FSMC_NORSRAM_TimingTypeDef结构体
typedef struct
{
uint32_t AddressSetupTime; /*!< 地址建立时间,范围最小是0,最大是15,不适用于同步 */
uint32_t AddressHoldTime; /*!< 地址保持时间,范围最小是1,最大是15,不适用于同步 */
uint32_t DataSetupTime; /*!< 数据建立时间,范围最小是1,最大是 255.适用于 SRAM, ROM 和异步NOR Flash . */
uint32_t BusTurnAroundDuration; /*!< 总线恢复时间,范围最小是1,最大是15,只适用于 NOR Flash */
uint32_t CLKDivision; /*!< 时钟分频因子,范围最小是2,最大是16,@不适用于异步*/
uint32_t DataLatency; /*!< 同步突发 模式数据延迟 */
uint32_t AccessMode; /*!< 异步模式配置 定义参考 @ref FSMC_Access_Mode*/
} FSMC_NORSRAM_TimingTypeDef;
时序配置:
每个bank内的小块 | 地址 映射 | 外部引脚 | HADDR[27:26] |
---|---|---|---|
1 | 0x60000000-0x63FFFFFF | FSMC_NE1 | 00 |
2 | 0x64000000-0x67FFFFFF | FSMC_NE2 | 01 |
3 | 0x68000000-0x6BFFFFFF | FSMC_NE3 | 10 |
4 | 0x6C000000-0x6FFFFFFF | FSMC_NE4 | 11 |
由上图可知,只需关心的是读和写操作的低脉宽是50ns,高脉宽是30ns,数据建立时间是5ns,数据保持时间是28ns。这些是时序要求的最小时间,实际操作时只要比这个大就行。
FSMC的时钟HCLK是168MHz,1 000 000 000 ns ÷ 168 000 000Hz =1000/168≈5.95ns
因为FSMC _NE1和8080_CS连接,所以访问0x60000000-0x63FFFFFF地址时,这个引脚就会产生有效的片选信号。
FSMC _A0接8080_RS, 所以访问0x60000000-0x63FFFFFF地址时,奇数地址就会产生高电平,偶数地址就会产生低电平。
FSMC-NOR信号线 | GPIO引脚 | 8080接口 |
---|---|---|
FSMC_NE1 | PD7 | CS 片选 |
FSMC_A0 | PF0 | RS 数据/命令选择 |
FSMC_NWE | PD5 | WR 写使能 |
FSMC_NOE | PD4 | RD 读使能 |
FSMC_D0 | PD14 | 数据信号 |
FSMC_D1 | PD15 | 数据信号 |
FSMC_D2 | PD0 | 数据信号 |
FSMC_D3 | PD1 | 数据信号 |
FSMC_D4 | PE7 | 数据信号 |
FSMC_D5 | PE8 | 数据信号 |
FSMC_D6 | PE9 | 数据信号 |
FSMC_D7 | PE10 | 数据信号 |
FSMC_D8 | PE11 | 数据信号 |
FSMC_D8 | PE12 | 数据信号 |
FSMC_D10 | PE13 | 数据信号 |
FSMC_D11 | PE14 | 数据信号 |
FSMC_D12 | PE15 | 数据信号 |
FSMC_D13 | PD8 | 数据信号 |
FSMC_D14 | PD9 | 数据信号 |
FSMC_D15 | PD10 | 数据信号 |
测试程序:
void LCD_Writr_Test()
{
*(__IO uint16_t*)(0x60000000) =0XFFA;
HAL_Delay(500);
*(__IO uint16_t*)(0x60000000+2) =0XFAF;
}
可以看得到写0XFFA时RS是低电平,写0XFAF时RS是高电平。