Skip to main content
Associate
July 28, 2026
Question

Random 0's in DMA buffer when using ADC + DMA

  • July 28, 2026
  • 6 replies
  • 89 views

Hello,

I’m using the ADC with DMA for my application where I read the values from a Pot. The DMA is configured to generate interrupts when the DMA buffer is half full and completely full. The readings obtained seem to be correct apart from the fact that there seems to be random 0’s in the buffer. I’m not sure why this happens. Below are the relevant portions of my code:

    vInit()
{

/* USER CODE BEGIN ADC1_Init 0 */

/* USER CODE END ADC1_Init 0 */

LL_ADC_InitTypeDef ADC_InitStruct = {0};
LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
LL_ADC_CommonInitTypeDef ADC_CommonInitStruct = {0};

LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

LL_RCC_SetADCClockSource(SPEED_CONTROL_POT_ADC_CLOCK_SOURCE);

/* Peripheral clock enable */
LL_AHB2_GRP1_EnableClock(SPEED_CONTROL_POT_ADC_PERIPH_CLOCK);

LL_AHB2_GRP1_EnableClock(SPEED_CONTROL_POT_GPIO_PERIPH_CLOCK);
/**ADC1 GPIO Configuration
PA0 ------> ADC1_IN1
*/
GPIO_InitStruct.Pin = SPEED_CONTROL_POT_ADC_GPIO_PIN;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
LL_GPIO_Init(SPEED_CONTROL_POT_ADC_GPIO_PORT, &GPIO_InitStruct);

/* ADC1 DMA Init */
vAdcInitDmaInterrupt_m();

/* ADC1 Init */
LL_DMA_SetPeriphRequest(SPEED_CONTROL_POT_ADC_DMA_MODULE, SPEED_CONTROL_POT_ADC_DMA_CHANNEL, LL_DMAMUX_REQ_ADC1);

LL_DMA_SetDataTransferDirection(SPEED_CONTROL_POT_ADC_DMA_MODULE, SPEED_CONTROL_POT_ADC_DMA_CHANNEL, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);

LL_DMA_SetChannelPriorityLevel(SPEED_CONTROL_POT_ADC_DMA_MODULE, SPEED_CONTROL_POT_ADC_DMA_CHANNEL, LL_DMA_PRIORITY_LOW);

LL_DMA_SetMode(SPEED_CONTROL_POT_ADC_DMA_MODULE, SPEED_CONTROL_POT_ADC_DMA_CHANNEL, LL_DMA_MODE_CIRCULAR);

LL_DMA_SetPeriphIncMode(SPEED_CONTROL_POT_ADC_DMA_MODULE, SPEED_CONTROL_POT_ADC_DMA_CHANNEL, LL_DMA_PERIPH_NOINCREMENT);

LL_DMA_SetMemoryIncMode(SPEED_CONTROL_POT_ADC_DMA_MODULE, SPEED_CONTROL_POT_ADC_DMA_CHANNEL, LL_DMA_MEMORY_INCREMENT);

LL_DMA_SetPeriphSize(SPEED_CONTROL_POT_ADC_DMA_MODULE, SPEED_CONTROL_POT_ADC_DMA_CHANNEL, LL_DMA_PDATAALIGN_HALFWORD);

LL_DMA_SetMemorySize(SPEED_CONTROL_POT_ADC_DMA_MODULE, SPEED_CONTROL_POT_ADC_DMA_CHANNEL, LL_DMA_MDATAALIGN_HALFWORD);

LL_DMA_SetDataLength(SPEED_CONTROL_POT_ADC_DMA_MODULE,
SPEED_CONTROL_POT_ADC_DMA_CHANNEL,
SPEED_CONTROL_POT_ADC_DMA_BUFFER_LENGTH);

LL_DMA_EnableIT_HT(SPEED_CONTROL_POT_ADC_DMA_MODULE,SPEED_CONTROL_POT_ADC_DMA_CHANNEL);

LL_DMA_EnableIT_TC(SPEED_CONTROL_POT_ADC_DMA_MODULE,SPEED_CONTROL_POT_ADC_DMA_CHANNEL);

//Register the ISR
//Register interrupt here

LL_DMA_ConfigAddresses(SPEED_CONTROL_POT_ADC_DMA_MODULE,
SPEED_CONTROL_POT_ADC_DMA_CHANNEL,
LL_ADC_DMA_GetRegAddr(SPEED_CONTROL_POT_ADC_MODULE, LL_ADC_DMA_REG_REGULAR_DATA),
(INT32U)pu16AdcBuffer_m,
LL_DMA_DIRECTION_PERIPH_TO_MEMORY);

LL_DMA_EnableChannel(SPEED_CONTROL_POT_ADC_DMA_MODULE,SPEED_CONTROL_POT_ADC_DMA_CHANNEL);


/* USER CODE BEGIN ADC1_Init 1 */

/* USER CODE END ADC1_Init 1 */

/** Common config
*/
ADC_InitStruct.Resolution = SPEED_CONTROL_POT_ADC_RESOLUTION;
ADC_InitStruct.DataAlignment = SPEED_CONTROL_POT_ADC_DATA_ALIGN;
ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE;
LL_ADC_Init(SPEED_CONTROL_POT_ADC_MODULE, &ADC_InitStruct);
ADC_REG_InitStruct.TriggerSource = SPEED_CONTROL_POT_ADC_TRGO_SOURCE;
ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE;
ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_SINGLE;
ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_UNLIMITED;
ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_PRESERVED;
LL_ADC_REG_Init(SPEED_CONTROL_POT_ADC_MODULE, &ADC_REG_InitStruct);
LL_ADC_SetGainCompensation(SPEED_CONTROL_POT_ADC_MODULE, 0);
LL_ADC_SetOverSamplingScope(SPEED_CONTROL_POT_ADC_MODULE, LL_ADC_OVS_DISABLE);
ADC_CommonInitStruct.CommonClock = LL_ADC_CLOCK_SYNC_PCLK_DIV4;
ADC_CommonInitStruct.Multimode = LL_ADC_MULTI_INDEPENDENT;
LL_ADC_CommonInit(__LL_ADC_COMMON_INSTANCE(SPEED_CONTROL_POT_ADC_MODULE), &ADC_CommonInitStruct);
LL_ADC_REG_SetTriggerEdge(ADC1, LL_ADC_REG_TRIG_EXT_RISING);

/* Disable ADC deep power down (enabled by default after reset state) */
LL_ADC_DisableDeepPowerDown(SPEED_CONTROL_POT_ADC_MODULE);
/* Enable ADC internal voltage regulator */
LL_ADC_EnableInternalRegulator(SPEED_CONTROL_POT_ADC_MODULE);
/* Delay for ADC internal voltage regulator stabilization. */
/* Compute number of CPU cycles to wait for, from delay in us. */
/* Note: Variable divided by 2 to compensate partially */
/* CPU processing cycles (depends on compilation optimization). */
/* Note: If system core clock frequency is below 200kHz, wait time */
/* is only a few CPU processing cycles. */
uint32_t wait_loop_index;
wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US * (SystemCoreClock / (100000 * 2))) / 10);
while(wait_loop_index != 0)
{
wait_loop_index--;
}

/** Configure Regular Channel
*/


LL_ADC_REG_SetSequencerRanks(SPEED_CONTROL_POT_ADC_MODULE, LL_ADC_REG_RANK_1, SPEED_CONTROL_POT_ADC_CHANNEL);
LL_ADC_SetChannelSamplingTime(SPEED_CONTROL_POT_ADC_MODULE, SPEED_CONTROL_POT_ADC_CHANNEL, LL_ADC_SAMPLINGTIME_2CYCLES_5);
LL_ADC_SetChannelSingleDiff(SPEED_CONTROL_POT_ADC_MODULE, SPEED_CONTROL_POT_ADC_CHANNEL, LL_ADC_SINGLE_ENDED);
/* USER CODE BEGIN ADC1_Init 2 */
vAdcCalibrate_m();
LL_ADC_Enable(SPEED_CONTROL_POT_ADC_MODULE);
while(TRUE != LL_ADC_IsActiveFlag_ADRDY(SPEED_CONTROL_POT_ADC_MODULE));
LL_ADC_ClearFlag_ADRDY(SPEED_CONTROL_POT_ADC_MODULE);

//Initialize the timer used to trigger the conversion
vAdcInitTimer_m();

/* USER CODE END ADC1_Init 2 */

}

vEnableAdc()
{
LL_TIM_EnableCounter(SPEED_CONTROL_POT_TIMER_MODULE);
LL_ADC_REG_StartConversion(SPEED_CONTROL_POT_ADC_MODULE);
}

vAdcInitDmaInterrupt_m()
{
/* Init with LL driver */
/* DMA controller clock enable */
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMAMUX1);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);

/* DMA interrupt init */
/* DMA1_Channel1_IRQn interrupt configuration */
NVIC_SetPriority(DMA1_Channel1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),3, 0));
NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}

vAdcInitTimer_m()
{
/* USER CODE BEGIN TIM3_Init 0 */

/* USER CODE END TIM3_Init 0 */

LL_TIM_InitTypeDef TIM_InitStruct = {0};

/* Peripheral clock enable */
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3);

/* USER CODE BEGIN TIM3_Init 1 */

/* USER CODE END TIM3_Init 1 */
TIM_InitStruct.Prescaler = SPEED_CONTROL_POT_TIMER_PRESCALER;
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
TIM_InitStruct.Autoreload = SPEED_CONTROL_POT_TIMER_AUTO_RELOAD;
TIM_InitStruct.ClockDivision = SPEED_CONTROL_POT_TIMER_CLK_DIVISION_FACTOR;
LL_TIM_Init(SPEED_CONTROL_POT_TIMER_MODULE, &TIM_InitStruct);
LL_TIM_DisableARRPreload(SPEED_CONTROL_POT_TIMER_MODULE);
LL_TIM_SetClockSource(SPEED_CONTROL_POT_TIMER_MODULE, LL_TIM_CLOCKSOURCE_INTERNAL);
LL_TIM_SetTriggerOutput(SPEED_CONTROL_POT_TIMER_MODULE, LL_TIM_TRGO_UPDATE);
LL_TIM_SetUpdateSource(SPEED_CONTROL_POT_TIMER_MODULE,LL_TIM_UPDATESOURCE_COUNTER);
LL_TIM_DisableMasterSlaveMode(SPEED_CONTROL_POT_TIMER_MODULE);
/* USER CODE BEGIN TIM3_Init 2 */

/* USER CODE END TIM3_Init 2 */
}

vAdcCalibrate_m()
{
LL_ADC_StartCalibration(SPEED_CONTROL_POT_ADC_MODULE,LL_ADC_SINGLE_ENDED);
while(LL_ADC_IsCalibrationOnGoing(SPEED_CONTROL_POT_ADC_MODULE));
}

 

6 replies

TDK
July 29, 2026

Nowhere in the posted code do you read the data in the buffer. I don’t even see code that starts ADC conversions.

Where’s the code that reads the ADC data and where exactly do you see zeroes?

"If you feel a post has answered your question, please click ""Accept as Solution""."
STMUser08Author
Associate
July 29, 2026

The code that starts the ADC conversion is on line 129.

I read the ADC data when the “buffer half full” and “full” interrupts occur. My ADC DMA buffer is of size 128, split in to 2 halves for this purpose. 

 

TDK
July 30, 2026

The code that starts the ADC conversion is on line 129.

That may be, but vEnableAdc isn’t called anywhere in the posted code. The IRQ handlers are also missing.

The bug is in your code and unless you show enough of it, we can only guess. Posting a minimal working example is the best strategy for getting your question answer effectively.

The 0 seems to occur at the very first position of the second half of the buffer. 

Based on what? How are you viewing the data? Show screenshots, or a log, or whatever is leading you to believe there’s a 0 there. We have no idea.

"If you feel a post has answered your question, please click ""Accept as Solution""."
STMUser08Author
Associate
July 30, 2026

@TDK I think I might have figured it out. I read the buffer values inside a function that lies within a forever while loop. Inside this function, I do check if a “Buffer half full” or “Buffer Full” interrupt has occurred. I seem to have been reading from the buffer when neither of these interrupts had occurred. I guess this could be a reason as to why I kept “seeing zeros” (image above) in the buffer.  

TDK
July 30, 2026

I can’t help without seeing the code with the bug in it.

"If you feel a post has answered your question, please click ""Accept as Solution""."