From c80ac26f7ad2a1cab8323d668d1e88d22fe218fa Mon Sep 17 00:00:00 2001 From: jeromecoutant Date: Wed, 3 Feb 2021 18:07:22 +0100 Subject: [PATCH] STM32WL : ANALOGIN full support --- .../TARGET_NUCLEO_WL55JC/PeripheralPins.c | 7 +- .../TARGET_STM32WL/analogin_device.c | 134 ++++++++++-------- 2 files changed, 75 insertions(+), 66 deletions(-) diff --git a/targets/TARGET_STM/TARGET_STM32WL/TARGET_STM32WL55xC/TARGET_NUCLEO_WL55JC/PeripheralPins.c b/targets/TARGET_STM/TARGET_STM32WL/TARGET_STM32WL55xC/TARGET_NUCLEO_WL55JC/PeripheralPins.c index 85171e991e..cc8c6eed4d 100644 --- a/targets/TARGET_STM/TARGET_STM32WL/TARGET_STM32WL55xC/TARGET_NUCLEO_WL55JC/PeripheralPins.c +++ b/targets/TARGET_STM/TARGET_STM32WL/TARGET_STM32WL55xC/TARGET_NUCLEO_WL55JC/PeripheralPins.c @@ -55,11 +55,10 @@ MBED_WEAK const PinMap PinMap_ADC[] = { {NC, NC, 0} }; -// !!! SECTION TO BE CHECKED WITH DEVICE REFERENCE MANUAL MBED_WEAK const PinMap PinMap_ADC_Internal[] = { -// {ADC_TEMP, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 16, 0)}, -// {ADC_VREF, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 17, 0)}, -// {ADC_VBAT, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 18, 0)}, + {ADC_TEMP, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 12, 0)}, + {ADC_VREF, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 13, 0)}, + {ADC_VBAT, ADC_1, STM_PIN_DATA_EXT(STM_MODE_ANALOG, GPIO_NOPULL, 0, 14, 0)}, {NC, NC, 0} }; diff --git a/targets/TARGET_STM/TARGET_STM32WL/analogin_device.c b/targets/TARGET_STM/TARGET_STM32WL/analogin_device.c index d97a5156bf..a6ff8be47c 100644 --- a/targets/TARGET_STM/TARGET_STM32WL/analogin_device.c +++ b/targets/TARGET_STM/TARGET_STM32WL/analogin_device.c @@ -19,30 +19,35 @@ #include "mbed_assert.h" #include "mbed_error.h" #include "mbed_debug.h" -#include "mbed_wait_api.h" #include "cmsis.h" #include "pinmap.h" #include "PeripheralPins.h" -void analogin_init(analogin_t *obj, PinName pin) + +#if STATIC_PINMAP_READY +#define ANALOGIN_INIT_DIRECT analogin_init_direct +void analogin_init_direct(analogin_t *obj, const PinMap *pinmap) +#else +#define ANALOGIN_INIT_DIRECT _analogin_init_direct +static void _analogin_init_direct(analogin_t *obj, const PinMap *pinmap) +#endif { - uint32_t function = (uint32_t)NC; + uint32_t function = (uint32_t)pinmap->function; + + // Get the peripheral name from the pin and assign it to the object + obj->handle.Instance = (ADC_TypeDef *)pinmap->peripheral; // ADC Internal Channels "pins" (Temperature, Vref, Vbat, ...) // are described in PinNames.h and PeripheralPins.c // Pin value must be between 0xF0 and 0xFF - if ((pin < 0xF0) || (pin >= 0x100)) { + if ((pinmap->pin < 0xF0) || (pinmap->pin >= 0x100)) { // Normal channels - // Get the peripheral name from the pin and assign it to the object - obj->handle.Instance = (ADC_TypeDef *)pinmap_peripheral(pin, PinMap_ADC); - // Get the functions (adc channel) from the pin and assign it to the object - function = pinmap_function(pin, PinMap_ADC); + // Configure GPIO - pinmap_pinout(pin, PinMap_ADC); + pin_function(pinmap->pin, pinmap->function); + pin_mode(pinmap->pin, PullNone); } else { // Internal channels - obj->handle.Instance = (ADC_TypeDef *)pinmap_peripheral(pin, PinMap_ADC_Internal); - function = pinmap_function(pin, PinMap_ADC_Internal); // No GPIO configuration for internal channels } MBED_ASSERT(obj->handle.Instance != (ADC_TypeDef *)NC); @@ -51,58 +56,77 @@ void analogin_init(analogin_t *obj, PinName pin) obj->channel = STM_PIN_CHANNEL(function); // Save pin number for the read function - obj->pin = pin; + obj->pin = pinmap->pin; // Configure ADC object structures obj->handle.State = HAL_ADC_STATE_RESET; - obj->handle.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2; // Asynchronous clock mode, input ADC clock + obj->handle.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2; obj->handle.Init.Resolution = ADC_RESOLUTION_12B; obj->handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; - obj->handle.Init.ScanConvMode = ADC_SCAN_DISABLE; // Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) - obj->handle.Init.EOCSelection = ADC_EOC_SINGLE_CONV; // On STM32L1xx ADC, overrun detection is enabled only if EOC selection is set to each conversion (or transfer by DMA enabled, this is not the case in this example). + obj->handle.Init.ScanConvMode = ADC_SCAN_DISABLE; + obj->handle.Init.EOCSelection = ADC_EOC_SINGLE_CONV; obj->handle.Init.LowPowerAutoWait = DISABLE; - obj->handle.Init.ContinuousConvMode = DISABLE; // Continuous mode disabled to have only 1 conversion at each conversion trig - obj->handle.Init.NbrOfConversion = 1; // Parameter discarded because sequencer is disabled - obj->handle.Init.DiscontinuousConvMode = DISABLE; // Parameter discarded because sequencer is disabled - //obj->handle.Init.NbrOfDiscConversion = 1; // Parameter discarded because sequencer is disabled - obj->handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; // Software start to trig the 1st conversion manually, without external event + obj->handle.Init.ContinuousConvMode = DISABLE; + obj->handle.Init.NbrOfConversion = 1; + obj->handle.Init.DiscontinuousConvMode = DISABLE; + obj->handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; obj->handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; obj->handle.Init.DMAContinuousRequests = DISABLE; - obj->handle.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; // DR register is overwritten with the last conversion result in case of overrun - obj->handle.Init.OversamplingMode = DISABLE; // No oversampling + obj->handle.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; + obj->handle.Init.LowPowerAutoPowerOff = DISABLE; + obj->handle.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_19CYCLES_5; + obj->handle.Init.SamplingTimeCommon2 = ADC_SAMPLETIME_160CYCLES_5; + obj->handle.Init.OversamplingMode = DISABLE; + obj->handle.Init.Oversampling.Ratio = 0; // workaround + obj->handle.Init.Oversampling.RightBitShift = 0; // workaround + obj->handle.Init.Oversampling.TriggeredMode = 0; // workaround + obj->handle.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH; - // Enable ADC core clock + // Enable ADC clock + __HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_SYSCLK); __HAL_RCC_ADC_CLK_ENABLE(); - // Enable ADC conversion clock. - // Only necessary with asynchronous clock source - __HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_SYSCLK); - if (HAL_ADC_Init(&obj->handle) != HAL_OK) { - error("ADC initialization failed\r\n"); + error("Cannot initialize ADC"); } // ADC calibration is done only once - //if (!HAL_ADCEx_Calibration_GetValue(&obj->handle, ADC_SINGLE_ENDED)) { - // HAL_ADCEx_Calibration_Start(&obj->handle, ADC_SINGLE_ENDED); - //} + if (!HAL_ADCEx_Calibration_GetValue(&obj->handle)) { + if (HAL_ADCEx_Calibration_Start(&obj->handle) != HAL_OK) { + error("HAL_ADCEx_Calibration_Start error"); + } + } } +void analogin_init(analogin_t *obj, PinName pin) +{ + int peripheral; + int function; + + if ((pin < 0xF0) || (pin >= 0x100)) { + peripheral = (int)pinmap_peripheral(pin, PinMap_ADC); + function = (int)pinmap_find_function(pin, PinMap_ADC); + } else { + peripheral = (int)pinmap_peripheral(pin, PinMap_ADC_Internal); + function = (int)pinmap_find_function(pin, PinMap_ADC_Internal); + } + + const PinMap static_pinmap = {pin, peripheral, function}; + + ANALOGIN_INIT_DIRECT(obj, &static_pinmap); +} + + uint16_t adc_read(analogin_t *obj) { ADC_ChannelConfTypeDef sConfig = {0}; - // Configure ADC channel sConfig.Rank = ADC_REGULAR_RANK_1; - //sConfig.SamplingTime = ADC_SAMPLETIME_47CYCLES_5; - //sConfig.SingleDiff = ADC_SINGLE_ENDED; - //sConfig.OffsetNumber = ADC_OFFSET_NONE; - //sConfig.Offset = 0; + sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1; switch (obj->channel) { case 0: - sConfig.Channel = ADC_CHANNEL_VREFINT; - //sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5; // Minimum ADC sampling time when reading the internal reference voltage is 4us + sConfig.Channel = ADC_CHANNEL_0; break; case 1: sConfig.Channel = ADC_CHANNEL_1; @@ -138,55 +162,41 @@ uint16_t adc_read(analogin_t *obj) sConfig.Channel = ADC_CHANNEL_11; break; case 12: - sConfig.Channel = ADC_CHANNEL_12; + sConfig.Channel = ADC_CHANNEL_TEMPSENSOR; + sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_2; break; case 13: - sConfig.Channel = ADC_CHANNEL_13; + sConfig.Channel = ADC_CHANNEL_VREFINT; + sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_2; break; case 14: - sConfig.Channel = ADC_CHANNEL_14; - break; - case 15: - sConfig.Channel = ADC_CHANNEL_15; - break; - case 16: - sConfig.Channel = ADC_CHANNEL_16; - break; - case 17: - sConfig.Channel = ADC_CHANNEL_TEMPSENSOR; - //sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5; // Minimum ADC sampling time when reading the temperature is 5us - break; - case 18: sConfig.Channel = ADC_CHANNEL_VBAT; - //sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5; // Minimum ADC sampling time when reading the VBAT is 12us + sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_2; break; default: return 0; } if (HAL_ADC_ConfigChannel(&obj->handle, &sConfig) != HAL_OK) { - debug("ADC channel configuration failed\r\n"); + debug("HAL_ADC_ConfigChannel error\n"); } - // Start conversion if (HAL_ADC_Start(&obj->handle) != HAL_OK) { - debug("ADC start of conversion failed\r\n"); + debug("HAL_ADC_Start error\n"); } // Wait end of conversion and get value uint16_t adcValue = 0; - if (HAL_ADC_PollForConversion(&obj->handle, 10) == HAL_OK) { + if (HAL_ADC_PollForConversion(&obj->handle, 100) == HAL_OK) { adcValue = (uint16_t)HAL_ADC_GetValue(&obj->handle); } - if (HAL_ADC_Stop(&obj->handle) != HAL_OK) { - debug("HAL_ADC_Stop failed\r\n"); - } - LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE((&obj->handle)->Instance), LL_ADC_PATH_INTERNAL_NONE); + return adcValue; } + const PinMap *analogin_pinmap() { return PinMap_ADC;