其实能专门来搜这个DCMI相关的博客的人基本上都对DCMI是个什么玩意儿有一定的了解了,
个人认为这个外设本身其实很简单,难的地方在于使用DCMI的时候会需要摄像头相关的配置以及屏幕相关的驱动以及外部RAM的拓展,到最后流畅的再屏幕上显示摄像头的画面涉及的东西比较多。
首先需要注意的一点就是,DCMI的这个FIFO一共是四个字(以H7举例,下面一样),而因此如果不及时读走就会导致DCMI进入错误中断
建议把这个中断回调实现一下不然DCMI出问题都不知道在哪(不要杠我为什么要在中断里用打印操作)
回到上面,如果是FIFO溢出这个错误,那就是没有及时读走数据,这时候我们就要检查一下是否是因为在调用这个开启DCMI的DMA搬运函数的时候把目标地址直接设置为外部SDRAM了

我们知道,外部SDRAM访问速度是不如外部SRAM的,外部SRAM是不如内部SRAM的,因此如果设置为外部RAM,很可能带宽速率不够导致跟不上摄像头不断输出的数据流导致DCMI的FIFO溢出。
所以我们在使用DCMI的时候,DMA的缓冲区就要在片内SRAM,但由于片内SRAM往往都比较小,且是分块的,例如
因此我们往往不能让DMA把一整帧的数据搬运到片内SRAM再去把这一整帧的数据搬到片外SDRAM上,所以就采取分块搬运的操作,等DMA搬运完一块区域(一般以行为单位,以800*480像素的屏幕来说,每次搬800*N大小的像素块),然后再去把这一块数据搬到外部SDRAM上,然后再次接收,直到把一整帧的数据搬完后再显示到显存上。
其实仅仅这样是不行的,因为摄像头的数据是一直在发的,我们不可能等用于接收的这块内部SRAM把数据搬到外部RAM后再回来接收,这样数据就丢失了,因此我们需要保证始终有一块缓冲区用来接受数据,因此我们需要第二块缓冲区,也就是DMA的双缓冲机制,当一块缓冲区接收满数据之后,切换另一块去接收,已经满的这部分开始向外部SRAM发送,也就是始终有一块缓冲区在向外发送数据,始终有一块缓冲区来接收数据,

在调用DCMI的这个开启函数后,如果数据量大于65535*4个字节,就会在函数内部自动开启双缓冲,把我们给的缓冲区分为两个Buffer,

可以看到,内部会检测数据量是否大于0xFFFFU,因为DMA的数据搬运计数器是16位的,因此一次能搬运的数据量最大就是65535,这里是说的普通DMA,如果是MDMA,就是32位的,而DMA能处理的数据最大单位是字节,因此在超过65535*4个字节的数据量后,就会在内部开启双缓冲,
当然你也可以手动开启双缓冲然后去编写相关的双缓冲处理,DMA发送完会进入中断,但是DMA的发送完成中断回调是不显式开放的,



和串口一样,DCMI也会自动注册DMA的传输完成回调为自己的回调函数

所以我们可以在对应的传输完成中断里把数据搬运到外部的SDRAM,但最后不要直接写入屏幕显存,因为LTDC外设是在一直刷新显存到屏幕的,如果在LTDC刷新某一帧的中间突然DMA把下一帧的数据搬运到显存就会导致画面出现割裂,因此要用一块SDRAM来存储整帧画面,然后调用LTDC的更改显存地址但不立刻生效的函数
并通过HAL_LTDC_Reload函数把生效时间设置为VSYNC信号也就是新的一帧开始的时候生效,
这样就不会出现在某张画面还在显示就被刷新的情况
STM32 DCMI使用要点解析
6700

被折叠的 条评论
为什么被折叠?



