From 7c7db00a7759a44bbca414d5d1e943f211483190 Mon Sep 17 00:00:00 2001 From: Song Qiang Date: Tue, 7 May 2019 16:37:35 +0800 Subject: [PATCH] drivers: adc: add driver support for ADC1 of stm32 This commit adds driver support for ADC1 on all 8 supported series of stm32 with resolution and conversion time selection and calibration. Currently DMA is not supported for all series, and without it, zephyr won't be able to catch up ADC's end of conversion interrupt, so this version of the driver supports one channel conversion only. Users want multi-channel conversion should use multiple sequences in their app code. This driver uses LL lib rather than HAL because the current HAL lib for ADC will call HAL_DMA_* functions rather than using zephyr's common DMA interface, so that way the driver will break the consistency of the code. This driver has been tested on multiple nucleo boards including NUCLEO_F091RC/F103RB/F207ZG/F302R8/F401RE/F746ZG/L073RZ/L476RG and all passed the test cases in tests/drivers/adc/adc_api. If the external ADC line is floating, it may fail the tests since ADC may get 0V and the test cases think 0 is failing. Connect it to any voltage source between 0-3.3V will help passing the test cases. Signed-off-by: Song Qiang --- CODEOWNERS | 2 + drivers/adc/CMakeLists.txt | 1 + drivers/adc/Kconfig | 2 + drivers/adc/Kconfig.stm32 | 25 + drivers/adc/adc_stm32.c | 640 ++++++++++++++++++ .../st_stm32/common/Kconfig.defconfig.series | 7 + soc/arm/st_stm32/stm32f0/soc.h | 4 + soc/arm/st_stm32/stm32f1/soc.h | 4 + soc/arm/st_stm32/stm32f2/soc.h | 4 + soc/arm/st_stm32/stm32f3/soc.h | 4 + soc/arm/st_stm32/stm32f4/soc.h | 4 + soc/arm/st_stm32/stm32f7/soc.h | 4 + soc/arm/st_stm32/stm32l0/soc.h | 4 + soc/arm/st_stm32/stm32l4/soc.h | 4 + 14 files changed, 709 insertions(+) create mode 100644 drivers/adc/Kconfig.stm32 create mode 100644 drivers/adc/adc_stm32.c diff --git a/CODEOWNERS b/CODEOWNERS index 76391c6a846..7a625e5b2f8 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -100,6 +100,7 @@ /drivers/*/*stm32* @erwango /drivers/*/*native_posix* @aescolar /drivers/adc/ @anangl +/drivers/adc/adc_stm32.c @cybertale /drivers/bluetooth/ @joerchan @jhedberg @Vudentz /drivers/can/ @alexanderwachter /drivers/can/*mcp2515* @karstenkoenig @@ -155,6 +156,7 @@ /dts/riscv32/rv32m1* @MaureenHelm /dts/bindings/ @galak /dts/bindings/can/ @alexanderwachter +/dts/bindings/iio/adc/st,stm32-adc.yaml @cybertale /dts/bindings/serial/ns16550.yaml @gnuless /dts/bindings/*/nordic* @anangl /dts/bindings/*/nxp* @MaureenHelm diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index 2654b3a0896..8193a14d36a 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -9,4 +9,5 @@ zephyr_library_sources_ifdef(CONFIG_ADC_NRFX_SAADC adc_nrfx_saadc.c) zephyr_library_sources_ifdef(CONFIG_ADC_INTEL_QUARK_SE_C1000_SS adc_intel_quark_se_c1000_ss.c) zephyr_library_sources_ifdef(CONFIG_ADC_INTEL_QUARK_D2000 adc_intel_quark_d2000.c) zephyr_library_sources_ifdef(CONFIG_ADC_SAM0 adc_sam0.c) +zephyr_library_sources_ifdef(CONFIG_ADC_STM32 adc_stm32.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE adc_handlers.c) diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index b981b8499da..65230269110 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -57,4 +57,6 @@ source "drivers/adc/Kconfig.intel_quark" source "drivers/adc/Kconfig.sam0" +source "drivers/adc/Kconfig.stm32" + endif # ADC diff --git a/drivers/adc/Kconfig.stm32 b/drivers/adc/Kconfig.stm32 new file mode 100644 index 00000000000..49fd2ba40f4 --- /dev/null +++ b/drivers/adc/Kconfig.stm32 @@ -0,0 +1,25 @@ +# Kconfig - ADC configuration options + +# +# Copyright (c) 2019 Intel Corporation +# Copyright (c) 2019 Endre Karlson +# Copyright (c) 2019 Song Qiang +# +# SPDX-License-Identifier: Apache-2.0 +# + +menuconfig ADC_STM32 + bool "STM32 ADC driver" + depends on SOC_FAMILY_STM32 + help + Enable the driver implementation for the stm32xx ADC + +if ADC_STM32 + +config ADC_1 + bool "ADC1" + default y + help + Enable ADC1 + +endif # ADC_STM32 diff --git a/drivers/adc/adc_stm32.c b/drivers/adc/adc_stm32.c new file mode 100644 index 00000000000..e96ccaf728f --- /dev/null +++ b/drivers/adc/adc_stm32.c @@ -0,0 +1,640 @@ +/* + * Copyright (c) 2018 Kokoon Technology Limited + * Copyright (c) 2019 Song Qiang + * Copyright (c) 2019 Endre Karlson + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include +#include + +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" + +#define LOG_LEVEL CONFIG_ADC_LOG_LEVEL +#include +LOG_MODULE_REGISTER(adc_stm32); + +#include + +#if !defined(CONFIG_SOC_SERIES_STM32F0X) && \ + !defined(CONFIG_SOC_SERIES_STM32L0X) +#define RANK(n) LL_ADC_REG_RANK_##n +static const u32_t table_rank[] = { + RANK(1), + RANK(2), + RANK(3), + RANK(4), + RANK(5), + RANK(6), + RANK(7), + RANK(8), + RANK(9), + RANK(10), + RANK(11), + RANK(12), + RANK(13), + RANK(14), + RANK(15), + RANK(16), +}; + +#define SEQ_LEN(n) LL_ADC_REG_SEQ_SCAN_ENABLE_##n##RANKS +static const u32_t table_seq_len[] = { + LL_ADC_REG_SEQ_SCAN_DISABLE, + SEQ_LEN(2), + SEQ_LEN(3), + SEQ_LEN(4), + SEQ_LEN(5), + SEQ_LEN(6), + SEQ_LEN(7), + SEQ_LEN(8), + SEQ_LEN(9), + SEQ_LEN(10), + SEQ_LEN(11), + SEQ_LEN(12), + SEQ_LEN(13), + SEQ_LEN(14), + SEQ_LEN(15), + SEQ_LEN(16), +}; +#endif + +#define RES(n) LL_ADC_RESOLUTION_##n##B +static const u32_t table_resolution[] = { +#if !defined(CONFIG_SOC_SERIES_STM32F1X) + RES(6), + RES(8), + RES(10), +#endif + RES(12), +}; + +#define SMP_TIME(x, y) LL_ADC_SAMPLINGTIME_##x##CYCLE##y + +/* + * Conversion time in ADC cycles. Many values should have been 0.5 less, + * but the adc api system currently does not support describing 'half cycles'. + * So all half cycles are counted as one. + */ +#if defined(CONFIG_SOC_SERIES_STM32F0X) || defined(CONFIG_SOC_SERIES_STM32F1X) +static const u16_t acq_time_tbl[8] = {2, 8, 14, 29, 42, 56, 72, 240}; +static const u32_t table_samp_time[] = { + SMP_TIME(1, _5), + SMP_TIME(7, S_5), + SMP_TIME(13, S_5), + SMP_TIME(28, S_5), + SMP_TIME(41, S_5), + SMP_TIME(55, S_5), + SMP_TIME(71, S_5), + SMP_TIME(239, S_5), +}; +#elif defined(CONFIG_SOC_SERIES_STM32F2X) || \ + defined(CONFIG_SOC_SERIES_STM32F4X) || \ + defined(CONFIG_SOC_SERIES_STM32F7X) +static const u16_t acq_time_tbl[8] = {3, 15, 28, 56, 84, 112, 144, 480}; +static const u32_t table_samp_time[] = { + SMP_TIME(3, S), + SMP_TIME(15, S), + SMP_TIME(28, S), + SMP_TIME(56, S), + SMP_TIME(84, S), + SMP_TIME(112, S), + SMP_TIME(144, S), + SMP_TIME(480, S), +}; +#elif defined(CONFIG_SOC_SERIES_STM32F3X) +#ifdef ADC5_V1_1 +static const u16_t acq_time_tbl[8] = {2, 3, 5, 8, 20, 62, 182, 602}; +static const u32_t table_samp_time[] = { + SMP_TIME(1, _5), + SMP_TIME(2, S_5), + SMP_TIME(4, S_5), + SMP_TIME(7, S_5), + SMP_TIME(19, S_5), + SMP_TIME(61, S_5), + SMP_TIME(181, S_5), + SMP_TIME(601, S_5), +}; +#else +static const u16_t acq_time_tbl[8] = {2, 8, 14, 29, 42, 56, 72, 240}; +static const u32_t table_samp_time[] = { + SMP_TIME(1, _5), + SMP_TIME(7, S_5), + SMP_TIME(13, S_5), + SMP_TIME(28, S_5), + SMP_TIME(41, S_5), + SMP_TIME(55, S_5), + SMP_TIME(71, S_5), + SMP_TIME(239, S_5), +}; +#endif /* ADC5_V1_1 */ +#elif defined(CONFIG_SOC_SERIES_STM32L0X) +static const u16_t acq_time_tbl[8] = {2, 4, 8, 13, 20, 40, 80, 161}; +static const u32_t table_samp_time[] = { + SMP_TIME(1, _5), + SMP_TIME(3, S_5), + SMP_TIME(7, S_5), + SMP_TIME(12, S_5), + SMP_TIME(19, S_5), + SMP_TIME(39, S_5), + SMP_TIME(79, S_5), + SMP_TIME(160, S_5), +}; +#elif defined(CONFIG_SOC_SERIES_STM32L4X) +static const u16_t acq_time_tbl[8] = {3, 7, 13, 25, 48, 93, 248, 641}; +static const u32_t table_samp_time[] = { + SMP_TIME(2, S_5), + SMP_TIME(6, S_5), + SMP_TIME(12, S_5), + SMP_TIME(24, S_5), + SMP_TIME(47, S_5), + SMP_TIME(92, S_5), + SMP_TIME(247, S_5), + SMP_TIME(640, S_5), +}; +#endif + +/* 16 external channels. */ +#define STM32_CHANNEL_COUNT 16 + +struct adc_stm32_data { + struct adc_context ctx; + struct device *dev; + u16_t *buffer; + u16_t *repeat_buffer; + + u8_t resolution; + u8_t channel_count; +#if defined(CONFIG_SOC_SERIES_STM32F0X) || defined(CONFIG_SOC_SERIES_STM32L0X) + s8_t acq_time_index; +#endif +}; + +struct adc_stm32_cfg { + ADC_TypeDef *base; + + void (*irq_cfg_func)(void); + + struct stm32_pclken pclken; + struct device *p_dev; +}; + +static int check_buffer_size(const struct adc_sequence *sequence, + u8_t active_channels) +{ + size_t needed_buffer_size; + + needed_buffer_size = active_channels * sizeof(u16_t); + + if (sequence->options) { + needed_buffer_size *= (1 + sequence->options->extra_samplings); + } + + if (sequence->buffer_size < needed_buffer_size) { + LOG_ERR("Provided buffer is too small (%u/%u)", + sequence->buffer_size, needed_buffer_size); + return -ENOMEM; + } + + return 0; +} + +static void adc_stm32_start_conversion(struct device *dev) +{ + const struct adc_stm32_cfg *config = dev->config->config_info; + ADC_TypeDef *adc = (ADC_TypeDef *)config->base; + + LOG_DBG("Starting conversion"); + +#if defined(CONFIG_SOC_SERIES_STM32F0X) || \ + defined(CONFIG_SOC_SERIES_STM32F3X) || \ + defined(CONFIG_SOC_SERIES_STM32L0X) || \ + defined(CONFIG_SOC_SERIES_STM32L4X) + LL_ADC_REG_StartConversion(adc); +#else + LL_ADC_REG_StartConversionSWStart(adc); +#endif +} + +static int start_read(struct device *dev, const struct adc_sequence *sequence) +{ + const struct adc_stm32_cfg *config = dev->config->config_info; + struct adc_stm32_data *data = dev->driver_data; + ADC_TypeDef *adc = (ADC_TypeDef *)config->base; + u8_t resolution; + int err; + + switch (sequence->resolution) { +#if !defined(CONFIG_SOC_SERIES_STM32F1X) + case 6: + resolution = table_resolution[0]; + break; + case 8: + resolution = table_resolution[1]; + break; + case 10: + resolution = table_resolution[2]; + break; +#endif + case 12: + resolution = table_resolution[3]; + break; + default: + LOG_ERR("Invalid resolution"); + return -EINVAL; + } + + u32_t channels = sequence->channels; + + data->buffer = sequence->buffer; + u8_t index; + + index = find_lsb_set(channels) - 1; + u32_t channel = __LL_ADC_DECIMAL_NB_TO_CHANNEL(index); +#if defined(CONFIG_SOC_SERIES_STM32F0X) || \ + defined(CONFIG_SOC_SERIES_STM32L0X) + LL_ADC_REG_SetSequencerChannels(adc, channel); +#else + LL_ADC_REG_SetSequencerRanks(adc, table_rank[0], channel); + LL_ADC_REG_SetSequencerLength(adc, table_seq_len[0]); +#endif + data->channel_count = 1; + + err = check_buffer_size(sequence, data->channel_count); + if (err) { + return err; + } + +#if !defined(CONFIG_SOC_SERIES_STM32F1X) + LL_ADC_SetResolution(adc, resolution); +#endif + +#if defined(CONFIG_SOC_SERIES_STM32F0X) || \ + defined(CONFIG_SOC_SERIES_STM32F3X) || \ + defined(CONFIG_SOC_SERIES_STM32L0X) || \ + defined(CONFIG_SOC_SERIES_STM32L4X) + LL_ADC_EnableIT_EOC(adc); +#elif defined(CONFIG_SOC_SERIES_STM32F1X) + LL_ADC_EnableIT_EOS(adc); +#else + LL_ADC_EnableIT_EOCS(adc); +#endif + + adc_context_start_read(&data->ctx, sequence); + + return adc_context_wait_for_completion(&data->ctx); +} + +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct adc_stm32_data *data = + CONTAINER_OF(ctx, struct adc_stm32_data, ctx); + + data->repeat_buffer = data->buffer; + + adc_stm32_start_conversion(data->dev); +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, + bool repeat_sampling) +{ + struct adc_stm32_data *data = + CONTAINER_OF(ctx, struct adc_stm32_data, ctx); + + if (repeat_sampling) { + data->buffer = data->repeat_buffer; + } +} + +static void adc_stm32_isr(void *arg) +{ + struct device *dev = (struct device *)arg; + struct adc_stm32_data *data = (struct adc_stm32_data *)dev->driver_data; + struct adc_stm32_cfg *config = + (struct adc_stm32_cfg *)dev->config->config_info; + ADC_TypeDef *adc = config->base; + + *data->buffer++ = LL_ADC_REG_ReadConversionData32(adc); + + adc_context_on_sampling_done(&data->ctx, dev); + + LOG_DBG("ISR triggered."); +} + +static int adc_stm32_read(struct device *dev, + const struct adc_sequence *sequence) +{ + struct adc_stm32_data *data = dev->driver_data; + int error; + + adc_context_lock(&data->ctx, false, NULL); + error = start_read(dev, sequence); + adc_context_release(&data->ctx, error); + + return error; +} + +#ifdef CONFIG_ADC_ASYNC +static int adc_stm32_read_async(struct device *dev, + const struct adc_sequence *sequence, + struct k_poll_signal *async) +{ + struct adc_stm32_data *data = dev->driver_data; + int error; + + adc_context_lock(&data->ctx, true, async); + error = start_read(dev, sequence); + adc_context_release(&data->ctx, error); + + return error; +} +#endif + +static int adc_stm32_check_acq_time(u16_t acq_time) +{ + for (int i = 0; i < 8; i++) { + if (acq_time == ADC_ACQ_TIME(ADC_ACQ_TIME_TICKS, + acq_time_tbl[i])) { + return i; + } + } + + if (acq_time == ADC_ACQ_TIME_DEFAULT) { + return 0; + } + + LOG_ERR("Conversion time not supportted."); + return -EINVAL; +} + +static void adc_stm32_setup_speed(struct device *dev, u8_t id, + u8_t acq_time_index) +{ + struct adc_stm32_cfg *config = + (struct adc_stm32_cfg *)dev->config->config_info; + ADC_TypeDef *adc = config->base; + +#if defined(CONFIG_SOC_SERIES_STM32F0X) || defined(CONFIG_SOC_SERIES_STM32L0X) + LL_ADC_SetSamplingTimeCommonChannels(adc, + table_samp_time[acq_time_index]); +#else + LL_ADC_SetChannelSamplingTime(adc, + __LL_ADC_DECIMAL_NB_TO_CHANNEL(id), + table_samp_time[acq_time_index]); +#endif +} + +static int adc_stm32_channel_setup(struct device *dev, + const struct adc_channel_cfg *channel_cfg) +{ +#if defined(CONFIG_SOC_SERIES_STM32F0X) || defined(CONFIG_SOC_SERIES_STM32L0X) + struct adc_stm32_data *data = dev->driver_data; +#endif + int acq_time_index; + + if (channel_cfg->channel_id >= STM32_CHANNEL_COUNT) { + LOG_ERR("Channel %d is not valid", channel_cfg->channel_id); + return -EINVAL; + } + + acq_time_index = adc_stm32_check_acq_time( + channel_cfg->acquisition_time); + if (acq_time_index < 0) { + return acq_time_index; + } +#if defined(CONFIG_SOC_SERIES_STM32F0X) || defined(CONFIG_SOC_SERIES_STM32L0X) + if (data->acq_time_index == -1) { + data->acq_time_index = acq_time_index; + } else { + /* All channels of F0/L0 must have identical acquisition time.*/ + if (acq_time_index != data->acq_time_index) { + return -EINVAL; + } + } +#endif + + if (channel_cfg->differential) { + LOG_ERR("Differential channels are not supported"); + return -EINVAL; + } + + if (channel_cfg->gain != ADC_GAIN_1) { + LOG_ERR("Invalid channel gain"); + return -EINVAL; + } + + if (channel_cfg->reference != ADC_REF_INTERNAL) { + LOG_ERR("Invalid channel reference"); + return -EINVAL; + } + + adc_stm32_setup_speed(dev, channel_cfg->channel_id, + acq_time_index); + + LOG_DBG("Channel setup succeeded!"); + + return 0; +} + +#if !defined(CONFIG_SOC_SERIES_STM32F2X) && \ + !defined(CONFIG_SOC_SERIES_STM32F4X) && \ + !defined(CONFIG_SOC_SERIES_STM32F7X) && \ + !defined(CONFIG_SOC_SERIES_STM32F1X) +static void adc_stm32_calib(struct device *dev) +{ + struct adc_stm32_cfg *config = + (struct adc_stm32_cfg *)dev->config->config_info; + ADC_TypeDef *adc = config->base; + +#if defined(CONFIG_SOC_SERIES_STM32F3X) || \ + defined(CONFIG_SOC_SERIES_STM32L4X) + LL_ADC_StartCalibration(adc, LL_ADC_SINGLE_ENDED); +#elif defined(CONFIG_SOC_SERIES_STM32F0X) || \ + defined(CONFIG_SOC_SERIES_STM32L0X) + LL_ADC_StartCalibration(adc); +#endif + while (LL_ADC_IsCalibrationOnGoing(adc)) + ; +} +#endif + +static int adc_stm32_init(struct device *dev) +{ + struct adc_stm32_data *data = dev->driver_data; + const struct adc_stm32_cfg *config = dev->config->config_info; + struct device *clk = + device_get_binding(STM32_CLOCK_CONTROL_NAME); + ADC_TypeDef *adc = (ADC_TypeDef *)config->base; + + LOG_DBG("Initializing...."); + + data->dev = dev; +#if defined(CONFIG_SOC_SERIES_STM32F0X) || defined(CONFIG_SOC_SERIES_STM32L0X) + /* + * All conversion time for all channels on one ADC instance for F0 and + * L0 series chips has to be the same. This additional variable is for + * checking if the conversion time selection of all channels on one ADC + * instance is the same. + */ + data->acq_time_index = -1; +#endif + + if (clock_control_on(clk, + (clock_control_subsys_t *) &config->pclken) != 0) { + return -EIO; + } + +#if defined(CONFIG_SOC_SERIES_STM32L4X) + /* + * L4 series STM32 needs to be awaken from deep sleep mode, and restore + * its calibration parameters if there are some previously stored + * calibration parameters. + */ + LL_ADC_DisableDeepPowerDown(adc); +#endif + /* + * F3 and L4 ADC modules need some time to be stabilized before + * performing any enable or calibration actions. + */ +#if defined(CONFIG_SOC_SERIES_STM32F3X) || \ + defined(CONFIG_SOC_SERIES_STM32L4X) + LL_ADC_EnableInternalRegulator(adc); + k_busy_wait(LL_ADC_DELAY_INTERNAL_REGUL_STAB_US); +#endif + +#if defined(CONFIG_SOC_SERIES_STM32F0X) || \ + defined(CONFIG_SOC_SERIES_STM32L0X) + LL_ADC_SetClock(adc, LL_ADC_CLOCK_SYNC_PCLK_DIV4); +#elif defined(CONFIG_SOC_SERIES_STM32F3X) || \ + defined(CONFIG_SOC_SERIES_STM32L4X) + LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(), + LL_ADC_CLOCK_SYNC_PCLK_DIV4); +#endif + +#if !defined(CONFIG_SOC_SERIES_STM32F2X) && \ + !defined(CONFIG_SOC_SERIES_STM32F4X) && \ + !defined(CONFIG_SOC_SERIES_STM32F7X) && \ + !defined(CONFIG_SOC_SERIES_STM32F1X) + /* + * Calibration of F1 series has to be started after ADC Module is + * enabled. + */ + adc_stm32_calib(dev); +#endif + +#if defined(CONFIG_SOC_SERIES_STM32F0X) || \ + defined(CONFIG_SOC_SERIES_STM32L0X) + if (LL_ADC_IsActiveFlag_ADRDY(adc)) { + LL_ADC_ClearFlag_ADRDY(adc); + } + + /* + * These two series STM32 has one internal voltage reference source + * to be enabled. + */ + LL_ADC_SetCommonPathInternalCh(ADC, LL_ADC_PATH_INTERNAL_VREFINT); +#endif + +#if defined(CONFIG_SOC_SERIES_STM32F0X) || \ + defined(CONFIG_SOC_SERIES_STM32F3X) || \ + defined(CONFIG_SOC_SERIES_STM32L0X) || \ + defined(CONFIG_SOC_SERIES_STM32L4X) + /* + * ADC modules on these series have to wait for some cycles to be + * enabled. + */ + u32_t adc_rate, wait_cycles; + + if (clock_control_get_rate(clk, + (clock_control_subsys_t *) &config->pclken, &adc_rate) < 0) { + LOG_ERR("ADC clock rate get error."); + } + + wait_cycles = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / adc_rate * + LL_ADC_DELAY_CALIB_ENABLE_ADC_CYCLES; + + for (int i = wait_cycles; i >= 0; i--) + ; +#endif + + LL_ADC_Enable(adc); + +#ifdef CONFIG_SOC_SERIES_STM32L4X + /* + * Enabling ADC modules in L4 series may fail if they are still not + * stabilized, this will wait for a short time to ensure ADC modules + * are properly enabled. + */ + u32_t countTimeout = 0; + + while (LL_ADC_IsActiveFlag_ADRDY(adc) == 0) { + if (LL_ADC_IsEnabled(adc) == 0UL) { + LL_ADC_Enable(adc); + countTimeout++; + if (countTimeout == 10) { + return -ETIMEDOUT; + } + } + } +#endif + + config->irq_cfg_func(); + +#ifdef CONFIG_SOC_SERIES_STM32F1X + /* Calibration of F1 must starts after two cycles after ADON is set. */ + LL_ADC_StartCalibration(adc); + LL_ADC_REG_SetTriggerSource(adc, LL_ADC_REG_TRIG_SOFTWARE); +#endif + adc_context_unlock_unconditionally(&data->ctx); + + return 0; +} + +static const struct adc_driver_api api_stm32_driver_api = { + .channel_setup = adc_stm32_channel_setup, + .read = adc_stm32_read, +#ifdef CONFIG_ADC_ASYNC + .read_async = adc_stm32_read_async, +#endif +}; + +#define STM32_ADC_INIT(index) \ + \ +static void adc_stm32_cfg_func_##index(void); \ + \ +static const struct adc_stm32_cfg adc_stm32_cfg_##index = { \ + .base = (ADC_TypeDef *)DT_ADC_##index##_BASE_ADDRESS, \ + .irq_cfg_func = adc_stm32_cfg_func_##index, \ + .pclken = { \ + .enr = DT_ADC_##index##_CLOCK_BITS, \ + .bus = DT_ADC_##index##_CLOCK_BUS, \ + }, \ +}; \ +static struct adc_stm32_data adc_stm32_data_##index = { \ + ADC_CONTEXT_INIT_TIMER(adc_stm32_data_##index, ctx), \ + ADC_CONTEXT_INIT_LOCK(adc_stm32_data_##index, ctx), \ + ADC_CONTEXT_INIT_SYNC(adc_stm32_data_##index, ctx), \ +}; \ + \ +DEVICE_AND_API_INIT(adc_##index, DT_ADC_##index##_NAME, &adc_stm32_init,\ + &adc_stm32_data_##index, &adc_stm32_cfg_##index, \ + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + &api_stm32_driver_api); \ + \ +static void adc_stm32_cfg_func_##index(void) \ +{ \ + IRQ_CONNECT(DT_ADC_##index##_IRQ, DT_ADC_##index##_IRQ_PRI, \ + adc_stm32_isr, DEVICE_GET(adc_##index), 0); \ + irq_enable(DT_ADC_##index##_IRQ); \ +} + +#ifdef CONFIG_ADC_1 +STM32_ADC_INIT(1) +#endif /* CONFIG_ADC_1 */ diff --git a/soc/arm/st_stm32/common/Kconfig.defconfig.series b/soc/arm/st_stm32/common/Kconfig.defconfig.series index dfc364b4ef0..6349e2c16d3 100644 --- a/soc/arm/st_stm32/common/Kconfig.defconfig.series +++ b/soc/arm/st_stm32/common/Kconfig.defconfig.series @@ -95,4 +95,11 @@ config CAN_STM32 endif +if ADC + +config ADC_STM32 + default y + +endif # ADC + endif # SOC_FAMILY_STM32 diff --git a/soc/arm/st_stm32/stm32f0/soc.h b/soc/arm/st_stm32/stm32f0/soc.h index c57965f789c..9e838d1ceb4 100644 --- a/soc/arm/st_stm32/stm32f0/soc.h +++ b/soc/arm/st_stm32/stm32f0/soc.h @@ -59,6 +59,10 @@ #include #endif +#ifdef CONFIG_ADC_STM32 +#include +#endif + #endif /* !_ASMLANGUAGE */ #endif /* _STM32F0_SOC_H_ */ diff --git a/soc/arm/st_stm32/stm32f1/soc.h b/soc/arm/st_stm32/stm32f1/soc.h index b12f359b507..5a69f5f1c0e 100644 --- a/soc/arm/st_stm32/stm32f1/soc.h +++ b/soc/arm/st_stm32/stm32f1/soc.h @@ -59,6 +59,10 @@ #include #endif +#ifdef CONFIG_ADC_STM32 +#include +#endif + #endif /* !_ASMLANGUAGE */ #endif /* _STM32F1_SOC_H_ */ diff --git a/soc/arm/st_stm32/stm32f2/soc.h b/soc/arm/st_stm32/stm32f2/soc.h index 2582b565648..f2fdfa4f044 100644 --- a/soc/arm/st_stm32/stm32f2/soc.h +++ b/soc/arm/st_stm32/stm32f2/soc.h @@ -50,6 +50,10 @@ #include #endif +#ifdef CONFIG_ADC_STM32 +#include +#endif + #endif /* !_ASMLANGUAGE */ #endif /* _STM32F2_SOC_H_ */ diff --git a/soc/arm/st_stm32/stm32f3/soc.h b/soc/arm/st_stm32/stm32f3/soc.h index 47f3a938b68..eb0202cd3a6 100644 --- a/soc/arm/st_stm32/stm32f3/soc.h +++ b/soc/arm/st_stm32/stm32f3/soc.h @@ -66,6 +66,10 @@ #include #endif +#ifdef CONFIG_ADC_STM32 +#include +#endif + #endif /* !_ASMLANGUAGE */ #endif /* _STM32F3_SOC_H_ */ diff --git a/soc/arm/st_stm32/stm32f4/soc.h b/soc/arm/st_stm32/stm32f4/soc.h index d0af3973850..5f00892031d 100644 --- a/soc/arm/st_stm32/stm32f4/soc.h +++ b/soc/arm/st_stm32/stm32f4/soc.h @@ -69,6 +69,10 @@ #include #endif +#ifdef CONFIG_ADC_STM32 +#include +#endif + #endif /* !_ASMLANGUAGE */ #endif /* _STM32F4_SOC_H_ */ diff --git a/soc/arm/st_stm32/stm32f7/soc.h b/soc/arm/st_stm32/stm32f7/soc.h index 287be586bcf..2c33c4e1b07 100644 --- a/soc/arm/st_stm32/stm32f7/soc.h +++ b/soc/arm/st_stm32/stm32f7/soc.h @@ -68,6 +68,10 @@ #include #endif +#ifdef CONFIG_ADC_STM32 +#include +#endif + #endif /* !_ASMLANGUAGE */ #endif /* _STM32F7_SOC_H_ */ diff --git a/soc/arm/st_stm32/stm32l0/soc.h b/soc/arm/st_stm32/stm32l0/soc.h index 4f8d826667a..4fbbdb3cb84 100644 --- a/soc/arm/st_stm32/stm32l0/soc.h +++ b/soc/arm/st_stm32/stm32l0/soc.h @@ -60,6 +60,10 @@ #include #endif +#ifdef CONFIG_ADC_STM32 +#include +#endif + #endif /* !_ASMLANGUAGE */ #endif /* _STM32L0_SOC_H_ */ diff --git a/soc/arm/st_stm32/stm32l4/soc.h b/soc/arm/st_stm32/stm32l4/soc.h index 19321ca5620..12b10cec60e 100644 --- a/soc/arm/st_stm32/stm32l4/soc.h +++ b/soc/arm/st_stm32/stm32l4/soc.h @@ -83,6 +83,10 @@ #include #endif +#ifdef CONFIG_ADC_STM32 +#include +#endif + #endif /* !_ASMLANGUAGE */ #endif /* _STM32L4X_SOC_H_ */