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:
parent
dfb8144037
commit
af9889f99a
55
stmhal/adc.c
55
stmhal/adc.c
|
@ -131,7 +131,13 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) {
|
||||||
mp_hal_gpio_clock_enable(pin->gpio);
|
mp_hal_gpio_clock_enable(pin->gpio);
|
||||||
GPIO_InitTypeDef GPIO_InitStructure;
|
GPIO_InitTypeDef GPIO_InitStructure;
|
||||||
GPIO_InitStructure.Pin = pin->pin_mask;
|
GPIO_InitStructure.Pin = pin->pin_mask;
|
||||||
|
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
|
||||||
GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
|
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;
|
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||||
HAL_GPIO_Init(pin->gpio, &GPIO_InitStructure);
|
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;
|
ADC_HandleTypeDef *adcHandle = &adc_obj->handle;
|
||||||
adcHandle->Instance = ADCx;
|
adcHandle->Instance = ADCx;
|
||||||
adcHandle->Init.Resolution = ADC_RESOLUTION12b;
|
|
||||||
adcHandle->Init.ContinuousConvMode = DISABLE;
|
adcHandle->Init.ContinuousConvMode = DISABLE;
|
||||||
adcHandle->Init.DiscontinuousConvMode = DISABLE;
|
adcHandle->Init.DiscontinuousConvMode = DISABLE;
|
||||||
adcHandle->Init.NbrOfDiscConversion = 0;
|
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.DataAlign = ADC_DATAALIGN_RIGHT;
|
||||||
adcHandle->Init.NbrOfConversion = 1;
|
adcHandle->Init.NbrOfConversion = 1;
|
||||||
adcHandle->Init.DMAContinuousRequests = DISABLE;
|
adcHandle->Init.DMAContinuousRequests = DISABLE;
|
||||||
adcHandle->Init.EOCSelection = DISABLE;
|
|
||||||
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
|
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
|
||||||
|
adcHandle->Init.Resolution = ADC_RESOLUTION12b;
|
||||||
adcHandle->Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
|
adcHandle->Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
|
||||||
adcHandle->Init.ScanConvMode = DISABLE;
|
adcHandle->Init.ScanConvMode = DISABLE;
|
||||||
adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
|
adcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
|
||||||
|
adcHandle->Init.EOCSelection = DISABLE;
|
||||||
#elif defined(MCU_SERIES_L4)
|
#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.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.LowPowerAutoWait = DISABLE;
|
||||||
adcHandle->Init.Overrun = ADC_OVR_DATA_PRESERVED;
|
adcHandle->Init.Overrun = ADC_OVR_DATA_PRESERVED;
|
||||||
adcHandle->Init.OversamplingMode = DISABLE;
|
adcHandle->Init.OversamplingMode = DISABLE;
|
||||||
|
@ -165,30 +174,42 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
HAL_ADC_Init(adcHandle);
|
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;
|
ADC_ChannelConfTypeDef sConfig;
|
||||||
|
|
||||||
sConfig.Channel = adc_obj->channel;
|
sConfig.Channel = channel;
|
||||||
sConfig.Rank = 1;
|
sConfig.Rank = 1;
|
||||||
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
|
#if defined(MCU_SERIES_F4) || defined(MCU_SERIES_F7)
|
||||||
sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
|
sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
|
||||||
#elif defined(MCU_SERIES_L4)
|
#elif defined(MCU_SERIES_L4)
|
||||||
sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5;
|
sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5;
|
||||||
|
sConfig.SingleDiff = ADC_SINGLE_ENDED;
|
||||||
|
sConfig.OffsetNumber = ADC_OFFSET_NONE;
|
||||||
#else
|
#else
|
||||||
#error Unsupported processor
|
#error Unsupported processor
|
||||||
#endif
|
#endif
|
||||||
sConfig.Offset = 0;
|
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) {
|
STATIC uint32_t adc_read_channel(ADC_HandleTypeDef *adcHandle) {
|
||||||
uint32_t rawValue = 0;
|
uint32_t rawValue = 0;
|
||||||
|
|
||||||
HAL_ADC_Start(adcHandle);
|
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);
|
rawValue = HAL_ADC_GetValue(adcHandle);
|
||||||
}
|
}
|
||||||
HAL_ADC_Stop(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) {
|
STATIC mp_obj_t adc_read(mp_obj_t self_in) {
|
||||||
pyb_obj_adc_t *self = 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);
|
uint32_t data = adc_read_channel(&self->handle);
|
||||||
return mp_obj_new_int(data);
|
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
|
// 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
|
// This uses the timer in polling mode to do the sampling
|
||||||
// TODO use DMA
|
// 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) {
|
uint32_t adc_config_and_read_channel(ADC_HandleTypeDef *adcHandle, uint32_t channel) {
|
||||||
ADC_ChannelConfTypeDef sConfig;
|
adc_config_channel(adcHandle, 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;
|
|
||||||
#else
|
|
||||||
#error Unsupported processor
|
|
||||||
#endif
|
|
||||||
sConfig.Offset = 0;
|
|
||||||
HAL_ADC_ConfigChannel(adcHandle, &sConfig);
|
|
||||||
|
|
||||||
return adc_read_channel(adcHandle);
|
return adc_read_channel(adcHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue