Question
Random 0's in DMA buffer when using ADC + DMA
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));
}
