diff --git a/targets/TARGET_STM/TARGET_STM32F0/analogin_api.c b/targets/TARGET_STM/TARGET_STM32F0/analogin_device.c similarity index 70% rename from targets/TARGET_STM/TARGET_STM32F0/analogin_api.c rename to targets/TARGET_STM/TARGET_STM32F0/analogin_device.c index bfa8adc443..f60f6bc02c 100644 --- a/targets/TARGET_STM/TARGET_STM32F0/analogin_api.c +++ b/targets/TARGET_STM/TARGET_STM32F0/analogin_device.c @@ -33,12 +33,13 @@ #include "mbed_wait_api.h" #include "cmsis.h" #include "pinmap.h" -#include "PeripheralPins.h" #include "mbed_error.h" +#include "PeripheralPins.h" +#include -int adc_inited = 0; - -void analogin_init(analogin_t *obj, PinName pin) { +void analogin_init(analogin_t *obj, PinName pin) +{ + static bool adc_calibrated = false; uint32_t function = (uint32_t)NC; // ADC Internal Channels "pins" (Temperature, Vref, Vbat, ...) @@ -47,14 +48,14 @@ void analogin_init(analogin_t *obj, PinName pin) { if ((pin < 0xF0) || (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); + 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); } else { // Internal channels - obj->handle.Instance = (ADC_TypeDef *) pinmap_peripheral(pin, PinMap_ADC_Internal); + obj->handle.Instance = (ADC_TypeDef *)pinmap_peripheral(pin, PinMap_ADC_Internal); function = pinmap_function(pin, PinMap_ADC_Internal); // No GPIO configuration for internal channels } @@ -66,40 +67,38 @@ void analogin_init(analogin_t *obj, PinName pin) { // Save pin number for the read function obj->pin = pin; - // The ADC initialization is done once - if (adc_inited == 0) { - adc_inited = 1; + // Configure ADC object structures + obj->handle.State = HAL_ADC_STATE_RESET; + obj->handle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; + obj->handle.Init.Resolution = ADC_RESOLUTION_12B; + obj->handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; + obj->handle.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD; + obj->handle.Init.EOCSelection = EOC_SINGLE_CONV; + obj->handle.Init.LowPowerAutoWait = DISABLE; + obj->handle.Init.LowPowerAutoPowerOff = DISABLE; + obj->handle.Init.ContinuousConvMode = DISABLE; + 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 = OVR_DATA_OVERWRITTEN; - // Enable ADC clock - __ADC1_CLK_ENABLE(); + __HAL_RCC_ADC1_CLK_ENABLE(); - // Configure ADC - obj->handle.State = HAL_ADC_STATE_RESET; - obj->handle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; - obj->handle.Init.Resolution = ADC_RESOLUTION12b; - obj->handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; - obj->handle.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD; - obj->handle.Init.EOCSelection = EOC_SINGLE_CONV; - obj->handle.Init.LowPowerAutoWait = DISABLE; - obj->handle.Init.LowPowerAutoPowerOff = DISABLE; - obj->handle.Init.ContinuousConvMode = DISABLE; - 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 = OVR_DATA_OVERWRITTEN; - if (HAL_ADC_Init(&obj->handle) != HAL_OK) { - error("Cannot initialize ADC"); - } - // Run the ADC calibration - if (HAL_ADCEx_Calibration_Start(&obj->handle) != HAL_OK) { - error("Cannot Start ADC_Calibration"); - } + if (HAL_ADC_Init(&obj->handle) != HAL_OK) { + error("Cannot initialize ADC"); + } + + // ADC calibration is done only once + if (!adc_calibrated) { + adc_calibrated = true; + HAL_ADCEx_Calibration_Start(&obj->handle); } } -static inline uint16_t adc_read(analogin_t *obj) { - ADC_ChannelConfTypeDef sConfig; +uint16_t adc_read(analogin_t *obj) +{ + ADC_ChannelConfTypeDef sConfig = {0}; // Configure ADC channel sConfig.Rank = ADC_RANK_CHANNEL_NUMBER; @@ -182,22 +181,10 @@ static inline uint16_t adc_read(analogin_t *obj) { // Wait end of conversion and get value if (HAL_ADC_PollForConversion(&obj->handle, 10) == HAL_OK) { - return (HAL_ADC_GetValue(&obj->handle)); + return (uint16_t)HAL_ADC_GetValue(&obj->handle); } else { return 0; } } -uint16_t analogin_read_u16(analogin_t *obj) { - uint16_t value = adc_read(obj); - // 12-bit to 16-bit conversion - value = ((value << 4) & (uint16_t)0xFFF0) | ((value >> 8) & (uint16_t)0x000F); - return value; -} - -float analogin_read(analogin_t *obj) { - uint16_t value = adc_read(obj); - return (float)value * (1.0f / (float)0xFFF); // 12 bits range -} - #endif diff --git a/targets/TARGET_STM/TARGET_STM32F1/analogin_api.c b/targets/TARGET_STM/TARGET_STM32F1/analogin_device.c similarity index 78% rename from targets/TARGET_STM/TARGET_STM32F1/analogin_api.c rename to targets/TARGET_STM/TARGET_STM32F1/analogin_device.c index 172a513d4b..4dd0e6cdec 100644 --- a/targets/TARGET_STM/TARGET_STM32F1/analogin_api.c +++ b/targets/TARGET_STM/TARGET_STM32F1/analogin_device.c @@ -35,11 +35,11 @@ #include "pinmap.h" #include "mbed_error.h" #include "PeripheralPins.h" - -int adc_inited = 0; +#include void analogin_init(analogin_t *obj, PinName pin) { + static bool adc_calibrated = false; RCC_PeriphCLKInitTypeDef PeriphClkInit; uint32_t function = (uint32_t)NC; @@ -49,14 +49,14 @@ void analogin_init(analogin_t *obj, PinName pin) if ((pin < 0xF0) || (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); + 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); } else { // Internal channels - obj->handle.Instance = (ADC_TypeDef *) pinmap_peripheral(pin, PinMap_ADC_Internal); + obj->handle.Instance = (ADC_TypeDef *)pinmap_peripheral(pin, PinMap_ADC_Internal); function = pinmap_function(pin, PinMap_ADC_Internal); // No GPIO configuration for internal channels } @@ -68,13 +68,26 @@ void analogin_init(analogin_t *obj, PinName pin) // Save pin number for the read function obj->pin = pin; - // The ADC initialization is done once - if (adc_inited == 0) { - adc_inited = 1; + // Enable ADC clock + __HAL_RCC_ADC1_CLK_ENABLE(); - // Enable ADC clock - __HAL_RCC_ADC1_CLK_ENABLE(); + // Configure ADC object structures + obj->handle.State = HAL_ADC_STATE_RESET; + obj->handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; + obj->handle.Init.ScanConvMode = DISABLE; + obj->handle.Init.ContinuousConvMode = DISABLE; + obj->handle.Init.NbrOfConversion = 1; + obj->handle.Init.DiscontinuousConvMode = DISABLE; + obj->handle.Init.NbrOfDiscConversion = 0; + obj->handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; + if (HAL_ADC_Init(&obj->handle) != HAL_OK) { + error("Cannot initialize ADC"); + } + + // This section is done only once + if (!adc_calibrated) { + adc_calibrated = true; // Configure ADC clock prescaler // Caution: On STM32F1, ADC clock frequency max is 14 MHz (refer to device datasheet). // Therefore, ADC clock prescaler must be configured in function @@ -84,29 +97,14 @@ void analogin_init(analogin_t *obj, PinName pin) PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC; PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6; HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit); - - // Configure ADC - obj->handle.State = HAL_ADC_STATE_RESET; - obj->handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; - obj->handle.Init.ScanConvMode = DISABLE; - obj->handle.Init.ContinuousConvMode = DISABLE; - obj->handle.Init.NbrOfConversion = 1; - obj->handle.Init.DiscontinuousConvMode = DISABLE; - obj->handle.Init.NbrOfDiscConversion = 0; - obj->handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; - - if (HAL_ADC_Init(&obj->handle) != HAL_OK) { - error("Cannot initialize ADC\n"); - } - - // Calibrate ADC + // Calibration HAL_ADCEx_Calibration_Start(&obj->handle); } } -static inline uint16_t adc_read(analogin_t *obj) +uint16_t adc_read(analogin_t *obj) { - ADC_ChannelConfTypeDef sConfig; + ADC_ChannelConfTypeDef sConfig = {0}; // Configure ADC channel sConfig.Rank = 1; @@ -177,24 +175,10 @@ static inline uint16_t adc_read(analogin_t *obj) // Wait end of conversion and get value if (HAL_ADC_PollForConversion(&obj->handle, 10) == HAL_OK) { - return (HAL_ADC_GetValue(&obj->handle)); + return (uint16_t)HAL_ADC_GetValue(&obj->handle); } else { return 0; } } -uint16_t analogin_read_u16(analogin_t *obj) -{ - uint16_t value = adc_read(obj); - // 12-bit to 16-bit conversion - value = ((value << 4) & (uint16_t)0xFFF0) | ((value >> 8) & (uint16_t)0x000F); - return value; -} - -float analogin_read(analogin_t *obj) -{ - uint16_t value = adc_read(obj); - return (float)value * (1.0f / (float)0xFFF); // 12 bits range -} - #endif diff --git a/targets/TARGET_STM/TARGET_STM32F2/analogin_api.c b/targets/TARGET_STM/TARGET_STM32F2/analogin_device.c similarity index 79% rename from targets/TARGET_STM/TARGET_STM32F2/analogin_api.c rename to targets/TARGET_STM/TARGET_STM32F2/analogin_device.c index 19c82c2036..c014c2f572 100644 --- a/targets/TARGET_STM/TARGET_STM32F2/analogin_api.c +++ b/targets/TARGET_STM/TARGET_STM32F2/analogin_device.c @@ -40,29 +40,20 @@ void analogin_init(analogin_t *obj, PinName pin) { uint32_t function = (uint32_t)NC; -#if defined(ADC1) - static int adc1_inited = 0; -#endif -#if defined(ADC2) - static int adc2_inited = 0; -#endif -#if defined(ADC3) - static int adc3_inited = 0; -#endif // 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)) { // 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); + 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); } else { // Internal channels - obj->handle.Instance = (ADC_TypeDef *) pinmap_peripheral(pin, PinMap_ADC_Internal); + obj->handle.Instance = (ADC_TypeDef *)pinmap_peripheral(pin, PinMap_ADC_Internal); function = pinmap_function(pin, PinMap_ADC_Internal); // No GPIO configuration for internal channels } @@ -74,33 +65,10 @@ void analogin_init(analogin_t *obj, PinName pin) // Save pin number for the read function obj->pin = pin; - // Check if ADC is already initialized - // Enable ADC clock -#if defined(ADC1) - if (((ADCName)obj->handle.Instance == ADC_1) && adc1_inited) return; - if ((ADCName)obj->handle.Instance == ADC_1) { - __ADC1_CLK_ENABLE(); - adc1_inited = 1; - } -#endif -#if defined(ADC2) - if (((ADCName)obj->handle.Instance == ADC_2) && adc2_inited) return; - if ((ADCName)obj->handle.Instance == ADC_2) { - __ADC2_CLK_ENABLE(); - adc2_inited = 1; - } -#endif -#if defined(ADC3) - if (((ADCName)obj->handle.Instance == ADC_3) && adc3_inited) return; - if ((ADCName)obj->handle.Instance == ADC_3) { - __ADC3_CLK_ENABLE(); - adc3_inited = 1; - } -#endif - // Configure ADC + // Configure ADC object structures obj->handle.State = HAL_ADC_STATE_RESET; - obj->handle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2; - obj->handle.Init.Resolution = ADC_RESOLUTION12b; + obj->handle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; + obj->handle.Init.Resolution = ADC_RESOLUTION_12B; obj->handle.Init.ScanConvMode = DISABLE; obj->handle.Init.ContinuousConvMode = DISABLE; obj->handle.Init.DiscontinuousConvMode = DISABLE; @@ -111,18 +79,35 @@ void analogin_init(analogin_t *obj, PinName pin) obj->handle.Init.NbrOfConversion = 1; obj->handle.Init.DMAContinuousRequests = DISABLE; obj->handle.Init.EOCSelection = DISABLE; + +#if defined(ADC1) + if ((ADCName)obj->handle.Instance == ADC_1) { + __HAL_RCC_ADC1_CLK_ENABLE(); + } +#endif +#if defined(ADC2) + if ((ADCName)obj->handle.Instance == ADC_2) { + __HAL_RCC_ADC2_CLK_ENABLE(); + } +#endif +#if defined(ADC3) + if ((ADCName)obj->handle.Instance == ADC_3) { + __HAL_RCC_ADC3_CLK_ENABLE(); + } +#endif + if (HAL_ADC_Init(&obj->handle) != HAL_OK) { - error("Cannot initialize ADC\n"); + error("Cannot initialize ADC"); } } -static inline uint16_t adc_read(analogin_t *obj) +uint16_t adc_read(analogin_t *obj) { ADC_ChannelConfTypeDef sConfig = {0}; // Configure ADC channel sConfig.Rank = 1; - sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; + sConfig.SamplingTime = ADC_SAMPLETIME_15CYCLES; sConfig.Offset = 0; switch (obj->channel) { @@ -193,24 +178,10 @@ static inline uint16_t adc_read(analogin_t *obj) // Wait end of conversion and get value if (HAL_ADC_PollForConversion(&obj->handle, 10) == HAL_OK) { - return (HAL_ADC_GetValue(&obj->handle)); + return (uint16_t)HAL_ADC_GetValue(&obj->handle); } else { return 0; } } -uint16_t analogin_read_u16(analogin_t *obj) -{ - uint16_t value = adc_read(obj); - // 12-bit to 16-bit conversion - value = ((value << 4) & (uint16_t)0xFFF0) | ((value >> 8) & (uint16_t)0x000F); - return value; -} - -float analogin_read(analogin_t *obj) -{ - uint16_t value = adc_read(obj); - return (float)value * (1.0f / (float)0xFFF); // 12 bits range -} - #endif diff --git a/targets/TARGET_STM/TARGET_STM32F3/analogin_api.c b/targets/TARGET_STM/TARGET_STM32F3/analogin_device.c similarity index 78% rename from targets/TARGET_STM/TARGET_STM32F3/analogin_api.c rename to targets/TARGET_STM/TARGET_STM32F3/analogin_device.c index 63c4681235..ba4970e3a8 100644 --- a/targets/TARGET_STM/TARGET_STM32F3/analogin_api.c +++ b/targets/TARGET_STM/TARGET_STM32F3/analogin_device.c @@ -35,23 +35,11 @@ #include "pinmap.h" #include "mbed_error.h" #include "PeripheralPins.h" - +#include void analogin_init(analogin_t *obj, PinName pin) { -#if defined(ADC1) - static int adc1_inited = 0; -#endif -#if defined(ADC2) - static int adc2_inited = 0; -#endif -#if defined(ADC3) - static int adc3_inited = 0; -#endif -#if defined(ADC4) - static int adc4_inited = 0; -#endif - + static bool adc_calibrated = false; uint32_t function = (uint32_t)NC; // ADC Internal Channels "pins" (Temperature, Vref, Vbat, ...) @@ -60,14 +48,14 @@ void analogin_init(analogin_t *obj, PinName pin) if ((pin < 0xF0) || (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); + 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); } else { // Internal channels - obj->handle.Instance = (ADC_TypeDef *) pinmap_peripheral(pin, PinMap_ADC_Internal); + obj->handle.Instance = (ADC_TypeDef *)pinmap_peripheral(pin, PinMap_ADC_Internal); function = pinmap_function(pin, PinMap_ADC_Internal); // No GPIO configuration for internal channels } @@ -79,41 +67,10 @@ void analogin_init(analogin_t *obj, PinName pin) // Save pin number for the read function obj->pin = pin; - // Check if ADC is already initialized - // Enable ADC clock -#if defined(ADC1) - if (((ADCName)obj->handle.Instance == ADC_1) && adc1_inited) return; - if ((ADCName)obj->handle.Instance == ADC_1) { - __ADC1_CLK_ENABLE(); - adc1_inited = 1; - } -#endif -#if defined(ADC2) - if (((ADCName)obj->handle.Instance == ADC_2) && adc2_inited) return; - if ((ADCName)obj->handle.Instance == ADC_2) { - __ADC2_CLK_ENABLE(); - adc2_inited = 1; - } -#endif -#if defined(ADC3) - if (((ADCName)obj->handle.Instance == ADC_3) && adc3_inited) return; - if ((ADCName)obj->handle.Instance == ADC_3) { - __ADC34_CLK_ENABLE(); - adc3_inited = 1; - } -#endif -#if defined(ADC4) - if (((ADCName)obj->handle.Instance == ADC_4) && adc4_inited) return; - if ((ADCName)obj->handle.Instance == ADC_4) { - __ADC34_CLK_ENABLE(); - adc4_inited = 1; - } -#endif - - // Configure ADC + // Configure ADC object structures obj->handle.State = HAL_ADC_STATE_RESET; - obj->handle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2; - obj->handle.Init.Resolution = ADC_RESOLUTION12b; + obj->handle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; + obj->handle.Init.Resolution = ADC_RESOLUTION_12B; obj->handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; obj->handle.Init.ScanConvMode = DISABLE; obj->handle.Init.EOCSelection = EOC_SINGLE_CONV; @@ -127,15 +84,39 @@ void analogin_init(analogin_t *obj, PinName pin) obj->handle.Init.DMAContinuousRequests = DISABLE; obj->handle.Init.Overrun = OVR_DATA_OVERWRITTEN; +#if defined(ADC1) + if ((ADCName)obj->handle.Instance == ADC_1) { + __HAL_RCC_ADC1_CLK_ENABLE(); + } +#endif +#if defined(ADC2) + if ((ADCName)obj->handle.Instance == ADC_2) { + __HAL_RCC_ADC2_CLK_ENABLE(); + } +#endif +#if defined(ADC3) + if ((ADCName)obj->handle.Instance == ADC_3) { + __HAL_RCC_ADC34_CLK_ENABLE(); + } +#endif +#if defined(ADC4) + if ((ADCName)obj->handle.Instance == ADC_4) { + __HAL_RCC_ADC34_CLK_ENABLE(); + } +#endif + if (HAL_ADC_Init(&obj->handle) != HAL_OK) { error("Cannot initialize ADC"); } - // Calibrate ADC - HAL_ADCEx_Calibration_Start(&obj->handle, ADC_SINGLE_ENDED); + // ADC calibration is done only once + if (!adc_calibrated) { + adc_calibrated = true; + HAL_ADCEx_Calibration_Start(&obj->handle, ADC_SINGLE_ENDED); + } } -static inline uint16_t adc_read(analogin_t *obj) +uint16_t adc_read(analogin_t *obj) { ADC_ChannelConfTypeDef sConfig = {0}; @@ -211,24 +192,10 @@ static inline uint16_t adc_read(analogin_t *obj) // Wait end of conversion and get value if (HAL_ADC_PollForConversion(&obj->handle, 10) == HAL_OK) { - return (HAL_ADC_GetValue(&obj->handle)); + return (uint16_t)HAL_ADC_GetValue(&obj->handle); } else { return 0; } } -uint16_t analogin_read_u16(analogin_t *obj) -{ - uint16_t value = adc_read(obj); - // 12-bit to 16-bit conversion - value = ((value << 4) & (uint16_t)0xFFF0) | ((value >> 8) & (uint16_t)0x000F); - return value; -} - -float analogin_read(analogin_t *obj) -{ - uint16_t value = adc_read(obj); - return (float)value * (1.0f / (float)0xFFF); // 12 bits range -} - #endif diff --git a/targets/TARGET_STM/TARGET_STM32F4/analogin_api.c b/targets/TARGET_STM/TARGET_STM32F4/analogin_device.c similarity index 85% rename from targets/TARGET_STM/TARGET_STM32F4/analogin_api.c rename to targets/TARGET_STM/TARGET_STM32F4/analogin_device.c index ada98bc4d7..54d266e4c1 100644 --- a/targets/TARGET_STM/TARGET_STM32F4/analogin_api.c +++ b/targets/TARGET_STM/TARGET_STM32F4/analogin_device.c @@ -40,29 +40,20 @@ void analogin_init(analogin_t *obj, PinName pin) { uint32_t function = (uint32_t)NC; -#if defined(ADC1) - static int adc1_inited = 0; -#endif -#if defined(ADC2) - static int adc2_inited = 0; -#endif -#if defined(ADC3) - static int adc3_inited = 0; -#endif // 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)) { // 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); + 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); } else { // Internal channels - obj->handle.Instance = (ADC_TypeDef *) pinmap_peripheral(pin, PinMap_ADC_Internal); + obj->handle.Instance = (ADC_TypeDef *)pinmap_peripheral(pin, PinMap_ADC_Internal); function = pinmap_function(pin, PinMap_ADC_Internal); // No GPIO configuration for internal channels } @@ -74,30 +65,7 @@ void analogin_init(analogin_t *obj, PinName pin) // Save pin number for the read function obj->pin = pin; - // Check if ADC is already initialized - // Enable ADC clock -#if defined(ADC1) - if (((ADCName)obj->handle.Instance == ADC_1) && adc1_inited) return; - if ((ADCName)obj->handle.Instance == ADC_1) { - __HAL_RCC_ADC1_CLK_ENABLE(); - adc1_inited = 1; - } -#endif -#if defined(ADC2) - if (((ADCName)obj->handle.Instance == ADC_2) && adc2_inited) return; - if ((ADCName)obj->handle.Instance == ADC_2) { - __HAL_RCC_ADC2_CLK_ENABLE(); - adc2_inited = 1; - } -#endif -#if defined(ADC3) - if (((ADCName)obj->handle.Instance == ADC_3) && adc3_inited) return; - if ((ADCName)obj->handle.Instance == ADC_3) { - __HAL_RCC_ADC3_CLK_ENABLE(); - adc3_inited = 1; - } -#endif - // Configure ADC + // Configure ADC object structures obj->handle.State = HAL_ADC_STATE_RESET; obj->handle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2; obj->handle.Init.Resolution = ADC_RESOLUTION_12B; @@ -112,12 +80,28 @@ void analogin_init(analogin_t *obj, PinName pin) obj->handle.Init.DMAContinuousRequests = DISABLE; obj->handle.Init.EOCSelection = DISABLE; +#if defined(ADC1) + if ((ADCName)obj->handle.Instance == ADC_1) { + __HAL_RCC_ADC1_CLK_ENABLE(); + } +#endif +#if defined(ADC2) + if ((ADCName)obj->handle.Instance == ADC_2) { + __HAL_RCC_ADC2_CLK_ENABLE(); + } +#endif +#if defined(ADC3) + if ((ADCName)obj->handle.Instance == ADC_3) { + __HAL_RCC_ADC3_CLK_ENABLE(); + } +#endif + if (HAL_ADC_Init(&obj->handle) != HAL_OK) { - error("Cannot initialize ADC\n"); + error("Cannot initialize ADC"); } } -static inline uint16_t adc_read(analogin_t *obj) +uint16_t adc_read(analogin_t *obj) { ADC_ChannelConfTypeDef sConfig = {0}; @@ -210,18 +194,4 @@ static inline uint16_t adc_read(analogin_t *obj) } } -uint16_t analogin_read_u16(analogin_t *obj) -{ - uint16_t value = adc_read(obj); - // 12-bit to 16-bit conversion - value = ((value << 4) & (uint16_t)0xFFF0) | ((value >> 8) & (uint16_t)0x000F); - return value; -} - -float analogin_read(analogin_t *obj) -{ - uint16_t value = adc_read(obj); - return (float)value * (1.0f / (float)0xFFF); // 12 bits range -} - #endif diff --git a/targets/TARGET_STM/TARGET_STM32F7/analogin_api.c b/targets/TARGET_STM/TARGET_STM32F7/analogin_device.c similarity index 79% rename from targets/TARGET_STM/TARGET_STM32F7/analogin_api.c rename to targets/TARGET_STM/TARGET_STM32F7/analogin_device.c index b0b566bd58..6592383e19 100644 --- a/targets/TARGET_STM/TARGET_STM32F7/analogin_api.c +++ b/targets/TARGET_STM/TARGET_STM32F7/analogin_device.c @@ -33,35 +33,27 @@ #include "mbed_wait_api.h" #include "cmsis.h" #include "pinmap.h" -#include "PeripheralPins.h" #include "mbed_error.h" +#include "PeripheralPins.h" void analogin_init(analogin_t *obj, PinName pin) { uint32_t function = (uint32_t)NC; -#if defined(ADC1) - static int adc1_inited = 0; -#endif -#if defined(ADC2) - static int adc2_inited = 0; -#endif -#if defined(ADC3) - static int adc3_inited = 0; -#endif // 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)) { // 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); + 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); } else { // Internal channels - obj->handle.Instance = (ADC_TypeDef *) pinmap_peripheral(pin, PinMap_ADC_Internal); + obj->handle.Instance = (ADC_TypeDef *)pinmap_peripheral(pin, PinMap_ADC_Internal); function = pinmap_function(pin, PinMap_ADC_Internal); // No GPIO configuration for internal channels } @@ -73,33 +65,9 @@ void analogin_init(analogin_t *obj, PinName pin) // Save pin number for the read function obj->pin = pin; - // Check if ADC is already initialized - // Enable ADC clock -#if defined(ADC1) - if (((ADCName)obj->handle.Instance == ADC_1) && adc1_inited) return; - if ((ADCName)obj->handle.Instance == ADC_1) { - __HAL_RCC_ADC1_CLK_ENABLE(); - adc1_inited = 1; - } -#endif -#if defined(ADC2) - if (((ADCName)obj->handle.Instance == ADC_2) && adc2_inited) return; - if ((ADCName)obj->handle.Instance == ADC_2) { - __HAL_RCC_ADC2_CLK_ENABLE(); - adc2_inited = 1; - } -#endif -#if defined(ADC3) - if (((ADCName)obj->handle.Instance == ADC_3) && adc3_inited) return; - if ((ADCName)obj->handle.Instance == ADC_3) { - __HAL_RCC_ADC3_CLK_ENABLE(); - adc3_inited = 1; - } -#endif - - // Configure ADC + // Configure ADC object structures obj->handle.State = HAL_ADC_STATE_RESET; - obj->handle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4; + obj->handle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; obj->handle.Init.Resolution = ADC_RESOLUTION_12B; obj->handle.Init.ScanConvMode = DISABLE; obj->handle.Init.ContinuousConvMode = DISABLE; @@ -112,12 +80,28 @@ void analogin_init(analogin_t *obj, PinName pin) obj->handle.Init.DMAContinuousRequests = DISABLE; obj->handle.Init.EOCSelection = DISABLE; +#if defined(ADC1) + if ((ADCName)obj->handle.Instance == ADC_1) { + __HAL_RCC_ADC1_CLK_ENABLE(); + } +#endif +#if defined(ADC2) + if ((ADCName)obj->handle.Instance == ADC_2) { + __HAL_RCC_ADC2_CLK_ENABLE(); + } +#endif +#if defined(ADC3) + if ((ADCName)obj->handle.Instance == ADC_3) { + __HAL_RCC_ADC3_CLK_ENABLE(); + } +#endif + if (HAL_ADC_Init(&obj->handle) != HAL_OK) { error("Cannot initialize ADC"); } } -static inline uint16_t adc_read(analogin_t *obj) +uint16_t adc_read(analogin_t *obj) { ADC_ChannelConfTypeDef sConfig = {0}; @@ -188,33 +172,16 @@ static inline uint16_t adc_read(analogin_t *obj) return 0; } - if (HAL_ADC_ConfigChannel(&obj->handle, &sConfig) != HAL_OK) { - error("Cannot configure ADC channel"); - } + HAL_ADC_ConfigChannel(&obj->handle, &sConfig); HAL_ADC_Start(&obj->handle); // Start conversion // Wait end of conversion and get value - HAL_ADC_PollForConversion(&obj->handle, 10); - if (HAL_ADC_GetState(&obj->handle) & HAL_ADC_STATE_EOC_REG) { - return (HAL_ADC_GetValue(&obj->handle)); + if (HAL_ADC_PollForConversion(&obj->handle, 10) == HAL_OK) { + return (uint16_t)HAL_ADC_GetValue(&obj->handle); } else { return 0; } } -uint16_t analogin_read_u16(analogin_t *obj) -{ - uint16_t value = adc_read(obj); - // 12-bit to 16-bit conversion - value = ((value << 4) & (uint16_t)0xFFF0) | ((value >> 8) & (uint16_t)0x000F); - return value; -} - -float analogin_read(analogin_t *obj) -{ - uint16_t value = adc_read(obj); - return (float)value * (1.0f / (float)0xFFF); // 12 bits range -} - #endif diff --git a/targets/TARGET_STM/TARGET_STM32L0/analogin_api.c b/targets/TARGET_STM/TARGET_STM32L0/analogin_device.c similarity index 71% rename from targets/TARGET_STM/TARGET_STM32L0/analogin_api.c rename to targets/TARGET_STM/TARGET_STM32L0/analogin_device.c index e6d68e29cf..f1ac6a8764 100644 --- a/targets/TARGET_STM/TARGET_STM32L0/analogin_api.c +++ b/targets/TARGET_STM/TARGET_STM32L0/analogin_device.c @@ -35,13 +35,12 @@ #include "pinmap.h" #include "mbed_error.h" #include "PeripheralPins.h" - -int adc_inited = 0; +#include void analogin_init(analogin_t *obj, PinName pin) { + static bool adc_calibrated = false; uint32_t function = (uint32_t)NC; - obj->handle.Instance = (ADC_TypeDef *)NC; // ADC Internal Channels "pins" (Temperature, Vref, Vbat, ...) // are described in PinNames.h and PeripheralPins.c @@ -68,44 +67,41 @@ void analogin_init(analogin_t *obj, PinName pin) // Save pin number for the read function obj->pin = pin; - // The ADC initialization is done once - if (adc_inited == 0) { - adc_inited = 1; + // Configure ADC object structures + obj->handle.State = HAL_ADC_STATE_RESET; + obj->handle.Init.OversamplingMode = DISABLE; + obj->handle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV1; + obj->handle.Init.Resolution = ADC_RESOLUTION_12B; + obj->handle.Init.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; + obj->handle.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD; + obj->handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; + obj->handle.Init.ContinuousConvMode = DISABLE; + obj->handle.Init.DiscontinuousConvMode = DISABLE; + obj->handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIG_EDGE_NONE; + obj->handle.Init.ExternalTrigConv = ADC_EXTERNALTRIG0_T6_TRGO; // Not used here + obj->handle.Init.DMAContinuousRequests = DISABLE; + obj->handle.Init.EOCSelection = EOC_SINGLE_CONV; + obj->handle.Init.Overrun = OVR_DATA_OVERWRITTEN; + obj->handle.Init.LowPowerAutoWait = ENABLE; + obj->handle.Init.LowPowerFrequencyMode = DISABLE; // To be enabled only if ADC clock < 2.8 MHz + obj->handle.Init.LowPowerAutoPowerOff = DISABLE; - obj->handle.State = HAL_ADC_STATE_RESET; - // Enable ADC clock - __ADC1_CLK_ENABLE(); + __HAL_RCC_ADC1_CLK_ENABLE(); - // Configure ADC - obj->handle.Init.OversamplingMode = DISABLE; - obj->handle.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV1; - obj->handle.Init.Resolution = ADC_RESOLUTION12b; - obj->handle.Init.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; - obj->handle.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD; - obj->handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; - obj->handle.Init.ContinuousConvMode = DISABLE; - obj->handle.Init.DiscontinuousConvMode = DISABLE; - obj->handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIG_EDGE_NONE; - obj->handle.Init.ExternalTrigConv = ADC_EXTERNALTRIG0_T6_TRGO; // Not used here - obj->handle.Init.DMAContinuousRequests = DISABLE; - obj->handle.Init.EOCSelection = EOC_SINGLE_CONV; - obj->handle.Init.Overrun = OVR_DATA_OVERWRITTEN; - obj->handle.Init.LowPowerAutoWait = ENABLE; - obj->handle.Init.LowPowerFrequencyMode = DISABLE; // To be enabled only if ADC clock < 2.8 MHz - obj->handle.Init.LowPowerAutoPowerOff = DISABLE; - - if (HAL_ADC_Init(&obj->handle) != HAL_OK) { - error("Cannot initialize ADC"); - } - - // Calibration - HAL_ADCEx_Calibration_Start(&obj->handle, ADC_SINGLE_ENDED); - - __HAL_ADC_ENABLE(&obj->handle); + if (HAL_ADC_Init(&obj->handle) != HAL_OK) { + error("Cannot initialize ADC"); } + + // ADC calibration is done only once + if (!adc_calibrated) { + adc_calibrated = true; + HAL_ADCEx_Calibration_Start(&obj->handle, ADC_SINGLE_ENDED); + } + + __HAL_ADC_ENABLE(&obj->handle); } -static inline uint16_t adc_read(analogin_t *obj) +uint16_t adc_read(analogin_t *obj) { ADC_ChannelConfTypeDef sConfig = {0}; @@ -182,24 +178,10 @@ static inline uint16_t adc_read(analogin_t *obj) // Wait end of conversion and get value if (HAL_ADC_PollForConversion(&obj->handle, 10) == HAL_OK) { - return (HAL_ADC_GetValue(&obj->handle)); + return (uint16_t)HAL_ADC_GetValue(&obj->handle); } else { return 0; } } -uint16_t analogin_read_u16(analogin_t *obj) -{ - uint16_t value = adc_read(obj); - // 12-bit to 16-bit conversion - value = ((value << 4) & (uint16_t)0xFFF0) | ((value >> 8) & (uint16_t)0x000F); - return value; -} - -float analogin_read(analogin_t *obj) -{ - uint16_t value = adc_read(obj); - return (float)value * (1.0f / (float)0xFFF); // 12 bits range -} - #endif diff --git a/targets/TARGET_STM/TARGET_STM32L1/analogin_api.c b/targets/TARGET_STM/TARGET_STM32L1/analogin_device.c similarity index 68% rename from targets/TARGET_STM/TARGET_STM32L1/analogin_api.c rename to targets/TARGET_STM/TARGET_STM32L1/analogin_device.c index d4eead2bbb..dfef3a3eb0 100644 --- a/targets/TARGET_STM/TARGET_STM32L1/analogin_api.c +++ b/targets/TARGET_STM/TARGET_STM32L1/analogin_device.c @@ -35,11 +35,11 @@ #include "pinmap.h" #include "mbed_error.h" #include "PeripheralPins.h" - -int adc_inited = 0; +#include void analogin_init(analogin_t *obj, PinName pin) { + static bool adc_hsi_inited = false; RCC_OscInitTypeDef RCC_OscInitStruct; uint32_t function = (uint32_t)NC; @@ -49,14 +49,14 @@ void analogin_init(analogin_t *obj, PinName pin) if ((pin < 0xF0) || (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); + 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); } else { // Internal channels - obj->handle.Instance = (ADC_TypeDef *) pinmap_peripheral(pin, PinMap_ADC_Internal); + obj->handle.Instance = (ADC_TypeDef *)pinmap_peripheral(pin, PinMap_ADC_Internal); function = pinmap_function(pin, PinMap_ADC_Internal); // No GPIO configuration for internal channels } @@ -68,45 +68,43 @@ void analogin_init(analogin_t *obj, PinName pin) // Save pin number for the read function obj->pin = pin; - // The ADC initialization is done once - if (adc_inited == 0) { - adc_inited = 1; + // Configure ADC object structures + obj->handle.State = HAL_ADC_STATE_RESET; + obj->handle.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV4; + obj->handle.Init.Resolution = ADC_RESOLUTION_12B; + obj->handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; + obj->handle.Init.ScanConvMode = DISABLE; // Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) + obj->handle.Init.EOCSelection = 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.LowPowerAutoWait = ADC_AUTOWAIT_UNTIL_DATA_READ; // Enable the dynamic low power Auto Delay: new conversion start only when the previous conversion (for regular group) or previous sequence (for injected group) has been treated by user software. + obj->handle.Init.LowPowerAutoPowerOff = ADC_AUTOPOWEROFF_IDLE_PHASE; // Enable the auto-off mode: the ADC automatically powers-off after a conversion and automatically wakes-up when a new conversion is triggered (with startup time between trigger and start of sampling). + obj->handle.Init.ChannelsBank = ADC_CHANNELS_BANK_A; + 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 = 0; // Not used + obj->handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; + obj->handle.Init.DMAContinuousRequests = DISABLE; + __HAL_RCC_ADC1_CLK_ENABLE(); + + if (HAL_ADC_Init(&obj->handle) != HAL_OK) { + error("Cannot initialize ADC"); + } + + // This section is done only once + if (!adc_hsi_inited) { + adc_hsi_inited = true; // Enable the HSI (to clock the ADC) RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; HAL_RCC_OscConfig(&RCC_OscInitStruct); - - obj->handle.State = HAL_ADC_STATE_RESET; - // Enable ADC clock - __ADC1_CLK_ENABLE(); - - // Configure ADC - obj->handle.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV4; - obj->handle.Init.Resolution = ADC_RESOLUTION12b; - obj->handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; - obj->handle.Init.ScanConvMode = DISABLE; // Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) - obj->handle.Init.EOCSelection = 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.LowPowerAutoWait = ADC_AUTOWAIT_UNTIL_DATA_READ; // Enable the dynamic low power Auto Delay: new conversion start only when the previous conversion (for regular group) or previous sequence (for injected group) has been treated by user software. - obj->handle.Init.LowPowerAutoPowerOff = ADC_AUTOPOWEROFF_IDLE_PHASE; // Enable the auto-off mode: the ADC automatically powers-off after a conversion and automatically wakes-up when a new conversion is triggered (with startup time between trigger and start of sampling). - obj->handle.Init.ChannelsBank = ADC_CHANNELS_BANK_A; - 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 = 0; // Not used - obj->handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; - obj->handle.Init.DMAContinuousRequests = DISABLE; - - if (HAL_ADC_Init(&obj->handle) != HAL_OK) { - error("Cannot initialize ADC"); - } } } -static inline uint16_t adc_read(analogin_t *obj) +uint16_t adc_read(analogin_t *obj) { ADC_ChannelConfTypeDef sConfig = {0}; @@ -231,24 +229,10 @@ static inline uint16_t adc_read(analogin_t *obj) // Wait end of conversion and get value if (HAL_ADC_PollForConversion(&obj->handle, 10) == HAL_OK) { - return (HAL_ADC_GetValue(&obj->handle)); + return (uint16_t)HAL_ADC_GetValue(&obj->handle); } else { return 0; } } -uint16_t analogin_read_u16(analogin_t *obj) -{ - uint16_t value = adc_read(obj); - // 12-bit to 16-bit conversion - value = ((value << 4) & (uint16_t)0xFFF0) | ((value >> 8) & (uint16_t)0x000F); - return value; -} - -float analogin_read(analogin_t *obj) -{ - uint16_t value = adc_read(obj); - return (float)value * (1.0f / (float)0xFFF); // 12 bits range -} - #endif diff --git a/targets/TARGET_STM/TARGET_STM32L4/analogin_api.c b/targets/TARGET_STM/TARGET_STM32L4/analogin_api.c deleted file mode 100644 index 9fc5e1ff00..0000000000 --- a/targets/TARGET_STM/TARGET_STM32L4/analogin_api.c +++ /dev/null @@ -1,204 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2016, STMicroelectronics - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "mbed_assert.h" -#include "analogin_api.h" - -#if DEVICE_ANALOGIN - -#include "mbed_wait_api.h" -#include "cmsis.h" -#include "pinmap.h" -#include "mbed_error.h" -#include "PeripheralPins.h" - -int adc_inited = 0; - -void analogin_init(analogin_t *obj, PinName pin) -{ - uint32_t function = (uint32_t)NC; - - // 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)) { - // 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); - } 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); - MBED_ASSERT(function != (uint32_t)NC); - - obj->channel = STM_PIN_CHANNEL(function); - - // Save pin number for the read function - obj->pin = pin; - - // The ADC initialization is done once - if (adc_inited == 0) { - adc_inited = 1; - - // Enable ADC clock - __HAL_RCC_ADC_CLK_ENABLE(); - __HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_SYSCLK); - - obj->handle.State = HAL_ADC_STATE_RESET; - // Configure ADC - obj->handle.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV2; // Asynchronous clock mode, input ADC clock - obj->handle.Init.Resolution = ADC_RESOLUTION_12B; - obj->handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; - obj->handle.Init.ScanConvMode = 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.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.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 - - if (HAL_ADC_Init(&obj->handle) != HAL_OK) { - error("Cannot initialize ADC\n"); - } - - // Calibrate ADC - HAL_ADCEx_Calibration_Start(&obj->handle, ADC_SINGLE_ENDED); - } -} - -static inline uint16_t adc_read(analogin_t *obj) -{ - ADC_ChannelConfTypeDef sConfig = {0}; - - // Configure ADC channel - switch (obj->channel) { - case 0: - sConfig.Channel = ADC_CHANNEL_VREFINT; - break; - case 1: - sConfig.Channel = ADC_CHANNEL_1; - break; - case 2: - sConfig.Channel = ADC_CHANNEL_2; - break; - case 3: - sConfig.Channel = ADC_CHANNEL_3; - break; - case 4: - sConfig.Channel = ADC_CHANNEL_4; - break; - case 5: - sConfig.Channel = ADC_CHANNEL_5; - break; - case 6: - sConfig.Channel = ADC_CHANNEL_6; - break; - case 7: - sConfig.Channel = ADC_CHANNEL_7; - break; - case 8: - sConfig.Channel = ADC_CHANNEL_8; - break; - case 9: - sConfig.Channel = ADC_CHANNEL_9; - break; - case 10: - sConfig.Channel = ADC_CHANNEL_10; - break; - case 11: - sConfig.Channel = ADC_CHANNEL_11; - break; - case 12: - sConfig.Channel = ADC_CHANNEL_12; - break; - case 13: - sConfig.Channel = ADC_CHANNEL_13; - 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; - break; - case 18: - sConfig.Channel = ADC_CHANNEL_VBAT; - break; - default: - return 0; - } - - 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; - - HAL_ADC_ConfigChannel(&obj->handle, &sConfig); - - HAL_ADC_Start(&obj->handle); // Start conversion - - // Wait end of conversion and get value - if (HAL_ADC_PollForConversion(&obj->handle, 10) == HAL_OK) { - return (HAL_ADC_GetValue(&obj->handle)); - } else { - return 0; - } -} - -uint16_t analogin_read_u16(analogin_t *obj) -{ - uint16_t value = adc_read(obj); - // 12-bit to 16-bit conversion - value = ((value << 4) & (uint16_t)0xFFF0) | ((value >> 8) & (uint16_t)0x000F); - return value; -} - -float analogin_read(analogin_t *obj) -{ - uint16_t value = adc_read(obj); - return (float)value * (1.0f / (float)0xFFF); // 12 bits range -} - -#endif diff --git a/targets/TARGET_STM/TARGET_STM32L4/analogin_device.c b/targets/TARGET_STM/TARGET_STM32L4/analogin_device.c new file mode 100644 index 0000000000..550589f311 --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L4/analogin_device.c @@ -0,0 +1,188 @@ +/* mbed Microcontroller Library + * Copyright (c) 2016, STMicroelectronics + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "mbed_assert.h" +#include "analogin_api.h" + +#if DEVICE_ANALOGIN + +#include "mbed_wait_api.h" +#include "cmsis.h" +#include "pinmap.h" +#include "mbed_error.h" +#include "PeripheralPins.h" +#include + +void analogin_init(analogin_t *obj, PinName pin) +{ + static bool adc_calibrated = false; + uint32_t function = (uint32_t)NC; + + // 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)) { + // 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); + } 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); + MBED_ASSERT(function != (uint32_t)NC); + + obj->channel = STM_PIN_CHANNEL(function); + + // Save pin number for the read function + obj->pin = 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.Resolution = ADC_RESOLUTION_12B; + obj->handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; + obj->handle.Init.ScanConvMode = 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.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.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 + + // Enable ADC clock + __HAL_RCC_ADC_CLK_ENABLE(); + __HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_SYSCLK); + + if (HAL_ADC_Init(&obj->handle) != HAL_OK) { + error("Cannot initialize ADC"); + } + + // ADC calibration is done only once + if (!adc_calibrated) { + adc_calibrated = true; + HAL_ADCEx_Calibration_Start(&obj->handle, ADC_SINGLE_ENDED); + } +} + +uint16_t adc_read(analogin_t *obj) +{ + ADC_ChannelConfTypeDef sConfig = {0}; + + // Configure ADC channel + switch (obj->channel) { + case 0: + sConfig.Channel = ADC_CHANNEL_VREFINT; + break; + case 1: + sConfig.Channel = ADC_CHANNEL_1; + break; + case 2: + sConfig.Channel = ADC_CHANNEL_2; + break; + case 3: + sConfig.Channel = ADC_CHANNEL_3; + break; + case 4: + sConfig.Channel = ADC_CHANNEL_4; + break; + case 5: + sConfig.Channel = ADC_CHANNEL_5; + break; + case 6: + sConfig.Channel = ADC_CHANNEL_6; + break; + case 7: + sConfig.Channel = ADC_CHANNEL_7; + break; + case 8: + sConfig.Channel = ADC_CHANNEL_8; + break; + case 9: + sConfig.Channel = ADC_CHANNEL_9; + break; + case 10: + sConfig.Channel = ADC_CHANNEL_10; + break; + case 11: + sConfig.Channel = ADC_CHANNEL_11; + break; + case 12: + sConfig.Channel = ADC_CHANNEL_12; + break; + case 13: + sConfig.Channel = ADC_CHANNEL_13; + 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; + break; + case 18: + sConfig.Channel = ADC_CHANNEL_VBAT; + break; + default: + return 0; + } + + 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; + + HAL_ADC_ConfigChannel(&obj->handle, &sConfig); + + HAL_ADC_Start(&obj->handle); // Start conversion + + // Wait end of conversion and get value + if (HAL_ADC_PollForConversion(&obj->handle, 10) == HAL_OK) { + return (uint16_t)HAL_ADC_GetValue(&obj->handle); + } else { + return 0; + } +} + +#endif diff --git a/targets/TARGET_STM/analogin_api.c b/targets/TARGET_STM/analogin_api.c new file mode 100644 index 0000000000..bb16c62816 --- /dev/null +++ b/targets/TARGET_STM/analogin_api.c @@ -0,0 +1,48 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017, STMicroelectronics + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "analogin_api.h" + +#if DEVICE_ANALOGIN + +uint16_t adc_read(analogin_t *obj); + +uint16_t analogin_read_u16(analogin_t *obj) +{ + uint16_t value = adc_read(obj); + // 12-bit to 16-bit conversion + value = ((value << 4) & (uint16_t)0xFFF0) | ((value >> 8) & (uint16_t)0x000F); + return value; +} + +float analogin_read(analogin_t *obj) +{ + uint16_t value = adc_read(obj); + return (float)value * (1.0f / (float)0xFFF); // 12 bits range +} + +#endif