FSMC实现8080时序驱动SSD1963(LCD驱动芯片)–原理->编码

一、本文摘要

本文主要基于STM32F407ZET6的FSMC控制器,实现了LCD的驱动芯片的读写通信测试,实现了对SSD1963的读写控制,后面将介绍其中的驱动代码和调试过程,着重结合实际调试波形分析读写时序。

二、硬件及原理介绍

图1 STM32与SSD1963硬件连接
如图所示,stm32与ssd1963通过FSMC总线连接,其中值得注意的是FSMC_A18地址线当作SSD1963的D/C#(数据/指令线),通过该信号告知SSD1963当前数据总线上的数据为parameter还是command。

1.SSD1963介绍(8080时序)

虽然该芯片具备6800和8080两种通信方式,但是由于至调试了8080时序,这里仅对8080时序做介绍。

(1)接口

图2 SSD1963硬件框图
表1 SSD1963 控制管脚信息
结合图表信息,8080时序主要使用表中红色框标注的控制及数据总线,先不写TE信号,自己没用到(尾注为#的说明该信号为低电位有效),包括片选信号线CS#,数据/指令信号线D/C#,读信号线RD#,写信号线WR#,和数据总线D[23:0]。这里说一下数据总线,虽然是24位总线,但实际MCU与SSD1963通信为8位并行总线。这里贴出手册的原文。
图3 数据总线解释
通过上面两段话,我们可以知道,***当读写SSD1963寄存器时,数据总线仅低八位有效,但当读写显示数据时,将根据按下表数据格式将颜色数据打包至数据总线上。***我采用565数据格式,则可以一次将显示数据通过D[15:0]将数据写入或读出。综上,在硬件连接时,使用16位数据总线。

图4 显示数据总线格式

(2)时序

下面三张图介绍了芯片通过8080时序读写数据的相关参数。主要包括tACC,数据访问时间,不少于32ns,片选信号时间tCS,不少于2ns,地址建立时间tAS,不少于1ns。片选信号高电位时间,即读写切换时间,tPWCSH,根据情况不同,时间长短不同,如连续写入,不少于13ns,使用典型值1.5*芯片主时钟周期(100M-10ns),不少于15ns,先写后读和连续读出,切换时间不少于80ns,使用典型值90ns。这段话,主要指导FSMC时序参数设置
表2 芯片时序参数
图5 写时序
图6 读时序

2.STM32F407ZET6 FSMC控制器介绍

先上框图。该模块,使用AHB总线配置寄存器,系统使用HCLK-168Mhz。根据***SSD1963硬件接口特征***,匹配FSMC总线,选用存储bank1,模式A访问。即片选信号线选用FSMC_NE1。读写信号线分别为FSMC_NOE和FSMC_NWE,均为低电位有效。选用FSMC_A18地址线当作指令/数据线。
图7 FSMC控制器框图

(1)地址映射

STM32为32位地址线,根据片选信号,确定使用地址空间为bank1:0x60000000-0x6fffffff;
其中高四位固定为6,HADDR[27:26]又将bank1划分为4个小分区,这里使用第一分区。剩下26位为地址线根据具体地址线连接和数据线格式确定实际地址。
在这里插入图片描述
在这里插入图片描述
注:FSMC地址线(HADDR)按字节寻址,内部存储器按字寻址。
因此,当数据线选用8位,即按八位数据寻址时,地址线组合出来的地址也是STM32内存访问地址。如本帖提到的采用A18地址线作为D/C#线,如下图所示,可得数据读写地址为0x60040000,指令读写地址为0x60000000;
数据读写地址
命令读写地址
但当数据线选用16位,按16位数据寻址时,根据,表186所示,HADDR[25:1]右移1位发送至地址线上。则内部访问地址应将A18左移一位,即改变第19位。则数据访问地址为0x60080000,指令访问地址为0x60000000。
在这里插入图片描述

(2)时序

这个也是困扰我很久的,如何将FSMC的控制时序与SSD1963 8080时序对应。
在这里插入图片描述
在这里插入图片描述

片选信号测量
写信号测量
读信号测量
两次读写实物转换时间测量

三、贴代码

GPIO、时钟、控制器时序参数设置

/**
 * FSMC I/O, clk, control and  time parameter configuration.
 * .
 * @param[in]	void.
 * @param[out]	void. 
 * @retval	void
 * @hardware 
 * NOE-PD4	NWE-PD5	NE1-PD7	D/C#(A18)-PD13
 * D0-PD14	D1-PD15	D2-PD0	D3-PD1	D4:D12-PE7:PE15
 * D13-PD8	D14-PD9	D15-PD10
 * RST-PB1
 * @par History
 * 		Lixiang,20211220,created
 */
void LCDHostConfig(void)
{
	//1.relevant clk config
	RCC->AHB1ENR |= (3<<3)|(1<<1);					//open gpiod/gpioe/gpiob clock
	//2.GPIO config
	GPIOD->MODER 		&= ~(((uint32_t)3<<0)|((uint32_t)3<<1*2)|((uint32_t)3<<4*2)|((uint32_t)3<<5*2)|((uint32_t)3<<7*2)|((uint32_t)3<<8*2)|((uint32_t)3<<9*2)|((uint32_t)3<<10*2)|((uint32_t)3<<13*2)|((uint32_t)3<<14*2)|((uint32_t)3<<15*2));
	GPIOD->MODER 		|= ((uint32_t)2<<0)|((uint32_t)2<<1*2)|((uint32_t)2<<4*2)|((uint32_t)2<<5*2)|((uint32_t)2<<7*2)|((uint32_t)2<<8*2)|((uint32_t)2<<9*2)|((uint32_t)2<<10*2)|((uint32_t)2<<13*2)|((uint32_t)2<<14*2)|((uint32_t)2<<15*2);					//设为复用模式
	GPIOD->OTYPER 	&= ~((1<<0)|(1<<1)|(1<<4)|(1<<5)|(1<<7)|(1<<8)|(1<<9)|(1<<10)|(1<<13)|(1<<14)|((uint32_t)1<<15));														//推挽输出
	GPIOD->OSPEEDR 	&= ~((3<<0)|(3<<1*2)|(3<<4*2)|(3<<5*2)|(3<<7*2)|(3<<8*2)|(3<<9*2)|(3<<10*2)|(3<<13*2)|((uint32_t)3<<14*2)|((uint32_t)3<<15*2));
	GPIOD->OSPEEDR 	|= ((uint32_t)2<<0)|((uint32_t)2<<1*2)|((uint32_t)2<<4*2)|((uint32_t)2<<5*2)|((uint32_t)2<<7*2)|((uint32_t)2<<8*2)|((uint32_t)2<<9*2)|((uint32_t)2<<10*2)|((uint32_t)2<<13*2)|((uint32_t)2<<14*2)|((uint32_t)2<<15*2);					//输出速度设为50Mhz
	GPIOD->PUPDR 		&= ~(((uint32_t)3<<0)|((uint32_t)3<<1*2)|((uint32_t)3<<4*2)|((uint32_t)3<<5*2)|((uint32_t)3<<7*2)|((uint32_t)3<<8*2)|((uint32_t)3<<9*2)|((uint32_t)3<<10*2)|((uint32_t)3<<13*2)|((uint32_t)3<<14*2)|((uint32_t)3<<15*2));				//无上下拉电阻	
	GPIOD->AFR[0] 	&= ~(((uint32_t)15<<0)|((uint32_t)15<<1*4)|((uint32_t)15<<4*4)|((uint32_t)15<<5*4)|((uint32_t)15<<7*4));
	GPIOD->AFR[1] 	&= ~(((uint32_t)15<<(8-8)*4)|((uint32_t)15<<(9-8)*4)|((uint32_t)15<<(10-8)*4)|((uint32_t)15<<(13-8)*4)|((uint32_t)15<<(14-8)*4)|((uint32_t)15<<(15-8)*4));
	GPIOD->AFR[0] 	|= ((uint32_t)12<<0)|((uint32_t)12<<1*4)|((uint32_t)12<<4*4)|((uint32_t)12<<5*4)|((uint32_t)12<<7*4);
	GPIOD->AFR[1] 	|= ((uint32_t)12<<(8-8)*4)|((uint32_t)12<<(9-8)*4)|((uint32_t)12<<(10-8)*4)|((uint32_t)12<<(13-8)*4)|((uint32_t)12<<(14-8)*4)|((uint32_t)12<<(15-8)*4);												//复用至FSMC
	GPIOE->MODER		&= ~((uint32_t)0x3FFFF<<14);
	GPIOE->MODER		|= (uint32_t)0x2AAAA<<14;																																													//复用模式
	GPIOE->OTYPER		&= ~(0x1F<<7);																																																		//推挽输出
	GPIOE->OSPEEDR	&= ~((uint32_t)0x3FFFF<<14);
	GPIOE->OSPEEDR	|= (uint32_t)0x2AAAA<<14;																																													//输出速度设为50Mhz
	GPIOE->PUPDR		&= ~((uint32_t)0x3FFFF<<14);																																											//无上下拉电阻
	GPIOE->AFR[0]		&= ~((uint32_t)15<<28);
	GPIOE->AFR[0]		|= ((uint32_t)12<<28);
	GPIOE->AFR[1]		=	0xCCCCCCCC;																																																			//复用至FSMC
	GPIOB->MODER		&= ~(3<<2);
	GPIOB->MODER		|= (1<<2);																																																				//通用输出
	GPIOB->OTYPER		&= ~(1<1);																																																				//推挽输出
	GPIOB->OSPEEDR	&= ~(3<<2);																																				
	GPIOB->OSPEEDR	|= (1<<2);																																																				//输出速度设为50Mhz
	GPIOB->PUPDR		&= ~(3<<2);
	GPIOB->PUPDR		|= (1<<2);																																																				//上拉电阻
	SSD1963RST(HIGH);//默认拉高
	//3.FSMC control and time parameter set--选用异步通信模式A
	RCC->AHB3ENR |= (1<<0);											//open fsmc register clock
	FSMC_Bank1->BTCR[0] = 0;										//BCR1配置
	FSMC_Bank1->BTCR[0] |= (1<<12) | (0<<4) |(1<<0);																																									//参照数据手册表197,数据位宽8位,自定义时序时间,(1<<14) --EXTMOD,| (0<<2) --存储器类型
	FSMC_Bank1->BTCR[1] =	0;						//BTR1配置
	FSMC_Bank1->BTCR[1] |=	(8<<8) | (15<<16) |(1<<0);																																													//数据建立时间:9*HCLK,地址建立时间5*HCLK
	//FSMC_Bank1E->BWTR[0] &= ~((3<<28) | (0xff<<8)| (0xf<<0) | (0xf<<16));	
	//FSMC_Bank1E->BWTR[0] |= (9<<8) |(5<<0);																																													//数据建立时间:9*HCLK,地址建立时间5*HCLK
}

SSD1963初始化代码

/**
 * ssd1963 chip initial.
 * .
 * @param[in]	void.
 * @param[out]	uint8_t,the result of initial,0--success,1--fail. 
 * @retval	void
 * @par History
 * 		Lixiang,20211223,created
 */
uint8_t LCDHardwareReset(void)
{	
	uint8_t err[5];
	
	LCDHostConfig();	//gpio and fsmc controller set
	SSD1963RST(LOW);
	DELAYMS(10);
	SSD1963RST(HIGH);															//根据手册,硬件复位时间不少于100us,设为1ms
	DELAYMS(10);
	
	CMD_REG = SET_PLL_MN;													//设置PLL分频系数
	DAT_REG = 0x1D;
	DAT_REG = 0x02;
	DAT_REG = 0x54;
	CMD_REG = SET_PLL;			
	DAT_REG = 0x01;															//使能PLL
	DELAYUS(120);
	CMD_REG = SET_PLL;				
	DAT_REG = 0x03;															//等待PLL稳定,设置为系统时钟
	CMD_REG = SOFT_RESET;												// software reset
	DELAYMS(5);
	while(err[0] != 0x04)											//get pll status
	{
		err[1] = 10;
		CMD_REG = GET_PLL_STATUS;
		err[0] = DAT_REG;	
	}
	CMD_REG = GET_PLL_MN;													//check the pll_mn,1D,02,04
	err[0] = DAT_REG;
	err[1] = DAT_REG;
	err[2] = DAT_REG;
	CMD_REG = READ_DDB;														//check the chip information,always01,57,61,01,ff
	err[0] = DAT_REG;
	err[1] = DAT_REG;
	err[2] = DAT_REG;
	err[3] = DAT_REG;
	err[4] = DAT_REG;
	if((err[0]==0x01)&&(err[1]==0x57)&&(err[2]==0x61)&&(err[3]==01)&&(err[4]==0xff))	return 0;//测试通信是否正常
	else return 1;
}

至此,完成了SSD1963的初始化和通信时序调试,下一步详细的驱动程序再做笔记。

四、调试问题

问题代码
在这里插入图片描述
如上面代码所示,将指针强制转换为32位数据访问,当写数据时,一条写操作代码,通过示波器捕捉cs信号,如下图所示,发现触发两次写数据操作。改为*(uint16_t*)就解决了这个问题。
在这里插入图片描述

先贴点图,后面补充完整。首次写长文,望多多鼓励,

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码

)">
< <上一篇

)">
下一篇>>