2018-01-19 02:16 PM
Hi. I need to have the value of 2 channels and the internal temperature.
My adc is setup as this:hadc.Instance = ADC1;
hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc.Init.Resolution = ADC_RESOLUTION_12B; hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD; hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV; hadc.Init.LowPowerAutoWait = DISABLE; hadc.Init.LowPowerAutoPowerOff = DISABLE; hadc.Init.ContinuousConvMode = DISABLE; hadc.Init.DiscontinuousConvMode = DISABLE; hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc.Init.DMAContinuousRequests = DISABLE; hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;and this is my callback:
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {
if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC)) { ADCValues[ADCIndex]= HAL_ADC_GetValue(hadc); ADCIndex++; } if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOS)) { ADCIndex= 0; Vdd= 3300 * (*VREFINT_CAL_ADDR) / ADCValues[3]; Temperature= (((int32_t)ADCValues[2] * Vdd / 3300)- (int32_t)*TEMP30_CAL_ADDR); Temperature= Temperature * (int32_t)(110- 30); Temperature= Temperature / (int32_t)(*TEMP110_CAL_ADDR- *TEMP30_CAL_ADDR); Temperature= Temperature+ 30; Reader125_0= ADCValues[1]; Reader125_1= ADCValues[0]; }}everything is working perfectly but only with 'hadc.Init.ContinuousConvMode = DISABLE;'
If I enable 'hadc.Init.ContinuousConvMode' I have wrong values.
What can I do to resolve the problem?
2018-01-19 04:48 PM
If the EOS processing takes longer than one ADC conversion, the next EOC process will be for the second or later conversion, out of sync with the ADCIndex.
If for some reason you can't disable continuous mode, try converting VREF or Temperature first where, I presume, you have the longer sampling times needed for accuracy. But you then run the risk that might not work for a different combination of ADC clock and system clock.
Cheers, Hal
2018-01-19 10:28 PM
yes, the values go crazy down here;
ADC_CLOCK_ASYNC_DIV1
and ADC_SAMPLETIME_1CYCLE_5
what sample time are you using ?
you really have to calibrate the ADC too, if you want some accuracy in the readings
2018-01-20 12:35 AM
Finally this is my CubeMX setup
This is my callback
unsigned int ADCValues[5];
unsigned int ADCIndex= 0;void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {
if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOC)) { ADCValues[ADCIndex]= HAL_ADC_GetValue(hadc); ADCIndex++; } if (__HAL_ADC_GET_FLAG(hadc, ADC_FLAG_EOS)) ADCIndex= 0;}And outside che callback I check the ADCValues[2] and ADCValues[3] where I should have the Temperature and Vdd values.
Is this the right approach? The Temperature value now seems to be ok.2018-01-20 04:06 AM
I have a similar approach,
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
if(!ADC_ChannelsCounter--) {
ADC_ChannelsCounter = ADC_ChannelCount;
ADC_CompleteCycle = true; // signal foreground to process
// copy 15 channels results away now
for(int i = 0 ; i < ADC_ChannelCount ; i++) {
ADC_Channel_Buffer[i] = ADC_DMABuffer[i];
}
}
}�?�?�?�?�?�?�?�?�?�?�?�?
2018-01-21 08:31 AM
Reading the values outside the sampling loop I believe is a better approach.
The internal channels are high impedance sources, so T. J.'s example using 1.5 cycles will produce inaccurate results with any sampling method.
The root difficulty that ADC programmers have to overcome is ST's design of using one data register per ADC. The best software approach is to use DMA to save a sampling sequence to memory, then process the results when the DMA counter gets to zero. ST's ADC Sequencer example is a highly convoluted, inefficient way to do a simple task, and I suspect it leads beginner's astray.
Cheers, Hal