21ic问答首页 - GD32W515 DCI ov2640摄像头连续捕获模式采集帧率低的问题
GD32W515 DCI ov2640摄像头连续捕获模式采集帧率低的问题
乌月明星稀2024-01-04
OV2640在800*600分辨率,JPG格式输出,日志信息如下:
[12:00:37.591]收←◆[ DEBUG ] ov2640 frame count:32768
[12:00:38.653]收←◆[ DEBUG ] ov2640 frame count:33792
[12:00:39.716]收←◆[ DEBUG ] ov2640 frame count:34816
[12:00:40.780]收←◆[ DEBUG ] ov2640 frame count:34816
[12:00:41.842]收←◆[ DEBUG ] ov2640 frame count:34816
[12:00:42.907]收←◆[ DEBUG ] ov2640 frame count:34816
[12:00:43.971]收←◆[ DEBUG ] ov2640 frame count:34816
[12:00:45.035]收←◆[ DEBUG ] ov2640 frame count:34816
即,将近1S才采集一帧。
用逻辑分析仪测试VSYNC,周期大概在37ms,也就是说,一秒有将近30帧输出(可先排除OV2640寄存器相关配置问题,通过串口将jpeg输出到上位机,查看图片也没有问题)。
只要DCI有中断回调,则打印日志,日志速率在500K左右(不用考虑日志速率过低导致漏帧问题)。
DCI的关键配置代码片段如下(参考官方ov2640例程):
// dci相关I/O口配置为166MHZ速率
// dci配置
dci_parameter_struct dci_struct;
dci_struct.capture_mode = DCI_CAPTURE_MODE_CONTINUOUS;//DCI_CAPTURE_MODE_SNAPSHOT;
dci_struct.clock_polarity = DCI_CK_POLARITY_RISING;
dci_struct.hsync_polarity = DCI_HSYNC_POLARITY_LOW;
dci_struct.vsync_polarity = DCI_VSYNC_POLARITY_LOW;
dci_struct.frame_rate = DCI_FRAME_RATE_ALL;
// dma配置
dma_multi_data_parameter_struct dma_multi_struct;
dma_multi_struct.periph_addr = (uint32_t)DCI_DATA_ADDRESS;
dma_multi_struct.memory0_addr = (uint32_t)(capture[0].image);
dma_multi_struct.direction = DMA_PERIPH_TO_MEMORY;
dma_multi_struct.number = (FRAME_BUFFER_SIZE)>>2;
dma_multi_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_multi_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_multi_struct.periph_width = DMA_PERIPH_WIDTH_32BIT;
dma_multi_struct.memory_width = DMA_MEMORY_WIDTH_32BIT;
dma_multi_struct.circular_mode = DMA_CIRCULAR_MODE_DISABLE,
dma_multi_struct.priority = DMA_PRIORITY_HIGH;
dma_multi_struct.critical_value = DMA_FIFO_4_WORD;
dma_multi_struct.memory_burst_width = DMA_MEMORY_BURST_SINGLE;
dma_multi_struct.periph_burst_width = DMA_PERIPH_BURST_SINGLE;
dci_struct.interface_format = DCI_INTERFACE_FORMAT_8BITS;
// ov2640的XCLK时钟输入(由于硬件接到PA2,只能用PWM输出16M左右的时钟作为OV2640时钟输入)
const timer_parameter_struct timer_init_struct={
.prescaler = 0,
.alignedmode = TIMER_COUNTER_EDGE,
.counterdirection = TIMER_COUNTER_UP,
.period = 180/32-1,
.clockdivision = 0,
.repetitioncounter = 0,
};
const timer_oc_parameter_struct timer_oc_init_struct={
.outputstate = TIMER_CCX_ENABLE,
.outputnstate = TIMER_CCXN_DISABLE,
.ocpolarity = TIMER_OC_POLARITY_HIGH,
.ocnpolarity = TIMER_OCN_POLARITY_HIGH,
.ocidlestate = TIMER_OC_IDLE_STATE_LOW,
.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW,
};
gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_2);
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_2);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_166MHZ, GPIO_PIN_2);
timer_init(TIMER1,(timer_parameter_struct*)&timer_init_struct);
timer_channel_output_mode_config(TIMER1,TIMER_CH_2,TIMER_OC_MODE_PWM0);
timer_channel_output_config(TIMER1,TIMER_CH_2,(timer_oc_parameter_struct*)&timer_oc_init_struct);
timer_break_disable(TIMER1);
timer_channel_output_pulse_value_config(TIMER1,TIMER_CH_2,180/32-2);
timer_channel_output_state_config(TIMER1,TIMER_CH_2,TIMER_CCX_ENABLE);
timer_enable(TIMER1);
// DCI连续采集使能
dma_channel_enable(DMA1,DMA_CH7);
dci_capture_enable();
dci_enable();
// DCI中断处理代码
/// @brief 拍照中断
/// @param
void DCI_IRQHandler(void)
{
int size;
size = FRAME_BUFFER_SIZE - (dma_transfer_number_get(DMA1,DMA_CH7)<<2);
dci_interrupt_flag_clear(DCI_INT_EF|DCI_INT_OVR);
// 看现在是捕获进哪个缓冲区,必须清DMA的标志,否则会导致无法继续捕获
dma_channel_disable(DMA1,DMA_CH7);
dma_flag_clear(DMA1,DMA_CH7,DMA_FLAG_FTF|DMA_FLAG_HTF);
if(capture_active){
if(capture_windex){
capture_windex = 0;
capture_rindex = 1;
}else{
capture_windex = 1;
capture_rindex = 0;
}
image_size = size;
capture_active = 0;
dma_memory_address_config(DMA1,DMA_CH7,DMA_MEMORY_0,(uint32_t)capture[capture_windex].image);
}
dma_transfer_number_config(DMA1,DMA_CH7,(FRAME_BUFFER_SIZE)>>2);
dma_channel_enable(DMA1,DMA_CH7);
//
if(fn_frame_cb)fn_frame_cb(size);
}
[12:00:37.591]收←◆[ DEBUG ] ov2640 frame count:32768
[12:00:38.653]收←◆[ DEBUG ] ov2640 frame count:33792
[12:00:39.716]收←◆[ DEBUG ] ov2640 frame count:34816
[12:00:40.780]收←◆[ DEBUG ] ov2640 frame count:34816
[12:00:41.842]收←◆[ DEBUG ] ov2640 frame count:34816
[12:00:42.907]收←◆[ DEBUG ] ov2640 frame count:34816
[12:00:43.971]收←◆[ DEBUG ] ov2640 frame count:34816
[12:00:45.035]收←◆[ DEBUG ] ov2640 frame count:34816
即,将近1S才采集一帧。
用逻辑分析仪测试VSYNC,周期大概在37ms,也就是说,一秒有将近30帧输出(可先排除OV2640寄存器相关配置问题,通过串口将jpeg输出到上位机,查看图片也没有问题)。
只要DCI有中断回调,则打印日志,日志速率在500K左右(不用考虑日志速率过低导致漏帧问题)。
DCI的关键配置代码片段如下(参考官方ov2640例程):
// dci相关I/O口配置为166MHZ速率
// dci配置
dci_parameter_struct dci_struct;
dci_struct.capture_mode = DCI_CAPTURE_MODE_CONTINUOUS;//DCI_CAPTURE_MODE_SNAPSHOT;
dci_struct.clock_polarity = DCI_CK_POLARITY_RISING;
dci_struct.hsync_polarity = DCI_HSYNC_POLARITY_LOW;
dci_struct.vsync_polarity = DCI_VSYNC_POLARITY_LOW;
dci_struct.frame_rate = DCI_FRAME_RATE_ALL;
// dma配置
dma_multi_data_parameter_struct dma_multi_struct;
dma_multi_struct.periph_addr = (uint32_t)DCI_DATA_ADDRESS;
dma_multi_struct.memory0_addr = (uint32_t)(capture[0].image);
dma_multi_struct.direction = DMA_PERIPH_TO_MEMORY;
dma_multi_struct.number = (FRAME_BUFFER_SIZE)>>2;
dma_multi_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_multi_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_multi_struct.periph_width = DMA_PERIPH_WIDTH_32BIT;
dma_multi_struct.memory_width = DMA_MEMORY_WIDTH_32BIT;
dma_multi_struct.circular_mode = DMA_CIRCULAR_MODE_DISABLE,
dma_multi_struct.priority = DMA_PRIORITY_HIGH;
dma_multi_struct.critical_value = DMA_FIFO_4_WORD;
dma_multi_struct.memory_burst_width = DMA_MEMORY_BURST_SINGLE;
dma_multi_struct.periph_burst_width = DMA_PERIPH_BURST_SINGLE;
dci_struct.interface_format = DCI_INTERFACE_FORMAT_8BITS;
// ov2640的XCLK时钟输入(由于硬件接到PA2,只能用PWM输出16M左右的时钟作为OV2640时钟输入)
const timer_parameter_struct timer_init_struct={
.prescaler = 0,
.alignedmode = TIMER_COUNTER_EDGE,
.counterdirection = TIMER_COUNTER_UP,
.period = 180/32-1,
.clockdivision = 0,
.repetitioncounter = 0,
};
const timer_oc_parameter_struct timer_oc_init_struct={
.outputstate = TIMER_CCX_ENABLE,
.outputnstate = TIMER_CCXN_DISABLE,
.ocpolarity = TIMER_OC_POLARITY_HIGH,
.ocnpolarity = TIMER_OCN_POLARITY_HIGH,
.ocidlestate = TIMER_OC_IDLE_STATE_LOW,
.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW,
};
gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_2);
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_2);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_166MHZ, GPIO_PIN_2);
timer_init(TIMER1,(timer_parameter_struct*)&timer_init_struct);
timer_channel_output_mode_config(TIMER1,TIMER_CH_2,TIMER_OC_MODE_PWM0);
timer_channel_output_config(TIMER1,TIMER_CH_2,(timer_oc_parameter_struct*)&timer_oc_init_struct);
timer_break_disable(TIMER1);
timer_channel_output_pulse_value_config(TIMER1,TIMER_CH_2,180/32-2);
timer_channel_output_state_config(TIMER1,TIMER_CH_2,TIMER_CCX_ENABLE);
timer_enable(TIMER1);
// DCI连续采集使能
dma_channel_enable(DMA1,DMA_CH7);
dci_capture_enable();
dci_enable();
// DCI中断处理代码
/// @brief 拍照中断
/// @param
void DCI_IRQHandler(void)
{
int size;
size = FRAME_BUFFER_SIZE - (dma_transfer_number_get(DMA1,DMA_CH7)<<2);
dci_interrupt_flag_clear(DCI_INT_EF|DCI_INT_OVR);
// 看现在是捕获进哪个缓冲区,必须清DMA的标志,否则会导致无法继续捕获
dma_channel_disable(DMA1,DMA_CH7);
dma_flag_clear(DMA1,DMA_CH7,DMA_FLAG_FTF|DMA_FLAG_HTF);
if(capture_active){
if(capture_windex){
capture_windex = 0;
capture_rindex = 1;
}else{
capture_windex = 1;
capture_rindex = 0;
}
image_size = size;
capture_active = 0;
dma_memory_address_config(DMA1,DMA_CH7,DMA_MEMORY_0,(uint32_t)capture[capture_windex].image);
}
dma_transfer_number_config(DMA1,DMA_CH7,(FRAME_BUFFER_SIZE)>>2);
dma_channel_enable(DMA1,DMA_CH7);
//
if(fn_frame_cb)fn_frame_cb(size);
}
赞0
评论
2024-01-04
您需要登录后才可以回复 登录 | 注册