2025-07-21 9:25 AM
Hello,
Because there is no active handle in DMA list for DCMI DMA initialization (bug!?) I searching for the ways to enable and use DMA, I can't find examples for parallel mode except for CSI serial, if I switch to use DCMIPP in parallel mode then the cubeMX do not generate msp initialization code function HAL_DCMIPP_MspInit for DCMIPP interface (no pinout, RCC, IRQ...), and in DMA list DCMI_PSSI handle stays inactive,
all my attempts to setup DCMI DMA do not work and DMA throws error 0x40, DCMI and camera working well, I getting hsync and vsync callbacks firing and counters show correct values, I tryed various settings but still cant start DMA transfer, there is my test and msp initialization code, please check:
uint32 err0 = HAL_DCMI_Start_DMA(&hdcmi, DCMI_MODE_CONTINUOUS, (uint32)frame_buff_DCMI, 320 * 240 / 2);
uint32 err1 = HAL_DCMI_GetError(&hdcmi);
HAL_Delay(5000);
uint32 err = HAL_DCMI_GetError(&hdcmi);
printf("DCMI %u %u, %u %u %u, %u %u\n", hdcmi.State, err, frNrCaptured, dcmiVsync, dcmiHsync, err0, err1);
HAL_DCMI_Stop(&hdcmi);
err = HAL_DCMI_GetError(&hdcmi);
printf("DCMI %u %u, %u %u %u\n", hdcmi.State, err, frNrCaptured, dcmiVsync, dcmiHsync);
void HAL_DCMI_MspInit(DCMI_HandleTypeDef* hdcmi)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
if(hdcmi->Instance==DCMI)
{
/* USER CODE BEGIN DCMI_MspInit 0 */
/* USER CODE END DCMI_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_DCMIPP;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* Peripheral clock enable */
__HAL_RCC_DCMI_PSSI_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPION_CLK_ENABLE();
/**DCMI GPIO Configuration
PF1 ------> DCMI_D7
PA1 ------> DCMI_D0
PG3 ------> DCMI_HSYNC
PG15 ------> DCMI_D4
PA10 ------> DCMI_D1
PG1 ------> DCMI_PIXCLK
PG10 ------> DCMI_D2
PG2 ------> DCMI_D6
PB4(NJTRST) ------> DCMI_VSYNC
PN9 ------> DCMI_D5
PA4 ------> DCMI_D3
*/
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_DCMI;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_10|GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_DCMI;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_15|GPIO_PIN_1|GPIO_PIN_10
|GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_DCMI;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF9_DCMI;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF10_DCMI;
HAL_GPIO_Init(GPION, &GPIO_InitStruct);
/* DCMI interrupt Init */
//HAL_NVIC_SetPriority(DCMI_PSSI_IRQn, 3, 0);
//HAL_NVIC_EnableIRQ(DCMI_PSSI_IRQn);
/* USER CODE BEGIN DCMI_MspInit 1 */
DMA_NodeConfTypeDef NodeConfig = {0};
NodeConfig.NodeType = DMA_GPDMA_LINEAR_NODE;
NodeConfig.Init.Request = GPDMA1_REQUEST_DCMI_PSSI;
NodeConfig.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
NodeConfig.Init.Direction = DMA_PERIPH_TO_MEMORY;
NodeConfig.Init.SrcInc = DMA_SINC_FIXED;
NodeConfig.Init.DestInc = DMA_DINC_INCREMENTED;
NodeConfig.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD;
NodeConfig.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD;
NodeConfig.Init.SrcBurstLength = 1;
NodeConfig.Init.DestBurstLength = 4;
NodeConfig.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0 | DMA_DEST_ALLOCATED_PORT1;
NodeConfig.Init.TransferEventMode = DMA_TCEM_LAST_LL_ITEM_TRANSFER;
NodeConfig.Init.Mode = DMA_NORMAL;
NodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_MASKED;
NodeConfig.DataHandlingConfig.DataExchange = DMA_EXCHANGE_NONE;
NodeConfig.DataHandlingConfig.DataAlignment = DMA_DATA_RIGHTALIGN_ZEROPADDED;
NodeConfig.SrcSecure = DMA_CHANNEL_SRC_SEC;
NodeConfig.DestSecure = DMA_CHANNEL_DEST_SEC;
NodeConfig.SrcAddress = (uint32_t)&DCMI->DR;
NodeConfig.DstAddress = (uint32_t)frame_buff_DCMI;
//NodeConfig.DataSize = 320 * 240 / 2; // in WORDs
NodeConfig.TriggerConfig.TriggerPolarity = DMA_TRIG_POLARITY_RISING;
if (HAL_DMAEx_List_BuildNode(&NodeConfig, &Node_GPDMA1_Channel6) != HAL_OK) {
Error_Handler();
}
if (HAL_DMAEx_List_InsertNode(&List_GPDMA1_Channel6, NULL, &Node_GPDMA1_Channel6) != HAL_OK) {
Error_Handler();
}
if (HAL_DMAEx_List_SetCircularMode(&List_GPDMA1_Channel6) != HAL_OK) {
Error_Handler();
}
handle_GPDMA1_Channel6.Instance = GPDMA1_Channel6;
handle_GPDMA1_Channel6.InitLinkedList.Priority = DMA_LOW_PRIORITY_MID_WEIGHT;
handle_GPDMA1_Channel6.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
handle_GPDMA1_Channel6.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;
handle_GPDMA1_Channel6.InitLinkedList.TransferEventMode = DMA_TCEM_LAST_LL_ITEM_TRANSFER;
handle_GPDMA1_Channel6.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
if (HAL_DMAEx_List_Init(&handle_GPDMA1_Channel6) != HAL_OK) {
Error_Handler();
}
if (HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel6, &List_GPDMA1_Channel6) != HAL_OK) {
Error_Handler();
}
HAL_DMAEx_List_Start(&handle_GPDMA1_Channel6);
__HAL_LINKDMA(hdcmi, DMA_Handle, handle_GPDMA1_Channel6);
HAL_NVIC_SetPriority(DCMI_PSSI_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(DCMI_PSSI_IRQn);
/* USER CODE END DCMI_MspInit 1 */
}
}
2025-07-30 5:10 AM
Hello,
There are a few key points to address regarding the DMA initialization for DCMI in your code:
GPDMA Clock Enable is Missing
The clock for the GPDMA peripheral must be explicitly enabled before using DMA channels. Without this, the DMA controller will not function properly.
Incorrect Call to HAL_DMAEx_List_Start at MSP Level
The call to HAL_DMAEx_List_Start(&handle_GPDMA1_Channel6); is placed too early in the MSP initialization. At this point, the DMA transfer size is not yet configured, which can cause errors. Instead, the DCMI driver itself should handle starting the DMA transfer with the appropriate size via the function:
HAL_DCMI_Start_DMA(DCMI_HandleTypeDef *hdcmi, uint32_t DCMI_Mode, uint32_t pData, uint32_t Length)
This ensures the DMA is started with the correct parameters.
NodeConfig.Init.DestBurstLength Should Be Set to 1
In your DMA node configuration, the DestBurstLength is currently set to 4. For DCMI DMA transfers, this should be set to 1 to match the peripheral's burst requirements and avoid transfer errors
The linking of the DMA handle to the DCMI handle, as well as enabling the DMA(missing)/DCMI IRQ, should be done before starting the transfer so that the DCMI driver knows which DMA handle to use and can correctly handle the received data.
You can use the example shared for STM32U5, which uses the same DMA linked list feature, as a reference.
Best Regards