From d8770476f06e18f16b79b87b30a165f55305404a Mon Sep 17 00:00:00 2001 From: "Frederic.Pillon" Date: Thu, 6 Jun 2019 16:24:43 +0200 Subject: [PATCH 1/5] [ADC] Harden adc_read_value() Signed-off-by: Frederic.Pillon --- cores/arduino/stm32/analog.c | 135 +++++++++++++++++++++++------------ 1 file changed, 91 insertions(+), 44 deletions(-) diff --git a/cores/arduino/stm32/analog.c b/cores/arduino/stm32/analog.c index d76bfcbaed..50e8c2433f 100644 --- a/cores/arduino/stm32/analog.c +++ b/cores/arduino/stm32/analog.c @@ -518,53 +518,87 @@ uint16_t adc_read_value(PinName pin) return 0; } -#ifndef STM32F1xx - AdcHandle.Init.ClockPrescaler = ADC_CLOCK_DIV; /* Asynchronous clock mode, input ADC clock divided */ +#ifdef ADC_CLOCK_DIV + AdcHandle.Init.ClockPrescaler = ADC_CLOCK_DIV; /* (A)synchronous clock mode, input ADC clock divided */ +#endif +#ifdef ADC_RESOLUTION_12B AdcHandle.Init.Resolution = ADC_RESOLUTION_12B; /* 12-bit resolution for converted data */ - AdcHandle.Init.EOCSelection = ADC_EOC_SINGLE_CONV; /* EOC flag picked-up to indicate conversion end */ - AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* Parameter discarded because software trigger chosen */ -#ifdef STM32H7xx - AdcHandle.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR; /* Regular Conversion data stored in DR register only */ -#else - AdcHandle.Init.DMAContinuousRequests = DISABLE; /* DMA one-shot mode selected (not applied to this example) */ -#endif /* STM32H7xx */ -#endif /* STM32F1xx */ -#ifndef STM32H7xx +#endif +#ifdef ADC_DATAALIGN_RIGHT AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* Right-alignment for converted data */ -#endif /* !STM32H7xx */ +#endif AdcHandle.Init.ScanConvMode = DISABLE; /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */ +#ifdef ADC_EOC_SINGLE_CONV + AdcHandle.Init.EOCSelection = ADC_EOC_SINGLE_CONV; /* EOC flag picked-up to indicate conversion end */ +#endif +#if !defined(STM32F1xx) && !defined(STM32F2xx) && !defined(STM32F4xx) && \ + !defined(STM32F7xx) && !defined(STM32F373xC) && !defined(STM32F378xx) + AdcHandle.Init.LowPowerAutoWait = DISABLE; /* Auto-delayed conversion feature disabled */ +#endif +#if !defined(STM32F1xx) && !defined(STM32F2xx) && !defined(STM32F3xx) && \ + !defined(STM32F4xx) && !defined(STM32F7xx) && !defined(STM32H7xx) && \ + !defined(STM32L4xx) && !defined(STM32WBxx) + AdcHandle.Init.LowPowerAutoPowerOff = DISABLE; /* ADC automatically powers-off after a conversion and automatically wakes-up when a new conversion is triggered */ +#endif +#ifdef ADC_CHANNELS_BANK_A + AdcHandle.Init.ChannelsBank = ADC_CHANNELS_BANK_A; +#endif AdcHandle.Init.ContinuousConvMode = DISABLE; /* Continuous mode disabled to have only 1 conversion at each conversion trig */ +#if !defined(STM32F0xx) && !defined(STM32L0xx) + AdcHandle.Init.NbrOfConversion = 1; /* Specifies the number of ranks that will be converted within the regular group sequencer. */ +#endif AdcHandle.Init.DiscontinuousConvMode = DISABLE; /* Parameter discarded because sequencer is disabled */ +#if !defined(STM32F0xx) && !defined(STM32G0xx) && !defined(STM32L0xx) + AdcHandle.Init.NbrOfDiscConversion = 0; /* Parameter discarded because sequencer is disabled */ +#endif AdcHandle.Init.ExternalTrigConv = ADC_SOFTWARE_START; /* Software start to trig the 1st conversion manually, without external event */ - AdcHandle.State = HAL_ADC_STATE_RESET; -#if defined (STM32F0xx) || defined(STM32G0xx) || defined (STM32L0xx) - AdcHandle.Init.LowPowerAutoWait = DISABLE; /* Auto-delayed conversion feature disabled */ - AdcHandle.Init.LowPowerAutoPowerOff = DISABLE; /* ADC automatically powers-off after a conversion and automatically wakes-up when a new conversion is triggered */ +#if !defined(STM32F1xx) + AdcHandle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; /* Parameter discarded because software trigger chosen */ +#endif +#if !defined(STM32F1xx) && !defined(STM32H7xx) && \ + !defined(STM32F373xC) && !defined(STM32F378xx) + AdcHandle.Init.DMAContinuousRequests = DISABLE; /* DMA one-shot mode selected (not applied to this example) */ +#endif +#ifdef ADC_CONVERSIONDATA_DR + AdcHandle.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR; /* Regular Conversion data stored in DR register only */ +#endif +#ifdef ADC_OVR_DATA_OVERWRITTEN AdcHandle.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; /* DR register is overwritten with the last conversion result in case of overrun */ -#ifdef STM32F0xx +#endif +#ifdef ADC_LEFTBITSHIFT_NONE + AdcHandle.Init.LeftBitShift = ADC_LEFTBITSHIFT_NONE; /* No bit shift left applied on the final ADC convesion data */ +#endif + +#if defined(STM32F0xx) AdcHandle.Init.SamplingTimeCommon = SAMPLINGTIME; -#elif STM32G0xx +#endif +#if defined(STM32G0xx) AdcHandle.Init.SamplingTimeCommon1 = SAMPLINGTIME; /* Set sampling time common to a group of channels. */ AdcHandle.Init.SamplingTimeCommon2 = SAMPLINGTIME; /* Set sampling time common to a group of channels, second common setting possible.*/ - AdcHandle.Init.OversamplingMode = DISABLE; AdcHandle.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH; -#else - //LowPowerFrequencyMode to enable if clk freq < 2.8Mhz +#endif +#if defined(STM32L0xx) + AdcHandle.Init.LowPowerFrequencyMode = DISABLE; /* To be enabled only if ADC clock < 2.8 MHz */ AdcHandle.Init.SamplingTime = SAMPLINGTIME; -#endif /* STM32F0xx */ -#else -#if defined (STM32F3xx) || defined (STM32H7xx) - AdcHandle.Init.LowPowerAutoWait = DISABLE; /* Auto-delayed conversion feature disabled */ -#ifndef STM32H7xx - AdcHandle.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; /* DR register is overwritten with the last conversion result in case of overrun */ -#endif /* !STM32H7xx */ -#endif /* STM32F3xx || STM32H7xx */ - AdcHandle.Init.NbrOfDiscConversion = 0; /* Parameter discarded because sequencer is disabled */ -#endif /* STM32F0xx || STM32G0xx || STM32L0xx */ - -#if !defined (STM32F0xx) && !defined (STM32L0xx) - AdcHandle.Init.NbrOfConversion = 1; /* Specifies the number of ranks that will be converted within the regular group sequencer. */ #endif +#if !defined(STM32F0xx) && !defined(STM32F1xx) && !defined(STM32F2xx) && \ + !defined(STM32F3xx) && !defined(STM32F4xx) && !defined(STM32F7xx) && \ + !defined(STM32L1xx) + AdcHandle.Init.OversamplingMode = DISABLE; + /* AdcHandle.Init.Oversample ignore for STM32L0xx as oversampling disabled */ + /* AdcHandle.Init.Oversampling ignored for other as oversampling disabled */ +#endif +#if defined(ADC_CFGR_DFSDMCFG) && defined(DFSDM1_Channel0) + AdcHandle.Init.DFSDMConfig = ADC_DFSDM_MODE_DISABLE; /* ADC conversions are not transferred by DFSDM. */ +#endif +#ifdef ADC_TRIGGER_FREQ_HIGH + AdcHandle.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH; +#endif + + AdcHandle.State = HAL_ADC_STATE_RESET; + AdcHandle.DMA_Handle = NULL; + AdcHandle.Lock = HAL_UNLOCKED; + /* Some other ADC_HandleTypeDef fields exists but not required */ g_current_pin = pin; /* Needed for HAL_ADC_MspInit*/ @@ -581,31 +615,44 @@ uint16_t adc_read_value(PinName pin) if (!IS_ADC_CHANNEL(AdcChannelConf.Channel)) { return 0; } -#endif /* STM32L4xx */ +#endif /* STM32L4xx || STM32WBxx */ AdcChannelConf.Rank = ADC_REGULAR_RANK_1; /* Specifies the rank in the regular group sequencer */ -#ifndef STM32L0xx -#if defined (STM32G0xx) - AdcChannelConf.SamplingTime = ADC_SAMPLINGTIME_COMMON_1; /* Sampling time value to be set for the selected channel */ -#else +#if !defined(STM32L0xx) +#if !defined(STM32G0xx) AdcChannelConf.SamplingTime = SAMPLINGTIME; /* Sampling time value to be set for the selected channel */ +#else + AdcChannelConf.SamplingTime = ADC_SAMPLINGTIME_COMMON_1; /* Sampling time value to be set for the selected channel */ #endif #endif -#if defined (STM32F3xx) || defined (STM32L4xx) || defined (STM32H7xx) || defined(STM32WBxx) +#if !defined(STM32F0xx) && !defined(STM32F1xx) && !defined(STM32F2xx) && \ + !defined(STM32F4xx) && !defined(STM32F7xx) && !defined(STM32G0xx) && \ + !defined(STM32L0xx) && !defined(STM32L1xx) && \ + !defined(STM32F373xC) && !defined(STM32F378xx) AdcChannelConf.SingleDiff = ADC_SINGLE_ENDED; /* Single-ended input channel */ AdcChannelConf.OffsetNumber = ADC_OFFSET_NONE; /* No offset subtraction */ +#endif +#if !defined(STM32F0xx) && !defined(STM32F1xx) && !defined(STM32F2xx) && \ + !defined(STM32G0xx) && !defined(STM32L0xx) && !defined(STM32L1xx) && \ + !defined(STM32WBxx) && !defined(STM32F373xC) && !defined(STM32F378xx) AdcChannelConf.Offset = 0; /* Parameter discarded because offset correction is disabled */ #endif +#if defined (STM32H7xx) + AdcChannelConf.OffsetRightShift = DISABLE; /* No Right Offset Shift */ + AdcChannelConf.OffsetSignedSaturation = DISABLE; /* Signed saturation feature is not used */ +#endif + /*##-2- Configure ADC regular channel ######################################*/ if (HAL_ADC_ConfigChannel(&AdcHandle, &AdcChannelConf) != HAL_OK) { /* Channel Configuration Error */ return 0; } -#if defined (STM32F0xx) || defined (STM32F1xx) || defined (STM32F3xx) ||\ - defined (STM32H7xx) || defined (STM32G0xx) || defined (STM32L0xx) ||\ - defined (STM32L4xx) || defined(STM32WBxx) +#if defined(STM32F0xx) || defined(STM32F1xx) || defined(STM32F3xx) || \ + defined(STM32G0xx) || defined(STM32H7xx) || defined(STM32L0xx) || \ + defined(STM32L4xx) || defined(STM32WBxx) /*##-2.1- Calibrate ADC then Start the conversion process ####################*/ -#if defined (STM32F0xx) || defined (STM32G0xx) || defined (STM32F1xx) +#if defined(STM32F0xx) || defined(STM32G0xx) || defined(STM32F1xx) || \ + defined(STM32F373xC) || defined(STM32F378xx) if (HAL_ADCEx_Calibration_Start(&AdcHandle) != HAL_OK) #elif defined (STM32H7xx) if (HAL_ADCEx_Calibration_Start(&AdcHandle, ADC_CALIB_OFFSET, ADC_SINGLE_ENDED) != HAL_OK) From 143e2d6cd20836046d5a52599fa7b2fcc619609a Mon Sep 17 00:00:00 2001 From: "Frederic.Pillon" Date: Thu, 6 Jun 2019 18:29:24 +0200 Subject: [PATCH 2/5] [ADC] Custom sampling time and clock sync ADC_SAMPLINGTIME and ADC_CLOCK_DIV could be redefined by the variant or using build_opt.h. Signed-off-by: Frederic.Pillon --- cores/arduino/stm32/analog.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/cores/arduino/stm32/analog.c b/cores/arduino/stm32/analog.c index 50e8c2433f..d303172493 100644 --- a/cores/arduino/stm32/analog.c +++ b/cores/arduino/stm32/analog.c @@ -54,35 +54,31 @@ static PinName g_current_pin = NC; /* Private_Defines */ #ifdef HAL_ADC_MODULE_ENABLED +#ifndef ADC_SAMPLINGTIME #if defined(ADC_SAMPLETIME_8CYCLES_5) -#define SAMPLINGTIME ADC_SAMPLETIME_8CYCLES_5; +#define ADC_SAMPLINGTIME ADC_SAMPLETIME_8CYCLES_5; #elif defined(ADC_SAMPLETIME_12CYCLES_5) -#define SAMPLINGTIME ADC_SAMPLETIME_12CYCLES_5; +#define ADC_SAMPLINGTIME ADC_SAMPLETIME_12CYCLES_5; #elif defined(ADC_SAMPLETIME_13CYCLES_5) -#define SAMPLINGTIME ADC_SAMPLETIME_13CYCLES_5; +#define ADC_SAMPLINGTIME ADC_SAMPLETIME_13CYCLES_5; #elif defined(ADC_SAMPLETIME_15CYCLES) -#define SAMPLINGTIME ADC_SAMPLETIME_15CYCLES; +#define ADC_SAMPLINGTIME ADC_SAMPLETIME_15CYCLES; #elif defined(ADC_SAMPLETIME_16CYCLES) -#define SAMPLINGTIME ADC_SAMPLETIME_16CYCLES; +#define ADC_SAMPLINGTIME ADC_SAMPLETIME_16CYCLES; #elif defined(ADC_SAMPLETIME_19CYCLES_5) -#define SAMPLINGTIME ADC_SAMPLETIME_19CYCLES_5; -#else -#error "ADC SAMPLINGTIME could not be defined" +#define ADC_SAMPLINGTIME ADC_SAMPLETIME_19CYCLES_5; #endif +#endif /* !ADC_SAMPLINGTIME */ -#ifndef STM32F1xx +#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 -#elif defined(ADC_CLOCKPRESCALER_PCLK_DIV2) -#define ADC_CLOCK_DIV ADC_CLOCKPRESCALER_PCLK_DIV2 -#else -#error "ADC_CLOCK_DIV could not be defined" #endif -#endif /* STM32F1xx */ +#endif /* !ADC_CLOCK_DIV */ #ifndef ADC_REGULAR_RANK_1 #define ADC_REGULAR_RANK_1 1 @@ -570,16 +566,16 @@ uint16_t adc_read_value(PinName pin) #endif #if defined(STM32F0xx) - AdcHandle.Init.SamplingTimeCommon = SAMPLINGTIME; + AdcHandle.Init.SamplingTimeCommon = ADC_SAMPLINGTIME; #endif #if defined(STM32G0xx) - AdcHandle.Init.SamplingTimeCommon1 = SAMPLINGTIME; /* Set sampling time common to a group of channels. */ - AdcHandle.Init.SamplingTimeCommon2 = SAMPLINGTIME; /* Set sampling time common to a group of channels, second common setting possible.*/ + AdcHandle.Init.SamplingTimeCommon1 = ADC_SAMPLINGTIME; /* Set sampling time common to a group of channels. */ + AdcHandle.Init.SamplingTimeCommon2 = ADC_SAMPLINGTIME; /* Set sampling time common to a group of channels, second common setting possible.*/ AdcHandle.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH; #endif #if defined(STM32L0xx) AdcHandle.Init.LowPowerFrequencyMode = DISABLE; /* To be enabled only if ADC clock < 2.8 MHz */ - AdcHandle.Init.SamplingTime = SAMPLINGTIME; + AdcHandle.Init.SamplingTime = ADC_SAMPLINGTIME; #endif #if !defined(STM32F0xx) && !defined(STM32F1xx) && !defined(STM32F2xx) && \ !defined(STM32F3xx) && !defined(STM32F4xx) && !defined(STM32F7xx) && \ @@ -619,7 +615,7 @@ uint16_t adc_read_value(PinName pin) AdcChannelConf.Rank = ADC_REGULAR_RANK_1; /* Specifies the rank in the regular group sequencer */ #if !defined(STM32L0xx) #if !defined(STM32G0xx) - AdcChannelConf.SamplingTime = SAMPLINGTIME; /* Sampling time value to be set for the selected channel */ + AdcChannelConf.SamplingTime = ADC_SAMPLINGTIME; /* Sampling time value to be set for the selected channel */ #else AdcChannelConf.SamplingTime = ADC_SAMPLINGTIME_COMMON_1; /* Sampling time value to be set for the selected channel */ #endif From d8338c886ad792584f642b995ec12dd60f59851d Mon Sep 17 00:00:00 2001 From: "Frederic.Pillon" Date: Fri, 7 Jun 2019 17:24:59 +0200 Subject: [PATCH 3/5] [ADC] Fix channels definition Signed-off-by: Frederic.Pillon --- cores/arduino/stm32/analog.c | 55 +++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/cores/arduino/stm32/analog.c b/cores/arduino/stm32/analog.c index d303172493..a521385551 100644 --- a/cores/arduino/stm32/analog.c +++ b/cores/arduino/stm32/analog.c @@ -140,16 +140,63 @@ static uint32_t get_adc_channel(PinName pin) case 15: channel = ADC_CHANNEL_15; break; +#ifdef ADC_CHANNEL_16 case 16: - channel = ADC_CHANNEL_TEMPSENSOR; + channel = ADC_CHANNEL_16; break; +#endif case 17: - channel = ADC_CHANNEL_VREFINT; + channel = ADC_CHANNEL_17; break; -#ifdef ADC_CHANNEL_VBAT +#ifdef ADC_CHANNEL_18 case 18: - channel = ADC_CHANNEL_VBAT; + channel = ADC_CHANNEL_18; + break; +#endif +#ifdef ADC_CHANNEL_19 + case 19: + channel = ADC_CHANNEL_19; + break; +#endif +#ifdef ADC_CHANNEL_20 + case 20: + channel = ADC_CHANNEL_20; + break; + case 21: + channel = ADC_CHANNEL_21; + break; + case 22: + channel = ADC_CHANNEL_22; + break; + case 23: + channel = ADC_CHANNEL_23; + break; + case 24: + channel = ADC_CHANNEL_24; break; + case 25: + channel = ADC_CHANNEL_25; + break; + case 26: + channel = ADC_CHANNEL_26; + break; +#ifdef ADC_CHANNEL_27 + case 27: + channel = ADC_CHANNEL_27; + break; + case 28: + channel = ADC_CHANNEL_28; + break; + case 29: + channel = ADC_CHANNEL_29; + break; + case 30: + channel = ADC_CHANNEL_30; + break; + case 31: + channel = ADC_CHANNEL_31; + break; +#endif #endif default: channel = 0; From 2ddfe71d47f9ddb44c043b541decda206eda001b Mon Sep 17 00:00:00 2001 From: "Frederic.Pillon" Date: Wed, 5 Jun 2019 17:55:30 +0200 Subject: [PATCH 4/5] [ADC] Add internal channels support Fix #474 Signed-off-by: Frederic.Pillon --- cores/arduino/pins_arduino.c | 27 +++++++++++ cores/arduino/pins_arduino.h | 15 +++++- cores/arduino/stm32/PinNames.h | 11 +++++ cores/arduino/stm32/analog.c | 87 ++++++++++++++++++++++++++++++---- keywords.txt | 7 +++ 5 files changed, 138 insertions(+), 9 deletions(-) diff --git a/cores/arduino/pins_arduino.c b/cores/arduino/pins_arduino.c index 13dd6dd374..8491e0f527 100644 --- a/cores/arduino/pins_arduino.c +++ b/cores/arduino/pins_arduino.c @@ -35,6 +35,33 @@ WEAK uint32_t pinNametoDigitalPin(PinName p) return i; } +PinName analogInputToPinName(uint32_t pin) +{ + PinName pn = digitalPinToPinName(analogInputToDigitalPin(pin)); + if (pn == NC) { + switch (pin) { +#ifdef ATEMP + case ATEMP: + pn = PADC_TEMP; + break; +#endif +#ifdef AVREF + case AVREF: + pn = PADC_VREF; + break; +#endif +#ifdef AVBAT + case AVBAT: + pn = PADC_VBAT; + break; +#endif + default: + break; + } + } + return pn; +} + #ifdef __cplusplus } #endif diff --git a/cores/arduino/pins_arduino.h b/cores/arduino/pins_arduino.h index 9f0625db7d..b78177d792 100644 --- a/cores/arduino/pins_arduino.h +++ b/cores/arduino/pins_arduino.h @@ -201,6 +201,18 @@ static const uint8_t SCK = PIN_SPI_SCK; static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; +// ADC internal channels (not a pins) +// Only used for analogRead() +#ifdef ADC_CHANNEL_TEMPSENSOR +#define ATEMP (NUM_DIGITAL_PINS + 1) +#endif +#ifdef ADC_CHANNEL_VREFINT +#define AVREF (NUM_DIGITAL_PINS + 2) +#endif +#ifdef ADC_CHANNEL_VBAT +#define AVBAT (NUM_DIGITAL_PINS + 3) +#endif + #ifdef __cplusplus extern "C" { #endif @@ -218,7 +230,8 @@ uint32_t pinNametoDigitalPin(PinName p); // Used by analogRead api to have A0 == 0 #define analogInputToDigitalPin(p) (((uint32_t)p < NUM_ANALOG_INPUTS) ? (p+A0) : p) // Convert an analog pin number Axx to a PinName PX_n -#define analogInputToPinName(p) (digitalPinToPinName(analogInputToDigitalPin(p))) +PinName analogInputToPinName(uint32_t pin); + // All pins could manage EXTI #define digitalPinToInterrupt(p) (digitalPinIsValid(p) ? p : NOT_AN_INTERRUPT) diff --git a/cores/arduino/stm32/PinNames.h b/cores/arduino/stm32/PinNames.h index 8e373ff2a9..d5d6eb5d83 100644 --- a/cores/arduino/stm32/PinNames.h +++ b/cores/arduino/stm32/PinNames.h @@ -207,6 +207,17 @@ typedef enum { PK_13 = (PortK << 4) + 0x0D, PK_14 = (PortK << 4) + 0x0E, PK_15 = (PortK << 4) + 0x0F, +#endif + // Specific pin name + PADC_BASE = 0x100, +#ifdef ADC_CHANNEL_TEMPSENSOR + PADC_TEMP, +#endif +#ifdef ADC_CHANNEL_VREFINT + PADC_VREF, +#endif +#ifdef ADC_CHANNEL_VBAT + PADC_VBAT, #endif // Specific pin name define in the variant #if __has_include("PinNamesVar.h") diff --git a/cores/arduino/stm32/analog.c b/cores/arduino/stm32/analog.c index a521385551..7d512df5f5 100644 --- a/cores/arduino/stm32/analog.c +++ b/cores/arduino/stm32/analog.c @@ -70,6 +70,35 @@ static PinName g_current_pin = NC; #endif #endif /* !ADC_SAMPLINGTIME */ +/* + * Minimum ADC sampling time is required when reading + * internal channels so set it to max possible value. + * It can be defined more precisely by defining: + * ADC_SAMPLINGTIME_INTERNAL + * to the desired ADC sample time. + */ +#ifndef ADC_SAMPLINGTIME_INTERNAL +#if defined(ADC_SAMPLETIME_480CYCLES) +#define ADC_SAMPLINGTIME_INTERNAL ADC_SAMPLETIME_480CYCLES +#elif defined(ADC_SAMPLETIME_384CYCLES) +#define ADC_SAMPLINGTIME_INTERNAL ADC_SAMPLETIME_384CYCLES +#elif defined(ADC_SAMPLETIME_810CYCLES_5) +#define ADC_SAMPLINGTIME_INTERNAL ADC_SAMPLETIME_810CYCLES_5 +#elif defined(ADC_SAMPLETIME_640CYCLES_5) +#define ADC_SAMPLINGTIME_INTERNAL ADC_SAMPLETIME_640CYCLES_5 +#elif defined(ADC_SAMPLETIME_601CYCLES_5) +#define ADC_SAMPLINGTIME_INTERNAL ADC_SAMPLETIME_601CYCLES_5 +#elif defined(ADC_SAMPLETIME_247CYCLES_5) +#define ADC_SAMPLINGTIME_INTERNAL ADC_SAMPLETIME_247CYCLES_5 +#elif defined(ADC_SAMPLETIME_239CYCLES_5) +#define ADC_SAMPLINGTIME_INTERNAL ADC_SAMPLETIME_239CYCLES_5 +#elif defined(ADC_SAMPLETIME_160CYCLES_5) +#define ADC_SAMPLINGTIME_INTERNAL ADC_SAMPLETIME_160CYCLES_5 +#else +#error "ADC sampling time could not be defined for internal channels!" +#endif +#endif /* !ADC_SAMPLINGTIME_INTERNAL */ + #ifndef ADC_CLOCK_DIV #ifdef ADC_CLOCK_SYNC_PCLK_DIV4 #define ADC_CLOCK_DIV ADC_CLOCK_SYNC_PCLK_DIV4 @@ -204,6 +233,32 @@ static uint32_t get_adc_channel(PinName pin) } return channel; } + +static uint32_t get_adc_internal_channel(PinName pin) +{ + uint32_t channel = 0; + switch (pin) { +#ifdef ADC_CHANNEL_TEMPSENSOR + case PADC_TEMP: + channel = ADC_CHANNEL_TEMPSENSOR; + break; +#endif +#ifdef ADC_CHANNEL_VREFINT + case PADC_VREF: + channel = ADC_CHANNEL_VREFINT; + break; +#endif +#ifdef ADC_CHANNEL_VBAT + case PADC_VBAT: + channel = ADC_CHANNEL_VBAT; + break; +#endif + default: + channel = 0; + break; + } + return channel; +} #endif /* HAL_ADC_MODULE_ENABLED */ #ifdef HAL_TIM_MODULE_ENABLED @@ -449,7 +504,9 @@ void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc) #endif /* Configure ADC GPIO pin */ - pinmap_pinout(g_current_pin, PinMap_ADC); + if (!(g_current_pin & PADC_BASE)) { + pinmap_pinout(g_current_pin, PinMap_ADC); + } } /** @@ -554,8 +611,21 @@ uint16_t adc_read_value(PinName pin) ADC_HandleTypeDef AdcHandle = {}; ADC_ChannelConfTypeDef AdcChannelConf = {}; __IO uint16_t uhADCxConvertedValue = 0; + uint32_t samplingTime = ADC_SAMPLINGTIME; + uint32_t channel = 0; - AdcHandle.Instance = pinmap_peripheral(pin, PinMap_ADC); + if (pin & PADC_BASE) { +#if defined(STM32H7xx) + AdcHandle.Instance = ADC3; +#else + AdcHandle.Instance = ADC1; +#endif + channel = get_adc_internal_channel(pin); + samplingTime = ADC_SAMPLINGTIME_INTERNAL; + } else { + AdcHandle.Instance = pinmap_peripheral(pin, PinMap_ADC); + channel = get_adc_channel(pin); + } if (AdcHandle.Instance == NP) { return 0; @@ -613,16 +683,16 @@ uint16_t adc_read_value(PinName pin) #endif #if defined(STM32F0xx) - AdcHandle.Init.SamplingTimeCommon = ADC_SAMPLINGTIME; + AdcHandle.Init.SamplingTimeCommon = samplingTime; #endif #if defined(STM32G0xx) - AdcHandle.Init.SamplingTimeCommon1 = ADC_SAMPLINGTIME; /* Set sampling time common to a group of channels. */ - AdcHandle.Init.SamplingTimeCommon2 = ADC_SAMPLINGTIME; /* Set sampling time common to a group of channels, second common setting possible.*/ + AdcHandle.Init.SamplingTimeCommon1 = samplingTime; /* Set sampling time common to a group of channels. */ + AdcHandle.Init.SamplingTimeCommon2 = samplingTime; /* Set sampling time common to a group of channels, second common setting possible.*/ AdcHandle.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH; #endif #if defined(STM32L0xx) AdcHandle.Init.LowPowerFrequencyMode = DISABLE; /* To be enabled only if ADC clock < 2.8 MHz */ - AdcHandle.Init.SamplingTime = ADC_SAMPLINGTIME; + AdcHandle.Init.SamplingTime = samplingTime; #endif #if !defined(STM32F0xx) && !defined(STM32F1xx) && !defined(STM32F2xx) && \ !defined(STM32F3xx) && !defined(STM32F4xx) && !defined(STM32F7xx) && \ @@ -649,7 +719,8 @@ uint16_t adc_read_value(PinName pin) return 0; } - AdcChannelConf.Channel = get_adc_channel(pin); /* Specifies the channel to configure into ADC */ + AdcChannelConf.Channel = channel; /* Specifies the channel to configure into ADC */ + #if defined(STM32L4xx) || defined(STM32WBxx) if (!IS_ADC_CHANNEL(&AdcHandle, AdcChannelConf.Channel)) { return 0; @@ -662,7 +733,7 @@ uint16_t adc_read_value(PinName pin) AdcChannelConf.Rank = ADC_REGULAR_RANK_1; /* Specifies the rank in the regular group sequencer */ #if !defined(STM32L0xx) #if !defined(STM32G0xx) - AdcChannelConf.SamplingTime = ADC_SAMPLINGTIME; /* Sampling time value to be set for the selected channel */ + AdcChannelConf.SamplingTime = samplingTime; /* Sampling time value to be set for the selected channel */ #else AdcChannelConf.SamplingTime = ADC_SAMPLINGTIME_COMMON_1; /* Sampling time value to be set for the selected channel */ #endif diff --git a/keywords.txt b/keywords.txt index 2a71fbcebe..0e496d3285 100644 --- a/keywords.txt +++ b/keywords.txt @@ -209,6 +209,9 @@ A20 LITERAL1 A21 LITERAL1 A22 LITERAL1 A23 LITERAL1 +ATEMP LITERAL1 +AVREF LITERAL1 +AVBAT LITERAL1 PIN_A0 LITERAL1 PIN_A1 LITERAL1 PIN_A2 LITERAL1 @@ -712,6 +715,10 @@ PK_12 LITERAL1 PK_13 LITERAL1 PK_14 LITERAL1 PK_15 LITERAL1 +PADC_BASE LITERAL1 +PADC_TEMP LITERAL1 +PADC_VREF LITERAL1 +PADC_VBAT LITERAL1 # Port Name PortName KEYWORD3 From ef20dc86243fc1a78e3702068f674b087db57ae3 Mon Sep 17 00:00:00 2001 From: Frederic Pillon Date: Sat, 8 Jun 2019 16:50:28 +0200 Subject: [PATCH 5/5] [ADC] Internal channels reset after read Internal channels use is enabling ADC "internal path" which needs to be disabled after measurement Signed-off-by: Frederic Pillon --- cores/arduino/stm32/analog.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cores/arduino/stm32/analog.c b/cores/arduino/stm32/analog.c index 7d512df5f5..b56007d845 100644 --- a/cores/arduino/stm32/analog.c +++ b/cores/arduino/stm32/analog.c @@ -39,6 +39,7 @@ #include "analog.h" #include "timer.h" #include "PinAF_STM32F1.h" +#include "stm32yyxx_ll_adc.h" #ifdef __cplusplus extern "C" { @@ -809,6 +810,8 @@ uint16_t adc_read_value(PinName pin) return 0; } + LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(AdcHandle.Instance), LL_ADC_PATH_INTERNAL_NONE); + return uhADCxConvertedValue; } #endif /* HAL_ADC_MODULE_ENABLED */