for(int i=0;i
{
ILI9488_Write_DATA_FAST(spi_rdata[1-read_rotation]);
}
if(len==0)break;
else
{
if(len
{
read_len=len;
len=0;
}
else
{
len-=SPI_READ_MAX;
read_len=SPI_READ_MAX;
}
}
}
刷图时间缩减到68ms;效果还是很明显的;
在测试过程中,刚开始只使用了DMA读取,这样SPI就需要进入只读模式,但是有一个问题,如果DMA传输的时间小于把数据发送到TFT的时间,就会出现错位;
解决办法,加入DMA发送,产生时钟,SPI依然工作全双工模式;问题得以解决,而且时间上也没有多余的消耗;
一、硬件环境:
1、主控STM32F103RC(无FSMC,I8080时序软件模拟)
2、TFTLCD,320480,ILI9488
3、SPI-FLASH,W25Q128(存放解码之后的JPEG图片数据)
4、图片320480,每张图片300.02K
二、测试结果:
1、刷屏(单色)耗时53ms
代码如下:
#define ILI9488_START_Write_DATA() {ILI9488_RS_G();ILI9488_RD_G();ILI9488_WR_G();ILI9488_CS_D();}
#define ILI9488_STOP_Write_DATA() {ILI9488_CS_G();}
#define ILI9488_Write_DATA_FAST(x) {ILI9488_W_DATA(x);
ILI9488_WR_D();ILI9488_WR_G();}
/*
*@brief LCD按指定颜色清屏(可以考虑是否优化,连续读写)
*@param color指定颜色
*@retval 无
/
void LCD_Clear(uint16_t color)
{
uint32_t index=0;
uint32_t totalpoint=lcddev.width;
totalpoint=lcddev.height; //得到总点数
ILI9488_SetCursor_AndEnd(0x0000,0x0000,319,479); //设置光标位置
ILI9488_Write_CMD(lcddev.wramcmd);//发送读GRAM指令
ILI9488_START_Write_DATA();
for(index=0;index
ILI9488_STOP_Write_DATA();
}
尝试过将for循环展开一部分,减少for循环判断次数,可以降低到40ms左右,但是好像无实际意义;
2、刷图(耗时182ms)
代码如下:
static void image_showex(uint16_t xsta,uint16_t ysta,uint16_t width,uint16_t height,uint8_t scan,uint32_t addr)
{
uint32_t len=0;
if((scan&0x03)==0)//水平扫描
{
ILI9488_Scan_Dir(L2R_U2D);//从左到右,从上到下
ILI9488_SetCursor_AndEnd(xsta,ysta,width-1+xsta,height-1+ysta);
ILI9488_SetCursor(xsta,ysta);//设置光标位置
}else //垂直扫描
{
ILI9488_Scan_Dir(U2D_L2R);//从上到下,从左到右
ILI9488_SetCursor_AndEnd(xsta,ysta,width-1+xsta,height-1+ysta);
ILI9488_SetCursor(xsta,ysta);//设置光标位置
}
len=width*height; //写入的数据长度
//开始数据搬运
SPI_NSS_D();//选中
EX_FLASH_SPI_ReadWriteByte(W25X_FastReadData); //发送读取命令
EX_FLASH_SPI_ReadWriteByte((uint8_t)((addr)>>16)); //发送24bit地址
EX_FLASH_SPI_ReadWriteByte((uint8_t)((addr)>>8));
EX_FLASH_SPI_ReadWriteByte((uint8_t)addr);
while((SPI1->SR&1<<1)==0){}//等待发送区空
SPI1->DR=0xffff; //发送一个byte
while((SPI1->SR&1<<0)==0){}//等待接收完一个byte
uint16_t spi_rdata=SPI1->DR;
SPI1->CR1&=~(1<<6);//关闭SPI
SPI1->CR1|=(1<<11);//16bit
SPI1->CR1|=(1<<6);//开启SPI
ILI9488_Write_CMD(lcddev.wramcmd); //发送读GRAM指令
ILI9488_START_Write_DATA();
while(len!=0)
{
while((SPI1->SR&1<<1)==0){}//等待发送区空
SPI1->DR=0; //发送一个byte
while((SPI1->SR&1<<0)==0){}//等待接收完一个byte
ILI9488_Write_DATA_FAST(SPI1->DR);//颠倒高第八位,所有图片数据消耗时间大致8ms
len–;
}
ILI9488_STOP_Write_DATA();
SPI_NSS_G(); //取消片选
SPI1->CR1&=~(1<<6);//关闭SPI
SPI1->CR1&=~(1<<11);//8bit
SPI1->CR1|=(1<<6);//开启SPI
}
(1)、CUBE在配置SPI的时候只能配置到18M,但是软件我实际配置到36M也暂时没有发现问题;
(2)、读取图像数据的时候,我将SPI设置到16bit模式,将刷图时间从244ms降低到现在的180ms;
三、持续优化思路
1、最终代码会被移植到一颗资源更加紧张的MCU上去(自己公司的MCU),因此不考虑FSMC的使用;
2、I8080时序上的优化是否还有可能性;
3、SPI的读取速度上是否还有优化的可能;
(1)、使用DMA读取一批数据然后刷到TFT,是否可以减小时间;
(2)、在读取数据的时候如果使用软件模拟SPI的Dual模式(2个数据线进行数据读取)是否可以减小时间;
后续:20190530-1240
前面从flash读一个数据写入TFT的过程为:
等待发送缓存器为空—>写一个亚数据—>等待接受缓存器不为空—>获取到一个数据写入TFT(while整个过程);
改为:等待发送缓存器为空—>写一个亚数据—>进入while循环
等待接受缓存器不为空—>获取到一个数据—>写一个亚数据—>将上一个数据写入TFT—>等待发送缓存器为空(while整个过程);
这样做的好处在于,等待亚数据写入的过程中,就可以吧上一个数据写入TFT,这样等TFT写入完成之后,亚数据也就写入完成了,
“等待发送缓存器为空”的过程基本上直接就略过了;
改完之后,写入一个图片的时间缩短到122ms;
后续:20190531-1042
在对汇编程序分析之后:
使用
#define ILI9488_Write_DATA_FAST(x) {GPIOB->ODR=x;GPIOC->BRR =0X0010;GPIOC->BSRR=0X0010;}
代替
#define ILI9488_Write_DATA_FAST(x) {ILI9488_W_DATA(x);
ILI9488_WR_D();ILI9488_WR_G();}
#define ILI9488_W_DATA(X) (GPIOB->ODR=X)
#define ILI9488_WR_G() (GPIOC->BSRR|=1<<4)//set bit
#define ILI9488_WR_D() (GPIOC->BRR|=1<<4)//clear bit
改完之后,写入一个图片的时间缩短到114ms;
后续:20190531-1538
使用DMA+双缓存模式读取SPI-FLASH数据
SPI1->CR1&=~(1<<6);//关闭SPI
SPI1->CR1|=(1<<11);//16bit
SPI1->CR2|=(1<<0);//启动接受缓存器DMA
SPI1->CR2|=(1<<1);//启动接受缓存器DMA
//SPI1->CR1|=(1<<10);//只读模式
uint16_t read_len=SPI_READ_MAX;
uint8_t read_rotation=0;
DMA1_Channel2->CCR&=~(1<<0);//关闭通道
DMA1_Channel2->CMAR=(uint32_t)(&spi_rdata[read_rotation][0]);
DMA1->IFCR=0XF0;
DMA1_Channel2->CNDTR=read_len;
DMA1_Channel3->CCR&=~(1<<0);//关闭通道
DMA1_Channel3->CMAR=(uint32_t)(&spi_rdata[read_rotation][0]);
DMA1->IFCR=0XF0;
DMA1_Channel3->CNDTR=read_len;
DMA1_Channel2->CCR|=(1<<0);//开启通道
DMA1_Channel3->CCR|=(1<<0);//开启通道
SPI1->CR1|=(1<<6);//开启SPI
//
ILI9488_Write_CMD(lcddev.wramcmd); //发送读GRAM指令
ILI9488_START_Write_DATA();
len-=SPI_READ_MAX;
read_len=SPI_READ_MAX;
while(1)
{
while(DMA1_Channel2->CNDTR!=0){}//等待DMA传输完成
read_rotation++;
if(read_rotation>1)read_rotation=0;
DMA1_Channel2->CCR&=~(1<<0);//关闭通道
DMA1_Channel2->CMAR=(uint32_t)(&spi_rdata[read_rotation][0]);
DMA1->IFCR=0XF0;
DMA1_Channel2->CNDTR=read_len;
DMA1_Channel3->CCR&=~(1<<0);//关闭通道
DMA1_Channel3->CMAR=(uint32_t)(&spi_rdata[read_rotation][0]);
DMA1->IFCR=0XF0;
DMA1_Channel3->CNDTR=read_len;
DMA1_Channel2->CCR|=(1<<0);//开启通道
DMA1_Channel3->CCR|=(1<<0);//开启通道,发送通道,在于产生SPI时钟,不然就需要进入只读模式,这样出现数据错位
for(int i=0;i
{
ILI9488_Write_DATA_FAST(spi_rdata[1-read_rotation]);
}
if(len==0)break;
else
{
if(len
{
read_len=len;
len=0;
}
else
{
len-=SPI_READ_MAX;
read_len=SPI_READ_MAX;
}
}
}
刷图时间缩减到68ms;效果还是很明显的;
在测试过程中,刚开始只使用了DMA读取,这样SPI就需要进入只读模式,但是有一个问题,如果DMA传输的时间小于把数据发送到TFT的时间,就会出现错位;
解决办法,加入DMA发送,产生时钟,SPI依然工作全双工模式;问题得以解决,而且时间上也没有多余的消耗;
举报