stm32/adc: Allow using ADC12 and ADC3 for H7.

* Modify common functions in adc.c to accept ADC handle.
* Most external channels are connected to ADC12 which is used by default.
* For ADCAll (internal channels) ADC3 is used instead.
* Issue #4435 is possibly related (at least partially fixed).
This commit is contained in:
iabdalkader 2021-06-16 23:44:52 +02:00 committed by Damien George
parent d1decdfa93
commit ff7be31f26
1 changed files with 40 additions and 28 deletions

View File

@ -51,16 +51,9 @@
/// val = adc.read_core_vref() # read MCU VREF /// val = adc.read_core_vref() # read MCU VREF
/* ADC defintions */ /* ADC defintions */
#if defined(STM32H7)
#define ADCx (ADC3)
#define PIN_ADC_MASK PIN_ADC3
#define pin_adc_table pin_adc3
#else
#define ADCx (ADC1) #define ADCx (ADC1)
#define PIN_ADC_MASK PIN_ADC1 #define PIN_ADC_MASK PIN_ADC1
#define pin_adc_table pin_adc1 #define pin_adc_table pin_adc1
#endif
#define ADCx_CLK_ENABLE __HAL_RCC_ADC1_CLK_ENABLE #define ADCx_CLK_ENABLE __HAL_RCC_ADC1_CLK_ENABLE
@ -142,7 +135,7 @@
defined(STM32F746xx) || defined(STM32F765xx) || \ defined(STM32F746xx) || defined(STM32F765xx) || \
defined(STM32F767xx) || defined(STM32F769xx) defined(STM32F767xx) || defined(STM32F769xx)
#define VBAT_DIV (4) #define VBAT_DIV (4)
#elif defined(STM32H743xx) #elif defined(STM32H743xx) || defined(STM32H747xx)
#define VBAT_DIV (4) #define VBAT_DIV (4)
#elif defined(STM32L432xx) || \ #elif defined(STM32L432xx) || \
defined(STM32L451xx) || defined(STM32L452xx) || \ defined(STM32L451xx) || defined(STM32L452xx) || \
@ -214,12 +207,12 @@ STATIC bool is_adcx_channel(int channel) {
#endif #endif
} }
STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) { STATIC void adc_wait_for_eoc_or_timeout(ADC_HandleTypeDef *adcHandle, int32_t timeout) {
uint32_t tickstart = HAL_GetTick(); uint32_t tickstart = HAL_GetTick();
#if defined(STM32F4) || defined(STM32F7) #if defined(STM32F4) || defined(STM32F7)
while ((ADCx->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) { while ((adcHandle->Instance->SR & ADC_FLAG_EOC) != ADC_FLAG_EOC) {
#elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB) #elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
while (READ_BIT(ADCx->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) { while (READ_BIT(adcHandle->Instance->ISR, ADC_FLAG_EOC) != ADC_FLAG_EOC) {
#else #else
#error Unsupported processor #error Unsupported processor
#endif #endif
@ -229,11 +222,15 @@ STATIC void adc_wait_for_eoc_or_timeout(int32_t timeout) {
} }
} }
STATIC void adcx_clock_enable(void) { STATIC void adcx_clock_enable(ADC_HandleTypeDef *adch) {
#if defined(STM32F0) || defined(STM32F4) || defined(STM32F7) #if defined(STM32F0) || defined(STM32F4) || defined(STM32F7)
ADCx_CLK_ENABLE(); ADCx_CLK_ENABLE();
#elif defined(STM32H7) #elif defined(STM32H7)
__HAL_RCC_ADC3_CLK_ENABLE(); if (adch->Instance == ADC3) {
__HAL_RCC_ADC3_CLK_ENABLE();
} else {
__HAL_RCC_ADC12_CLK_ENABLE();
}
__HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP); __HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP);
#elif defined(STM32L4) || defined(STM32WB) #elif defined(STM32L4) || defined(STM32WB)
if (__HAL_RCC_GET_ADC_SOURCE() == RCC_ADCCLKSOURCE_NONE) { if (__HAL_RCC_GET_ADC_SOURCE() == RCC_ADCCLKSOURCE_NONE) {
@ -246,9 +243,8 @@ STATIC void adcx_clock_enable(void) {
} }
STATIC void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) { STATIC void adcx_init_periph(ADC_HandleTypeDef *adch, uint32_t resolution) {
adcx_clock_enable(); adcx_clock_enable(adch);
adch->Instance = ADCx;
adch->Init.Resolution = resolution; adch->Init.Resolution = resolution;
adch->Init.ContinuousConvMode = DISABLE; adch->Init.ContinuousConvMode = DISABLE;
adch->Init.DiscontinuousConvMode = DISABLE; adch->Init.DiscontinuousConvMode = DISABLE;
@ -308,6 +304,7 @@ STATIC void adc_init_single(pyb_obj_adc_t *adc_obj) {
mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0); mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0);
} }
adc_obj->handle.Instance = ADCx;
adcx_init_periph(&adc_obj->handle, ADC_RESOLUTION_12B); adcx_init_periph(&adc_obj->handle, ADC_RESOLUTION_12B);
#if defined(STM32L4) && defined(ADC_DUALMODE_REGSIMULT_INJECSIMULT) #if defined(STM32L4) && defined(ADC_DUALMODE_REGSIMULT_INJECSIMULT)
@ -335,7 +332,11 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel)
#if defined(STM32F0) #if defined(STM32F0)
sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5; sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5;
#elif defined(STM32F4) || defined(STM32F7) #elif defined(STM32F4) || defined(STM32F7)
sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel)) {
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
} else {
sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES;
}
#elif defined(STM32H7) #elif defined(STM32H7)
if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel)) { if (__HAL_ADC_IS_CHANNEL_INTERNAL(channel)) {
sConfig.SamplingTime = ADC_SAMPLETIME_810CYCLES_5; sConfig.SamplingTime = ADC_SAMPLETIME_810CYCLES_5;
@ -370,8 +371,8 @@ STATIC void adc_config_channel(ADC_HandleTypeDef *adc_handle, uint32_t channel)
STATIC uint32_t adc_read_channel(ADC_HandleTypeDef *adcHandle) { STATIC uint32_t adc_read_channel(ADC_HandleTypeDef *adcHandle) {
HAL_ADC_Start(adcHandle); HAL_ADC_Start(adcHandle);
adc_wait_for_eoc_or_timeout(EOC_TIMEOUT); adc_wait_for_eoc_or_timeout(adcHandle, EOC_TIMEOUT);
uint32_t value = ADCx->DR; uint32_t value = adcHandle->Instance->DR;
HAL_ADC_Stop(adcHandle); HAL_ADC_Stop(adcHandle);
return value; return value;
} }
@ -529,19 +530,19 @@ STATIC mp_obj_t adc_read_timed(mp_obj_t self_in, mp_obj_t buf_in, mp_obj_t freq_
} else { } else {
// for subsequent samples we can just set the "start sample" bit // for subsequent samples we can just set the "start sample" bit
#if defined(STM32F4) || defined(STM32F7) #if defined(STM32F4) || defined(STM32F7)
ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART; self->handle.Instance->CR2 |= (uint32_t)ADC_CR2_SWSTART;
#elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB) #elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
SET_BIT(ADCx->CR, ADC_CR_ADSTART); SET_BIT(self->handle.Instance->CR, ADC_CR_ADSTART);
#else #else
#error Unsupported processor #error Unsupported processor
#endif #endif
} }
// wait for sample to complete // wait for sample to complete
adc_wait_for_eoc_or_timeout(EOC_TIMEOUT); adc_wait_for_eoc_or_timeout(&self->handle, EOC_TIMEOUT);
// read value // read value
uint value = ADCx->DR; uint value = self->handle.Instance->DR;
// store value in buffer // store value in buffer
if (typesize == 1) { if (typesize == 1) {
@ -608,9 +609,9 @@ STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_i
adc_config_channel(&adc0->handle, adc0->channel); adc_config_channel(&adc0->handle, adc0->channel);
HAL_ADC_Start(&adc0->handle); HAL_ADC_Start(&adc0->handle);
// Wait for sample to complete and discard // Wait for sample to complete and discard
adc_wait_for_eoc_or_timeout(EOC_TIMEOUT); adc_wait_for_eoc_or_timeout(&adc0->handle, EOC_TIMEOUT);
// Read (and discard) value // Read (and discard) value
uint value = ADCx->DR; uint value = adc0->handle.Instance->DR;
// Ensure first sample is on a timer tick // Ensure first sample is on a timer tick
__HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE); __HAL_TIM_CLEAR_FLAG(tim, TIM_FLAG_UPDATE);
@ -639,17 +640,17 @@ STATIC mp_obj_t adc_read_timed_multi(mp_obj_t adc_array_in, mp_obj_t buf_array_i
// for the first sample we need to turn the ADC on // for the first sample we need to turn the ADC on
// ADC is started: set the "start sample" bit // ADC is started: set the "start sample" bit
#if defined(STM32F4) || defined(STM32F7) #if defined(STM32F4) || defined(STM32F7)
ADCx->CR2 |= (uint32_t)ADC_CR2_SWSTART; adc->handle.Instance->CR2 |= (uint32_t)ADC_CR2_SWSTART;
#elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB) #elif defined(STM32F0) || defined(STM32H7) || defined(STM32L4) || defined(STM32WB)
SET_BIT(ADCx->CR, ADC_CR_ADSTART); SET_BIT(adc->handle.Instance->CR, ADC_CR_ADSTART);
#else #else
#error Unsupported processor #error Unsupported processor
#endif #endif
// wait for sample to complete // wait for sample to complete
adc_wait_for_eoc_or_timeout(EOC_TIMEOUT); adc_wait_for_eoc_or_timeout(&adc->handle, EOC_TIMEOUT);
// read value // read value
value = ADCx->DR; value = adc->handle.Instance->DR;
// store values in buffer // store values in buffer
if (typesize == 1) { if (typesize == 1) {
@ -723,13 +724,24 @@ void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution, uint32_t en_m
if (en_mask & (1 << channel)) { if (en_mask & (1 << channel)) {
// Channels 0-16 correspond to real pins. Configure the GPIO pin in // Channels 0-16 correspond to real pins. Configure the GPIO pin in
// ADC mode. // ADC mode.
#if defined(STM32H7)
const pin_obj_t *pin = pin_adc3[channel];
#else
const pin_obj_t *pin = pin_adc_table[channel]; const pin_obj_t *pin = pin_adc_table[channel];
#endif
if (pin) { if (pin) {
mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0); mp_hal_pin_config(pin, MP_HAL_PIN_MODE_ADC, MP_HAL_PIN_PULL_NONE, 0);
} }
} }
} }
#if defined(STM32H7)
// On the H7 the internal channels are connected to ADC3. To read internal channels
// with ADCAll, ADC3 must be used here, and ADC12 is used to read the GPIO channels.
adc_all->handle.Instance = ADC3;
#else
adc_all->handle.Instance = ADCx;
#endif
adcx_init_periph(&adc_all->handle, resolution); adcx_init_periph(&adc_all->handle, resolution);
} }