1、在STM32F407在发送到上位机,用串口调试助手显示的时候,需要给摄像头采集过来的数据申请一个缓冲区。由于DCMI的 DMA发送数据是使用循环模式,缓冲区地址自动增长,当地址指针达到缓冲区的末尾就会返回缓冲区的首地址,重新开始执行。
STM32F407 DCMI DMA的设置如下:
DMA_InitStructure.DMA_Channel = DMA_Channel_1; //通道1 DCMI通道
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&DCMI->DR;//外设地址为CMI->DR
DMA_InitStructure.DMA_Memory0BaseAddr = DMA_Memory0BaseAddr;//DMA 存储器0地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//外设到存储器模式
DMA_InitStructure.DMA_BufferSize = DMA_BufferSize;//数据传输量
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc;//存储器增量模式
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//外设数据长度:32位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize;//存储器数据长度
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;// 使用循环模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High;//高优先级
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable; //FIFO模式
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;//使用全FIFO
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//外设突发单次传输
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//存储器突发单次传输
DMA_Init(DMA2_Stream1, &DMA_InitStructure);//初始化DMA Stream
2、DCMI的中断函数是帧中断,即每捕获到一帧数据,产生一次中断,处理一次数据,
DCMI 中断函数:
数据缓冲区的定义:
#define jpeg_buf_size 31*1024 //定义JPEG数据缓存jpeg_buf的大小(*4字节)
__align(4) u32 jpeg_buf[jpeg_buf_size]; //JPEG数据缓存buf
volatile u32 jpeg_data_len=0; //buf中的JPEG有效数据长度
volatile u8 jpeg_data_ok=0; //JPEG数据采集完成标志
void DCMI_IRQHandler(void)
{
if(DCMI_GetITStatus(DCMI_IT_FRAME)==SET)//捕获到一帧图像
{
jpeg_data_process(); //jpeg数据处理
DCMI_ClearITPendingBit(DCMI_IT_FRAME);//清除帧中断
LED1=!LED1;
ov_frame++;
}
}
数据处理函数:
void jpeg_data_process(void)
{
if(ov2640_mode)//只有在JPEG格式下,才需要做处理.
{
if(jpeg_data_ok==0) //jpeg数据还未采集完?
{
DMA_Cmd(DMA2_Stream1, DISABLE);//停止当前传输
while (DMA_GetCmdStatus(DMA2_Stream1) != DISABLE){}//等待DMA2_Stream1可配置
jpeg_data_len=jpeg_buf_size-DMA_GetCurrDataCounter(DMA2_Stream1);//得到此次数据传输的长度
jpeg_data_ok=1; //标记JPEG数据采集完按成,等待其他函数处理
}
if(jpeg_data_ok==2) //上一次的jpeg数据已经被处理了
{
DMA2_Stream1->NDTR=jpeg_buf_size;
DMA_SetCurrDataCounter(DMA2_Stream1,jpeg_buf_size);//传输长度为jpeg_buf_size*4字节
DMA_Cmd(DMA2_Stream1, ENABLE); //重新传输
jpeg_data_ok=0; //标记数据未采集
}
}
}
事实上,没处理一次函数,都会重新配置DMA的传输数据流:
DMA_SetCurrDataCounter(DMA2_Stream1,jpeg_buf_size);//传输长度为jpeg_buf_size*4字节
而每一次传输的数据长度都是一帧数据,并不是jpeg_buf_size(31*1024个字)。如果将数据缓冲区设置为jpeg_buf[jpeg_buf_size],缓冲区满的时候存放的是整个图片的数据。每发送一帧数据,缓冲区指针移动一帧数据所占有的空间。当整个图片的数据发送完毕,指针再回到缓冲区的首地址继续执行,如此往复。如果将缓冲区设置为一帧数据的大小,执行过程就是:发送第一帧数据,缓冲区的指针从开始移动到缓冲区的结束为止,发送第二帧数据的时候,再回到缓冲区的首地址继续执行。事实上,缓冲区存储的就是一帧数据。通过串口调试助手可以发现,一帧数据的长度为1088字,有的时候会达到1288字,为确保实验的准确性,可以将图片的缓冲区大小设置为1400字。通过调试发现,和缓冲区设置为 u32 jpeg_buf[jpeg_buf_size]的时候,串口调试助手显示的结果是一样的。如果DCMI DMA 设置传输完成中断的情况另当别论。 |