问题描述 使用主控STM32H750VBT6的DCMI外设与FPGA进行大数据交互。在测试中发现,程序会偶发性地收不到前几个FPGA发过来的字节数据 DCMI外设的配置代码如下 void MX_DCMI_Init(void)
{
​
/* USER CODE BEGIN DCMI_Init 0 */
​
/* USER CODE END DCMI_Init 0 */
​
/* USER CODE BEGIN DCMI_Init 1 */
​
/* USER CODE END DCMI_Init 1 */
hdcmi.Instance = DCMI;
hdcmi.Init.SynchroMode = DCMI_SYNCHRO_HARDWARE;
hdcmi.Init.PCKPolarity = DCMI_PCKPOLARITY_RISING;
hdcmi.Init.VSPolarity = DCMI_VSPOLARITY_HIGH;
hdcmi.Init.HSPolarity = DCMI_HSPOLARITY_HIGH;
hdcmi.Init.CaptureRate = DCMI_CR_ALL_FRAME;
hdcmi.Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B;
hdcmi.Init.JPEGMode = DCMI_JPEG_DISABLE;
hdcmi.Init.ByteSelectMode = DCMI_BSM_ALL;
hdcmi.Init.ByteSelectStart = DCMI_OEBS_ODD;
hdcmi.Init.LineSelectMode = DCMI_LSM_ALL;
hdcmi.Init.LineSelectStart = DCMI_OELS_ODD;
if (HAL_DCMI_Init(&hdcmi) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN DCMI_Init 2 */
​
/* USER CODE END DCMI_Init 2 */
​
}
​
void HAL_DCMI_MspInit(DCMI_HandleTypeDef* dcmiHandle)
{
​
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(dcmiHandle->Instance==DCMI)
{
/* USER CODE BEGIN DCMI_MspInit 0 */
​
/* USER CODE END DCMI_MspInit 0 */
/* DCMI clock enable */
__HAL_RCC_DCMI_CLK_ENABLE();
​
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**DCMI GPIO Configuration
PE4 ------> DCMI_D4
PA4 ------> DCMI_HSYNC
PA6 ------> DCMI_PIXCLK
PA9 ------> DCMI_D0
PA10 ------> DCMI_D1
PD3 ------> DCMI_D5
PB7 ------> DCMI_VSYNC
PB8 ------> DCMI_D6
PB9 ------> DCMI_D7
PE0 ------> DCMI_D2
PE1 ------> DCMI_D3
*/
GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_0|GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF13_DCMI;
HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
​
GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_6|GPIO_PIN_9|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF13_DCMI;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
​
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF13_DCMI;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
​
GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF13_DCMI;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
​
/* DCMI DMA Init */
/* DCMI Init */
hdma_dcmi.Instance = DMA2_Stream1;
hdma_dcmi.Init.Request = DMA_REQUEST_DCMI;
hdma_dcmi.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_dcmi.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_dcmi.Init.MemInc = DMA_MINC_ENABLE;
hdma_dcmi.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_dcmi.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_dcmi.Init.Mode = DMA_CIRCULAR;
hdma_dcmi.Init.Priority = DMA_PRIORITY_VERY_HIGH;
hdma_dcmi.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_dcmi) != HAL_OK)
{
Error_Handler();
}
​
__HAL_LINKDMA(dcmiHandle,DMA_Handle,hdma_dcmi);
​
/* DCMI interrupt Init */
HAL_NVIC_SetPriority(DCMI_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DCMI_IRQn);
/* USER CODE BEGIN DCMI_MspInit 1 */
​
/* USER CODE END DCMI_MspInit 1 */
}
}
​
void HAL_DCMI_MspDeInit(DCMI_HandleTypeDef* dcmiHandle)
{
​
if(dcmiHandle->Instance==DCMI)
{
/* USER CODE BEGIN DCMI_MspDeInit 0 */
​
/* USER CODE END DCMI_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_DCMI_CLK_DISABLE();
​
/**DCMI GPIO Configuration
PE4 ------> DCMI_D4
PA4 ------> DCMI_HSYNC
PA6 ------> DCMI_PIXCLK
PA9 ------> DCMI_D0
PA10 ------> DCMI_D1
PD3 ------> DCMI_D5
PB7 ------> DCMI_VSYNC
PB8 ------> DCMI_D6
PB9 ------> DCMI_D7
PE0 ------> DCMI_D2
PE1 ------> DCMI_D3
*/
HAL_GPIO_DeInit(GPIOE, GPIO_PIN_4|GPIO_PIN_0|GPIO_PIN_1);
​
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_4|GPIO_PIN_6|GPIO_PIN_9|GPIO_PIN_10);
​
HAL_GPIO_DeInit(GPIOD, GPIO_PIN_3);
​
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9);
​
/* DCMI DMA DeInit */
HAL_DMA_DeInit(dcmiHandle->DMA_Handle);
​
/* DCMI interrupt Deinit */
HAL_NVIC_DisableIRQ(DCMI_IRQn);
/* USER CODE BEGIN DCMI_MspDeInit 1 */
​
/* USER CODE END DCMI_MspDeInit 1 */
}
}程序使用DCMI的快照模式 HAL_DCMI_Start_DMA(&hdcmi,DCMI_MODE_SNAPSHOT, (uint32_t)DCMI_DataBuffer[idx], DCMI_FRAME_WORDS * DCMI_PACKET_FRAMES);在DCMI帧完成回调中处理DCMI的数据 void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi)
{
HAL_DCMI_Stop(&hdcmi); //停止DCMI接收
/* DCMI数据处理过程 */
HAL_DCMI_Start_DMA(&hdcmi,DCMI_MODE_SNAPSHOT, (uint32_t)DCMI_DataBuffer[idx], DCMI_FRAME_WORDS * DCMI_PACKET_FRAMES); //重新开启DCMI接收
}问题是在复位MCU后会偶发性的出现。DCMI缓存里,前几个数据一直是0值 问题查找MCU这端因为使用的是STM32H7系列芯片,涉及到了DMA。所以在每次处理DCMI的数据前,都用使用Cache无效化缓存函数,避免数据一致性问题。同时测量了整个帧中断周期的耗时。发现是完全满足FPGA传输数据的速率。不会因为中断太占时间而导致数据没有接收到。 FPGA端抓取过时钟和数据信号。发现是没问题的。 硬件端使用示波器勘测过DCMI的时钟信号。也是没有问题。 最后发现是DMA配置这里,应该是有问题的 hdma_dcmi.Init.Mode = DMA_CIRCULAR;因为使用的是DCMI的快照模式,在每次接收完一帧完成的数据后会停止DCMI.在处理完数据后再打开DMA接收。但是这里DMA的模式是循环模式。意思是在接收完一帧完整的信号后。DMA的指针地址会回到缓存开头的地址。但是此时DCMI的数据信号全是0(这里看过时钟信号。虽然VSYNC和HSYNNC信号无效了,但是PIXEL信号是一直在输出的)。所以DMA会收到PIXEL信号的驱使。继续搬运数据总线上的信号到缓存中。改掉DMA的CIRCULAR模式为NORMAL模式。问题得到解决 时序图:
|