You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
665 lines
17 KiB
665 lines
17 KiB
/* |
|
* Copyright (c) 2018 Kokoon Technology Limited |
|
* Copyright (c) 2019 Song Qiang <songqiang1304521@gmail.com> |
|
* Copyright (c) 2019 Endre Karlson |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#include <errno.h> |
|
|
|
#include <drivers/adc.h> |
|
#include <device.h> |
|
#include <kernel.h> |
|
#include <init.h> |
|
#include <soc.h> |
|
|
|
#define ADC_CONTEXT_USES_KERNEL_TIMER |
|
#include "adc_context.h" |
|
|
|
#define LOG_LEVEL CONFIG_ADC_LOG_LEVEL |
|
#include <logging/log.h> |
|
LOG_MODULE_REGISTER(adc_stm32); |
|
|
|
#include <clock_control/stm32_clock_control.h> |
|
|
|
#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) || \ |
|
defined(CONFIG_SOC_SERIES_STM32WBX) || \ |
|
defined(CONFIG_SOC_SERIES_STM32G4X) |
|
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) || \ |
|
defined(CONFIG_SOC_SERIES_STM32WBX) || \ |
|
defined(CONFIG_SOC_SERIES_STM32G4X) |
|
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; |
|
case 12: |
|
resolution = table_resolution[3]; |
|
break; |
|
#else |
|
case 12: |
|
resolution = table_resolution[0]; |
|
break; |
|
#endif |
|
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) || \ |
|
defined(CONFIG_SOC_SERIES_STM32WBX) || \ |
|
defined(CONFIG_SOC_SERIES_STM32G4X) |
|
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) || \ |
|
defined(CONFIG_SOC_SERIES_STM32WBX) || \ |
|
defined(CONFIG_SOC_SERIES_STM32G4X) |
|
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) || \ |
|
defined(CONFIG_SOC_SERIES_STM32WBX) || \ |
|
defined(CONFIG_SOC_SERIES_STM32G4X) |
|
/* |
|
* L4, WB and G4 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, L4, WB and G4 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) || \ |
|
defined(CONFIG_SOC_SERIES_STM32WBX) || \ |
|
defined(CONFIG_SOC_SERIES_STM32G4X) |
|
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) || \ |
|
defined(CONFIG_SOC_SERIES_STM32WBX) || \ |
|
defined(CONFIG_SOC_SERIES_STM32G4X) |
|
LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(adc), |
|
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) || \ |
|
defined(CONFIG_SOC_SERIES_STM32WBX) || \ |
|
defined(CONFIG_SOC_SERIES_STM32G4X) |
|
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(__LL_ADC_COMMON_INSTANCE(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) || \ |
|
defined(CONFIG_SOC_SERIES_STM32WBX) || \ |
|
defined(CONFIG_SOC_SERIES_STM32G4X) |
|
/* |
|
* 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 = SystemCoreClock / adc_rate * |
|
LL_ADC_DELAY_CALIB_ENABLE_ADC_CYCLES; |
|
|
|
for (int i = wait_cycles; i >= 0; i--) { |
|
} |
|
#endif |
|
|
|
LL_ADC_Enable(adc); |
|
|
|
#if defined(CONFIG_SOC_SERIES_STM32L4X) || \ |
|
defined(CONFIG_SOC_SERIES_STM32WBX) || \ |
|
defined(CONFIG_SOC_SERIES_STM32G4X) |
|
/* |
|
* Enabling ADC modules in L4, WB and G4 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 */
|
|
|