[STM32L4]基于STM32L4R5 LCD刷新率优化

本文章主要是记录一下优化LCD刷新率的过程。
一般情况,嵌入式工程师大部分使用的是LCD屏,其中LCD也分好几种,就拿常用的LCD_TFT来说,与普通液晶显示器相比,TFT LCD能提供非常清晰的图像/文字,响应时间更短,非常省电、高亮度也做得非常不错,那么本次测试将使用这个屏幕,进行刷新率的优化。我将通过三种方法,优化刷新率。
一、硬件
1、NUCLEO-L4R5 DEMO板
2、2.5寸 TFT-LCD 显示屏(ILI9341驱动芯片)模块3、8根杜邦线(主要用于与LCD屏连接)
4、Type-A的USB线
二、LCD屏模块显示图像原理
TFT-LCD内部驱动原理主要是使用FET场效应管产生驱动电压,进而使得点亮像素点。e而TFT-LCD显示屏一共包含有240*320的像素点,而每个像素有红绿蓝3个子像素点,混合这3种颜色即可显示各种颜色。只需要像素点亮起来就会显示相应的图案和颜色。并且显示屏模块内部已集成DDRAM,也就是显存。如图,要使LCD显示内容,只需要通过SPI把显示的内容放到这个显存就可以了。
 


因此优化SPI传输数据的速率就可以优化LCD的刷新率。
三、驱动编写
对于这部分的驱动,商家已经提供了DEMO,并且网上也有很多大佬出了很多教程,那么就直接移植相关代码即可。
驱动部分代码如下:

复制
/* @attention

  *

  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS

  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE

  * TIME. AS A RESULT, QD electronic SHALL NOT BE HELD LIABLE FOR ANY

  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING

  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE

  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.

**************************************************************************************************/    

#include "lcd.h"

#include "spi.h"

#include <stdio.h>

#

//管理LCD重要参数

//默认为竖屏

_lcd_dev lcddev;

extern DMA_HandleTypeDef hdma_spi1_tx;

//画笔颜色,背景颜色

uint16_t POINT_COLOR = 0x0000,BACK_COLOR = 0xFFFF;

uint16_t DeviceCode;



uint8_t LCD_SPI_WriteByte(uint8_t TxData) {

    uint8_t RxData = 0X00;





    if(HAL_SPI_TransmitReceive(LCD_SPI_Handle, &TxData, &RxData, 1, 100) != HAL_OK)

    {

        RxData = 0XFF;

    }

    return RxData;

}

/*****************************************************************************

 * [url=home.php?mod=space&uid=139335]@name[/url]       :void LCD_WR_REG(uint8_t data)

 * [url=home.php?mod=space&uid=212281]@date[/url]       :2018-08-09 

 * [url=home.php?mod=space&uid=42490]@function[/url]   :Write an 8-bit command to the LCD screen

 * [url=home.php?mod=space&uid=2814924]@parameters[/url] :data:Command value to be written

 * @retvalue   :None

******************************************************************************/

void LCD_WR_REG(uint8_t data)

{ 

   LCD_CS_CLR;     

   LCD_RS_CLR;

   LCD_SPI_WriteByte(data);

   LCD_CS_SET;    

}



/*****************************************************************************

 * [url=home.php?mod=space&uid=139335]@name[/url]       :void LCD_WR_DATA(uint8_t data)

 * [url=home.php?mod=space&uid=212281]@date[/url]       :2018-08-09 

 * [url=home.php?mod=space&uid=42490]@function[/url]   :Write an 8-bit data to the LCD screen

 * [url=home.php?mod=space&uid=2814924]@parameters[/url] :data:data value to be written

 * @retvalue   :None

******************************************************************************/

void LCD_WR_DATA(uint8_t data)

{

   LCD_CS_CLR;

   LCD_RS_SET;

   LCD_SPI_WriteByte(data);

   LCD_CS_SET;

}



/*****************************************************************************

 * [url=home.php?mod=space&uid=139335]@name[/url]       :void LCD_WriteReg(uint8_t LCD_Reg, uint16_t LCD_RegValue)

 * [url=home.php?mod=space&uid=212281]@date[/url]       :2018-08-09 

 * [url=home.php?mod=space&uid=42490]@function[/url]   :Write data into registers

 * [url=home.php?mod=space&uid=2814924]@parameters[/url] :LCD_Reg:Register address

                LCD_RegValue:Data to be written

 * @retvalue   :None

******************************************************************************/

void LCD_WriteReg(uint8_t LCD_Reg, uint16_t LCD_RegValue)

{    

    LCD_WR_REG(LCD_Reg);  

    LCD_WR_DATA(LCD_RegValue);                 

}       



/*****************************************************************************

 * [url=home.php?mod=space&uid=139335]@name[/url]       :void LCD_WriteRAM_Prepare(void)

 * [url=home.php?mod=space&uid=212281]@date[/url]       :2018-08-09 

 * [url=home.php?mod=space&uid=42490]@function[/url]   :Write GRAM

 * [url=home.php?mod=space&uid=2814924]@parameters[/url] :None

 * @retvalue   :None

******************************************************************************/     

void LCD_WriteRAM_Prepare(void)

{

    LCD_WR_REG(lcddev.wramcmd);

}     



/*****************************************************************************

 * [url=home.php?mod=space&uid=139335]@name[/url]       :void Lcd_WriteData_16Bit(uint16_t Data)

 * [url=home.php?mod=space&uid=212281]@date[/url]       :2018-08-09 

 * [url=home.php?mod=space&uid=42490]@function[/url]   :Write an 16-bit command to the LCD screen

 * [url=home.php?mod=space&uid=2814924]@parameters[/url] :Data:Data to be written

 * @retvalue   :None

******************************************************************************/     

void Lcd_WriteData_16Bit(uint16_t Data)

{    

   LCD_CS_CLR;

   LCD_RS_SET;  

   LCD_SPI_WriteByte(Data>>8);

   LCD_SPI_WriteByte(Data);

   LCD_CS_SET;

}



/*****************************************************************************

 * [url=home.php?mod=space&uid=139335]@name[/url]       :void LCD_DrawPoint(uint16_t x,uint16_t y)

 * [url=home.php?mod=space&uid=212281]@date[/url]       :2018-08-09 

 * [url=home.php?mod=space&uid=42490]@function[/url]   :Write a pixel data at a specified location

 * [url=home.php?mod=space&uid=2814924]@parameters[/url] :x:the x coordinate of the pixel

                y:the y coordinate of the pixel

 * @retvalue   :None

******************************************************************************/    

void LCD_DrawPoint(uint16_t x,uint16_t y)

{

    LCD_SetCursor(x,y);//设置光标位置

    Lcd_WriteData_16Bit(POINT_COLOR); 

}



/*****************************************************************************

 * [url=home.php?mod=space&uid=139335]@name[/url]       :void LCD_Clear(uint16_t Color)

 * [url=home.php?mod=space&uid=212281]@date[/url]       :2018-08-09 

 * [url=home.php?mod=space&uid=42490]@function[/url]   :Full screen filled LCD screen

 * [url=home.php?mod=space&uid=2814924]@parameters[/url] :color:Filled color

 * @retvalue   :None

******************************************************************************/    

void LCD_Clear(uint16_t Color)

{

  unsigned int i,m;  

    LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);   

    LCD_CS_CLR;

    LCD_RS_SET;

    for(i=0;i<lcddev.height;i++)

    {

    for(m=0;m<lcddev.width;m++)

    {    

            Lcd_WriteData_16Bit(Color);

        }

    }

     LCD_CS_SET;

} 



/*****************************************************************************

 * [url=home.php?mod=space&uid=139335]@name[/url]       :void LCD_RESET(void)

 * [url=home.php?mod=space&uid=212281]@date[/url]       :2018-08-09 

 * [url=home.php?mod=space&uid=42490]@function[/url]   :Reset LCD screen

 * [url=home.php?mod=space&uid=2814924]@parameters[/url] :None

 * @retvalue   :None

******************************************************************************/    

void LCD_RESET(void)

{

    LCD_RST_CLR;

    HAL_Delay(100);

    LCD_RST_SET;

    HAL_Delay(50);

}



/*****************************************************************************

 * @name       :void LCD_RESET(void)

 * @date       :2018-08-09 

 * @function   :Initialization LCD screen

 * @parameters :None

 * @retvalue   :None

******************************************************************************/          

void LCD_Init(void)

{  

     LCD_RESET(); //LCD 复位

//*************3.2inch ILI9341初始化**********//

    LCD_WR_REG(0xCF);

    LCD_WR_DATA(0x00); 

    LCD_WR_DATA(0xD9); //C1

    LCD_WR_DATA(0X30); 

    LCD_WR_REG(0xED);  

    LCD_WR_DATA(0x64); 

    LCD_WR_DATA(0x03); 

    LCD_WR_DATA(0X12); 

    LCD_WR_DATA(0X81); 

    LCD_WR_REG(0xE8);  

    LCD_WR_DATA(0x85); 

    LCD_WR_DATA(0x10); 

    LCD_WR_DATA(0x7A); 

    LCD_WR_REG(0xCB);  

    LCD_WR_DATA(0x39); 

    LCD_WR_DATA(0x2C); 

    LCD_WR_DATA(0x00); 

    LCD_WR_DATA(0x34); 

    LCD_WR_DATA(0x02); 

    LCD_WR_REG(0xF7);  

    LCD_WR_DATA(0x20); 

    LCD_WR_REG(0xEA);  

    LCD_WR_DATA(0x00); 

    LCD_WR_DATA(0x00); 

    LCD_WR_REG(0xC0);    //Power control 

    LCD_WR_DATA(0x1B);   //VRH[5:0] 

    LCD_WR_REG(0xC1);    //P0

    LCD_WR_DATA(0x12);   //SAP[2:0];BT[3:0] //0x01

    LCD_WR_REG(0xC5);    //VCM control 

    LCD_WR_DATA(0x26);      //3F

    LCD_WR_DATA(0x26);      //3C

    LCD_WR_REG(0xC7);    //VCM control2 

    LCD_WR_DATA(0XB0);

    LCD_WR_REG(0x36);    // Memory Access Control 

    LCD_WR_DATA(0x08); 

    LCD_WR_REG(0x3A);   

    LCD_WR_DATA(0x55); 

    LCD_WR_REG(0xB1);   

    LCD_WR_DATA(0x00);   

    LCD_WR_DATA(0x1A); 

    LCD_WR_REG(0xB6);    // Display Function Control 

    LCD_WR_DATA(0x0A); 

    LCD_WR_DATA(0xA2); 

    LCD_WR_REG(0xF2);    // 3Gamma Function Disable 

    LCD_WR_DATA(0x00); 

    LCD_WR_REG(0x26);    //Gamma curve selected 

    LCD_WR_DATA(0x01); 

    LCD_WR_REG(0xE0); //Set Gamma

    LCD_WR_DATA(0x1F);

    LCD_WR_DATA(0x24);

    LCD_WR_DATA(0x24);

    LCD_WR_DATA(0x0D);

    LCD_WR_DATA(0x12);

    LCD_WR_DATA(0x09);

    LCD_WR_DATA(0x52);

    LCD_WR_DATA(0xB7);

    LCD_WR_DATA(0x3F);

    LCD_WR_DATA(0x0C);

    LCD_WR_DATA(0x15);

    LCD_WR_DATA(0x06);

    LCD_WR_DATA(0x0E);

    LCD_WR_DATA(0x08);

    LCD_WR_DATA(0x00);

    LCD_WR_REG(0XE1); //Set Gamma

    LCD_WR_DATA(0x00);

    LCD_WR_DATA(0x1B);

    LCD_WR_DATA(0x1B);

    LCD_WR_DATA(0x02);

    LCD_WR_DATA(0x0E);

    LCD_WR_DATA(0x06);

    LCD_WR_DATA(0x2E);

    LCD_WR_DATA(0x48);

    LCD_WR_DATA(0x3F);

    LCD_WR_DATA(0x03);

    LCD_WR_DATA(0x0A);

    LCD_WR_DATA(0x09);

    LCD_WR_DATA(0x31);

    LCD_WR_DATA(0x37);

    LCD_WR_DATA(0x1F);



    LCD_WR_REG(0x2B); 

    LCD_WR_DATA(0x00);

    LCD_WR_DATA(0x00);

    LCD_WR_DATA(0x01);

    LCD_WR_DATA(0x3f);

    LCD_WR_REG(0x2A); 

    LCD_WR_DATA(0x00);

    LCD_WR_DATA(0x00);

    LCD_WR_DATA(0x00);

    LCD_WR_DATA(0xef);     

    LCD_WR_REG(0x11); //Exit Sleep



    HAL_Delay(120);

    LCD_WR_REG(0x29); //display on        



  LCD_direction(USE_HORIZONTAL);//设置LCD显示方向

    LCD_BL_ON;//点亮背光

    LCD_Clear(GREEN);//清全屏白色

}

 

/*****************************************************************************

 * @name       :void LCD_SetWindows(uint16_t xStar, uint16_t yStar,uint16_t xEnd,uint16_t yEnd)

 * @date       :2018-08-09 

 * @function   :Setting LCD display window

 * @parameters :xStar:the bebinning x coordinate of the LCD display window

                                yStar:the bebinning y coordinate of the LCD display window

                                xEnd:the endning x coordinate of the LCD display window

                                yEnd:the endning y coordinate of the LCD display window

 * @retvalue   :None

******************************************************************************/ 

void LCD_SetWindows(uint16_t xStar, uint16_t yStar,uint16_t xEnd,uint16_t yEnd)

{    

    LCD_WR_REG(lcddev.setxcmd);    

    LCD_WR_DATA(xStar>>8);

    LCD_WR_DATA(0x00FF&xStar);        

    LCD_WR_DATA(xEnd>>8);

    LCD_WR_DATA(0x00FF&xEnd);



    LCD_WR_REG(lcddev.setycmd);    

    LCD_WR_DATA(yStar>>8);

    LCD_WR_DATA(0x00FF&yStar);        

    LCD_WR_DATA(yEnd>>8);

    LCD_WR_DATA(0x00FF&yEnd);



    LCD_WriteRAM_Prepare();    //开始写入GRAM

}   



/*****************************************************************************

 * @name       :void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)

 * @date       :2018-08-09 

 * @function   :Set coordinate value

 * @parameters :Xpos:the  x coordinate of the pixel

                                Ypos:the  y coordinate of the pixel

 * @retvalue   :None

******************************************************************************/ 

void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)

{                          

    LCD_SetWindows(Xpos,Ypos,Xpos,Ypos);    

} 



/*****************************************************************************

 * @name       :void LCD_direction(uint8_t direction)

 * @date       :2018-08-09 

 * @function   :Setting the display direction of LCD screen

 * @parameters :direction:0-0 degree

                          1-90 degree

                                                    2-180 degree

                                                    3-270 degree

 * @retvalue   :None

******************************************************************************/ 

void LCD_direction(uint8_t direction)

{ 

            lcddev.setxcmd=0x2A;

            lcddev.setycmd=0x2B;

            lcddev.wramcmd=0x2C;

    switch(direction){          

        case 0:                                      

            lcddev.width=LCD_W;

            lcddev.height=LCD_H;        

            LCD_WriteReg(0x36,(1<<3)|(0<<6)|(0<<7));//BGR==1,MY==0,MX==0,MV==0

        break;

        case 1:

            lcddev.width=LCD_H;

            lcddev.height=LCD_W;

            LCD_WriteReg(0x36,(1<<3)|(0<<7)|(1<<6)|(1<<5));//BGR==1,MY==1,MX==0,MV==1

        break;

        case 2:                                      

            lcddev.width=LCD_W;

            lcddev.height=LCD_H;    

            LCD_WriteReg(0x36,(1<<3)|(1<<6)|(1<<7));//BGR==1,MY==0,MX==0,MV==0

        break;

        case 3:

            lcddev.width=LCD_H;

            lcddev.height=LCD_W;

            LCD_WriteReg(0x36,(1<<3)|(1<<7)|(1<<5));//BGR==1,MY==1,MX==0,MV==1

        break;    

        default:break;

    }        

}





void SPI_DMATransmitCplt(DMA_HandleTypeDef *hdma) {

//    if (hdma == hdma_spi1_tx) {

    LCD_CS_SET;

    LCD_RS_SET;



//    }

}


四、如何优化SPI的传输速率
一般情况下,直接提升SPI传输速率的方法是,提高SPI的工作频率。在数据手册中,也没有看到最大工作频率;那么就只能看MCU支持多大的工作频率;
 


除了以上方法,还有以下几种方法:
——SPI传输使用DMA方式;
——提高IDE的优化等级;
——使用RAM存储LCD显示数据。

下面就实测以上几种方法的刷新率;
1、先来看看正常配置后的刷新率;2s一张图;如下视频
 


2、设置编译器优化等级;刷新率快了一点;1s一张图;如下
 


等级优化设置:
 



3、设置SPI为DMA传输;也是2s一张图;1s一张图,如下视频
 

复制
    LCD_CS_CLR;

    HAL_SPI_Transmit_DMA(LCD_SPI_Handle, &TxData, 1);

    while((HAL_SPI_GetState(&hspi1)) != HAL_SPI_STATE_READY);

    LCD_CS_SET;

4、设置SPI为DMA传输,并且优化等级为fast;没有什么变化;2s一张图,如下视频
 


5、把SPI的数据缓存放在RAM中;使用DMA传输;刷新率大幅提高;见如下视频;
 



具体操作如下:

复制
/* 在STM32L4R5ZITX_RAM.ld 中声明一个段,这个段在RAM中;*/

  /*add user section*/

  .lcdbuffer   :

  {

    . = ALIGN(4);

    . = ALIGN(4);

  } >RAM

  

/*  最后在头文件中设置LCD显示数据数组在声明的段中*/

__attribute__((section(".lcdbuffer"))) unsigned short LCD_BUFFER[320][240] ;


编译后可以看到LCD_BUFFER运行地址是在RAM中;
 


此前DMA是传输一个字节,传输大量数据就会重复进行传输过程。
而直接使用RAM中的缓存,则可以把数据通过DMA把半屏数据传输到LCD的DDRAM中。
---------------------
作者:怀揣少年梦
链接:https://bbs.21ic.com/icview-3376222-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值