kundi 发表于 2021-8-6 12:54:06

【已解决】STC8A8K64D4如何正确通过DMA方式在ILI9325显示图片?

本帖最后由 kundi 于 2021-8-6 22:19 编辑

DMA方式,是一种不经过CPU的快速批量传输数据的方式。而STC官方网站上的相关例程中,关于TFT专用接口和DMA方式驱动TFT屏的,只有指定颜色写入刷屏与读取LCD的ID的程序,但是却没有通过DMA方式显示一张图片的大面积改变TFT显示区域的程序(少量字符可不考虑)。我就想参考其他程序,写一个DMA方式显示一个图片的程序。目前,STC8A8K64D4的DMA,支持XRAM与LCM之间数据的交换。
现在问题来了,下面第二个程序就是我已经写好的DMA方式显示图片的程序,发现显示的时候图片糊了,会不会是每批次写入XRAM的时间大于DMA传送的时间,由于使用了中断,XRAM内容没有更行完就被打断并传输给TFT LCD了,就会使得发送顺序混乱的错误的内容,图片就糊了?单色刷屏可能是因为每批次写入XRAM的时间小于等于DMA传送的时间而没有出错。

关键部分程序如下:
1.例程中的DMA方式刷屏的函数
void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color)
{         
      u16 i,j;                        
      u16 width=ex-sx+1;               //得到填充的宽度
      u16 height=ey-sy+1;                //高度
      LCD_SetWindows(sx,sy,ex,ey);//设置显示窗口

#if USR_LCM_IF == 1
      
      for(j=0,i=0;i<256;i++)//一次往XRAM写入256个16bit数据
      {
                Color = color;
      }
      index = 300;//总共传输300个批次,因为300*256=320*240=76800(像素)
      LCD_CS=0;
      LCMIF_BMM_CR = 0xa0;      //Write dat
//      P40 = 0;
      
#else//不使用DMA的传统刷频方式
      
//      P40 = 0;
      for(i=0;i<height;i++)
      {
                for(j=0;j<width;j++)
                LCD_WR_DATA_16Bit(color);      //写入数据         
      }
//      P40 = 1;
      
#endif
}2.我目前根据其他程序,写的DMA方式传输数据达到显示图片的目的,就是上边问题的部分(此部分正解见2,3楼)。
void Gui_Drawbmp16(u16 x,u16 y,const unsigned char *p) //显示40*40 QQ图片
{
unsigned int i,k;
      unsigned char picH,picL;
      LCD_SetWindows(x,y,x+40-1,y+40-1);//窗口设置
      #if USR_LCM_IF == 1//有问题的方式,图片糊了
      k=0;
while(k<40)
      {
         for(i=0;i<40;i++)//一次写40个
         {
                picL=*(p+j*2);      //数据低位在前
                picH=*(p+j*2+1);                              
                Color = (picH<<8)|picL;
    j++;               
         }
         k++;
         index = 40;//传40批。40*40=1600像素
         LCD_CS = 0;
         LCMIF_BMM_CR = 0xa0;      //Write dat
}
      #else//这是传统的方式,显示是正常的。
    for(i=0;i<40*40;i++)
      {      
               picL=*(p+i*2);      //数据低位在前
                picH=*(p+i*2+1);                              
                LCD_WR_DATA_16Bit(picH<<8|picL);                                                
      }      
      #endif
      LCD_SetWindows(0,0,LCD_W,LCD_H);//恢复显示窗口为全屏      
}3.Test——Color在大循环中调用
void Test_Color(void)
{
      u16 lcd_id;
      u8 buf = {0};

//      P40 = 0;
      LCD_Fill(0,0,LCD_W,LCD_H,WHITE);
//      P40 = 1;
      while(!LCD_CS);

      LCMIF_BMM_AMT = 0x01;                //Exe 2(n+1) bytes
      lcd_id = LCD_Read_ID();
      sprintf((char *)buf,"ID:0x%x",lcd_id);
      Show_Str(50,25,BLUE,YELLOW,buf,16,1);
      LCMIF_BMM_AMT = 0xff;                //Exe 256(n+1) bytes,DMA单次传输的个数为(255+1)*2字节

      delay_ms(800);
//      P40 = 0;
      LCD_Fill(0,0,LCD_W,LCD_H,RED);
//      P40 = 1;
      delay_ms(800);
//      P40 = 0;
      LCD_Fill(0,0,LCD_W,LCD_H,GREEN);
//      P40 = 1;
      delay_ms(800);
//      P40 = 0;
      LCD_Fill(0,0,LCD_W,LCD_H,BLUE);
//      P40 = 1;
      delay_ms(800);
      LCMIF_BMM_AMT = 39; //Exe 39(n+1) bytes,设置DMA单次传输的个数为(39+1)*2字节
      j=0;
      Gui_Drawbmp16(30,30,gImage_qq);//显示40*40图片
      j=0;
      delay_ms(1000);
      LCMIF_BMM_AMT = 0xff; //Exe 256(n+1) bytes
}
4.DMA的中断服务程序
void LCMIF_BMM_Interrupt(void) interrupt 13
{
      if(LCMIFSTA & 0x01)
      {
                LCMIFSTA = 0x00;
                LcmFlag = 0;
      }
      
      if(LCMIF_BMM_STA & 0x01)
      {
                if(BmmFlag)
                {
                        BmmFlag = 0;
                        LCMIF_BMM_CR = 0;
                }
                else
                {
                        index--;
                        if(index == 0)
                        {
                              LCMIF_BMM_CR = 0;
                              LCD_CS=1;
//                              P40 = 1;
                        }
                        else
                        {
                              LCMIF_BMM_CR = 0xa0;      //Write dat
                        }
                }
                LCMIF_BMM_STA = 0;
      }
}更改后的结果和说明见2-3楼,这里附完整的代码文件于附件中,希望STC官方可在后续示例程序中参考一下我的成果。


kundi 发表于 2021-8-6 15:37:47

本帖最后由 kundi 于 2021-8-6 15:45 编辑

基本成功了,只是最后一个被发送的像素是黑点。

程序如下:
void Gui_Drawbmp16(u16 x,u16 y,const unsigned char *p) //显示40*40 QQ图片
{
unsigned int i,k;
        unsigned char picH,picL;
        LCD_SetWindows(x,y,x+40-1,y+40-1);//窗口设置
        #if USR_LCM_IF == 1
        k=0;
        index = 40;//放到外层循环的外面
while(k<40)
        {
       LCMIF_BMM_CFG =0x02;//使得DMA 的LCM中段允许位变0
       LCMIFCFG = 0x02;//使得LCM接口的中断允许位是0,程序写入XRAM之前这两个中断要禁用,然后恢复。
       for(i=0;i<40;i++)
       {
                picL=*(p+j*2);        //数据低位在前
                picH=*(p+j*2+1);                               
                Color = (picH<<8)|picL;
    j++;               
       }
       k++;
       LCD_CS = 0;
       LCMIFCFG = 0x82;//恢复这2个中断的允许
       LCMIF_BMM_CFG= 0x82;
       LCMIF_BMM_CR = 0xa0;        //Write dat
}
        #else
    for(i=0;i<40*40;i++)
        {       
               picL=*(p+i*2);        //数据低位在前
                picH=*(p+i*2+1);                               
                LCD_WR_DATA_16Bit(picH<<8|picL);                                               
        }       
        #endif
        LCD_SetWindows(0,0,LCD_W,LCD_H);//恢复显示窗口为全屏       
}

kundi 发表于 2021-8-6 17:04:32

本帖最后由 kundi 于 2021-8-6 22:21 编辑

测试了大的图片,尺寸是160*160。就没有发现最末尾像素是黑点,看来DMA在大数据量时比较合适。
测试过程中,图片用DMA方式传输都比用传统方式快,特别是在主频升到45MHZ时(45MHZ时,如果电压偏低可能读取LCM数据会容易出错)。

此测试图片之版权归其作者所有。
代码:(调用此函数前要把LCMIF_BMM_AMT的值改为159)


最终更改后的程序代码文件在1楼。

hbzxx 发表于 2021-8-7 12:06:13

不错,学习了。DMA都是在ARM上用,没想到STC也可以。

shi_90 发表于 2021-8-7 14:48:05

牛逼!学习一下!

eddia2012 发表于 2021-8-9 18:16:39

好东西,学习了!

qjp1988113 发表于 2021-8-10 08:32:29

谢谢楼主的分享~

kundi 发表于 2021-10-29 15:18:19

45MHZ下,DMA刷屏演示,见压缩包内视频文件。

shandian007 发表于 2021-11-2 19:44:49

比较遗憾的是不支持SPI到LCM的DMA操作,需要在XRAM中转,速度提升有限。

zzsczz 发表于 2021-11-15 18:29:57

LCD外设 规格是啥?


每个商家都自定义一套。。。。。有没有通用的?

kundi 发表于 2021-11-16 13:24:16

zzsczz 发表于 2021-11-15 18:29
LCD外设 规格是啥?




对于8/16位的并行口,STC8A8K64D4内部的LCM接口是可以设置接口模式的,包括8080/68000。
SPI接口的LCM话,就用不到这个LCM接口了,毕竟SPI也有DMA.

bias 发表于 2021-11-23 08:05:53

可以从spi flash dma 搬运到lcd吗

chenyuhan 发表于 2022-8-23 10:33:55

好像只是搬运小图片有用 320x240x2 = 153kb
51单片机无论如何也放不下一个framebuffer
页: [1]
查看完整版本: 【已解决】STC8A8K64D4如何正确通过DMA方式在ILI9325显示图片?