2024-05-16 12:32 PM - edited 2024-05-16 01:00 PM
I'm using ADC1 to measure the Temperature Sensor channel and the Vrefint channel. I expect those to vary very slowly and I am in not in a hurry so I am maximizing the sampling time. These are my settings in STM32CubeIDE:
It generates the following in main.c:
static void MX_ADC1_Init(void)
{
/* 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};
/* Peripheral clock enable */
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_ADC);
/* ADC1 DMA Init */
/* ADC1 Init */
LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_1, LL_DMA_REQUEST_0);
LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_MEDIUM);
LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_CIRCULAR);
LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);
LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT);
LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_HALFWORD);
LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_HALFWORD);
/* ADC1 interrupt Init */
NVIC_SetPriority(ADC1_2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
NVIC_EnableIRQ(ADC1_2_IRQn);
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Common config
*/
ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B;
ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;
ADC_InitStruct.LowPowerMode = LL_ADC_LP_AUTOWAIT;
LL_ADC_Init(ADC1, &ADC_InitStruct);
ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;
ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_ENABLE_2RANKS;
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_OVERWRITTEN;
LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
LL_ADC_ConfigOverSamplingRatioShift(ADC1, LL_ADC_OVS_RATIO_256, LL_ADC_OVS_SHIFT_RIGHT_8);
LL_ADC_SetOverSamplingDiscont(ADC1, LL_ADC_OVS_REG_CONT);
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_CHANNEL_VREFINT|LL_ADC_CHANNEL_TEMPSENSOR);
ADC_CommonInitStruct.CommonClock = LL_ADC_CLOCK_ASYNC_DIV64;
ADC_CommonInitStruct.Multimode = LL_ADC_MULTI_INDEPENDENT;
LL_ADC_CommonInit(__LL_ADC_COMMON_INSTANCE(ADC1), &ADC_CommonInitStruct);
/* Disable ADC deep power down (enabled by default after reset state) */
LL_ADC_DisableDeepPowerDown(ADC1);
/* Enable ADC internal voltage regulator */
LL_ADC_EnableInternalRegulator(ADC1);
/* 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(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_VREFINT);
LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_VREFINT, LL_ADC_SAMPLINGTIME_640CYCLES_5);
LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_VREFINT, LL_ADC_SINGLE_ENDED);
/** Configure Regular Channel
*/
LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_2, LL_ADC_CHANNEL_TEMPSENSOR);
LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_TEMPSENSOR, LL_ADC_SAMPLINGTIME_640CYCLES_5);
LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_TEMPSENSOR, LL_ADC_SINGLE_ENDED);
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
The ADC clock is set to PLLSAI1R, and
printf("ADC1 clock freq.: %lu\n", HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_ADC));
prints "ADC1 clock freq.: 48000000".
EDIT: ADC_CCR is
// 3 2 1
// 10987654321098765432109876543210
0b111001000000000000000000
Bits 21:18 PRESC[3:0]: ADC prescaler: 1001: input ADC clock divided by 64
My theory is that a sequence of conversions should take about 446 milliseconds:
However, when I run this:
LL_ADC_ClearFlag_EOS(ADC1);
__COMPILER_BARRIER();
start = micros();
LL_ADC_REG_StartConversion(ADC1);
while(!LL_ADC_IsActiveFlag_EOS(ADC1) && micros() - start < 1000000);
assert(LL_ADC_IsActiveFlag_EOS(ADC1));
printf("EOS wait: %lu us\n", micros() - start);
I consistently see "EOS wait: 1757 us". That is a couple of orders of magnitude less time than I was expecting.
What am I missing?
Solved! Go to Solution.
2024-09-23 05:47 AM
Hello,
Please note that issue #181796 was fixed in the STM32CubeMX 6.12.0 release.
-Amel
To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.