Hey guys,
I’ve spent some time in the last few weeks trying to implement a simple yet efficient way to read the adc for the stm32 boards, and more specifically to read the adc efficiently enough to be able to run it in each cycle of the PWM (for low side sensing).
I am trying to avoid using DMA, now I am not sure if this is going to be a final verdict, but at the moment I would like to create the simplest possible code which works
And pooling seems like the reasonable solution.
The problem is that analogRead
takes around 60us per phase. which is far too long.
I was able to come to around 10us for 3 phases using better adc settings. And this works pretty well and this basically solves the problem, the only problem is that since I am using polling the execution time is not deterministic. So it gives me some strange behavior. (sometimes it polls for millisecond before it receives a value).
Here is the latest code I came up to, it is for nucleo f401re, but it should work more or less on all the stm chips with stm32duino package. If someone has more experience setting these adc’s more efficiently I would be happy to hear your thoughts. The community is really limited in this sense and I am having a hard time to find good resources.
// some sytm32duino specific code not important for understanding
// --------------------------------------------------------------------------------------
#ifndef ADC_CLOCK_DIV
#ifdef ADC_CLOCK_SYNC_PCLK_DIV4
#define ADC_CLOCK_DIV ADC_CLOCK_SYNC_PCLK_DIV4
#elif ADC_CLOCK_SYNC_PCLK_DIV2
#define ADC_CLOCK_DIV ADC_CLOCK_SYNC_PCLK_DIV2
#elif defined(ADC_CLOCK_ASYNC_DIV1)
#define ADC_CLOCK_DIV ADC_CLOCK_ASYNC_DIV1
#endif
#endif /* !ADC_CLOCK_DIV */
#ifndef ADC_SAMPLINGTIME
#if defined(ADC_SAMPLETIME_8CYCLES_5)
#define ADC_SAMPLINGTIME ADC_SAMPLETIME_8CYCLES_5;
#elif defined(ADC_SAMPLETIME_12CYCLES_5)
#define ADC_SAMPLINGTIME ADC_SAMPLETIME_12CYCLES_5;
#elif defined(ADC_SAMPLETIME_13CYCLES_5)
#define ADC_SAMPLINGTIME ADC_SAMPLETIME_13CYCLES_5;
#elif defined(ADC_SAMPLETIME_15CYCLES)
#define ADC_SAMPLINGTIME ADC_SAMPLETIME_15CYCLES;
#elif defined(ADC_SAMPLETIME_16CYCLES)
#define ADC_SAMPLINGTIME ADC_SAMPLETIME_16CYCLES;
#elif defined(ADC_SAMPLETIME_19CYCLES_5)
#define ADC_SAMPLINGTIME ADC_SAMPLETIME_19CYCLES_5;
#endif
#endif /* !ADC_SAMPLINGTIME */
// --------------------------------------------------------------------------------------
ADC_HandleTypeDef hadc;
void setup()
{
pinMode(13,OUTPUT);
pinMode(A0,INPUT);
pinMode(A1,INPUT);
pinMode(A2,INPUT);
Serial.begin(115200);
delay(2000);
MX_ADC_Init();
}
int value[3]={0};
void loop()
{
digitalWrite(13, HIGH);
//adc_read(&hadc, value, 3);
HAL_ADC_Start(&hadc);
HAL_ADC_PollForConversion(&hadc, 1); // polling timeout 1ms - cannot go lower
value[0] = HAL_ADC_GetValue(&hadc);
HAL_ADC_PollForConversion(&hadc, 1);
value[1] = HAL_ADC_GetValue(&hadc);
HAL_ADC_PollForConversion(&hadc, 1);
value[2] = HAL_ADC_GetValue(&hadc);
digitalWrite(13, LOW);
Serial.print(value[0]);
Serial.print("\t");
Serial.print(value[1]);
Serial.print("\t");
Serial.println(value[2]);
}
void MX_ADC_Init()
{
ADC_ChannelConfTypeDef sConfig;
/**Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc.Instance = ADC1;
hadc.Init.ClockPrescaler = ADC_CLOCK_DIV;
hadc.Init.Resolution = ADC_RESOLUTION_12B;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ScanConvMode = ENABLE;
hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc.Init.ContinuousConvMode = DISABLE;
hadc.Init.NbrOfConversion = 3;
hadc.Init.DiscontinuousConvMode = ENABLE;
hadc.Init.NbrOfDiscConversion = 3;
// this is the important bit
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.DMAContinuousRequests = DISABLE;
HAL_ADC_Init(&hadc);
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLINGTIME;
HAL_ADC_ConfigChannel(&hadc, &sConfig);
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = 2;
HAL_ADC_ConfigChannel(&hadc, &sConfig);
/**Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_4;
sConfig.Rank = 3;
HAL_ADC_ConfigChannel(&hadc, &sConfig);
/* Configure ADC GPIO pin */
pinmap_pinout(analogInputToPinName(A0), PinMap_ADC);
pinmap_pinout(analogInputToPinName(A1), PinMap_ADC);
pinmap_pinout(analogInputToPinName(A2), PinMap_ADC);
}