2023-07-17 01:30 AM
Hi,
I want to read analogue values out of the ADC of an STM32F446. This works well when using CubeMX-based functions.
The initialisation:
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = ENABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_4;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
Reading one single ADC value (simplified code):
if (HAL_ADC_Start(&hadc1)==HAL_OK)
{
HAL_ADC_PollForConversion(&hadc1,100);
if ((HAL_ADC_GetState(&hadc1) & HAL_ADC_STATE_EOC_REG)==HAL_ADC_STATE_EOC_REG))
{
adcVal1=HAL_ADC_GetValue(&hadc1);
}
}
My problem here: this approach is way too complicated and time-consuming. So these three functions to be called do a lot of interesting but complex stuff, just for reading one single ADC value.
So my question: Isn't this possible much easier? Can't I simply invoke a permanent ADC conversion, then check a register value if one conversion cycle is complete, read the converted value from an other register and then clear the conversion-ready-bit in order to be able to detect the next conversion being complete?
I guess these three HAL-functions are doing something like that but they are doing that with loads of more stuff (setting/clearing several registers and states instead of having a few, simple register accesses only).
So any idea how this can be done - may be there is some example code available somewhere that shows how to do that?
Thanks :)
2023-07-17 04:18 AM
Let the DMA fill a buffer with ADC values, if the buffer is full the DMA triggers an interrupt, there you can set a flag, and then analyse the buffer in main.
Unless you want to check single values all the time, if that's the case you could let the ADC trigger an interrupt (EOC, end of conversion) - but this would be a terrible idea for high sampling rates. Calling interrupt handlers and getting back takes also CPU cycles / time.
2023-07-17 07:09 AM
I neither wat to have DMA nor interrupt access to the ADC values. ADC has the lowest priority in this system, so it has to be done by polling (as stated in my original question).
For my application it is mandatory no ADC interrupt delays any of the other, much more important interrupts, that's why only polling is an option here.
2023-07-17 11:03 PM
> I guess these three HAL-functions are doing something like that but they are doing that with loads of more stuff (setting/clearing several registers and states instead of having a few, simple register accesses only).
That's HAL! :D
So grab the reference manual and stop guessing.
Check what HAL_ADC_PollForConversion() is actually doing and check that flag / bit without the while loop, maybe in a main state machine with a timer you have running anyway.