From 0c9039ebd9f7e1931f08e034457b4c03b76d017d Mon Sep 17 00:00:00 2001 From: Nathan Olff Date: Wed, 2 Oct 2024 23:26:22 +0200 Subject: [PATCH 1/4] drivers: adc: adc_emul: write function to set const raw value implement storage and retrieval of raw value in adc_emul Signed-off-by: Nathan Olff --- drivers/adc/adc_emul.c | 35 ++++++++++++++++++++++++--- include/zephyr/drivers/adc/adc_emul.h | 12 +++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/drivers/adc/adc_emul.c b/drivers/adc/adc_emul.c index 20b9764fd5fbb..b47996c0df399 100644 --- a/drivers/adc/adc_emul.c +++ b/drivers/adc/adc_emul.c @@ -31,6 +31,7 @@ typedef uint16_t adc_emul_res_t; enum adc_emul_input_source { ADC_EMUL_CONST_VALUE, ADC_EMUL_CUSTOM_FUNC, + ADC_EMUL_CONST_RAW_VALUE, }; /** @@ -43,7 +44,7 @@ struct adc_emul_chan_cfg { adc_emul_value_func func; /** Pointer to data that are passed to @a func on call */ void *func_data; - /** Constant mV input value */ + /** Constant mV input value or raw input value */ uint32_t const_value; /** Gain used on output value */ enum adc_gain gain; @@ -127,8 +128,31 @@ int adc_emul_const_value_set(const struct device *dev, unsigned int chan, return 0; } -int adc_emul_value_func_set(const struct device *dev, unsigned int chan, - adc_emul_value_func func, void *func_data) +int adc_emul_const_raw_value_set(const struct device *dev, unsigned int chan, uint32_t raw_value) +{ + const struct adc_emul_config *config = dev->config; + struct adc_emul_data *data = dev->data; + struct adc_emul_chan_cfg *chan_cfg; + + if (chan >= config->num_channels) { + LOG_ERR("unsupported channel %d", chan); + return -EINVAL; + } + + chan_cfg = &data->chan_cfg[chan]; + + k_mutex_lock(&data->cfg_mtx, K_FOREVER); + + chan_cfg->input = ADC_EMUL_CONST_RAW_VALUE; + chan_cfg->const_value = raw_value; + + k_mutex_unlock(&data->cfg_mtx); + + return 0; +} + +int adc_emul_value_func_set(const struct device *dev, unsigned int chan, adc_emul_value_func func, + void *func_data) { const struct adc_emul_config *config = dev->config; struct adc_emul_data *data = dev->data; @@ -428,6 +452,10 @@ static int adc_emul_get_chan_value(struct adc_emul_data *data, } break; + case ADC_EMUL_CONST_RAW_VALUE: + temp = chan_cfg->const_value; + goto check_bound_and_out; + default: LOG_ERR("unknown input source %d", chan_cfg->input); err = -EINVAL; @@ -446,6 +474,7 @@ static int adc_emul_get_chan_value(struct adc_emul_data *data, /* Calculate output value */ temp = (uint64_t)input_mV * data->res_mask / ref_v; +check_bound_and_out: /* If output value is greater than resolution, it has to be trimmed */ if (temp > data->res_mask) { temp = data->res_mask; diff --git a/include/zephyr/drivers/adc/adc_emul.h b/include/zephyr/drivers/adc/adc_emul.h index 03c2fbbb3fd0d..82da4fd0c0ced 100644 --- a/include/zephyr/drivers/adc/adc_emul.h +++ b/include/zephyr/drivers/adc/adc_emul.h @@ -72,6 +72,18 @@ typedef int (*adc_emul_value_func)(const struct device *dev, unsigned int chan, int adc_emul_const_value_set(const struct device *dev, unsigned int chan, uint32_t value); +/** + * @brief Set constant raw value input for emulated ADC @p chan + * + * @param dev The emulated ADC device + * @param chan The channel of ADC which input is assigned + * @param raw_value New raw value to assign to @p chan input + * + * @return 0 on success + * @return -EINVAL if an invalid argument is provided + */ +int adc_emul_const_raw_value_set(const struct device *dev, unsigned int chan, uint32_t raw_value); + /** * @brief Set function used to obtain voltage for input of emulated * ADC @p chan From f7febfbc2bd2e600dfbecc1c70a381f81fe202da Mon Sep 17 00:00:00 2001 From: Nathan Olff Date: Thu, 3 Oct 2024 22:56:28 +0200 Subject: [PATCH 2/4] tests: drivers: adc: adc_emul: add test for const raw value function write test for raw const adc emul function Signed-off-by: Nathan Olff --- tests/drivers/adc/adc_emul/src/main.c | 62 +++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/drivers/adc/adc_emul/src/main.c b/tests/drivers/adc/adc_emul/src/main.c index 1cd6d746bcd57..5afcdafea4eab 100644 --- a/tests/drivers/adc/adc_emul/src/main.c +++ b/tests/drivers/adc/adc_emul/src/main.c @@ -216,6 +216,68 @@ ZTEST_USER(adc_emul, test_adc_emul_single_value) /* Test sampling */ start_adc_read(adc_dev, BIT(ADC_1ST_CHANNEL_ID), samples); + /* Check samples */ + check_samples(samples, input_mv, 0 /* step */, 1 /* channels */, 0 /* first channel data */, + ADC_REF_INTERNAL_MV, ADC_GAIN_1); + + check_empty_samples(samples); +} + +/** @brief Test setting one channel with constant raw output. */ +ZTEST_USER(adc_emul, test_adc_emul_single_raw_value_half_reference) +{ + const uint16_t input_raw_value = (1 << ADC_RESOLUTION) / 2; + const uint16_t input_mv = ADC_REF_INTERNAL_MV / 2; + const int samples = 4; + int ret, i; + + for (i = 0; i < BUFFER_SIZE; ++i) { + m_sample_buffer[i] = INVALID_ADC_VALUE; + } + + /* Generic ADC setup */ + const struct device *adc_dev = get_adc_device(); + + channel_setup(adc_dev, ADC_REF_INTERNAL, ADC_GAIN_1, ADC_1ST_CHANNEL_ID); + + /* ADC emulator-specific setup */ + ret = adc_emul_const_raw_value_set(adc_dev, ADC_1ST_CHANNEL_ID, input_raw_value); + zassert_ok(ret, "adc_emul_const_value_set() failed with code %d", ret); + + /* Test sampling */ + start_adc_read(adc_dev, BIT(ADC_1ST_CHANNEL_ID), samples); + + /* Check samples */ + check_samples(samples, input_mv, 0 /* step */, 1 /* channels */, 0 /* first channel data */, + ADC_REF_INTERNAL_MV, ADC_GAIN_1); + + check_empty_samples(samples); +} + +/** @brief Test setting one channel with constant raw output. */ +ZTEST_USER(adc_emul, test_adc_emul_single_raw_value_quarter_reference) +{ + const uint16_t input_raw_value = (1 << ADC_RESOLUTION) / 4; + const uint16_t input_mv = ADC_REF_INTERNAL_MV / 4; + const int samples = 4; + int ret, i; + + for (i = 0; i < BUFFER_SIZE; ++i) { + m_sample_buffer[i] = INVALID_ADC_VALUE; + } + + /* Generic ADC setup */ + const struct device *adc_dev = get_adc_device(); + + channel_setup(adc_dev, ADC_REF_INTERNAL, ADC_GAIN_1, ADC_1ST_CHANNEL_ID); + + /* ADC emulator-specific setup */ + ret = adc_emul_const_raw_value_set(adc_dev, ADC_1ST_CHANNEL_ID, input_raw_value); + zassert_ok(ret, "adc_emul_const_value_set() failed with code %d", ret); + + /* Test sampling */ + start_adc_read(adc_dev, BIT(ADC_1ST_CHANNEL_ID), samples); + /* Check samples */ check_samples(samples, input_mv, 0 /* step */, 1 /* channels */, 0 /* first channel data */, ADC_REF_INTERNAL_MV, From 374662a583b558e6a6bf47743ff1caf15d7d3f3c Mon Sep 17 00:00:00 2001 From: Nathan Olff Date: Thu, 3 Oct 2024 23:20:19 +0200 Subject: [PATCH 3/4] drivers: adc: adc_emul: implement raw func set function in adc_emul allow setting a function as generator of raw adc values in adc_emul Signed-off-by: Nathan Olff --- drivers/adc/adc_emul.c | 37 ++++++++++++++++++++++++++- include/zephyr/drivers/adc/adc_emul.h | 15 +++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/drivers/adc/adc_emul.c b/drivers/adc/adc_emul.c index b47996c0df399..88dcccbdfeb91 100644 --- a/drivers/adc/adc_emul.c +++ b/drivers/adc/adc_emul.c @@ -32,6 +32,7 @@ enum adc_emul_input_source { ADC_EMUL_CONST_VALUE, ADC_EMUL_CUSTOM_FUNC, ADC_EMUL_CONST_RAW_VALUE, + ADC_EMUL_CUSTOM_FUNC_RAW_VALUE, }; /** @@ -40,7 +41,7 @@ enum adc_emul_input_source { * This structure contains configuration of one channel of emulated ADC. */ struct adc_emul_chan_cfg { - /** Pointer to function used to obtain input mV */ + /** Pointer to function used to obtain input mV or raw input value */ adc_emul_value_func func; /** Pointer to data that are passed to @a func on call */ void *func_data; @@ -176,6 +177,31 @@ int adc_emul_value_func_set(const struct device *dev, unsigned int chan, adc_emu return 0; } +int adc_emul_raw_value_func_set(const struct device *dev, unsigned int chan, + adc_emul_value_func func, void *func_data) +{ + const struct adc_emul_config *config = dev->config; + struct adc_emul_data *data = dev->data; + struct adc_emul_chan_cfg *chan_cfg; + + if (chan >= config->num_channels) { + LOG_ERR("unsupported channel %d", chan); + return -EINVAL; + } + + chan_cfg = &data->chan_cfg[chan]; + + k_mutex_lock(&data->cfg_mtx, K_FOREVER); + + chan_cfg->func = func; + chan_cfg->func_data = func_data; + chan_cfg->input = ADC_EMUL_CUSTOM_FUNC_RAW_VALUE; + + k_mutex_unlock(&data->cfg_mtx); + + return 0; +} + int adc_emul_ref_voltage_set(const struct device *dev, enum adc_reference ref, uint16_t value) { @@ -456,6 +482,15 @@ static int adc_emul_get_chan_value(struct adc_emul_data *data, temp = chan_cfg->const_value; goto check_bound_and_out; + case ADC_EMUL_CUSTOM_FUNC_RAW_VALUE: + err = chan_cfg->func(data->dev, chan, chan_cfg->func_data, &input_mV); + if (err) { + LOG_ERR("failed to read channel %d (err %d)", chan, err); + goto out; + } + temp = input_mV; + goto check_bound_and_out; + default: LOG_ERR("unknown input source %d", chan_cfg->input); err = -EINVAL; diff --git a/include/zephyr/drivers/adc/adc_emul.h b/include/zephyr/drivers/adc/adc_emul.h index 82da4fd0c0ced..9c95dd8ab4dd9 100644 --- a/include/zephyr/drivers/adc/adc_emul.h +++ b/include/zephyr/drivers/adc/adc_emul.h @@ -99,6 +99,21 @@ int adc_emul_const_raw_value_set(const struct device *dev, unsigned int chan, ui int adc_emul_value_func_set(const struct device *dev, unsigned int chan, adc_emul_value_func func, void *data); +/** + * @brief Set function used to obtain voltage for raw input value of emulated + * ADC @p chan + * + * @param dev The emulated ADC device + * @param chan The channel of ADC to which @p func is assigned + * @param func New function to assign to @p chan + * @param data Pointer to data passed to @p func on call + * + * @return 0 on success + * @return -EINVAL if an invalid argument is provided + */ +int adc_emul_raw_value_func_set(const struct device *dev, unsigned int chan, + adc_emul_value_func func, void *data); + /** * @brief Set reference voltage * From c5cb4ca1282636250b279296350f3c215a01cb73 Mon Sep 17 00:00:00 2001 From: Nathan Olff Date: Thu, 3 Oct 2024 23:21:30 +0200 Subject: [PATCH 4/4] tests: drivers: adc: adc_emul: write test for raw func set write test for raw value func set function Signed-off-by: Nathan Olff --- tests/drivers/adc/adc_emul/src/main.c | 35 +++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/drivers/adc/adc_emul/src/main.c b/tests/drivers/adc/adc_emul/src/main.c index 5afcdafea4eab..7052f60c34b58 100644 --- a/tests/drivers/adc/adc_emul/src/main.c +++ b/tests/drivers/adc/adc_emul/src/main.c @@ -364,6 +364,41 @@ ZTEST_USER(adc_emul, test_adc_emul_custom_function) check_empty_samples(samples); } +/** @brief Test setting one channel with custom function raw value. */ +ZTEST_USER(adc_emul, test_adc_emul_custom_function_raw_value) +{ + struct handle_seq_params channel1_param; + const uint16_t raw_value = 1000; + const uint16_t input_mV = (raw_value * ADC_REF_INTERNAL_MV / BIT(ADC_RESOLUTION)); + const int samples = 4; + int ret, i; + + for (i = 0; i < BUFFER_SIZE; ++i) { + m_sample_buffer[i] = INVALID_ADC_VALUE; + } + + /* Generic ADC setup */ + const struct device *adc_dev = get_adc_device(); + + channel_setup(adc_dev, ADC_REF_INTERNAL, ADC_GAIN_1, ADC_1ST_CHANNEL_ID); + + /* ADC emulator-specific setup */ + channel1_param.value = raw_value; + + ret = adc_emul_raw_value_func_set(adc_dev, ADC_1ST_CHANNEL_ID, handle_seq, &channel1_param); + zassert_ok(ret, "adc_emul_value_func_set() failed with code %d", ret); + + /* Test sampling */ + start_adc_read(adc_dev, BIT(ADC_1ST_CHANNEL_ID), samples); + + /* Check samples */ + check_samples(samples, input_mV, + (SEQUENCE_STEP * ADC_REF_INTERNAL_MV / BIT(ADC_RESOLUTION)), 1 /* channels */, + 0 /* first channel data */, ADC_REF_INTERNAL_MV, ADC_GAIN_1); + + check_empty_samples(samples); +} + /** * @brief Test setting two channels with custom function and different * params.