STM32F407驱动TFT LCD的学习记录

  今天学习了正点原子STM32F407的TFT LCD显示实验,教程代码为了兼容多款液晶,做了检测和判断等,代码量较大。经过我的简化,专用于NT35510。

  学习过程中发现了一个关于读写通讯时序的问题,记录如下:

教程代码:

  readWriteTiming.FSMC_AddressSetupTime = 0XF;     //地址建立时间(ADDSET)为16个HCLK 1/168M=6ns*16=96ns    
  readWriteTiming.FSMC_AddressHoldTime = 0x00;     //地址保持时间(ADDHLD)模式A未用到    
  readWriteTiming.FSMC_DataSetupTime = 60;            //数据保存时间为60个HCLK    =6*60=360ns
  readWriteTiming.FSMC_BusTurnAroundDuration = 0x00;
  readWriteTiming.FSMC_CLKDivision = 0x00;
  readWriteTiming.FSMC_DataLatency = 0x00;
  readWriteTiming.FSMC_AccessMode = FSMC_AccessMode_A;     //模式A 
    

  writeTiming.FSMC_AddressSetupTime =9;          //地址建立时间(ADDSET)为9个HCLK =54ns 
  writeTiming.FSMC_AddressHoldTime = 0x00;     //地址保持时间(A        
  writeTiming.FSMC_DataSetupTime = 8;         //数据保存时间为6ns*9个HCLK=54ns
  writeTiming.FSMC_BusTurnAroundDuration = 0x00;
  writeTiming.FSMC_CLKDivision = 0x00;
  writeTiming.FSMC_DataLatency = 0x00;
  writeTiming.FSMC_AccessMode = FSMC_AccessMode_A;     //模式A 

//教程代码在下方进行液晶控制器id判断后,又重设了模式a的写时序:
//重新配置写时序控制寄存器的时序                                        
  FSMC_Bank1E->BWTR[6]&=~(0XF<<0);//地址建立时间(ADDSET)清零      
  FSMC_Bank1E->BWTR[6]&=~(0XF<<8);//数据保存时间清零
  FSMC_Bank1E->BWTR[6]|=3<<0;        //地址建立时间(ADDSET)为3个HCLK =18ns       
  FSMC_Bank1E->BWTR[6]|=2<<8;     //数据保存时间(DATAST)为6ns*3个HCLK=18ns

上述代码第一部分配置了模式A的读时序,第二部分配置了写时序,分别操作FSMC模块的寄存器BTR和BWTR。

  以写时序为例分析(读时序的道理相同),在阅读NT35510数据手册以及STM32F4参考手册后可以发现,地址建立时间ADDSET,是NWE拉低之前的高电平时间,这个时间对于NT35510来说是没有意义的,允许范围内设为任意值都可以,经实测该值确实无影响。

  而数据保持时间DATAST就是WRX的拉低时间,这个时间结束后的上升沿,液晶控制器会把端口上的数据读走。

  (图片取自我以前的其他博客,故有水印)

  

  

  根据下表,WRX拉低时间应大于15ns,整个写入周期应大于33ns。

  同理,读液晶ID时,则有RDX拉低时间大于45ns等要求。

  因此,我把时序重新配置如下:

    /* 扩展模式A读时序配置, 适应nt35510 */    
  readWriteTiming.FSMC_AddressSetupTime = 0x00; //AddressSetupTime,n*hclk
  readWriteTiming.FSMC_AddressHoldTime = 0x00; //模式A不使用AddressHoldTime    
  readWriteTiming.FSMC_DataSetupTime = 0x08;//DataSetupTime,n*hclk
  readWriteTiming.FSMC_BusTurnAroundDuration = 0x00;
  readWriteTiming.FSMC_CLKDivision = 0x00;
  readWriteTiming.FSMC_DataLatency = 0x00;
  readWriteTiming.FSMC_AccessMode = FSMC_AccessMode_A;     //模式A 
  
  /* 扩展模式A写时序配置, 适应nt35510 */
    writeTiming.FSMC_AddressSetupTime = 0x00;      //n*hclk
  writeTiming.FSMC_AddressHoldTime = 0x00;     //    
  writeTiming.FSMC_DataSetupTime = 0x02;         //(n+1)*hclk
  writeTiming.FSMC_BusTurnAroundDuration = 0x00;
  writeTiming.FSMC_CLKDivision = 0x00;
  writeTiming.FSMC_DataLatency = 0x00;
  writeTiming.FSMC_AccessMode = FSMC_AccessMode_A;     //模式A 

  问题就在这里出现,经过测试,就算我把写时序中的DATAST配置成0,一样可以正常运行,可能是因为主机进行改变IO口电平的操作本身就具有一定延迟,足以让液晶控制器准备好读走端口数据,或者其他原因。

  而读时序中的DATAST却不可以太小,否则程序就会不稳定,或者直接出错,原因应该是液晶控制器需要足够的时间在端口上准备好数据,以让主机读取。

  此外,NT35510要求的每个读周期或者写周期所要求的最小时间(例如写周期33ns),以及RDX或者WRX要求的上升沿后高电平延时(如上表所示,例如写操作要求最少15ns),我不清楚FSMC模块在硬件上是怎样实现的,配置程序中没有涉及到这一部分参数,又或者这些要求可以不满足?有待研究

  故我认为,配置读写时序的重点在于WRX和RDX上的低电平时间。

  暂做记录,希望高手指正,欢迎交流讨论。

  

补充关于液晶触屏控制器gt9147的一些说明:

  正点原子出品的一款4.3寸液晶屏,使用nt35510控制器和gt9147触摸控制器,对于使用该公司stm32教程的人来说是非常熟悉的。其教程只给出了轮询扫描获取触摸坐标的方式,且初始化配置代码有些混乱,我略作整理,给出中断方式获取坐标的初始化配置方式,亲测可用但仅供参考:

 

//初始化GT9147触摸屏
void GT9147_Init(void)
{
    u8 temp; 
    GPIO_InitTypeDef  GPIO_InitStructure;    
    NVIC_InitTypeDef   NVIC_InitStructure;
    EXTI_InitTypeDef   EXTI_InitStructure;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOF, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG时钟

    /* 模拟IIC SCL PB0;电容屏中断引脚 PB1 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1 ;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//输出
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
    PBout(1)=1; //使初始化时INT=1,设备地址设定为0x14
    
    /* 电容屏复位引脚 PC13 */    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
    GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化    
    
    /* 模拟IIC SDA PF11 */    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化    
    
    /* 设置设备地址为0x14,对应特定的读写命令 */     
    GT_RST=0;                //复位
    delay_ms(1);     //大于100us
    GT_RST=1;                //释放复位            
    delay_ms(10); //大于5ms
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;//PB1设置为浮空输入
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化        
    delay_ms(100);  //必须大于50ms
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);//重新配置为上拉
    /* 配置中断线来源,使能中断线 */
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource1);//PB1 连接到中断线1
    EXTI_InitStructure.EXTI_Line = EXTI_Line1;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断模式
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;//中断线使能
    EXTI_Init(&EXTI_InitStructure);//配置
    /* 配置中断优先级 */
    NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;//外部中断1
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x03;//抢占优先级3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级2
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
    NVIC_Init(&NVIC_InitStructure);//配置
    
    temp=0X02;
    GT9147_WR_Reg(GT_CTRL_REG,&temp,1);//软复位GT9147
    GT9147_RD_Reg(GT_CFGS_REG,&temp,1);//读取GT_CFGS_REG寄存器
    if(temp<0X60)GT9147_Send_Cfg(1);//原版本比较低,更新并保存配置
    delay_ms(10);
    temp=0X00;     
    GT9147_WR_Reg(GT_CTRL_REG,&temp,1);//结束复位   
}

  在中断服务函数中读取坐标即可。

猜你喜欢

转载自www.cnblogs.com/wangjianlin1996/p/10636888.html