** 1 **
** 前言 **
上期我们解决了STM32H5中DCMI无法工作的问题,但是DCMI与DMA通讯一直出现了问题。本期详细介绍下是如何一步一步Debug排除错误的。
** 2 **
** DMA总是出问题 **
当我们解决了DCMI的工作问题之后。
开启H563的GPDMA,之前是没怎么搞明白GPDMA的各项设置,因此基本都是默认配置。所以最开始的DataWidth是默认HalfWord也就是16位的,结果DMA一直不会开启传输。
得幸于找到 ST的一篇应用笔记 。
其中推荐了配置,并且强调了应该使用Word(32位)设置来使用GPDMA。
启动DCMI之后,发现DMA传输依旧有问题,缓存区只有第一个有数据,其他都是0x00;ErrorCode是0x20(图中是正常的)。DCMI的ErrorCode是0x41.
互联网上基本没有关于具体ErrorCode的描述,因此只能依靠自己来解决这个问题。
查看关于DMA的ErrorCode的定义,表示大概是传输目标出现了问题 ,而DCMI的ErrorCode
0x41正是表明这DMA传输出现了Error因此首先要解决的是GPDMA传输的问题。
** 3 **
** 问题解决 **
在Debug的过程中我突然发现(注意力惊人)缓存区的第一个数据在极快的情况下更新,之后不更新。
** 会不会是缓存区实际更新到了缓存区的第一个位置,而不是整个缓存区 ** ?
DMA的参数不是必须传入一个指针,而是传入一个整型数( ** 注意嗷,指针代表的是地址,32单片机是32位的,所以也可以用uint32_t来存放指针
** )。
在常规的DMA中右边有一个Increment Address它默认是开启的。
它的作用的每次传输完成后,将目标地址的值递增。
前面的Peripheral是外设地址,外设地址是不变的,它永远指向DCMI的SR指针。
但是我们的缓存区,也就是内存地址Memory地址是需要递增的,以便我们的数据可以顺序的存储下去。
因此需要在GPDMA中开启目标地址的递增。这样子就可以成功的实现DMA传输。
** 4 **
** 代码实现 **
void DMA2_Stream1_IRQHandler(void){ /* USER CODE BEGIN DMA2_Stream1_IRQn 0 */
/* USER CODE END DMA2_Stream1_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_dcmi); /* USER CODE BEGIN DMA2_Stream1_IRQn 1 */ frame_complete_flag = 1; /* USER CODE END DMA2_Stream1_IRQn 1 */}
定义一个传输完成的标志变量,当这个变量是1的时候开始将DCMI的数据转到屏幕中。 ** 这一步也可以用中断来实现 ** 。
if(frame_complete_flag) { HAL_DCMI_Stop(&hdcmi); frame_complete_flag = 0; //ST7789_DrawImage(0,0,IMAGE_WEIGH,IMAGE_HEIGH,frame_buffer); ST7789_Fill_Image(frame_buffer); HAL_DCMI_Start_DMA(&hdcmi,DCMI_MODE_CONTINUOUS,(uint32_t)frame_buffer,IMAGE_WEIGH*IMAGE_HEIGH/2); } if(hdcmi.Instance->RISR & 0x02) { hdcmi.Instance->ICR = 0x02;//清除损坏位 } if(!(hdcmi.Instance->CR & 0x01)) { HAL_DCMI_Start_DMA(&hdcmi,DCMI_MODE_CONTINUOUS,(uint32_t)frame_buffer,IMAGE_WEIGH*IMAGE_HEIGH/2); }
主循环中添加轮询的代码,包括错误处理和图像捕获完成之后的图像传输。
这样子就完成了我们的代码实现。