2026-05-06 5:10 AM - last edited on 2026-05-06 6:27 AM by mƎALLEm
Hi,
I would like to use MDMA to get values from ADC.
I have one adc set with 6 channels, starting conversion with timer (100µs).
So I would like to save in memory adc values like that :
val1, val2, val3, val4, val5, val6 -> val1(100µs),val1(200µs)...val1(1000µs),val2(100µs),val2(200µs)...val2(1000µs)...val6(1000µs)
the destination memory is 60 values of 16 bits. That means I would like to be interrupted every 1ms by MDMA.
So I use this configuration (at beginning I would like to test only 2 first values val1 and val2):
this is the code to initialize MDMA
MDMA_HandleTypeDef hmdma_mdma_channel0_dma1_stream2_tc_0;
MDMA_LinkNodeTypeDef node_mdma_channel0_dma1_stream2_tc_1;
/**
* Enable MDMA controller clock
* Configure MDMA for global transfers
* hmdma_mdma_channel0_dma1_stream2_tc_0
* node_mdma_channel0_dma1_stream2_tc_1
*/
void MX_MDMA_Init(void)
{
/* MDMA controller clock enable */
__HAL_RCC_MDMA_CLK_ENABLE();
/* Local variables */
MDMA_LinkNodeConfTypeDef nodeConfig;
/* Configure MDMA channel MDMA_Channel0 */
/* Configure MDMA request hmdma_mdma_channel0_dma1_stream2_tc_0 on MDMA_Channel0 */
hmdma_mdma_channel0_dma1_stream2_tc_0.Instance = MDMA_Channel0;
hmdma_mdma_channel0_dma1_stream2_tc_0.Init.Request = MDMA_REQUEST_DMA1_Stream2_TC;
hmdma_mdma_channel0_dma1_stream2_tc_0.Init.TransferTriggerMode = MDMA_REPEAT_BLOCK_TRANSFER;
hmdma_mdma_channel0_dma1_stream2_tc_0.Init.Priority = MDMA_PRIORITY_LOW;
hmdma_mdma_channel0_dma1_stream2_tc_0.Init.Endianness = MDMA_LITTLE_ENDIANNESS_PRESERVE;
hmdma_mdma_channel0_dma1_stream2_tc_0.Init.SourceInc = MDMA_SRC_INC_HALFWORD;
hmdma_mdma_channel0_dma1_stream2_tc_0.Init.DestinationInc = MDMA_DEST_INC_HALFWORD;
hmdma_mdma_channel0_dma1_stream2_tc_0.Init.SourceDataSize = MDMA_SRC_DATASIZE_HALFWORD;
hmdma_mdma_channel0_dma1_stream2_tc_0.Init.DestDataSize = MDMA_DEST_DATASIZE_HALFWORD;
hmdma_mdma_channel0_dma1_stream2_tc_0.Init.DataAlignment = MDMA_DATAALIGN_PACKENABLE;
hmdma_mdma_channel0_dma1_stream2_tc_0.Init.BufferTransferLength = 2;
hmdma_mdma_channel0_dma1_stream2_tc_0.Init.SourceBurst = MDMA_SOURCE_BURST_SINGLE;
hmdma_mdma_channel0_dma1_stream2_tc_0.Init.DestBurst = MDMA_DEST_BURST_SINGLE;
hmdma_mdma_channel0_dma1_stream2_tc_0.Init.SourceBlockAddressOffset = 0;
hmdma_mdma_channel0_dma1_stream2_tc_0.Init.DestBlockAddressOffset = 18;
if (HAL_MDMA_Init(&hmdma_mdma_channel0_dma1_stream2_tc_0) != HAL_OK)
{
Error_Handler();
}
/* Configure post request address and data masks */
if (HAL_MDMA_ConfigPostRequestMask(&hmdma_mdma_channel0_dma1_stream2_tc_0, (uint32_t)(&(DMA1->LIFCR)), DMA_LIFCR_CTCIF2) != HAL_OK)
{
Error_Handler();
}
/* Initialize MDMA link node according to specified parameters */
nodeConfig.Init.Request = MDMA_REQUEST_DMA1_Stream2_TC;
nodeConfig.Init.TransferTriggerMode = MDMA_REPEAT_BLOCK_TRANSFER;
nodeConfig.Init.Priority = MDMA_PRIORITY_LOW;
nodeConfig.Init.Endianness = MDMA_LITTLE_ENDIANNESS_PRESERVE;
nodeConfig.Init.SourceInc = MDMA_SRC_INC_HALFWORD;
nodeConfig.Init.DestinationInc = MDMA_DEST_INC_HALFWORD;
nodeConfig.Init.SourceDataSize = MDMA_SRC_DATASIZE_HALFWORD;
nodeConfig.Init.DestDataSize = MDMA_DEST_DATASIZE_HALFWORD;
nodeConfig.Init.DataAlignment = MDMA_DATAALIGN_PACKENABLE;
nodeConfig.Init.BufferTransferLength = 2;
nodeConfig.Init.SourceBurst = MDMA_SOURCE_BURST_SINGLE;
nodeConfig.Init.DestBurst = MDMA_DEST_BURST_SINGLE;
nodeConfig.Init.SourceBlockAddressOffset = 0;
nodeConfig.Init.DestBlockAddressOffset = 18;
nodeConfig.PostRequestMaskAddress = (uint32_t)(&(DMA1->LIFCR));
nodeConfig.PostRequestMaskData = DMA_LIFCR_CTCIF2;
nodeConfig.SrcAddress = 0;
nodeConfig.DstAddress = _v_BufAdc1;
nodeConfig.BlockDataLength = 2;
nodeConfig.BlockCount = 6;
if (HAL_MDMA_LinkedList_CreateNode(&node_mdma_channel0_dma1_stream2_tc_1, &nodeConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN mdma_channel0_dma1_stream2_tc_1 */
/* USER CODE END mdma_channel0_dma1_stream2_tc_1 */
/* Connect a node to the linked list */
if (HAL_MDMA_LinkedList_AddNode(&hmdma_mdma_channel0_dma1_stream2_tc_0, &node_mdma_channel0_dma1_stream2_tc_1, 0) != HAL_OK)
{
Error_Handler();
}
/* MDMA interrupt initialization */
/* MDMA_IRQn interrupt configuration */
HAL_NVIC_SetPriority(MDMA_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(MDMA_IRQn);
}
this is the code to start MDMA
static ALIGN_32BYTES(uint16_t __attribute__((section (".RAM_D1"))) _v_BufAdc [10 * 6]);
ALIGN_32BYTES(uint32_t __attribute__((section (".RAM_D1"))) _v_BufAdc1);
ALIGN_32BYTES(uint32_t __attribute__((section (".RAM_D1"))) _v_BufAdc2);
_v_BufAdc1 = (uint32_t)&_v_BufAdc [1];
_v_BufAdc2 = (uint32_t)&_v_BufAdc [2];
MX_MDMA_Init();
// Start ADC conversion
HAL_ADC_Start_DMA (_k_ADC1, (DEF_t_U32 *) &_v_AdcValues1, _SPVRT_k_NUMBER_OF_ADC1);
// Start timer for adc
if (HAL_TIM_Base_Start_IT(&htim8) != HAL_OK)
{
Error_Handler();
}
if (HAL_MDMA_Start_IT(&hmdma_mdma_channel0_dma1_stream2_tc_0, (uint32_t)&_v_AdcValues1, (uint32_t)&_v_BufAdc, (2), 6) != HAL_OK)
{
/* Transfer Error */
Error_Handler();
}
When I run this code, the first time the DMA ends ADC conversion, it works, MDMA copy the 6 values to _v_BufAdc at position 0, 10, 20, 30, 40 ,50.
But the second DMA ends ADC conversion doesn't work.
So I checks MDMA registers and I saw something I don't understand :
normally (if I well understood the manual) at the end of the first repeat block transfer, the MDMA registers C0MAR and C0MDR are used to reset the TC flag of DMA (ADC).
but when the function "HAL_MDMA_Start_IT" is executed, and at this line :
/* Enable the Peripheral */
__HAL_MDMA_ENABLE(hmdma);
the both registers C0MAR and C0MDR are lost.
before the call of the macro __HAL_MDMA_ENABLE, C0MAR = 0x40020008 and C0MDR = 0x200000 that is correct, and after the macro is executed; registers C0MAR = 0x0 and C0MDR = 0x40020008.
Before macro :
Before macro
After macro :
After macro
it seems the registers are shifted ?!
Maybe an issue with the MDMA settings ?
2026-05-07 6:14 AM
Hello @lclor ,
Thank you for sharing the MDMA configuration and the debug observation.
The values you see in the MDMA registers are consistent with the configuration of the linked-list node you have made:
- nodeConfig.SrcAddress = 0
This means the source address programmed in the node is explicitly zero. So seeing a source address of 0 in the SFRs is expected from the code as written.
- nodeConfig.Init.DestBlockAddressOffset = 18
This means the destination address is incremented by 18 bytes at the end of each block. So, the destination address appearing shifted in the registers is also expected behavior.
If your goal is to transfer ADC data into a contiguous memory buffer, you should verify that:
Best regards,
DHIF Khaled
2026-05-07 6:59 AM
hello,
thank you for your reply.
-> yes there is a mistake here :
- nodeConfig.SrcAddress = 0
this should be nodeConfig.SrcAddress = (uint32_t)&_v_AdcValues1;
but it didn't work as well
- nodeConfig.Init.DestBlockAddressOffset = 18
This means the destination address is incremented by 18 bytes at the end of each block. So, the destination address appearing shifted in the registers is also expected behavior.
-> yes that correct, I draw a bitmap to explain the behavior I would like to have :
So for the first Adc conversion, it's ok, I have the values on index 0, 10, 20, 30, 40, 50
But the issue comes on the first linked list that doesn't work. And MDMA registers are shifted with bad values.
Best regards,
Laurent
2026-05-07 7:17 AM
this the copy of memory and MDMA registers when the software halt inside MDMA_RepeatBlockTransferCompleteCallback function :
normally the structure node_mdma_channel0_dma1_stream2_tc_1 is copied to registers after first node executed :
MDMA_CxTCR, MDMA_CxBNDTR, MDMA_CxSAR, MDMA_CxDAR, MDMA_CxBRUR, MDMA_CxLAR,
MDMA_CxTBR, MDMA_CxMAR and MDMA_CxMDR
but here, it seems that the structure is copied starting from register CBNDTR instead of TCR ???
best regards,
2026-05-07 8:18 AM
hello
maybe I found the issue, not sure, but now it seems to work :
in file mdma.c generated by CubeMX (all my tools are updated and libraries too) :
MDMA_HandleTypeDef hmdma_mdma_channel0_dma1_stream2_tc_0;
MDMA_LinkNodeTypeDef node_mdma_channel0_dma1_stream2_tc_1;
the data node_mdma_channel0_dma1_stream2_tc_1 is not aligned 64 bits, or i seems that register LAR should have a data aligned 64 bits.
so I change the source code by :
MDMA_HandleTypeDef hmdma_mdma_channel0_dma1_stream2_tc_0;
ALIGN_64BYTES(MDMA_LinkNodeTypeDef node_mdma_channel0_dma1_stream2_tc_1);
and now it works.
Could you confirm me that it's the issue ?
Best regards,
Laurent.