2025-10-05 11:52 AM
Hello dear ST forum.
I need again you precious help.
I am working on a data acquisition device, and need to get 14bit data from a parallel ADC connected on DCMI pins,
at 48MHz, and move it to a 32MB SDRAM (W9825G6KH-6I) till almost full. The MCU is STM32H743IIT6.
After reading, and reading, I did understand that the only available way, is to use MDMA linked list.
Create 255 nodes and transfer the 16 bit data to the SDRAM.
Can someone point me the right direction?
2025-10-05 1:31 PM
Hello nedelcu
The approach using MDMA linked list nodes is indeed a very efficient way to handle such high-throughput data transfers without CPU overhead.
Here are some tips to help:
2025-10-05 3:47 PM
Thank you for your concise answer!
To be sure that I ask the right questions and not wasting your time, I will point exactly what is my plan
for the ongoing project.
My current approach:
DCMI configured in continuous mode, no HSYNC/VSYNC (ADC-like data source)
14-bit parallel data at 48 MHz on D[13:0], with DCMI_PCLK = 48 MHz
MDMA linked-list mode with 255 nodes
Each node transfers 65,535 half-words (131,070 bytes)
Each node destination: incremental SDRAM address
LAR of last node optionally points to the first for circular capture (maybe implement trigger in future)
SDRAM configured and verified working via FMC at +100 MHz x16
Cache cleaned/invalidation handled for MDMA buffers
Please help me with the following questions:
Can DCMI continuous mode capture correctly without HSYNC/VSYNC at 48 MHz if the input clock and data are stable?
Any special configuration needed for ADC-style capture (no frame sync)?
Is DCMI → DMAMUX → MDMA request rate sufficient to sustain 48 MHz continuous half-word transfers, or should I enable internal burst mode or FIFO threshold settings? Can I go up to 60 MHz?
Can the MDMA linked list operate in circular mode if the last node’s LAR points back to the first node?
Or does the MDMA stop automatically after the last node?
For SDRAM writes via FMC, are there any recommended AXI or MPU memory attributes (e.g., non-cacheable, write-through) to avoid cache incoherency or MDMA stalls?
Is 48 MHz DCMI pixel clock within the practical limit for STM32H743IIT6 when capturing continuously through MDMA to SDRAM? Can I go up to 60 MHz?
Any ST examples or application notes demonstrating DCMI + MDMA → SDRAM (e.g., from internal test projects)?
I already reviewed:
RM0433 (DCMI, DMAMUX, and MDMA sections)
AN5020 (Using DCMI, 6.4.9 DMA configuration for higher resolutions)
But I’d appreciate confirmation or advice from ST experts before diving deeper finalizing the hardware.
Thank you for your support,
Nedelcu Bogdan Sebastian
2025-10-06
5:21 AM
- last edited on
2025-10-07
4:37 AM
by
Maxime_MARCHETT
Hello @nedelcu
1 Can DCMI capture correctly without HSYNC/VSYNC if input clock and data are stable?
Yes, the STM32H7 DCMI peripheral supports continuous capture mode without HSYNC and VSYNC signals, which is suitable for ADC-like data streams.
Special configuration needed?
Important: The input data and clock must be stable and synchronized to the MCU clock domain or have proper FIFO buffering to avoid metastability.
2 Is the request rate sufficient for 48 MHz continuous half-word transfers?
Can you go up to 60 MHz?
3 Can MDMA linked list operate circularly by pointing last node’s LAR back to first node?
4 Cache and MPU settings to avoid cache incoherency or MDMA stalls:
5 Yes, 48 MHz is within the practical limit for continuous DCMI capture on STM32H743IIT6.
6 ST provides some example projects and application notes that can help:
BR
2025-10-10 2:15 PM - edited 2025-10-10 3:55 PM
Hello!
Well..., until now, unfortunately no success. I did try a lot of modifications of the DMA linked list configuration, DCMI configuration, and nothing.
I use TIM2_CH1 to generate 24MHz on PA5, and route the signal with jumper wire to PCXLK PA6 pin.
On the data pins I don't have anything connected!
I use PA0 as acquisition start trigger.
In the last HAL, the MDMA_REQUEST_DCMI is not defined, and I did used the 75 value found in DMA file.
On running it never get's to transfer the data.
I don't use any optimizations!
Hope someone will have some spare time and throw an eye, maybe you can see any mistake that can
be corrected to make the code work.
Maybe I don't use peripherals the right way, or maybe I don't initialize them as I should???!!!
I am now struggling to make a 14 bit sine generator on an Artix7 and a 24MHz clock, maybe the DCMI
does not trigger the MDMA first node because it doesn't see any data on D0..13 pins??? Maybe?
I did add the:
/* -----------------------------------------------------------------
Section for MDMA linked-list nodes or other AXI/D1 SRAM objects.
Anything declared as:
__attribute__((section(".RAM_D1")))
will be placed here (AXI-accessible memory for DMA/MDMA).
----------------------------------------------------------------- */
.RAM_D1 (NOLOAD) :
{
. = ALIGN(32);
*(.RAM_D1)
*(.RAM_D1*)
. = ALIGN(32);
} >RAM_D1
to the STM32H743IITX_FLASH.ld.
The MDMA Linked Node List are declared as:
ALIGN_32BYTES ( static MDMA_LinkNodeTypeDef mdma_nodes[MDMA_NODE_COUNT] __attribute__((section(".RAM_D1"))) );Thank you!
If needed I can post the full project, made under STM32CubeIDE Version: 1.19.0 and with:
stm32cubeh7-v1-12-0, and stm32cubeh7-v1-12-1.
2025-10-11 4:52 PM - edited 2025-10-12 1:51 PM
I did start another approach, because in the documentation states that by not using HSYNC/VSYNC you can not work with 14bit data. At least that is what I understand by now. Maybe someone will teach me something different, please.
I generate DCMI PXCLK using TIM2 at 24MHz ,and chain TIM3 HSYNC 30 kHz, and TIM4 VSYNC 60 Hz.
I will test using this configuration to see if DCMI will loose samples.
On the run I will need your valuable help.
If someone consider useful, here is the timers TIM2 -> TIM3 -> TIM4 chaining function, tested with oscilloscope and working:
// ====================== STM32H743IIT6 ========================
// TIM2 -> TIM3 -> TIM4 synchronized chain
// TIM2: PXCLK 24 MHz (PA5)
// TIM3: HSYNC 30 kHz (PB5)
// TIM4: VSYNC 60 Hz (PB6)
// =============================================================
static void TIMERS_Init(void) {
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_SlaveConfigTypeDef sSlaveConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* Enable GPIO & TIM clocks */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_TIM2_CLK_ENABLE();
__HAL_RCC_TIM3_CLK_ENABLE();
__HAL_RCC_TIM4_CLK_ENABLE();
// ===================== TIM2 : Pixel Clock =====================
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0; // 240 MHz timer clock
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 9; // 240 MHz / (9+1) = 24 MHz
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&htim2);
HAL_TIM_PWM_Init(&htim2);
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; // Send update events to TIM3
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 5; // 50% duty (5/10)
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1);
// PA5 - TIM2_CH1 - PCLK out
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// ===================== TIM3 : HSYNC =====================
htim3.Instance = TIM3;
htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 799; // 800 pixels per line
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&htim3);
HAL_TIM_PWM_Init(&htim3);
// TIM3 counts TIM2 update events (pixel clocks)
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_EXTERNAL1;
sSlaveConfig.InputTrigger = TIM_TS_ITR1; // TIM2 -> TIM3
HAL_TIM_SlaveConfigSynchro(&htim3, &sSlaveConfig);
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; // HSYNC trigger for TIM4
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig);
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 4; // HSYNC 4 pixels (166.7 ns)
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2);
// PB5 - TIM3_CH2 - HSYNC out
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// ===================== TIM4 : VSYNC =====================
htim4.Instance = TIM4;
htim4.Init.Prescaler = 0;
htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
htim4.Init.Period = 499; // 500 lines per frame
htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
HAL_TIM_Base_Init(&htim4);
HAL_TIM_PWM_Init(&htim4);
// TIM4 counts TIM3 update events (lines)
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_EXTERNAL1;
sSlaveConfig.InputTrigger = TIM_TS_ITR2; // TIM3 -> TIM4 (ITR2 on H743)
HAL_TIM_SlaveConfigSynchro(&htim4, &sSlaveConfig);
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 1; // VSYNC 1 line (33.3 µs)
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_1);
// PB6 - TIM4_CH1 - VSYNC out
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM4;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// ===================== Start the chain =====================
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1); // Deepest slave first
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); // Master last
}
2025-10-12 2:04 PM - edited 2025-10-13 1:36 AM
Can anyone confirm
if DCMI does not store data during sync signals ?
I am worried about this issue.
Can a full port, like GPIOB bits, be copied to SDRAM using MDMA linked list ?
Or some other proven-to-work method to read 14 bit parallel data from a port, and storing to SDRAM ?
I am struggling to make DCMI->MDMA Linked List->SDRAM, but by much I test, I am beginning to believe that it is impossible. In the las HAL, MDMA_DCMI_REQUEST it does not exist, and I have used 75 which is DMA_DCMI_REQUEST, but even if I see DCMI FIFO having data, even if I trigger MDMA node list by software trigger, the DCMI does not want to trigger MDMA to start data transfer.
Thank you!
2025-10-21 12:15 PM
Hello!
I need to ask again, does the DCMI works to move 14 bit data without HSYNC/VSYNC?
Does the MDMA works to move DCMI data to FMC?
In a post here on the forum Clive1 stated that maybe it is not working at all.