stmhal/adc.c: Get ADC working on STM32L4 MCUs.

Fixing Issue #2243. Main problems were:

- HAL_ADC_GetState(adcHandle) may return other bits set (not only
  HAL_ADC_STATE_EOC_REG) when called - so I AND-ed it out as proposed by
  mattbrejza in Issue #2243.
- ADC Pin has to be configured as GPIO_MODE_ANALOG_ADC_CONTROL not only
  GPIO_MODE_ANALOG.
- Resolved ADC resolution L4 specific (Use L4 define ADC_RESOLUTION_12B).
- Changed setting of Init.EOCSelection toADC_EOC_SINGLE_CONV for L4.
- Added call to ADC_MultiModeTypeDef as this is done on a STM32Cube
  generated project too.
- Clean up: Configuration of ADC is done only in ONE function not the same
  is done in two functions.

Test is done on PA5 pin of STM32L4Discovery-Kit which is connected to the
DOWN button.

Thanks to mattbrejza for discovering the bug.
This commit is contained in:
Tobias Badertscher 2016-07-19 11:35:33 +02:00 committed by Damien George
parent dfb8144037
commit af9889f99a

View File

@ -131,7 +131,13 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) {
mp_hal_gpio_clock_enable(pin->gpio);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = pin->pin_mask;
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
#elif defined(MCU_SERIES_L4)
GPIO_InitStructure.Mode = GPIO_MODE_ANALOG_ADC_CONTROL;
#else
#error Unsupported processor
#endif
GPIO_InitStructure.Pull = GPIO_NOPULL;
HAL_GPIO_Init(pin->gpio, &GPIO_InitStructure);
}
@ -140,7 +146,6 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) {
ADC_HandleTypeDef *adcHandle = &adc_obj->handle;
adcHandle->Instance = ADCx;
adcHandle->Init.Resolution = ADC_RESOLUTION12b;
adcHandle->Init.ContinuousConvMode = DISABLE;
adcHandle->Init.DiscontinuousConvMode = DISABLE;
adcHandle->Init.NbrOfDiscConversion = 0;
@ -148,15 +153,19 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) {
adcHandle->Init.DataAlign = ADC_DATAALIGN_RIGHT;
adcHandle->Init.NbrOfConversion = 1;
adcHandle->Init.DMAContinuousRequests = DISABLE;
adcHandle->Init.EOCSelection = DISABLE;
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
adcHandle->Init.Resolution = ADC_RESOLUTION12b;
adcHandle->Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
adcHandle->Init.ScanConvMode = DISABLE;
adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
adcHandle->Init.EOCSelection = DISABLE;
#elif defined(MCU_SERIES_L4)
adcHandle->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2;
adcHandle->Init.Resolution = ADC_RESOLUTION_12B;
adcHandle->Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
adcHandle->Init.ScanConvMode = ADC_SCAN_DISABLE;
adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIG_T1_CC1;
adcHandle->Init.EOCSelection = ADC_EOC_SINGLE_CONV;
adcHandle->Init.ExternalTrigConv = ADC_SOFTWARE_START;
adcHandle->Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
adcHandle->Init.LowPowerAutoWait = DISABLE;
adcHandle->Init.Overrun = ADC_OVR_DATA_PRESERVED;
adcHandle->Init.OversamplingMode = DISABLE;
@ -165,30 +174,42 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) {
#endif
HAL_ADC_Init(adcHandle);
#if defined(MCU_SERIES_L4)
ADC_MultiModeTypeDef multimode;
multimode.Mode = ADC_MODE_INDEPENDENT;
if (HAL_ADCEx_MultiModeConfigChannel(adcHandle, &multimode) != HAL_OK)
{
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Can not set multimode on ADC1 channel: %d", adc_obj->channel));
}
#endif
}
STATIC void adc_config_channel(pyb_obj_adc_t *adc_obj) {
STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel) {
ADC_ChannelConfTypeDef sConfig;
sConfig.Channel = adc_obj->channel;
sConfig.Channel = channel;
sConfig.Rank = 1;
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
#elif defined(MCU_SERIES_L4)
sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_NONE;
#else
#error Unsupported processor
#endif
sConfig.Offset = 0;
HAL_ADC_ConfigChannel(&adc_obj->handle, &sConfig);
HAL_ADC_ConfigChannel(adc_handle, &sConfig);
}
STATIC uint32_t adc_read_channel(ADC_HandleTypeDef *adcHandle) {
uint32_t rawValue = 0;
HAL_ADC_Start(adcHandle);
if (HAL_ADC_PollForConversion(adcHandle, 10) == HAL_OK && HAL_ADC_GetState(adcHandle) == HAL_ADC_STATE_EOC_REG) {
if (HAL_ADC_PollForConversion(adcHandle, 10) == HAL_OK
&& (HAL_ADC_GetState(adcHandle) & HAL_ADC_STATE_EOC_REG) == HAL_ADC_STATE_EOC_REG) {
rawValue = HAL_ADC_GetValue(adcHandle);
}
HAL_ADC_Stop(adcHandle);
@ -252,7 +273,7 @@ STATIC mp_obj_t adc_make_new(const mp_obj_type_t *type, mp_uint_t n_args, mp_uin
STATIC mp_obj_t adc_read(mp_obj_t self_in) {
pyb_obj_adc_t *self = self_in;
adc_config_channel(self);
adc_config_channel(&self->handle, self->channel);
uint32_t data = adc_read_channel(&self->handle);
return mp_obj_new_int(data);
}
@ -313,7 +334,7 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_
}
// configure the ADC channel
adc_config_channel(self);
adc_config_channel(&self->handle, self->channel);
// This uses the timer in polling mode to do the sampling
// TODO use DMA
@ -446,19 +467,7 @@ void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution) {
}
uint32_t adc_config_and_read_channel(ADC_HandleTypeDef *adcHandle, uint32_t channel) {
ADC_ChannelConfTypeDef sConfig;
sConfig.Channel = channel;
sConfig.Rank = 1;
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
#elif defined(MCU_SERIES_L4)
sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5;
#else
#error Unsupported processor
#endif
sConfig.Offset = 0;
HAL_ADC_ConfigChannel(adcHandle, &sConfig);
adc_config_channel(adcHandle, channel);
return adc_read_channel(adcHandle);
}