[RISC-V MCU 应用开发] 求助,关于CH32V307驱动ST7789V画面移位花屏的问题

[复制链接]
 楼主| momoto 发表于 2023-4-13 00:05 | 显示全部楼层 |阅读模式
本帖最后由 momoto 于 2023-4-13 00:15 编辑

各位大佬好,我是刚学32的一个小白,在学习CH32V307驱动ST7789V时出现了花屏以及错位,显示效果如下
11.png

开发板:官方CH32V307V-R1-1v0开发板
LCD:金逸晨2.4寸 ST7789V 240*320 4线SPI接口
参考例程:中景园  2.4LCD显示屏STM32F103硬件SPI+DMA例程
曾尝试的方法:软件模拟SPI,以及硬件SPI都是正常的。当在硬件SPI中加入DMA时,刷图片就会出现上图中的哪种情况,所以我判定是我的DMA弄的有问题,可是搞了好几天还是没解决,希望大佬们指点下,感谢感谢。

以下为DMA相关的代码:

1. DMA配置
  1. void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
  2. {
  3.          RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);                                //使能DMA传输
  4.         
  5.          DMA_DeInit(DMA_CHx);                                                        //将DMA的通道1寄存器重设为缺省值
  6.         DMA1_MEM_LEN=cndtr;
  7.         DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;                            //DMA外设ADC基地址
  8.         DMA_InitStructure.DMA_MemoryBaseAddr = cmar;                                //DMA内存基地址
  9.         DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;                          //数据传输方向,从内存读取发送到外设
  10.         DMA_InitStructure.DMA_BufferSize = cndtr;                                   //DMA通道的DMA缓存的大小
  11.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;            //外设地址寄存器不变
  12.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                     //内存地址寄存器递增
  13.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;     //数据宽度为8位
  14.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;             //数据宽度为8位
  15.         DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                               //工作在正常缓存模式
  16.         DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;                       //DMA通道 x拥有中优先级
  17.         DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                //DMA通道x没有设置为内存到内存传输
  18.         DMA_Init(DMA_CHx, &DMA_InitStructure);                                      //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器
  19.                   
  20. }
  21. //开启一次DMA传输
  22. void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
  23. {
  24.         DMA_Cmd(DMA_CHx, DISABLE );
  25.          DMA_SetCurrDataCounter(DMA_CHx,DMA1_MEM_LEN);
  26.          DMA_Cmd(DMA_CHx, ENABLE);
  27. }

2. ShowPicture的函数
  1. void LCD_ShowPicture(u16 x,u16 y,u16 length,u16 width,const u8 pic[])
  2. {
  3.     u8 t=1;
  4.     u32 num=length*width*2,num1;
  5.     LCD_Address_Set(x,y,x+length-1,y+width-1);
  6.     LCD_CS_Clr();
  7.     while(t)
  8.     {
  9.         if(num>65534)
  10.         {
  11.             num-=65534;
  12.             num1=65534;
  13.         }
  14.         else
  15.         {
  16.             t=0;
  17.             num1=num;
  18.         }
  19.         MYDMA_Config(DMA1_Channel3,(u32)&SPI1->DATAR,(u32)pic,num1);
  20.         SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx,ENABLE);
  21.         MYDMA_Enable(DMA1_Channel3);
  22.         while(1)
  23.         {
  24.             if(DMA_GetFlagStatus(DMA1_FLAG_TC3)!=RESET)//等待通道3传输完成
  25.             {
  26.                 DMA_ClearFlag(DMA1_FLAG_TC3);//清除通道3传输完成标志
  27.                 break;
  28.             }
  29.         }
  30.         pic+=65534;
  31.     }
  32.     LCD_CS_Set();
  33. }

另外也贴下SPI的设置
  1. // 使用硬件SPI1读写数据
  2. void SPI1_Init(void)
  3. {
  4.     // 开启响应的RCC时钟
  5.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
  6.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

  7.     // 初始化GPIOA引脚
  8.     GPIO_InitTypeDef GPIO_InitStructure;

  9.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                     // SCK,MOSI配置为复用推挽输出
  10.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;              // PA5-->SCK,PA7-->MOSI
  11.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  12.     GPIO_Init(GPIOA, &GPIO_InitStructure);
  13.     GPIO_SetBits(GPIOA, GPIO_Pin_5|GPIO_Pin_7);


  14.     // 初始化SPI1
  15.     SPI_InitTypeDef SPI_InitStructure;
  16.     SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  // 传输模式2线全双工
  17.     SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                       // MCU作为主机
  18.     SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                           // 使用软件进行片选
  19.     // 使用SPI的模式0
  20.     SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                          // 时钟线默认为低电平
  21.     SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;                        // 在时钟线的第一个边沿读取数据
  22.     SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                   // 数据帧大小为8位
  23.     SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                  // 数据传输时高位在前
  24.     SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;  // SPI波特率分频因子为4分频
  25.     SPI_InitStructure.SPI_CRCPolynomial = 7;                            // SPI的CRC校验中多项式的值
  26.     SPI_Init(SPI1, &SPI_InitStructure);

  27.     // 使能SPI1
  28.     SPI_Cmd(SPI1, ENABLE);
  29. }






zhangdgzdg 发表于 2023-4-13 10:56 | 显示全部楼层
本帖最后由 zhangdgzdg 于 2023-4-13 10:59 编辑

u8 pic[]这个传入的数组请240*320*2 =  153,600 ,请把这个数组分为三个数组(每个数组不超过65535个),分别用DMA刷新,每个数组分别按照65536字节对齐,就是在每个数组名加上 __attribute__ ((aligned(0x10000))) , ShowPicture的函数的刷新位置与数量,根据你数组的大小设置一下。(附上了SPI-DMA驱G601A的代码,请参考)。
zhangdgzdg 发表于 2023-4-13 10:57 | 显示全部楼层
附件程序

CH32V307VCT6-float.rar

771.67 KB, 下载次数: 8

 楼主| momoto 发表于 2023-4-13 12:11 | 显示全部楼层
zhangdgzdg 发表于 2023-4-13 10:56
u8 pic[]这个传入的数组请240*320*2 =  153,600 ,请把这个数组分为三个数组(每个数组不超过65535个),分 ...

大佬,你好。现在还不方便测试您的方法,要到晚上了。
我有个疑问,按照您的方法是在ShowPicture这个函数中,先拆分这个大数组,之后再依次通过dma发送拆分后的小数组。中景园的例程里是在外层while循环时进行拆分(计算出每次要发送的字节个数),拆分一次,发送一次,并且更新pic[]的地址。两种方法具体的区别含义是什么啊,新人小白请多多指教。
看图片显示的故障区域,感觉就是在每次发送完65535个数据后,再下次发送数据这段时间出了问题。想不通为什么,难道要在这个地方加个延时?
zhangdgzdg 发表于 2023-4-13 13:16 | 显示全部楼层
这个具体我也不太清楚,反正一次发太多就会出问题,应该跟地址有关系,反正指定地址数组的地址65536字节对齐,每个数组别超过65535个

评论

是啊,把数据量设小点,多传几次试试  发表于 2023-4-13 14:18
timerc 发表于 2023-4-13 13:44 | 显示全部楼层
本帖最后由 timerc 于 2023-4-13 13:47 编辑

会不会DMA的计数是16位的,溢出了什么的? 1952164379778be418.png
 楼主| momoto 发表于 2023-4-13 14:11 | 显示全部楼层
timerc 发表于 2023-4-13 13:44
会不会DMA的计数是16位的,溢出了什么的?

每次DMA发送的时候都是手动触发的,手动触发的时候将值传入CNTR,这个值传的是65534,CNTR是个递减型的,应该不存在溢出吧。
timerc 发表于 2023-4-13 16:49 | 显示全部楼层
本帖最后由 timerc 于 2023-4-13 17:01 编辑
momoto 发表于 2023-4-13 14:11
每次DMA发送的时候都是手动触发的,手动触发的时候将值传入CNTR,这个值传的是65534,CNTR是个递减型的, ...

试试降低SPI的时钟频率看看,或者一行一行写试试呗;
 楼主| momoto 发表于 2023-4-13 16:57 | 显示全部楼层
timerc 发表于 2023-4-13 16:49
试试降低SPI的时钟频率看看

降了直接花
timerc 发表于 2023-4-13 17:17 | 显示全部楼层

你用GPIO模拟的都可以,没道理SPI频率降下来不行啊,把其他代码都给搞掉,就只跑这个显示看看,会不会被啥其他部分程序影响了
 楼主| momoto 发表于 2023-4-13 18:39 | 显示全部楼层
timerc 发表于 2023-4-13 17:17
你用GPIO模拟的都可以,没道理SPI频率降下来不行啊,把其他代码都给搞掉,就只跑这个显示看看,会不会被 ...

哦哦之前我记错了,刚才试了降低频率可以显示,但是花屏和错位的情况依然在。按照楼中另一位老师的方法减少发送数据量,多次发送。花屏和错位的区域变小了,但是当再次渐少发送量时,故障区域又开始变大。也毫无头绪,想不出是什么地方的问题。GPIO模拟和单独的硬件SPI都是可以的,加入DMA就不行,很烦
zhangdgzdg 发表于 2023-4-13 20:18 | 显示全部楼层
按照程序中的,将一个图片里的数据分成不大于65535个字节的数组分开定义存储,在数组前面加上__attribute__ ((aligned(0x10000))),指定其数组的首地址的低十六位为0,可以参考附件中的程序,那是将115200个数据分成2个数组传进去的。
timerc 发表于 2023-4-13 20:42 | 显示全部楼层
momoto 发表于 2023-4-13 18:39
哦哦之前我记错了,刚才试了降低频率可以显示,但是花屏和错位的情况依然在。按照楼中另一位老师的方法减 ...

只发送第一个65534的数据,显示啥样子,搞个图看看
 楼主| momoto 发表于 2023-4-13 22:15 | 显示全部楼层
timerc 发表于 2023-4-13 20:42
只发送第一个65534的数据,显示啥样子,搞个图看看

好呢,这时发送第一个65534数据大小后显示的图片 22.png
timerc 发表于 2023-4-14 09:26 | 显示全部楼层
本帖最后由 timerc 于 2023-4-14 10:23 编辑
momoto 发表于 2023-4-13 22:15
好呢,这时发送第一个65534数据大小后显示的图片

代码如果不是要保密的话,整个压缩包,发出来看看吧,看了官方例程的SPIDMA,感觉你贴出来的代码好像没啥毛病。
 楼主| momoto 发表于 2023-4-14 10:45 | 显示全部楼层
timerc 发表于 2023-4-14 09:26
代码如果不是要保密的话,整个压缩包,发出来看看吧,看了官方例程的SPIDMA,感觉你贴出来的代码好像没啥 ...

好呢,不保密的,本来就是学习的代码,麻烦您了,下面是代码的压缩包 LCD显示.zip (299.63 KB, 下载次数: 6)


zhangdgzdg 发表于 2023-4-18 19:48 | 显示全部楼层
你改一下刷新的起始与末尾void LCD_ShowPicture(u16 x,u16 y,u16 length,u16 width,const u8 pic[])

SPI_DMA_LCD.rar

1.03 MB, 下载次数: 10

您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

16

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部

2

主题

16

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部