From 18c15549e747e39b68cc178deb743d72c9775fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Thu, 28 Jun 2018 14:47:45 +0200 Subject: [PATCH 01/21] dts: nrf: Add ADC nodes and bindings for nRF SoCs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds ADC nodes to DTS files for nRF SoCs and introduces corresponding bindings for these nodes. Signed-off-by: Andrzej Głąbek --- arch/arm/soc/nordic_nrf/nrf51/dts.fixup | 5 ++++ arch/arm/soc/nordic_nrf/nrf52/dts.fixup | 5 ++++ dts/arm/nordic/nrf51822.dtsi | 8 +++++ dts/arm/nordic/nrf52810.dtsi | 8 +++++ dts/arm/nordic/nrf52832.dtsi | 8 +++++ dts/arm/nordic/nrf52840.dtsi | 8 +++++ dts/bindings/iio/adc/nordic,nrf-adc.yaml | 35 ++++++++++++++++++++++ dts/bindings/iio/adc/nordic,nrf-saadc.yaml | 35 ++++++++++++++++++++++ 8 files changed, 112 insertions(+) create mode 100644 dts/bindings/iio/adc/nordic,nrf-adc.yaml create mode 100644 dts/bindings/iio/adc/nordic,nrf-saadc.yaml diff --git a/arch/arm/soc/nordic_nrf/nrf51/dts.fixup b/arch/arm/soc/nordic_nrf/nrf51/dts.fixup index f3c170d2a0da7..19a4a0352d61d 100644 --- a/arch/arm/soc/nordic_nrf/nrf51/dts.fixup +++ b/arch/arm/soc/nordic_nrf/nrf51/dts.fixup @@ -1,6 +1,11 @@ /* SoC level DTS fixup file */ #define CONFIG_NUM_IRQ_PRIO_BITS ARM_V6M_NVIC_E000E100_ARM_NUM_IRQ_PRIORITY_BITS + +#define CONFIG_ADC_0_IRQ NORDIC_NRF_ADC_40007000_IRQ_0 +#define CONFIG_ADC_0_IRQ_PRI NORDIC_NRF_ADC_40007000_IRQ_0_PRIORITY +#define CONFIG_ADC_0_NAME NORDIC_NRF_ADC_40007000_LABEL + #define CONFIG_UART_0_BASE NORDIC_NRF_UART_40002000_BASE_ADDRESS #define CONFIG_UART_0_IRQ_PRI NORDIC_NRF_UART_40002000_IRQ_0_PRIORITY #define CONFIG_UART_0_IRQ_NUM NORDIC_NRF_UART_40002000_IRQ_0 diff --git a/arch/arm/soc/nordic_nrf/nrf52/dts.fixup b/arch/arm/soc/nordic_nrf/nrf52/dts.fixup index 4016dec047e74..c921a68117728 100644 --- a/arch/arm/soc/nordic_nrf/nrf52/dts.fixup +++ b/arch/arm/soc/nordic_nrf/nrf52/dts.fixup @@ -1,6 +1,11 @@ /* SoC level DTS fixup file */ #define CONFIG_NUM_IRQ_PRIO_BITS ARM_V7M_NVIC_E000E100_ARM_NUM_IRQ_PRIORITY_BITS + +#define CONFIG_ADC_0_IRQ NORDIC_NRF_SAADC_40007000_IRQ_0 +#define CONFIG_ADC_0_IRQ_PRI NORDIC_NRF_SAADC_40007000_IRQ_0_PRIORITY +#define CONFIG_ADC_0_NAME NORDIC_NRF_SAADC_40007000_LABEL + #if defined(NORDIC_NRF_UARTE_40002000_BASE_ADDRESS) #define CONFIG_UART_0_BASE NORDIC_NRF_UARTE_40002000_BASE_ADDRESS #define CONFIG_UART_0_IRQ_PRI NORDIC_NRF_UARTE_40002000_IRQ_0_PRIORITY diff --git a/dts/arm/nordic/nrf51822.dtsi b/dts/arm/nordic/nrf51822.dtsi index d662f821a3213..db98c40eafbbf 100644 --- a/dts/arm/nordic/nrf51822.dtsi +++ b/dts/arm/nordic/nrf51822.dtsi @@ -39,6 +39,14 @@ }; soc { + adc: adc@40007000 { + compatible = "nordic,nrf-adc"; + reg = <0x40007000 0x1000>; + interrupts = <7 1>; + status = "disabled"; + label = "ADC_0"; + }; + uart0: uart@40002000 { compatible = "nordic,nrf-uart"; reg = <0x40002000 0x1000>; diff --git a/dts/arm/nordic/nrf52810.dtsi b/dts/arm/nordic/nrf52810.dtsi index 708f64859e121..d358f587257b8 100644 --- a/dts/arm/nordic/nrf52810.dtsi +++ b/dts/arm/nordic/nrf52810.dtsi @@ -39,6 +39,14 @@ }; soc { + adc: adc@40007000 { + compatible = "nordic,nrf-saadc"; + reg = <0x40007000 0x1000>; + interrupts = <7 1>; + status = "disabled"; + label = "ADC_0"; + }; + uart0: uart@40002000 { compatible = "nordic,nrf-uarte"; reg = <0x40002000 0x1000>; diff --git a/dts/arm/nordic/nrf52832.dtsi b/dts/arm/nordic/nrf52832.dtsi index bd92c8f266243..a88896369a307 100644 --- a/dts/arm/nordic/nrf52832.dtsi +++ b/dts/arm/nordic/nrf52832.dtsi @@ -39,6 +39,14 @@ }; soc { + adc: adc@40007000 { + compatible = "nordic,nrf-saadc"; + reg = <0x40007000 0x1000>; + interrupts = <7 1>; + status = "disabled"; + label = "ADC_0"; + }; + uart0: uart@40002000 { /* uart can be either UART or UARTE, for the user to pick */ /* compatible = "nordic,nrf-uarte" or "nordic,nrf-uart"; */ diff --git a/dts/arm/nordic/nrf52840.dtsi b/dts/arm/nordic/nrf52840.dtsi index dd5d478abed16..de914dc297802 100644 --- a/dts/arm/nordic/nrf52840.dtsi +++ b/dts/arm/nordic/nrf52840.dtsi @@ -40,6 +40,14 @@ }; soc { + adc: adc@40007000 { + compatible = "nordic,nrf-saadc"; + reg = <0x40007000 0x1000>; + interrupts = <7 1>; + status = "disabled"; + label = "ADC_0"; + }; + uart0: uart@40002000 { /* uart can be either UART or UARTE, for the user to pick */ /* compatible = "nordic,nrf-uarte" or "nordic,nrf-uart"; */ diff --git a/dts/bindings/iio/adc/nordic,nrf-adc.yaml b/dts/bindings/iio/adc/nordic,nrf-adc.yaml new file mode 100644 index 0000000000000..2617c22a1a979 --- /dev/null +++ b/dts/bindings/iio/adc/nordic,nrf-adc.yaml @@ -0,0 +1,35 @@ +# +# Copyright (c) 2018, Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +title: Nordic Semiconductor nRF Family ADC +id: nordic,nrf-adc +version: 0.1 + +description: > + This is a representation of the nRF ADC node + +inherits: + !include adc.yaml + +properties: + compatible: + type: string + category: required + description: compatible strings + constraint: "nordic,nrf-adc" + + reg: + type: array + description: mmio register space + generation: define + category: required + + interrupts: + type: array + category: required + description: required interrupts + generation: define +... diff --git a/dts/bindings/iio/adc/nordic,nrf-saadc.yaml b/dts/bindings/iio/adc/nordic,nrf-saadc.yaml new file mode 100644 index 0000000000000..0c988d3717c66 --- /dev/null +++ b/dts/bindings/iio/adc/nordic,nrf-saadc.yaml @@ -0,0 +1,35 @@ +# +# Copyright (c) 2018, Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +title: Nordic Semiconductor nRF Family SAADC +id: nordic,nrf-saadc +version: 0.1 + +description: > + This is a representation of the nRF SAADC node + +inherits: + !include adc.yaml + +properties: + compatible: + type: string + category: required + description: compatible strings + constraint: "nordic,nrf-saadc" + + reg: + type: array + description: mmio register space + generation: define + category: required + + interrupts: + type: array + category: required + description: required interrupts + generation: define +... From 54a10cf9f70196a52627ae9c1cd4065a1765a60c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Thu, 28 Jun 2018 14:56:19 +0200 Subject: [PATCH 02/21] boards: nrf: Enable ADC nodes in DTS for nRF boards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ADC nodes are enabled in DTS for the following nRF development kits: - nrf51_pca10028 - nrf52_pca10040 - nrf52_pca20020 - nrf52810_pca10040 - nrf52840_pca10056 Signed-off-by: Andrzej Głąbek --- boards/arm/nrf51_pca10028/nrf51_pca10028.dts | 4 ++++ boards/arm/nrf52810_pca10040/nrf52810_pca10040.dts | 4 ++++ boards/arm/nrf52840_pca10056/nrf52840_pca10056.dts | 4 ++++ boards/arm/nrf52_pca10040/nrf52_pca10040.dts | 4 ++++ boards/arm/nrf52_pca20020/nrf52_pca20020.dts | 4 ++++ 5 files changed, 20 insertions(+) diff --git a/boards/arm/nrf51_pca10028/nrf51_pca10028.dts b/boards/arm/nrf51_pca10028/nrf51_pca10028.dts index f0a77d03441f8..13f1903228f74 100644 --- a/boards/arm/nrf51_pca10028/nrf51_pca10028.dts +++ b/boards/arm/nrf51_pca10028/nrf51_pca10028.dts @@ -30,6 +30,10 @@ status ="ok"; }; +&adc { + status ="ok"; +}; + &uart0 { current-speed = <115200>; status = "ok"; diff --git a/boards/arm/nrf52810_pca10040/nrf52810_pca10040.dts b/boards/arm/nrf52810_pca10040/nrf52810_pca10040.dts index 15cd471b2fed8..2374d641417b5 100644 --- a/boards/arm/nrf52810_pca10040/nrf52810_pca10040.dts +++ b/boards/arm/nrf52810_pca10040/nrf52810_pca10040.dts @@ -66,6 +66,10 @@ }; }; +&adc { + status = "ok"; +}; + &gpiote { status ="ok"; }; diff --git a/boards/arm/nrf52840_pca10056/nrf52840_pca10056.dts b/boards/arm/nrf52840_pca10056/nrf52840_pca10056.dts index cf76b7aedaf73..1ef89fef8ff4e 100644 --- a/boards/arm/nrf52840_pca10056/nrf52840_pca10056.dts +++ b/boards/arm/nrf52840_pca10056/nrf52840_pca10056.dts @@ -22,6 +22,10 @@ }; }; +&adc { + status ="ok"; +}; + &gpiote { status ="ok"; }; diff --git a/boards/arm/nrf52_pca10040/nrf52_pca10040.dts b/boards/arm/nrf52_pca10040/nrf52_pca10040.dts index 4c98a86836355..984f75d5e04aa 100644 --- a/boards/arm/nrf52_pca10040/nrf52_pca10040.dts +++ b/boards/arm/nrf52_pca10040/nrf52_pca10040.dts @@ -23,6 +23,10 @@ }; }; +&adc { + status ="ok"; +}; + &gpiote { status ="ok"; }; diff --git a/boards/arm/nrf52_pca20020/nrf52_pca20020.dts b/boards/arm/nrf52_pca20020/nrf52_pca20020.dts index 41143a85c858e..d8197b27ef7d0 100644 --- a/boards/arm/nrf52_pca20020/nrf52_pca20020.dts +++ b/boards/arm/nrf52_pca20020/nrf52_pca20020.dts @@ -21,6 +21,10 @@ }; }; +&adc { + status = "ok"; +}; + &gpiote { status = "ok"; }; From 5f23ec2f33f04710b29090b2dd2d3e30d2629e55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Mon, 21 May 2018 15:00:28 +0200 Subject: [PATCH 03/21] drivers: adc: Introduce reworked API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit replaces the API for ADC drivers with a reworked one. As requested in the issue #3980, the adc_enable/adc_disable functions are removed. Additionaly, some new features are introduced, like: - asynchronous calls - configuration of channels - multi-channel sampling Common parts of code that are supposed to appear in each implementation of the driver (like locking, synchronization, triggering of consecutive samplings) are provided in the "adc_context.h" file to keep consistency with the SPI driver. Syscalls are no longer present in the API because the functions starting read requests cannot use them, since they can be provided with a callback that is executed in the ISR context, and there is no point in supporting syscalls only for the channels configuration. "adc_api" test is updated and extended with additional test cases, with intention to show how the API is supposed to be used. "adc_simple" test is removed as it does not seem to add much value. Signed-off-by: Andrzej Głąbek --- drivers/adc/CMakeLists.txt | 14 +- drivers/adc/Kconfig | 14 +- drivers/adc/adc_context.h | 268 +++++++++++++++ drivers/adc/adc_handlers.c | 69 ---- include/adc.h | 360 ++++++++++++++++---- tests/drivers/adc/adc_api/CMakeLists.txt | 8 + tests/drivers/adc/adc_api/README | 15 - tests/drivers/adc/adc_api/prj.conf | 2 - tests/drivers/adc/adc_api/prj_base.conf | 8 + tests/drivers/adc/adc_api/src/main.c | 13 +- tests/drivers/adc/adc_api/src/test_adc.c | 360 ++++++++++++++++---- tests/drivers/adc/adc_simple/CMakeLists.txt | 6 - tests/drivers/adc/adc_simple/prj.conf | 3 - tests/drivers/adc/adc_simple/src/main.c | 127 ------- tests/drivers/adc/adc_simple/testcase.yaml | 4 - 15 files changed, 903 insertions(+), 368 deletions(-) create mode 100644 drivers/adc/adc_context.h delete mode 100644 drivers/adc/adc_handlers.c delete mode 100644 tests/drivers/adc/adc_api/README delete mode 100644 tests/drivers/adc/adc_api/prj.conf create mode 100644 tests/drivers/adc/adc_api/prj_base.conf delete mode 100644 tests/drivers/adc/adc_simple/CMakeLists.txt delete mode 100644 tests/drivers/adc/adc_simple/prj.conf delete mode 100644 tests/drivers/adc/adc_simple/src/main.c delete mode 100644 tests/drivers/adc/adc_simple/testcase.yaml diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index 787145630d39f..bcc3fa35bc215 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -1,10 +1,8 @@ zephyr_library() -zephyr_library_sources_ifdef(CONFIG_ADC_DW adc_dw.c) -zephyr_library_sources_ifdef(CONFIG_ADC_MCUX_ADC16 adc_mcux_adc16.c) -zephyr_library_sources_ifdef(CONFIG_ADC_QMSI adc_qmsi.c) -zephyr_library_sources_ifdef(CONFIG_ADC_QMSI_SS adc_qmsi_ss.c) -zephyr_library_sources_ifdef(CONFIG_ADC_SAM_AFEC adc_sam_afec.c) -zephyr_library_sources_ifdef(CONFIG_ADC_TI_ADC108S102 adc_ti_adc108s102.c) - -zephyr_library_sources_ifdef(CONFIG_USERSPACE adc_handlers.c) +zephyr_library_sources_ifdef(CONFIG_ADC_DW adc_dw.c) +zephyr_library_sources_ifdef(CONFIG_ADC_MCUX_ADC16 adc_mcux_adc16.c) +zephyr_library_sources_ifdef(CONFIG_ADC_QMSI adc_qmsi.c) +zephyr_library_sources_ifdef(CONFIG_ADC_QMSI_SS adc_qmsi_ss.c) +zephyr_library_sources_ifdef(CONFIG_ADC_SAM_AFEC adc_sam_afec.c) +zephyr_library_sources_ifdef(CONFIG_ADC_TI_ADC108S102 adc_ti_adc108s102.c) diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index 5a72c1dbeb2b2..37c4eddb58cb9 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -12,10 +12,22 @@ menuconfig ADC bool "ADC drivers" help - Enable ADC (Analog to Digital Converter) driver configuration + Enable ADC (Analog to Digital Converter) driver configuration. if ADC +# By selecting or not this option particular ADC drivers indicate if it is +# required to explicitly specify analog inputs when configuring channels or +# just the channel identifier is sufficient. +config ADC_CONFIGURABLE_INPUTS + bool + +config ADC_ASYNC + bool "Enable asynchronous call support" + select POLL + help + This option enables the asynchronous API calls. + config SYS_LOG_ADC_LEVEL int "ADC drivers log level" depends on SYS_LOG diff --git a/drivers/adc/adc_context.h b/drivers/adc/adc_context.h new file mode 100644 index 0000000000000..bb7751759255a --- /dev/null +++ b/drivers/adc/adc_context.h @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __ADC_CONTEXT_H__ +#define __ADC_CONTEXT_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct adc_context; + +/* + * Each driver should provide implementations of the following two functions: + * - adc_context_start_sampling() that will be called when a sampling (of one + * or more channels, depending on the realized sequence) is to be started + * - adc_context_update_buffer_pointer() that will be called when the sample + * buffer pointer should be prepared for writing of next sampling results, + * the "repeat_sampling" parameter indicates if the results should be written + * in the same place as before (when true) or as consecutive ones (otherwise). + */ +static void adc_context_start_sampling(struct adc_context *ctx); +static void adc_context_update_buffer_pointer(struct adc_context *ctx, + bool repeat_sampling); +/* + * If a given driver uses some dedicated hardware timer to trigger consecutive + * samplings, it should implement also the following two functions. Otherwise, + * it should define the ADC_CONTEXT_USES_KERNEL_TIMER macro to enable parts of + * this module that utilize a standard kernel timer. + */ +static void adc_context_enable_timer(struct adc_context *ctx); +static void adc_context_disable_timer(struct adc_context *ctx); + + +struct adc_context { + atomic_t sampling_requested; +#ifdef ADC_CONTEXT_USES_KERNEL_TIMER + struct k_timer timer; +#endif /* ADC_CONTEXT_USES_KERNEL_TIMER */ + + struct k_sem lock; + struct k_sem sync; + int status; + +#ifdef CONFIG_ADC_ASYNC + struct k_poll_signal *signal; + bool asynchronous; +#endif /* CONFIG_ADC_ASYNC */ + + const struct adc_sequence *sequence; + u16_t sampling_index; +}; + +#ifdef ADC_CONTEXT_USES_KERNEL_TIMER +#define ADC_CONTEXT_INIT_TIMER(_data, _ctx_name) \ + ._ctx_name.timer = _K_TIMER_INITIALIZER(_data._ctx_name.timer, \ + adc_context_on_timer_expired, \ + NULL) +#endif /* ADC_CONTEXT_USES_KERNEL_TIMER */ + +#define ADC_CONTEXT_INIT_LOCK(_data, _ctx_name) \ + ._ctx_name.lock = _K_SEM_INITIALIZER(_data._ctx_name.lock, 0, 1) + +#define ADC_CONTEXT_INIT_SYNC(_data, _ctx_name) \ + ._ctx_name.sync = _K_SEM_INITIALIZER(_data._ctx_name.sync, 0, 1) + + +static inline void adc_context_request_next_sampling(struct adc_context *ctx) +{ + if (atomic_inc(&ctx->sampling_requested) == 0) { + adc_context_start_sampling(ctx); + } else { + /* + * If a sampling was already requested and was not finished yet, + * do not start another one from here, this will be done from + * adc_context_on_sampling_done() after the current sampling is + * complete. Instead, note this fact, and inform the user about + * it after the sequence is done. + */ + ctx->status = -EIO; + } +} + +#ifdef ADC_CONTEXT_USES_KERNEL_TIMER +static inline void adc_context_enable_timer(struct adc_context *ctx) +{ + u32_t interval_us = ctx->sequence->options->interval_us; + u32_t interval_ms = ceiling_fraction(interval_us, 1000UL); + + k_timer_start(&ctx->timer, 0, interval_ms); +} + +static inline void adc_context_disable_timer(struct adc_context *ctx) +{ + k_timer_stop(&ctx->timer); +} + +static void adc_context_on_timer_expired(struct k_timer *timer_id) +{ + struct adc_context *ctx = + CONTAINER_OF(timer_id, struct adc_context, timer); + + adc_context_request_next_sampling(ctx); +} +#endif /* ADC_CONTEXT_USES_KERNEL_TIMER */ + + +static inline void adc_context_lock(struct adc_context *ctx, + bool asynchronous, + struct k_poll_signal *signal) +{ + k_sem_take(&ctx->lock, K_FOREVER); + +#ifdef CONFIG_ADC_ASYNC + ctx->asynchronous = asynchronous; + ctx->signal = signal; +#endif /* CONFIG_ADC_ASYNC */ +} + +static inline void adc_context_release(struct adc_context *ctx, int status) +{ +#ifdef CONFIG_ADC_ASYNC + if (ctx->asynchronous && (status == 0)) { + return; + } +#endif /* CONFIG_ADC_ASYNC */ + + k_sem_give(&ctx->lock); +} + +static inline void adc_context_unlock_unconditionally(struct adc_context *ctx) +{ + if (!k_sem_count_get(&ctx->lock)) { + k_sem_give(&ctx->lock); + } +} + +static inline int adc_context_wait_for_completion(struct adc_context *ctx) +{ +#ifdef CONFIG_ADC_ASYNC + if (ctx->asynchronous) { + return 0; + } +#endif /* CONFIG_ADC_ASYNC */ + + k_sem_take(&ctx->sync, K_FOREVER); + return ctx->status; +} + +static inline void adc_context_complete(struct adc_context *ctx, int status) +{ +#ifdef CONFIG_ADC_ASYNC + if (ctx->asynchronous) { + if (ctx->signal) { + k_poll_signal(ctx->signal, status); + } + + k_sem_give(&ctx->lock); + return; + } +#endif /* CONFIG_ADC_ASYNC */ + + /* + * Override the status only when an error is signaled to this function. + * Please note that adc_context_request_next_sampling() might have set + * this field. + */ + if (status != 0) { + ctx->status = status; + } + k_sem_give(&ctx->sync); +} + +static inline void adc_context_start_read(struct adc_context *ctx, + const struct adc_sequence *sequence) +{ + ctx->sequence = sequence; + ctx->status = 0; + + if (ctx->sequence->options) { + ctx->sampling_index = 0; + + if (ctx->sequence->options->interval_us != 0) { + atomic_set(&ctx->sampling_requested, 0); + adc_context_enable_timer(ctx); + return; + } + } + + adc_context_start_sampling(ctx); +} + +/* + * This function should be called after a sampling (of one or more channels, + * depending on the realized sequence) is done. It calls the defined callback + * function if required and takes further actions accordingly. + */ +static inline void adc_context_on_sampling_done(struct adc_context *ctx, + struct device *dev) +{ + if (ctx->sequence->options) { + adc_sequence_callback callback = + ctx->sequence->options->callback; + enum adc_action action; + bool finish = false; + bool repeat = false; + + if (callback) { + action = callback(dev, + ctx->sequence, + ctx->sampling_index); + } else { + action = ADC_ACTION_CONTINUE; + } + + switch (action) { + case ADC_ACTION_REPEAT: + repeat = true; + break; + case ADC_ACTION_FINISH: + finish = true; + break; + default: /* ADC_ACTION_CONTINUE */ + if (ctx->sampling_index < + ctx->sequence->options->extra_samplings) { + ++ctx->sampling_index; + } else { + finish = true; + } + } + + if (!finish) { + adc_context_update_buffer_pointer(ctx, repeat); + + /* + * Immediately start the next sampling if working with + * a zero interval or if the timer expired again while + * the current sampling was in progress. + */ + if (ctx->sequence->options->interval_us == 0) { + adc_context_start_sampling(ctx); + } else if (atomic_dec(&ctx->sampling_requested) > 1) { + adc_context_start_sampling(ctx); + } + + return; + } + + if (ctx->sequence->options->interval_us != 0) { + adc_context_disable_timer(ctx); + } + } + + adc_context_complete(ctx, 0); +} + +#ifdef __cplusplus +} +#endif + +#endif /* __ADC_CONTEXT_H__ */ diff --git a/drivers/adc/adc_handlers.c b/drivers/adc/adc_handlers.c deleted file mode 100644 index d88d955db8b96..0000000000000 --- a/drivers/adc/adc_handlers.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -Z_SYSCALL_HANDLER(adc_enable, dev) -{ - Z_OOPS(Z_SYSCALL_DRIVER_ADC(dev, enable)); - _impl_adc_enable((struct device *)dev); - return 0; -} - -Z_SYSCALL_HANDLER(adc_disable, dev) -{ - Z_OOPS(Z_SYSCALL_DRIVER_ADC(dev, disable)); - _impl_adc_disable((struct device *)dev); - return 0; -} - -Z_SYSCALL_HANDLER(adc_read, dev, seq_table_p) -{ - struct adc_seq_entry *entry, *entries_copy; - struct adc_seq_table *seq_table = (struct adc_seq_table *)seq_table_p; - struct adc_seq_table seq_table_copy; - unsigned int entries_bounds; - int i = 0, ret; - - Z_OOPS(Z_SYSCALL_DRIVER_ADC(dev, read)); - Z_OOPS(Z_SYSCALL_MEMORY_READ(seq_table, sizeof(struct adc_seq_table))); - - seq_table_copy = *seq_table; - if (Z_SYSCALL_VERIFY_MSG( - !__builtin_umul_overflow(seq_table_copy.num_entries, - sizeof(struct adc_seq_entry), - &entries_bounds), - "num_entries too large")) { - ret = -EINVAL; - goto out; - } - - Z_OOPS(Z_SYSCALL_MEMORY_READ(seq_table_copy.entries, entries_bounds)); - entries_copy = z_thread_malloc(entries_bounds); - if (!entries_copy) { - ret = -ENOMEM; - goto out; - } - - memcpy(entries_copy, seq_table_copy.entries, entries_bounds); - seq_table_copy.entries = entries_copy; - - for (entry = seq_table_copy.entries; i < seq_table_copy.num_entries; - i++, entry++) { - if (Z_SYSCALL_MEMORY_WRITE(entry->buffer, - entry->buffer_length)) { - k_free(entries_copy); - Z_OOPS(1); - } - } - - ret = _impl_adc_read((struct device *)dev, &seq_table_copy); - k_free(entries_copy); -out: - return ret; -} diff --git a/include/adc.h b/include/adc.h index f4dee8e401183..4da12f82182aa 100644 --- a/include/adc.h +++ b/include/adc.h @@ -4,6 +4,7 @@ */ /* + * Copyright (c) 2018 Nordic Semiconductor ASA * Copyright (c) 2015 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 @@ -12,7 +13,6 @@ #ifndef __INCLUDE_ADC_H__ #define __INCLUDE_ADC_H__ -#include #include #ifdef __cplusplus @@ -26,121 +26,345 @@ extern "C" { * @{ */ +/** @brief ADC channel gain factors. */ +enum adc_gain { + ADC_GAIN_1_6, /**< x 1/6. */ + ADC_GAIN_1_5, /**< x 1/5. */ + ADC_GAIN_1_4, /**< x 1/4. */ + ADC_GAIN_1_3, /**< x 1/3. */ + ADC_GAIN_1_2, /**< x 1/2. */ + ADC_GAIN_2_3, /**< x 2/3. */ + ADC_GAIN_1, /**< x 1. */ + ADC_GAIN_2, /**< x 2. */ + ADC_GAIN_3, /**< x 3. */ + ADC_GAIN_4, /**< x 4. */ + ADC_GAIN_8, /**< x 8. */ + ADC_GAIN_16, /**< x 16. */ + ADC_GAIN_32, /**< x 32. */ + ADC_GAIN_64, /**< x 64. */ +}; + +/** @brief ADC references. */ +enum adc_reference { + ADC_REF_VDD_1, /**< VDD. */ + ADC_REF_VDD_1_2, /**< VDD/2. */ + ADC_REF_VDD_1_3, /**< VDD/3. */ + ADC_REF_VDD_1_4, /**< VDD/4. */ + ADC_REF_INTERNAL, /**< Internal. */ + ADC_REF_EXTERNAL0, /**< External, input 0. */ + ADC_REF_EXTERNAL1, /**< External, input 1. */ +}; + +/** Acquisition time is expressed in microseconds. */ +#define ADC_ACQ_TIME_MICROSECONDS (1u) +/** Acquisition time is expressed in nanoseconds. */ +#define ADC_ACQ_TIME_NANOSECONDS (2u) +/** Acquisition time is expressed in ADC ticks. */ +#define ADC_ACQ_TIME_TICKS (3u) +/** Macro for composing the acquisition time value in given units. */ +#define ADC_ACQ_TIME(unit, value) (((unit) << 14) | ((value) & BIT_MASK(14))) +/** Value indicating that the default acquisition time should be used. */ +#define ADC_ACQ_TIME_DEFAULT 0 + +#define ADC_ACQ_TIME_UNIT(time) (((time) >> 14) & BIT_MASK(2)) +#define ADC_ACQ_TIME_VALUE(time) ((time) & BIT_MASK(14)) + /** - * @brief ADC driver Sequence entry - * - * This structure defines a sequence entry used - * to define a sample from a specific channel. + * @brief Structure for specifying the configuration of an ADC channel. */ -struct adc_seq_entry { - /** Clock ticks delay before sampling the ADC. */ - s32_t sampling_delay; +struct adc_channel_cfg { + /** Gain selection. */ + enum adc_gain gain; + + /** Reference selection. */ + enum adc_reference reference; + + /** + * Acquisition time. + * Use the ADC_ACQ_TIME macro to compose the value for this field or + * pass ADC_ACQ_TIME_DEFAULT to use the default setting for a given + * hardware (e.g. when the hardware does not allow to configure the + * acquisition time). + * Particular drivers do not necessarily support all the possible units. + * Value range is 0-16383 for a given unit. + */ + u16_t acquisition_time; + + /** + * Channel identifier. + * This value primarily identifies the channel within the ADC API - when + * a read request is done, the corresponding bit in the "channels" field + * of the "adc_sequence" structure must be set to include this channel + * in the sampling. + * For hardware that does not allow selection of analog inputs for given + * channels, but rather have dedicated ones, this value also selects the + * physical ADC input to be used in the sampling. Otherwise, when it is + * needed to explicitly select an analog input for the channel, or two + * inputs when the channel is a differential one, the selection is done + * in "input_positive" and "input_negative" fields. + * Particular drivers indicate which one of the above two cases they + * support by selecting or not a special hidden Kconfig option named + * ADC_CONFIGURABLE_INPUTS. If this option is not selected, the macro + * CONFIG_ADC_CONFIGURABLE_INPUTS is not defined and consequently the + * mentioned two fields are not present in this structure. + * While this API allows identifiers from range 0-31, particular drivers + * may support only a limited number of channel identifiers (dependent + * on the underlying hardware capabilities or configured via a dedicated + * Kconfig option). + */ + u8_t channel_id : 5; + + /** Channel type: single-ended or differential. */ + u8_t differential : 1; + +#ifdef CONFIG_ADC_CONFIGURABLE_INPUTS + /** + * Positive ADC input. + * This is a driver dependent value that identifies an ADC input to be + * associated with the channel. + */ + u8_t input_positive; + + /** + * Negative ADC input (used only for differential channels). + * This is a driver dependent value that identifies an ADC input to be + * associated with the channel. + */ + u8_t input_negative; +#endif /* CONFIG_ADC_CONFIGURABLE_INPUTS */ +}; + - /** Buffer pointer where the sample is written.*/ - u8_t *buffer; +/* Forward declaration of the adc_sequence structure. */ +struct adc_sequence; - /** Length of the sampling buffer.*/ - u32_t buffer_length; +/** + * @brief Action to be performed after a sampling is done. + */ +enum adc_action { + /** The sequence should be continued normally. */ + ADC_ACTION_CONTINUE = 0, - /** Channel ID that should be sampled from the ADC */ - u8_t channel_id; + /** + * The sampling should be repeated. New samples or sample should be + * read from the ADC and written in the same place as the recent ones. + */ + ADC_ACTION_REPEAT, - u8_t stride[3]; + /** The sequence should be finished immediately. */ + ADC_ACTION_FINISH, }; /** - * @brief ADC driver Sequence table + * @brief Type definition of the optional callback function to be called after + * a requested sampling is done. * - * This structure defines a list of sequence entries - * used to execute a sequence of samplings. + * @param dev Pointer to the device structure for the driver + * instance. + * @param sequence Pointer to the sequence structure that triggered the + * sampling. + * @param sampling_index Index (0-65535) of the sampling done. + * + * @returns Action to be performed by the driver. See @ref adc_action. + */ +typedef enum adc_action (*adc_sequence_callback)( + struct device *dev, + const struct adc_sequence *sequence, + u16_t sampling_index); + +/** + * @brief Structure defining additional options for an ADC sampling sequence. + */ +struct adc_sequence_options { + /** + * Interval between consecutive samplings (in microseconds), 0 means + * sample as fast as possible, without involving any timer. + * The accuracy of this interval is dependent on the implementation of + * a given driver. The default routine that handles the intervals uses + * a kernel timer for this purpose, thus, it has the accuracy of the + * kernel's system clock. Particular drivers may use some dedicated + * hardware timers and achieve a better precision. + */ + u32_t interval_us; + + /** + * Callback function to be called after each sampling is done. + * Optional - set to NULL if it is not needed. + */ + adc_sequence_callback callback; + + /** + * Number of extra samplings to perform (the total number of samplings + * is 1 + extra_samplings). + */ + u16_t extra_samplings; +}; + +/** + * @brief Structure defining an ADC sampling sequence. */ -struct adc_seq_table { - /* Pointer to a sequence entry array. */ - struct adc_seq_entry *entries; +struct adc_sequence { + /** + * Pointer to a structure defining additional options for the sequence. + * If NULL, the sequence consists of a single sampling. + */ + const struct adc_sequence_options *options; + + /** + * Bit-mask indicating the channels to be included in each sampling + * of this sequence. + * All selected channels must be configured with adc_channel_setup() + * before they are used in a sequence. + */ + u32_t channels; + + /** + * Pointer to a buffer where the samples are to be written. Samples + * from subsequent samplings are written sequentially in the buffer. + * The number of samples written for each sampling is determined by + * the number of channels selected in the "channels" field. + * The buffer must be of an appropriate size, taking into account + * the number of selected channels and the ADC resolution used, + * as well as the number of samplings contained in the sequence. + */ + void *buffer; + + /** + * Specifies the actual size of the buffer pointed by the "buffer" + * field (in bytes). The driver must ensure that samples are not + * written beyond the limit and it must return an error if the buffer + * turns out to be not large enough to hold all the requested samples. + */ + size_t buffer_size; - /* Number of entries in the sequence entry array. */ - u8_t num_entries; - u8_t stride[3]; + /** + * ADC resolution. + * For single-ended channels the sample values are from range: + * 0 .. 2^resolution - 1, + * for differential ones: + * - 2^(resolution-1) .. 2^(resolution-1) - 1. + */ + u8_t resolution; + + /** + * Oversampling setting. + * Each sample is averaged from 2^oversampling conversion results. + * This feature may be unsupported by a given ADC hardware, or in + * a specific mode (e.g. when sampling multiple channels). + */ + u8_t oversampling; }; + +/** + * @brief Type definition of ADC API function for configuring a channel. + * See adc_channel_setup() for argument descriptions. + */ +typedef int (*adc_api_channel_setup)(struct device *dev, + const struct adc_channel_cfg *channel_cfg); + +/** + * @brief Type definition of ADC API function for setting a read request. + * See adc_read() for argument descriptions. + */ +typedef int (*adc_api_read)(struct device *dev, + const struct adc_sequence *sequence); + +#ifdef CONFIG_ADC_ASYNC +/** + * @brief Type definition of ADC API function for setting an asynchronous + * read request. + * See adc_read_async() for argument descriptions. + */ +typedef int (*adc_api_read_async)(struct device *dev, + const struct adc_sequence *sequence, + struct k_poll_signal *async); +#endif + /** * @brief ADC driver API * - * This structure holds all API function pointers. + * This is the mandatory API any ADC driver needs to expose. */ struct adc_driver_api { - /** Pointer to the enable routine. */ - void (*enable)(struct device *dev); - - /** Pointer to the disable routine. */ - void (*disable)(struct device *dev); - - /** Pointer to the read routine. */ - int (*read)(struct device *dev, struct adc_seq_table *seq_table); + adc_api_channel_setup channel_setup; + adc_api_read read; +#ifdef CONFIG_ADC_ASYNC + adc_api_read_async read_async; +#endif }; /** - * @brief Enable ADC hardware + * @brief Configure an ADC channel. * - * This routine enables the ADC hardware block for data sampling for the - * specified device. + * It is required to call this function and configure each channel before it is + * selected for a read request. * - * @param dev Pointer to the device structure for the driver instance. + * @param dev Pointer to the device structure for the driver instance. + * @param channel_cfg Channel configuration. * - * @return N/A + * @retval 0 On success. + * @retval -EINVAL If a parameter with an invalid value has been provided. */ -__syscall void adc_enable(struct device *dev); - -static inline void _impl_adc_enable(struct device *dev) +static inline int adc_channel_setup(struct device *dev, + const struct adc_channel_cfg *channel_cfg) { const struct adc_driver_api *api = dev->driver_api; - api->enable(dev); + return api->channel_setup(dev, channel_cfg); } /** - * @brief Disable ADC hardware - * - * This routine disables the ADC hardware block for data sampling for the - * specified device. + * @brief Set a read request. * - * @param dev Pointer to the device structure for the driver instance. + * @param dev Pointer to the device structure for the driver instance. + * @param sequence Structure specifying requested sequence of samplings. * - * @return N/A + * @retval 0 On success. + * @retval -EINVAL If a parameter with an invalid value has been provided. + * @retval -ENOMEM If the provided buffer is to small to hold the results + * of all requested samplings. + * @retval -ENOTSUP If the requested mode of operation is not supported. + * @retval -EIO If another sampling was triggered while the previous one + * was still in progress. This may occur only when samplings + * are done with intervals, and it indicates that the selected + * interval was too small. All requested samples are written + * in the buffer, but at least some of them were taken with + * an extra delay compared to what was scheduled. */ -__syscall void adc_disable(struct device *dev); - -static inline void _impl_adc_disable(struct device *dev) +static inline int adc_read(struct device *dev, + const struct adc_sequence *sequence) { const struct adc_driver_api *api = dev->driver_api; - api->disable(dev); + return api->read(dev, sequence); } +#ifdef CONFIG_ADC_ASYNC /** - * @brief Set a read request. + * @brief Set an asynchronous read request. * - * This routine sends a read or sampling request to the ADC hardware block. - * A sequence table describes the read request. - * The routine returns once the ADC completes the read sequence. - * The sample data can be retrieved from the memory buffers in - * the sequence table structure. + * @param dev Pointer to the device structure for the driver instance. + * @param sequence Structure specifying requested sequence of samplings. + * @param async Pointer to a valid and ready to be signaled struct + * k_poll_signal. (Note: if NULL this function will not notify + * the end of the transaction, and whether it went successfully + * or not). * - * @param dev Pointer to the device structure for the driver instance. - * @param seq_table Pointer to the structure representing the sequence table. + * @returns The same + * 0 on success, negative error code otherwise. The returned values + * are the * - * @retval 0 On success - * @retval else Otherwise. */ -__syscall int adc_read(struct device *dev, struct adc_seq_table *seq_table); - -static inline int _impl_adc_read(struct device *dev, - struct adc_seq_table *seq_table) +static inline int adc_read_async(struct device *dev, + const struct adc_sequence *sequence, + struct k_poll_signal *async) { const struct adc_driver_api *api = dev->driver_api; - return api->read(dev, seq_table); + return api->read_async(dev, sequence, async); } +#endif /* CONFIG_ADC_ASYNC */ /** * @} @@ -150,6 +374,4 @@ static inline int _impl_adc_read(struct device *dev, } #endif -#include - #endif /* __INCLUDE_ADC_H__ */ diff --git a/tests/drivers/adc/adc_api/CMakeLists.txt b/tests/drivers/adc/adc_api/CMakeLists.txt index 800ba5841af30..d94f55d415341 100644 --- a/tests/drivers/adc/adc_api/CMakeLists.txt +++ b/tests/drivers/adc/adc_api/CMakeLists.txt @@ -1,4 +1,12 @@ cmake_minimum_required(VERSION 3.8.2) +macro(set_conf_file) + if(EXISTS ${APPLICATION_SOURCE_DIR}/boards/${BOARD}.conf) + set(CONF_FILE "prj_base.conf ${APPLICATION_SOURCE_DIR}/boards/${BOARD}.conf") + else() + set(CONF_FILE "prj_base.conf") + endif() +endmacro() + include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) project(NONE) diff --git a/tests/drivers/adc/adc_api/README b/tests/drivers/adc/adc_api/README deleted file mode 100644 index 7bb7402999331..0000000000000 --- a/tests/drivers/adc/adc_api/README +++ /dev/null @@ -1,15 +0,0 @@ -This is the test app which test ADC on Quark SE processor. - -Default ADC mode is interrupt mode. -The case tests ADC working in different resolutions. - -The analog input pin and channel number mapping -for Quark Se Devboard. -A0 Channel 10 -A1 Channel 11 -A2 Channel 12 -A3 Channel 13 -A4 Channel 14 - -This test uses channel 10 to sample the voltage of VCC3.3. -So connect A0 to VCC3.3 and start the APP. diff --git a/tests/drivers/adc/adc_api/prj.conf b/tests/drivers/adc/adc_api/prj.conf deleted file mode 100644 index c286916189532..0000000000000 --- a/tests/drivers/adc/adc_api/prj.conf +++ /dev/null @@ -1,2 +0,0 @@ -CONFIG_ADC=y -CONFIG_ZTEST=y diff --git a/tests/drivers/adc/adc_api/prj_base.conf b/tests/drivers/adc/adc_api/prj_base.conf new file mode 100644 index 0000000000000..17f655ec2eddd --- /dev/null +++ b/tests/drivers/adc/adc_api/prj_base.conf @@ -0,0 +1,8 @@ +CONFIG_ZTEST=y + +CONFIG_ADC=y +CONFIG_ADC_ASYNC=y +CONFIG_ADC_0=y + +CONFIG_SYS_LOG=y +CONFIG_SYS_LOG_ADC_LEVEL=1 diff --git a/tests/drivers/adc/adc_api/src/main.c b/tests/drivers/adc/adc_api/src/main.c index fca46436cc220..21f50d17295af 100644 --- a/tests/drivers/adc/adc_api/src/main.c +++ b/tests/drivers/adc/adc_api/src/main.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2018 Nordic Semiconductor ASA * Copyright (c) 2016 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 @@ -11,7 +12,11 @@ * @} */ -extern void test_adc_sample(void); +extern void test_adc_sample_one_channel(void); +extern void test_adc_sample_two_channels(void); +extern void test_adc_asynchronous_call(void); +extern void test_adc_sample_with_interval(void); +extern void test_adc_repeated_samplings(void); #include #include @@ -19,6 +24,10 @@ extern void test_adc_sample(void); void test_main(void) { ztest_test_suite(adc_basic_test, - ztest_unit_test(test_adc_sample)); + ztest_unit_test(test_adc_sample_one_channel), + ztest_unit_test(test_adc_sample_two_channels), + ztest_unit_test(test_adc_asynchronous_call), + ztest_unit_test(test_adc_sample_with_interval), + ztest_unit_test(test_adc_repeated_samplings)); ztest_run_test_suite(adc_basic_test); } diff --git a/tests/drivers/adc/adc_api/src/test_adc.c b/tests/drivers/adc/adc_api/src/test_adc.c index 84b75f07f1a98..7d8f79bacb3f5 100644 --- a/tests/drivers/adc/adc_api/src/test_adc.c +++ b/tests/drivers/adc/adc_api/src/test_adc.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2018 Nordic Semiconductor ASA * Copyright (c) 2016 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 @@ -8,19 +9,7 @@ * @addtogroup test_adc_basic_operations * @{ * @defgroup t_adc_basic_basic_operations test_adc_sample - * @brief TestPurpose: verify ADC works well with different resolutions - * and sample mode - * @details - * - Test Steps - * -# Connect A0 to VCC3.3. - * -# Prepare ADC sequence table. - * -# Bind ADC device. - * -# Enable ADC device. - * -# Call adc_read() to fetch ADC sample. - * -# Dump the sample results. - * - Expected Results - * -# ADC will return the sample result for VCC3.3. Different resolutions - * will all return almost the biggest value in each sample width. + * @brief TestPurpose: verify ADC driver handles different sampling scenarios * @} */ @@ -28,78 +17,325 @@ #include #include -#define BUFFER_SIZE 5 - -#if defined(CONFIG_BOARD_FRDM_K64F) -#define ADC_DEV_NAME CONFIG_ADC_1_NAME -#define ADC_CHANNEL 14 -#elif defined(CONFIG_BOARD_FRDM_KL25Z) -#define ADC_DEV_NAME CONFIG_ADC_0_NAME -#define ADC_CHANNEL 12 -#elif defined(CONFIG_BOARD_FRDM_KW41Z) -#define ADC_DEV_NAME CONFIG_ADC_0_NAME -#define ADC_CHANNEL 3 -#elif defined(CONFIG_BOARD_HEXIWEAR_K64) -#define ADC_DEV_NAME CONFIG_ADC_0_NAME -#define ADC_CHANNEL 16 -#elif defined(CONFIG_BOARD_HEXIWEAR_KW40Z) -#define ADC_DEV_NAME CONFIG_ADC_0_NAME -#define ADC_CHANNEL 1 -#else -#define ADC_DEV_NAME CONFIG_ADC_0_NAME -#define ADC_CHANNEL 10 -#endif +/* These settings need to be defined separately for particular boards. */ +#define ADC_DEVICE_NAME CONFIG_ADC_0_NAME +#define ADC_RESOLUTION 10 +#define ADC_GAIN ADC_GAIN_1_2 +#define ADC_REFERENCE ADC_REF_INTERNAL +#define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT +#define ADC_1ST_CHANNEL_ID 0 +/*#define ADC_2ND_CHANNEL_ID 2*/ -static u16_t seq_buffer[BUFFER_SIZE]; +#define BUFFER_SIZE 6 +static s16_t m_sample_buffer[BUFFER_SIZE]; -static struct adc_seq_entry entry = { - .sampling_delay = 30, - .channel_id = ADC_CHANNEL, - .buffer = (void *)seq_buffer, - .buffer_length = BUFFER_SIZE * sizeof(seq_buffer[0]) +static const struct adc_channel_cfg m_1st_channel_cfg = { + .gain = ADC_GAIN, + .reference = ADC_REFERENCE, + .acquisition_time = ADC_ACQUISITION_TIME, + .channel_id = ADC_1ST_CHANNEL_ID, +#if defined(CONFIG_ADC_CONFIGURABLE_INPUTS) + .input_positive = ADC_1ST_CHANNEL_INPUT, +#endif }; - -static struct adc_seq_table table = { - .entries = &entry, - .num_entries = 1, +#if defined(ADC_2ND_CHANNEL_ID) +static const struct adc_channel_cfg m_2nd_channel_cfg = { + .gain = ADC_GAIN, + .reference = ADC_REFERENCE, + .acquisition_time = ADC_ACQUISITION_TIME, + .channel_id = ADC_2ND_CHANNEL_ID, +#if defined(CONFIG_ADC_CONFIGURABLE_INPUTS) + .input_positive = ADC_2ND_CHANNEL_INPUT, +#endif }; +#endif /* defined(ADC_2ND_CHANNEL_ID) */ + +static struct device *init_adc(void) +{ + int ret; + struct device *adc_dev = device_get_binding(ADC_DEVICE_NAME); + + zassert_not_null(adc_dev, "Cannot get ADC device"); + + ret = adc_channel_setup(adc_dev, &m_1st_channel_cfg); + zassert_equal(ret, 0, + "Setting up of the first channel failed with code %d", ret); + +#if defined(ADC_2ND_CHANNEL_ID) + ret = adc_channel_setup(adc_dev, &m_2nd_channel_cfg); + zassert_equal(ret, 0, + "Setting up of the second channel failed with code %d", ret); +#endif /* defined(ADC_2ND_CHANNEL_ID) */ + + memset(m_sample_buffer, 0, sizeof(m_sample_buffer)); -static int test_task(void) + return adc_dev; +} + +static void check_samples(int expected_count) { int i; + + TC_PRINT("Samples read: "); + for (i = 0; i < BUFFER_SIZE; i++) { + s16_t sample_value = m_sample_buffer[i]; + + TC_PRINT("0x%04x ", sample_value); + if (i < expected_count) { + zassert_not_equal(0, sample_value, + "[%u] should be non-zero", i); + } else { + zassert_equal(0, sample_value, + "[%u] should be zero", i); + } + } + TC_PRINT("\n"); +} + +/******************************************************************************* + * test_adc_sample_one_channel + */ +static int test_task_one_channel(void) +{ int ret; - struct device *adc_dev = device_get_binding(ADC_DEV_NAME); + const struct adc_sequence sequence = { + .channels = BIT(ADC_1ST_CHANNEL_ID), + .buffer = m_sample_buffer, + .buffer_size = sizeof(m_sample_buffer), + .resolution = ADC_RESOLUTION, + }; + + struct device *adc_dev = init_adc(); if (!adc_dev) { - TC_PRINT("Cannot get ADC device\n"); return TC_FAIL; } - /* 1. Verify adc_enable() */ - adc_enable(adc_dev); + ret = adc_read(adc_dev, &sequence); + zassert_equal(ret, 0, "adc_read() failed with code %d", ret); - k_sleep(500); + check_samples(1); - /* 2. Verify adc_read() */ - ret = adc_read(adc_dev, &table); - if (ret != 0) { - TC_PRINT("Failed to fetch sample data from ADC controller\n"); + return TC_PASS; +} +void test_adc_sample_one_channel(void) +{ + zassert_true(test_task_one_channel() == TC_PASS, NULL); +} + +/******************************************************************************* + * test_adc_sample_two_channels + */ +#if defined(ADC_2ND_CHANNEL_ID) +static int test_task_two_channels(void) +{ + int ret; + const struct adc_sequence sequence = { + .channels = BIT(ADC_1ST_CHANNEL_ID) | + BIT(ADC_2ND_CHANNEL_ID), + .buffer = m_sample_buffer, + .buffer_size = sizeof(m_sample_buffer), + .resolution = ADC_RESOLUTION, + }; + + struct device *adc_dev = init_adc(); + + if (!adc_dev) { return TC_FAIL; } - TC_PRINT("Channel %d ADC Sample: ", ADC_CHANNEL); - for (i = 0; i < BUFFER_SIZE; i++) { - TC_PRINT("%d ", seq_buffer[i]); + ret = adc_read(adc_dev, &sequence); + zassert_equal(ret, 0, "adc_read() failed with code %d", ret); + + check_samples(2); + + return TC_PASS; +} +#endif /* defined(ADC_2ND_CHANNEL_ID) */ +void test_adc_sample_two_channels(void) +{ +#if defined(ADC_2ND_CHANNEL_ID) + zassert_true(test_task_two_channels() == TC_PASS, NULL); +#else + ztest_test_skip(); +#endif /* defined(ADC_2ND_CHANNEL_ID) */ +} + + +/******************************************************************************* + * test_adc_asynchronous_call + */ +#if defined(CONFIG_ADC_ASYNC) +static int test_task_asynchronous_call(void) +{ + int ret; + const struct adc_sequence_options options = { + .extra_samplings = 4, + }; + const struct adc_sequence sequence = { + .options = &options, + .channels = BIT(ADC_1ST_CHANNEL_ID), + .buffer = m_sample_buffer, + .buffer_size = sizeof(m_sample_buffer), + .resolution = ADC_RESOLUTION, + }; + struct k_poll_signal async_sig = K_POLL_SIGNAL_INITIALIZER(async_sig); + struct k_poll_event async_evt = + K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL, + K_POLL_MODE_NOTIFY_ONLY, + &async_sig); + + struct device *adc_dev = init_adc(); + + if (!adc_dev) { + return TC_FAIL; } - TC_PRINT("\n"); - /* 3. Verify adc_disable() */ - adc_disable(adc_dev); + ret = adc_read_async(adc_dev, &sequence, &async_sig); + zassert_equal(ret, 0, "adc_read_async() failed with code %d", ret); + + ret = k_poll(&async_evt, 1, K_MSEC(1000)); + zassert_equal(ret, 0, "async signal not received as expected"); + + check_samples(1 + options.extra_samplings); + + return TC_PASS; +} +#endif /* defined(CONFIG_ADC_ASYNC) */ +void test_adc_asynchronous_call(void) +{ +#if defined(CONFIG_ADC_ASYNC) + zassert_true(test_task_asynchronous_call() == TC_PASS, NULL); +#else + ztest_test_skip(); +#endif /* defined(CONFIG_ADC_ASYNC) */ +} + + +/******************************************************************************* + * test_adc_sample_with_interval + */ +static enum adc_action sample_with_interval_callback( + struct device *dev, + const struct adc_sequence *sequence, + u16_t sampling_index) +{ + TC_PRINT("%s: sampling %d\n", __func__, sampling_index); + return ADC_ACTION_CONTINUE; +} +static int test_task_with_interval(void) +{ + int ret; + const struct adc_sequence_options options = { + .interval_us = 100 * 1000UL, + .callback = sample_with_interval_callback, + .extra_samplings = 4, + }; + const struct adc_sequence sequence = { + .options = &options, + .channels = BIT(ADC_1ST_CHANNEL_ID), + .buffer = m_sample_buffer, + .buffer_size = sizeof(m_sample_buffer), + .resolution = ADC_RESOLUTION, + }; + + struct device *adc_dev = init_adc(); + + if (!adc_dev) { + return TC_FAIL; + } + + ret = adc_read(adc_dev, &sequence); + zassert_equal(ret, 0, "adc_read() failed with code %d", ret); + + check_samples(1 + options.extra_samplings); return TC_PASS; } +void test_adc_sample_with_interval(void) +{ + zassert_true(test_task_with_interval() == TC_PASS, NULL); +} + + +/******************************************************************************* + * test_adc_repeated_samplings + */ +static u8_t m_samplings_done = 0; +static enum adc_action repeated_samplings_callback( + struct device *dev, + const struct adc_sequence *sequence, + u16_t sampling_index) +{ + ++m_samplings_done; + TC_PRINT("%s: done %d\n", __func__, m_samplings_done); + if (m_samplings_done == 1) { + #if defined(ADC_2ND_CHANNEL_ID) + check_samples(2); + #else + check_samples(1); + #endif /* defined(ADC_2ND_CHANNEL_ID) */ + + /* After first sampling continue normally. */ + return ADC_ACTION_CONTINUE; + } else { + #if defined(ADC_2ND_CHANNEL_ID) + check_samples(4); + #else + check_samples(2); + #endif /* defined(ADC_2ND_CHANNEL_ID) */ + + /* + * The second sampling is repeated 9 times (the samples are + * written in the same place), then the sequence is finished + * prematurely. + */ + if (m_samplings_done < 10) { + return ADC_ACTION_REPEAT; + } else { + return ADC_ACTION_FINISH; + } + } +} +static int test_task_repeated_samplings(void) +{ + int ret; + const struct adc_sequence_options options = { + .callback = repeated_samplings_callback, + /* + * This specifies that 3 samplings are planned. However, + * the callback function above is constructed in such way + * that the first sampling is done normally, the second one + * is repeated 9 times, and then the sequence is finished. + * Hence, the third sampling will not take place. + */ + .extra_samplings = 2, + }; + const struct adc_sequence sequence = { + .options = &options, +#if defined(ADC_2ND_CHANNEL_ID) + .channels = BIT(ADC_1ST_CHANNEL_ID) | + BIT(ADC_2ND_CHANNEL_ID), +#else + .channels = BIT(ADC_1ST_CHANNEL_ID), +#endif /* defined(ADC_2ND_CHANNEL_ID) */ + .buffer = m_sample_buffer, + .buffer_size = sizeof(m_sample_buffer), + .resolution = ADC_RESOLUTION, + }; + + struct device *adc_dev = init_adc(); + + if (!adc_dev) { + return TC_FAIL; + } -void test_adc_sample(void) + ret = adc_read(adc_dev, &sequence); + zassert_equal(ret, 0, "adc_read() failed with code %d", ret); + + return TC_PASS; +} +void test_adc_repeated_samplings(void) { - zassert_true(test_task() == TC_PASS, NULL); + zassert_true(test_task_repeated_samplings() == TC_PASS, NULL); } diff --git a/tests/drivers/adc/adc_simple/CMakeLists.txt b/tests/drivers/adc/adc_simple/CMakeLists.txt deleted file mode 100644 index 800ba5841af30..0000000000000 --- a/tests/drivers/adc/adc_simple/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -cmake_minimum_required(VERSION 3.8.2) -include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) -project(NONE) - -FILE(GLOB app_sources src/*.c) -target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/adc/adc_simple/prj.conf b/tests/drivers/adc/adc_simple/prj.conf deleted file mode 100644 index 44074b400a942..0000000000000 --- a/tests/drivers/adc/adc_simple/prj.conf +++ /dev/null @@ -1,3 +0,0 @@ -CONFIG_ZTEST=y -CONFIG_ADC=y -CONFIG_SYS_LOG_ADC_LEVEL=4 diff --git a/tests/drivers/adc/adc_simple/src/main.c b/tests/drivers/adc/adc_simple/src/main.c deleted file mode 100644 index 7a50d5893ed86..0000000000000 --- a/tests/drivers/adc/adc_simple/src/main.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2015 Intel Corporation. - * - * SPDX-License-Identifier: Apache-2.0 - */ -/* - * Copyright (c) 2016 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include - -#include -#include -#include -#include - -/* in millisecond */ -#define SLEEPTIME 2000 - -#if defined(CONFIG_BOARD_FRDM_K64F) -#define ADC_DEVICE_NAME CONFIG_ADC_1_NAME -#define CHANNEL 14 -#elif defined(CONFIG_BOARD_FRDM_KL25Z) -#define ADC_DEVICE_NAME CONFIG_ADC_0_NAME -#define CHANNEL 12 -#elif defined(CONFIG_BOARD_FRDM_KW41Z) -#define ADC_DEVICE_NAME CONFIG_ADC_0_NAME -#define CHANNEL 3 -#elif defined(CONFIG_BOARD_HEXIWEAR_K64) -#define ADC_DEVICE_NAME CONFIG_ADC_0_NAME -#define CHANNEL 16 -#elif defined(CONFIG_BOARD_HEXIWEAR_KW40Z) -#define ADC_DEVICE_NAME CONFIG_ADC_0_NAME -#define CHANNEL 1 -#else -#define ADC_DEVICE_NAME CONFIG_ADC_0_NAME -#define CHANNEL 10 -#endif - -/* - * The analog input pin and channel number mapping - * for Arduino 101 board. - * A0 Channel 10 - * A1 Channel 11 - * A2 Channel 12 - * A3 Channel 13 - * A4 Channel 14 - */ - -#define BUFFER_SIZE 10 - -static u32_t seq_buffer[2][BUFFER_SIZE]; - -static struct adc_seq_entry sample = { - .sampling_delay = 30, - .channel_id = CHANNEL, - .buffer_length = BUFFER_SIZE * sizeof(seq_buffer[0][0]) -}; - -static struct adc_seq_table table = { - .entries = &sample, - .num_entries = 1, -}; - -static void _print_sample_in_hex(const u32_t *buf, u32_t length) -{ - const u32_t *top; - - printk("Buffer content:\n"); - for (top = buf + length; buf < top; buf++) - printk("0x%x ", *buf); - printk("\n"); -} - -static long _abs(long x) -{ - return x < 0 ? -x : x; -} - - -static void test_adc(void) -{ - int result = TC_FAIL; - struct device *adc; - unsigned int loops = 10; - unsigned int bufi0 = ~0, bufi; - - adc = device_get_binding(ADC_DEVICE_NAME); - zassert_not_null(adc, "Cannot get adc controller"); - - adc_enable(adc); - while (loops--) { - bufi = loops & 0x1; - /* .buffer should be void * ... */ - sample.buffer = (void *) seq_buffer[bufi]; - result = adc_read(adc, &table); - zassert_equal(result, 0, "Sampling could not proceed, " - "an error occurred"); - printk("loop %u: sampling done to buffer #%u\n", loops, bufi); - _print_sample_in_hex(seq_buffer[bufi], BUFFER_SIZE); - if (bufi0 != ~0) { - unsigned int cnt; - long delta; - - for (cnt = 0; cnt < BUFFER_SIZE; cnt++) { - delta = _abs((long)seq_buffer[bufi][cnt] - - seq_buffer[bufi0][cnt]); - printk("loop %u delta %u = %ld\n", - loops, cnt, delta); - } - } - k_sleep(SLEEPTIME); - bufi0 = bufi; - } - adc_disable(adc); -} - - -void test_main(void) -{ - ztest_test_suite(_adc_test, - ztest_unit_test(test_adc)); - ztest_run_test_suite(_adc_test); -} - diff --git a/tests/drivers/adc/adc_simple/testcase.yaml b/tests/drivers/adc/adc_simple/testcase.yaml deleted file mode 100644 index c9325da5ee312..0000000000000 --- a/tests/drivers/adc/adc_simple/testcase.yaml +++ /dev/null @@ -1,4 +0,0 @@ -tests: - peripheral.adc: - depends_on: adc - tags: driver adc From 23135a23464ec17881d45340ce4b56ec1cc0ab90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Mon, 21 May 2018 15:01:08 +0200 Subject: [PATCH 04/21] drivers: adc: Add shims for nrfx ADC and SAADC drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds translation layers to make nrfx drivers for the nRF ADC (nRF51 series) and SAADC (nRF52 series) peripherals accessible via the Zephyr's API. The SAADC peripheral is accessed using nrfx HAL only as it turns out that usage of the nrfx driver in this case would be inconvenient and would unnecessarily complicate the shim. Signed-off-by: Andrzej Głąbek --- drivers/adc/CMakeLists.txt | 2 + drivers/adc/Kconfig | 2 + drivers/adc/Kconfig.nrfx | 34 +++ drivers/adc/adc_nrfx_adc.c | 277 ++++++++++++++++++ drivers/adc/adc_nrfx_saadc.c | 401 ++++++++++++++++++++++++++ ext/hal/nordic/Kconfig | 6 + ext/hal/nordic/nrfx_config_nrf51.h | 4 +- ext/hal/nordic/nrfx_config_nrf52810.h | 4 +- ext/hal/nordic/nrfx_config_nrf52832.h | 4 +- ext/hal/nordic/nrfx_config_nrf52840.h | 4 +- 10 files changed, 730 insertions(+), 8 deletions(-) create mode 100644 drivers/adc/Kconfig.nrfx create mode 100644 drivers/adc/adc_nrfx_adc.c create mode 100644 drivers/adc/adc_nrfx_saadc.c diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index bcc3fa35bc215..cc21a323ce115 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -6,3 +6,5 @@ zephyr_library_sources_ifdef(CONFIG_ADC_QMSI adc_qmsi.c) zephyr_library_sources_ifdef(CONFIG_ADC_QMSI_SS adc_qmsi_ss.c) zephyr_library_sources_ifdef(CONFIG_ADC_SAM_AFEC adc_sam_afec.c) zephyr_library_sources_ifdef(CONFIG_ADC_TI_ADC108S102 adc_ti_adc108s102.c) +zephyr_library_sources_ifdef(CONFIG_ADC_NRFX_ADC adc_nrfx_adc.c) +zephyr_library_sources_ifdef(CONFIG_ADC_NRFX_SAADC adc_nrfx_saadc.c) diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index 37c4eddb58cb9..d11dddbb9182e 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -85,6 +85,8 @@ source "drivers/adc/Kconfig.dw" source "drivers/adc/Kconfig.mcux" +source "drivers/adc/Kconfig.nrfx" + source "drivers/adc/Kconfig.qmsi" source "drivers/adc/Kconfig.sam_afec" diff --git a/drivers/adc/Kconfig.nrfx b/drivers/adc/Kconfig.nrfx new file mode 100644 index 0000000000000..421408a0675d1 --- /dev/null +++ b/drivers/adc/Kconfig.nrfx @@ -0,0 +1,34 @@ +# Kconfig - ADC configuration options + +# +# Copyright (c) 2018, Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +config ADC_NRFX_ADC + bool "nRF ADC nrfx driver" + depends on HAS_HW_NRF_ADC + select HAS_DTS_ADC + select NRFX_ADC + select ADC_CONFIGURABLE_INPUTS + help + Enable support for nrfx ADC driver for nRF51 MCU series. + +config ADC_NRFX_ADC_CHANNEL_COUNT + int "Number of ADC channels" + depends on ADC_NRFX_ADC + range 1 8 + default 1 + help + Number of ADC channels to be supported by the driver. Each channel + needs a dedicated structure in RAM that stores the ADC settings + to be used when sampling this channel. + +config ADC_NRFX_SAADC + bool "nRF SAADC nrfx driver" + depends on HAS_HW_NRF_SAADC + select HAS_DTS_ADC + select ADC_CONFIGURABLE_INPUTS + help + Enable support for nrfx SAADC driver for nRF52 MCU series. diff --git a/drivers/adc/adc_nrfx_adc.c b/drivers/adc/adc_nrfx_adc.c new file mode 100644 index 0000000000000..5fe4a19e59100 --- /dev/null +++ b/drivers/adc/adc_nrfx_adc.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" +#include + +#define SYS_LOG_DOMAIN "adc_nrfx_adc" +#define SYS_LOG_LEVEL CONFIG_SYS_LOG_ADC_LEVEL +#include + +struct driver_data { + struct adc_context ctx; + + nrf_adc_value_t *buffer; + u8_t active_channels; +}; + +static struct driver_data m_data = { + ADC_CONTEXT_INIT_TIMER(m_data, ctx), + ADC_CONTEXT_INIT_LOCK(m_data, ctx), + ADC_CONTEXT_INIT_SYNC(m_data, ctx), +}; + +static nrfx_adc_channel_t m_channels[CONFIG_ADC_NRFX_ADC_CHANNEL_COUNT]; + + +/* Implementation of the ADC driver API function: adc_channel_setup. */ +static int adc_nrfx_channel_setup(struct device *dev, + const struct adc_channel_cfg *channel_cfg) +{ + u8_t channel_id = channel_cfg->channel_id; + nrf_adc_config_t *config = &m_channels[channel_id].config; + + if (channel_id >= CONFIG_ADC_NRFX_ADC_CHANNEL_COUNT) { + return -EINVAL; + } + + if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) { + SYS_LOG_ERR("Selected ADC acquisition time is not valid"); + return -EINVAL; + } + + if (channel_cfg->differential) { + SYS_LOG_ERR("Differential channels are not supported"); + return -EINVAL; + } + + switch (channel_cfg->gain) { + case ADC_GAIN_1_3: + config->scaling = NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD; + break; + case ADC_GAIN_2_3: + config->scaling = NRF_ADC_CONFIG_SCALING_INPUT_TWO_THIRDS; + break; + case ADC_GAIN_1: + config->scaling = NRF_ADC_CONFIG_SCALING_INPUT_FULL_SCALE; + break; + default: + SYS_LOG_ERR("Selected ADC gain is not valid"); + return -EINVAL; + } + + switch (channel_cfg->reference) { + case ADC_REF_INTERNAL: + config->reference = NRF_ADC_CONFIG_REF_VBG; + config->extref = NRF_ADC_CONFIG_EXTREFSEL_NONE; + break; + case ADC_REF_VDD_1_2: + config->reference = NRF_ADC_CONFIG_REF_SUPPLY_ONE_HALF; + config->extref = NRF_ADC_CONFIG_EXTREFSEL_NONE; + break; + case ADC_REF_VDD_1_3: + config->reference = NRF_ADC_CONFIG_REF_SUPPLY_ONE_THIRD; + config->extref = NRF_ADC_CONFIG_EXTREFSEL_NONE; + break; + case ADC_REF_EXTERNAL0: + config->reference = NRF_ADC_CONFIG_REF_EXT; + config->extref = NRF_ADC_CONFIG_EXTREFSEL_AREF0; + break; + case ADC_REF_EXTERNAL1: + config->reference = NRF_ADC_CONFIG_REF_EXT; + config->extref = NRF_ADC_CONFIG_EXTREFSEL_AREF1; + break; + default: + SYS_LOG_ERR("Selected ADC reference is not valid"); + return -EINVAL; + } + + config->input = channel_cfg->input_positive; + + config->resolution = NRF_ADC_CONFIG_RES_8BIT; + + return 0; +} + +static void adc_context_start_sampling(struct adc_context *ctx) +{ + ARG_UNUSED(ctx); + + nrfx_adc_buffer_convert(m_data.buffer, m_data.active_channels); + nrfx_adc_sample(); +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, + bool repeat) +{ + ARG_UNUSED(ctx); + + if (!repeat) { + m_data.buffer += m_data.active_channels; + } +} + +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(nrf_adc_value_t); + if (sequence->options) { + needed_buffer_size *= (1 + sequence->options->extra_samplings); + } + + if (sequence->buffer_size < needed_buffer_size) { + SYS_LOG_ERR("Provided buffer is too small (%u/%u)", + sequence->buffer_size, needed_buffer_size); + return -ENOMEM; + } + + return 0; +} + +static int start_read(struct device *dev, const struct adc_sequence *sequence) +{ + int error = 0; + u32_t selected_channels = sequence->channels; + u8_t active_channels; + u8_t channel_id; + nrf_adc_config_resolution_t nrf_resolution; + + /* Signal an error if channel selection is invalid (no channels or + * a non-existing one is selected). + */ + if (!selected_channels || + (selected_channels & + ~BIT_MASK(CONFIG_ADC_NRFX_ADC_CHANNEL_COUNT))) { + SYS_LOG_ERR("Invalid selection of channels"); + return -EINVAL; + } + + if (sequence->oversampling != 0) { + SYS_LOG_ERR("Oversampling is not supported"); + return -EINVAL; + } + + switch (sequence->resolution) { + case 8: + nrf_resolution = NRF_ADC_CONFIG_RES_8BIT; + break; + case 9: + nrf_resolution = NRF_ADC_CONFIG_RES_9BIT; + break; + case 10: + nrf_resolution = NRF_ADC_CONFIG_RES_10BIT; + break; + default: + SYS_LOG_ERR("ADC resolution value %d is not valid", + sequence->resolution); + return -EINVAL; + } + + active_channels = 0; + nrfx_adc_all_channels_disable(); + + /* Enable the channels selected for the pointed sequence. + */ + channel_id = 0; + while (selected_channels) { + if (selected_channels & BIT(0)) { + /* The nrfx driver requires setting the resolution + * for each enabled channel individually. + */ + m_channels[channel_id].config.resolution = + nrf_resolution; + nrfx_adc_channel_enable(&m_channels[channel_id]); + ++active_channels; + } + selected_channels >>= 1; + ++channel_id; + } + + error = check_buffer_size(sequence, active_channels); + if (error) { + return error; + } + + m_data.buffer = sequence->buffer; + m_data.active_channels = active_channels; + + adc_context_start_read(&m_data.ctx, sequence); + + if (!error) { + error = adc_context_wait_for_completion(&m_data.ctx); + adc_context_release(&m_data.ctx, error); + } + + return error; +} + +/* Implementation of the ADC driver API function: adc_read. */ +static int adc_nrfx_read(struct device *dev, + const struct adc_sequence *sequence) +{ + adc_context_lock(&m_data.ctx, false, NULL); + return start_read(dev, sequence); +} + +#ifdef CONFIG_ADC_ASYNC +/* Implementation of the ADC driver API function: adc_read_sync. */ +static int adc_nrfx_read_async(struct device *dev, + const struct adc_sequence *sequence, + struct k_poll_signal *async) +{ + adc_context_lock(&m_data.ctx, true, async); + return start_read(dev, sequence); +} +#endif + +DEVICE_DECLARE(adc_0); + +static void event_handler(const nrfx_adc_evt_t *p_event) +{ + struct device *dev = DEVICE_GET(adc_0); + + if (p_event->type == NRFX_ADC_EVT_DONE) { + adc_context_on_sampling_done(&m_data.ctx, dev); + } +} + +static int init_adc(struct device *dev) +{ + const nrfx_adc_config_t config = NRFX_ADC_DEFAULT_CONFIG; + + nrfx_err_t result = nrfx_adc_init(&config, event_handler); + + if (result != NRFX_SUCCESS) { + SYS_LOG_ERR("Failed to initialize device: %s", + dev->config->name); + return -EBUSY; + } + + IRQ_CONNECT(CONFIG_ADC_0_IRQ, CONFIG_ADC_0_IRQ_PRI, + nrfx_isr, nrfx_adc_irq_handler, 0); + + adc_context_unlock_unconditionally(&m_data.ctx); + + return 0; +} + +static const struct adc_driver_api adc_nrfx_driver_api = { + .channel_setup = adc_nrfx_channel_setup, + .read = adc_nrfx_read, +#ifdef CONFIG_ADC_ASYNC + .read_async = adc_nrfx_read_async, +#endif +}; + +#ifdef CONFIG_ADC_0 +DEVICE_AND_API_INIT(adc_0, CONFIG_ADC_0_NAME, + init_adc, NULL, NULL, + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &adc_nrfx_driver_api); +#endif /* CONFIG_ADC_0 */ diff --git a/drivers/adc/adc_nrfx_saadc.c b/drivers/adc/adc_nrfx_saadc.c new file mode 100644 index 0000000000000..328d9fd51d667 --- /dev/null +++ b/drivers/adc/adc_nrfx_saadc.c @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" +#include + +#define SYS_LOG_DOMAIN "adc_nrfx_saadc" +#define SYS_LOG_LEVEL CONFIG_SYS_LOG_ADC_LEVEL +#include + +struct driver_data { + struct adc_context ctx; + + u8_t positive_inputs[NRF_SAADC_CHANNEL_COUNT]; +}; + +static struct driver_data m_data = { + ADC_CONTEXT_INIT_TIMER(m_data, ctx), + ADC_CONTEXT_INIT_LOCK(m_data, ctx), + ADC_CONTEXT_INIT_SYNC(m_data, ctx), +}; + + +/* Implementation of the ADC driver API function: adc_channel_setup. */ +static int adc_nrfx_channel_setup(struct device *dev, + const struct adc_channel_cfg *channel_cfg) +{ + nrf_saadc_channel_config_t config = { + .resistor_p = NRF_SAADC_RESISTOR_DISABLED, + .resistor_n = NRF_SAADC_RESISTOR_DISABLED, + .burst = NRF_SAADC_BURST_DISABLED, + }; + u8_t channel_id = channel_cfg->channel_id; + + if (channel_id >= NRF_SAADC_CHANNEL_COUNT) { + return -EINVAL; + } + + switch (channel_cfg->gain) { + case ADC_GAIN_1_6: + config.gain = NRF_SAADC_GAIN1_6; + break; + case ADC_GAIN_1_5: + config.gain = NRF_SAADC_GAIN1_5; + break; + case ADC_GAIN_1_4: + config.gain = NRF_SAADC_GAIN1_4; + break; + case ADC_GAIN_1_3: + config.gain = NRF_SAADC_GAIN1_3; + break; + case ADC_GAIN_1_2: + config.gain = NRF_SAADC_GAIN1_2; + break; + case ADC_GAIN_1: + config.gain = NRF_SAADC_GAIN1; + break; + case ADC_GAIN_2: + config.gain = NRF_SAADC_GAIN2; + break; + case ADC_GAIN_4: + config.gain = NRF_SAADC_GAIN4; + break; + default: + SYS_LOG_ERR("Selected ADC gain is not valid"); + return -EINVAL; + } + + switch (channel_cfg->reference) { + case ADC_REF_INTERNAL: + config.reference = NRF_SAADC_REFERENCE_INTERNAL; + break; + case ADC_REF_VDD_1_4: + config.reference = NRF_SAADC_REFERENCE_VDD4; + break; + default: + SYS_LOG_ERR("Selected ADC reference is not valid"); + return -EINVAL; + } + + switch (channel_cfg->acquisition_time) { + case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 3): + config.acq_time = NRF_SAADC_ACQTIME_3US; + break; + case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 5): + config.acq_time = NRF_SAADC_ACQTIME_5US; + break; + case ADC_ACQ_TIME_DEFAULT: + case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 10): + config.acq_time = NRF_SAADC_ACQTIME_10US; + break; + case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 15): + config.acq_time = NRF_SAADC_ACQTIME_15US; + break; + case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 20): + config.acq_time = NRF_SAADC_ACQTIME_20US; + break; + case ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 40): + config.acq_time = NRF_SAADC_ACQTIME_40US; + break; + default: + SYS_LOG_ERR("Selected ADC acquisition time is not valid"); + return -EINVAL; + } + + config.mode = (channel_cfg->differential ? + NRF_SAADC_MODE_DIFFERENTIAL : NRF_SAADC_MODE_SINGLE_ENDED); + + /* Keep the channel disabled in hardware (set positive input to + * NRF_SAADC_INPUT_DISABLED) until it is selected to be included + * in a sampling sequence. + */ + config.pin_p = NRF_SAADC_INPUT_DISABLED; + config.pin_n = channel_cfg->input_negative; + + nrf_saadc_channel_init(channel_id, &config); + + /* Store the positive input selection in a dedicated array, + * to get it later when the channel is selected for a sampling + * and to mark the channel as configured (ready to be selected). + */ + m_data.positive_inputs[channel_id] = channel_cfg->input_positive; + + return 0; +} + +static void adc_context_start_sampling(struct adc_context *ctx) +{ + ARG_UNUSED(ctx); + + nrf_saadc_enable(); + + nrf_saadc_task_trigger(NRF_SAADC_TASK_START); + nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE); +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, + bool repeat) +{ + ARG_UNUSED(ctx); + + if (!repeat) { + nrf_saadc_buffer_pointer_set( + nrf_saadc_buffer_pointer_get() + + nrf_saadc_amount_get()); + } +} + +static int set_resolution(const struct adc_sequence *sequence) +{ + nrf_saadc_resolution_t nrf_resolution; + + switch (sequence->resolution) { + case 8: + nrf_resolution = NRF_SAADC_RESOLUTION_8BIT; + break; + case 10: + nrf_resolution = NRF_SAADC_RESOLUTION_10BIT; + break; + case 12: + nrf_resolution = NRF_SAADC_RESOLUTION_12BIT; + break; + case 14: + nrf_resolution = NRF_SAADC_RESOLUTION_14BIT; + break; + default: + SYS_LOG_ERR("ADC resolution value %d is not valid", + sequence->resolution); + return -EINVAL; + } + + nrf_saadc_resolution_set(nrf_resolution); + return 0; +} + +static int set_oversampling(const struct adc_sequence *sequence, + u8_t active_channels) +{ + nrf_saadc_oversample_t nrf_oversampling; + + if ((active_channels > 1) && (sequence->oversampling > 0)) { + SYS_LOG_ERR( + "Oversampling is supported for single channel only"); + return -EINVAL; + } + + switch (sequence->oversampling) { + case 0: + nrf_oversampling = NRF_SAADC_OVERSAMPLE_DISABLED; + break; + case 1: + nrf_oversampling = NRF_SAADC_OVERSAMPLE_2X; + break; + case 2: + nrf_oversampling = NRF_SAADC_OVERSAMPLE_4X; + break; + case 3: + nrf_oversampling = NRF_SAADC_OVERSAMPLE_8X; + break; + case 4: + nrf_oversampling = NRF_SAADC_OVERSAMPLE_16X; + break; + case 5: + nrf_oversampling = NRF_SAADC_OVERSAMPLE_32X; + break; + case 6: + nrf_oversampling = NRF_SAADC_OVERSAMPLE_64X; + break; + case 7: + nrf_oversampling = NRF_SAADC_OVERSAMPLE_128X; + break; + case 8: + nrf_oversampling = NRF_SAADC_OVERSAMPLE_256X; + break; + default: + SYS_LOG_ERR("Oversampling value %d is not valid", + sequence->oversampling); + return -EINVAL; + } + + nrf_saadc_oversample_set(nrf_oversampling); + return 0; +} + +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(nrf_saadc_value_t); + if (sequence->options) { + needed_buffer_size *= (1 + sequence->options->extra_samplings); + } + + if (sequence->buffer_size < needed_buffer_size) { + SYS_LOG_ERR("Provided buffer is too small (%u/%u)", + sequence->buffer_size, needed_buffer_size); + return -ENOMEM; + } + + return 0; +} + +/* TODO: Move to . */ +static void _nrf_saadc_burst_set(uint8_t channel, + nrf_saadc_burst_t burst) +{ + NRF_SAADC->CH[channel].CONFIG = + (NRF_SAADC->CH[channel].CONFIG & ~SAADC_CH_CONFIG_BURST_Msk) | + (burst << SAADC_CH_CONFIG_BURST_Pos); +} + +static int start_read(struct device *dev, const struct adc_sequence *sequence) +{ + int error = 0; + u32_t selected_channels = sequence->channels; + u8_t active_channels; + u8_t channel_id; + + /* Signal an error if channel selection is invalid (no channels or + * a non-existing one is selected). + */ + if (!selected_channels || + (selected_channels & ~BIT_MASK(NRF_SAADC_CHANNEL_COUNT))) { + SYS_LOG_ERR("Invalid selection of channels"); + return -EINVAL; + } + + active_channels = 0; + + /* Enable only the channels selected for the pointed sequence. + * Disable all the rest. + */ + channel_id = 0; + do { + if (selected_channels & BIT(channel_id)) { + /* Signal an error if a selected channel has not been + * configured yet. + */ + if (m_data.positive_inputs[channel_id] == 0) { + SYS_LOG_ERR("Channel %u not configured", + channel_id); + return -EINVAL; + } + /* When oversampling is used, the burst mode needs to + * be activated. Unfortunately, this mode cannot be + * activated permanently in the channel setup, because + * then the multiple channel sampling fails (the END + * event is not generated) after switching to a single + * channel sampling and back. Thus, when oversampling + * is not used (hence, the multiple channel sampling is + * possible), the burst mode have to be deactivated. + */ + _nrf_saadc_burst_set(channel_id, + (sequence->oversampling != 0 ? + NRF_SAADC_BURST_ENABLED : + NRF_SAADC_BURST_DISABLED)); + nrf_saadc_channel_pos_input_set( + channel_id, + m_data.positive_inputs[channel_id]); + ++active_channels; + } else { + nrf_saadc_channel_pos_input_set( + channel_id, + NRF_SAADC_INPUT_DISABLED); + } + } while (++channel_id < NRF_SAADC_CHANNEL_COUNT); + + error = set_resolution(sequence); + if (error) { + return error; + } + + error = set_oversampling(sequence, active_channels); + if (error) { + return error; + } + + error = check_buffer_size(sequence, active_channels); + if (error) { + return error; + } + + nrf_saadc_buffer_init((nrf_saadc_value_t *)sequence->buffer, + active_channels); + + adc_context_start_read(&m_data.ctx, sequence); + + error = adc_context_wait_for_completion(&m_data.ctx); + adc_context_release(&m_data.ctx, error); + + return error; +} + +/* Implementation of the ADC driver API function: adc_read. */ +static int adc_nrfx_read(struct device *dev, + const struct adc_sequence *sequence) +{ + adc_context_lock(&m_data.ctx, false, NULL); + return start_read(dev, sequence); +} + +#ifdef CONFIG_ADC_ASYNC +/* Implementation of the ADC driver API function: adc_read_async. */ +static int adc_nrfx_read_async(struct device *dev, + const struct adc_sequence *sequence, + struct k_poll_signal *async) +{ + adc_context_lock(&m_data.ctx, true, async); + return start_read(dev, sequence); +} +#endif + +static void saadc_irq_handler(void *param) +{ + struct device *dev = (struct device *)param; + + if (nrf_saadc_event_check(NRF_SAADC_EVENT_END)) { + nrf_saadc_event_clear(NRF_SAADC_EVENT_END); + + nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP); + nrf_saadc_disable(); + + adc_context_on_sampling_done(&m_data.ctx, dev); + } +} + +DEVICE_DECLARE(adc_0); + +static int init_saadc(struct device *dev) +{ + nrf_saadc_event_clear(NRF_SAADC_EVENT_END); + nrf_saadc_int_enable(NRF_SAADC_INT_END); + NRFX_IRQ_ENABLE(CONFIG_ADC_0_IRQ); + + IRQ_CONNECT(CONFIG_ADC_0_IRQ, CONFIG_ADC_0_IRQ_PRI, + saadc_irq_handler, DEVICE_GET(adc_0), 0); + + adc_context_unlock_unconditionally(&m_data.ctx); + + return 0; +} + +static const struct adc_driver_api adc_nrfx_driver_api = { + .channel_setup = adc_nrfx_channel_setup, + .read = adc_nrfx_read, +#ifdef CONFIG_ADC_ASYNC + .read_async = adc_nrfx_read_async, +#endif +}; + +#ifdef CONFIG_ADC_0 +DEVICE_AND_API_INIT(adc_0, CONFIG_ADC_0_NAME, + init_saadc, NULL, NULL, + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &adc_nrfx_driver_api); +#endif /* CONFIG_ADC_0 */ diff --git a/ext/hal/nordic/Kconfig b/ext/hal/nordic/Kconfig index 81c6cd33235c4..ab80a1dc86ade 100644 --- a/ext/hal/nordic/Kconfig +++ b/ext/hal/nordic/Kconfig @@ -10,9 +10,15 @@ config HAS_NORDIC_DRIVERS config HAS_NRFX bool +config NRFX_ADC + bool + config NRFX_PWM bool +config NRFX_SAADC + bool + config NRFX_SPI bool diff --git a/ext/hal/nordic/nrfx_config_nrf51.h b/ext/hal/nordic/nrfx_config_nrf51.h index 18328cd5c6841..005b4116b5ed5 100644 --- a/ext/hal/nordic/nrfx_config_nrf51.h +++ b/ext/hal/nordic/nrfx_config_nrf51.h @@ -38,8 +38,8 @@ // NRFX_ADC_ENABLED - nrfx_adc - ADC peripheral driver //========================================================== -#ifndef NRFX_ADC_ENABLED -#define NRFX_ADC_ENABLED 0 +#ifdef CONFIG_NRFX_ADC +#define NRFX_ADC_ENABLED 1 #endif // NRFX_ADC_CONFIG_IRQ_PRIORITY - Interrupt priority diff --git a/ext/hal/nordic/nrfx_config_nrf52810.h b/ext/hal/nordic/nrfx_config_nrf52810.h index cb17db3e97625..f1b370c460653 100644 --- a/ext/hal/nordic/nrfx_config_nrf52810.h +++ b/ext/hal/nordic/nrfx_config_nrf52810.h @@ -1125,8 +1125,8 @@ // NRFX_SAADC_ENABLED - nrfx_saadc - SAADC peripheral driver //========================================================== -#ifndef NRFX_SAADC_ENABLED -#define NRFX_SAADC_ENABLED 0 +#ifdef CONFIG_NRFX_SAADC +#define NRFX_SAADC_ENABLED 1 #endif // NRFX_SAADC_CONFIG_RESOLUTION - Resolution diff --git a/ext/hal/nordic/nrfx_config_nrf52832.h b/ext/hal/nordic/nrfx_config_nrf52832.h index ab1d70c259839..e29b994075930 100644 --- a/ext/hal/nordic/nrfx_config_nrf52832.h +++ b/ext/hal/nordic/nrfx_config_nrf52832.h @@ -1500,8 +1500,8 @@ // NRFX_SAADC_ENABLED - nrfx_saadc - SAADC peripheral driver //========================================================== -#ifndef NRFX_SAADC_ENABLED -#define NRFX_SAADC_ENABLED 0 +#ifdef CONFIG_NRFX_SAADC +#define NRFX_SAADC_ENABLED 1 #endif // NRFX_SAADC_CONFIG_RESOLUTION - Resolution diff --git a/ext/hal/nordic/nrfx_config_nrf52840.h b/ext/hal/nordic/nrfx_config_nrf52840.h index 096b7403e0b27..675678a28f661 100644 --- a/ext/hal/nordic/nrfx_config_nrf52840.h +++ b/ext/hal/nordic/nrfx_config_nrf52840.h @@ -1607,8 +1607,8 @@ // NRFX_SAADC_ENABLED - nrfx_saadc - SAADC peripheral driver //========================================================== -#ifndef NRFX_SAADC_ENABLED -#define NRFX_SAADC_ENABLED 0 +#ifdef CONFIG_NRFX_SAADC +#define NRFX_SAADC_ENABLED 1 #endif // NRFX_SAADC_CONFIG_RESOLUTION - Resolution From 4fffbf7a9244c482bb28d1e8b47ee57dfa9378e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Fri, 29 Jun 2018 08:07:05 +0200 Subject: [PATCH 05/21] tests: adc_api: Add configurations for nRF5 boards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds to the adc_api test board-specific configurations for the following boards: - nrf51_pca10028 - nrf52_pca10040 - nrf52840_pca10056 "adc" is indicated as supported in the yaml files for these boards so that they are included in sanitycheck. Signed-off-by: Andrzej Głąbek --- boards/arm/nrf51_pca10028/nrf51_pca10028.yaml | 1 + .../nrf52840_pca10056/nrf52840_pca10056.yaml | 1 + boards/arm/nrf52_pca10040/nrf52_pca10040.yaml | 1 + .../adc/adc_api/boards/nrf51_pca10028.conf | 2 ++ .../adc/adc_api/boards/nrf52840_pca10056.conf | 1 + .../adc/adc_api/boards/nrf52_pca10040.conf | 1 + tests/drivers/adc/adc_api/src/test_adc.c | 30 ++++++++++++++++--- 7 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 tests/drivers/adc/adc_api/boards/nrf51_pca10028.conf create mode 100644 tests/drivers/adc/adc_api/boards/nrf52840_pca10056.conf create mode 100644 tests/drivers/adc/adc_api/boards/nrf52_pca10040.conf diff --git a/boards/arm/nrf51_pca10028/nrf51_pca10028.yaml b/boards/arm/nrf51_pca10028/nrf51_pca10028.yaml index 2224f6a31fb9d..b8fede2aeec8d 100644 --- a/boards/arm/nrf51_pca10028/nrf51_pca10028.yaml +++ b/boards/arm/nrf51_pca10028/nrf51_pca10028.yaml @@ -7,5 +7,6 @@ toolchain: - gnuarmemb ram: 32 supported: + - adc - ble - nvs diff --git a/boards/arm/nrf52840_pca10056/nrf52840_pca10056.yaml b/boards/arm/nrf52840_pca10056/nrf52840_pca10056.yaml index 96b6b31ed8315..9dfdca9c0de5b 100644 --- a/boards/arm/nrf52840_pca10056/nrf52840_pca10056.yaml +++ b/boards/arm/nrf52840_pca10056/nrf52840_pca10056.yaml @@ -6,6 +6,7 @@ toolchain: - zephyr - gnuarmemb supported: + - adc - usb_device - ble - ieee802154 diff --git a/boards/arm/nrf52_pca10040/nrf52_pca10040.yaml b/boards/arm/nrf52_pca10040/nrf52_pca10040.yaml index 69f545375f05a..7beaeee516998 100644 --- a/boards/arm/nrf52_pca10040/nrf52_pca10040.yaml +++ b/boards/arm/nrf52_pca10040/nrf52_pca10040.yaml @@ -8,4 +8,5 @@ toolchain: ram: 64 flash: 512 supported: + - adc - nvs diff --git a/tests/drivers/adc/adc_api/boards/nrf51_pca10028.conf b/tests/drivers/adc/adc_api/boards/nrf51_pca10028.conf new file mode 100644 index 0000000000000..55b034a04948a --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/nrf51_pca10028.conf @@ -0,0 +1,2 @@ +CONFIG_ADC_NRFX_ADC=y +CONFIG_ADC_NRFX_ADC_CHANNEL_COUNT=3 diff --git a/tests/drivers/adc/adc_api/boards/nrf52840_pca10056.conf b/tests/drivers/adc/adc_api/boards/nrf52840_pca10056.conf new file mode 100644 index 0000000000000..4fa585362ecf4 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/nrf52840_pca10056.conf @@ -0,0 +1 @@ +CONFIG_ADC_NRFX_SAADC=y diff --git a/tests/drivers/adc/adc_api/boards/nrf52_pca10040.conf b/tests/drivers/adc/adc_api/boards/nrf52_pca10040.conf new file mode 100644 index 0000000000000..4fa585362ecf4 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/nrf52_pca10040.conf @@ -0,0 +1 @@ +CONFIG_ADC_NRFX_SAADC=y diff --git a/tests/drivers/adc/adc_api/src/test_adc.c b/tests/drivers/adc/adc_api/src/test_adc.c index 7d8f79bacb3f5..167d2158ac12f 100644 --- a/tests/drivers/adc/adc_api/src/test_adc.c +++ b/tests/drivers/adc/adc_api/src/test_adc.c @@ -17,14 +17,36 @@ #include #include -/* These settings need to be defined separately for particular boards. */ +#if defined(CONFIG_BOARD_NRF51_PCA10028) + +#include #define ADC_DEVICE_NAME CONFIG_ADC_0_NAME #define ADC_RESOLUTION 10 -#define ADC_GAIN ADC_GAIN_1_2 +#define ADC_GAIN ADC_GAIN_1_3 #define ADC_REFERENCE ADC_REF_INTERNAL #define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT #define ADC_1ST_CHANNEL_ID 0 -/*#define ADC_2ND_CHANNEL_ID 2*/ +#define ADC_1ST_CHANNEL_INPUT NRF_ADC_CONFIG_INPUT_2 +#define ADC_2ND_CHANNEL_ID 2 +#define ADC_2ND_CHANNEL_INPUT NRF_ADC_CONFIG_INPUT_3 + +#elif defined(CONFIG_BOARD_NRF52_PCA10040) || \ + defined(CONFIG_BOARD_NRF52840_PCA10056) + +#include +#define ADC_DEVICE_NAME CONFIG_ADC_0_NAME +#define ADC_RESOLUTION 10 +#define ADC_GAIN ADC_GAIN_1_6 +#define ADC_REFERENCE ADC_REF_INTERNAL +#define ADC_ACQUISITION_TIME ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 10) +#define ADC_1ST_CHANNEL_ID 0 +#define ADC_1ST_CHANNEL_INPUT NRF_SAADC_INPUT_AIN1 +#define ADC_2ND_CHANNEL_ID 2 +#define ADC_2ND_CHANNEL_INPUT NRF_SAADC_INPUT_AIN2 + +#else +#error "Unsupported board." +#endif #define BUFFER_SIZE 6 static s16_t m_sample_buffer[BUFFER_SIZE]; @@ -261,7 +283,7 @@ void test_adc_sample_with_interval(void) /******************************************************************************* * test_adc_repeated_samplings */ -static u8_t m_samplings_done = 0; +static u8_t m_samplings_done; static enum adc_action repeated_samplings_callback( struct device *dev, const struct adc_sequence *sequence, From 174940a3a6073478ada192c34f2e0a24470f99e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrzej=20G=C5=82=C4=85bek?= Date: Wed, 11 Jul 2018 09:10:30 +0200 Subject: [PATCH 06/21] drivers: adc: Select HAS_DTS_ADC for all ADC drivers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To require relevant DTS entries on all platforms providing the ADC driver. Signed-off-by: Andrzej Głąbek --- drivers/adc/Kconfig | 3 +++ drivers/adc/Kconfig.mcux | 1 - drivers/adc/Kconfig.nrfx | 2 -- drivers/adc/Kconfig.sam_afec | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/adc/Kconfig b/drivers/adc/Kconfig index d11dddbb9182e..a7c4d90be9ada 100644 --- a/drivers/adc/Kconfig +++ b/drivers/adc/Kconfig @@ -11,6 +11,9 @@ # menuconfig ADC bool "ADC drivers" + # All platforms that implement the ADC driver are now required to + # provide relevant DTS entries. + select HAS_DTS_ADC help Enable ADC (Analog to Digital Converter) driver configuration. diff --git a/drivers/adc/Kconfig.mcux b/drivers/adc/Kconfig.mcux index 62704c256549f..a7a714b828476 100644 --- a/drivers/adc/Kconfig.mcux +++ b/drivers/adc/Kconfig.mcux @@ -9,6 +9,5 @@ config ADC_MCUX_ADC16 bool "MCUX ADC16 driver" depends on HAS_MCUX_ADC16 - select HAS_DTS_ADC help Enable the MCUX ADC16 driver. diff --git a/drivers/adc/Kconfig.nrfx b/drivers/adc/Kconfig.nrfx index 421408a0675d1..304b01c212ab7 100644 --- a/drivers/adc/Kconfig.nrfx +++ b/drivers/adc/Kconfig.nrfx @@ -9,7 +9,6 @@ config ADC_NRFX_ADC bool "nRF ADC nrfx driver" depends on HAS_HW_NRF_ADC - select HAS_DTS_ADC select NRFX_ADC select ADC_CONFIGURABLE_INPUTS help @@ -28,7 +27,6 @@ config ADC_NRFX_ADC_CHANNEL_COUNT config ADC_NRFX_SAADC bool "nRF SAADC nrfx driver" depends on HAS_HW_NRF_SAADC - select HAS_DTS_ADC select ADC_CONFIGURABLE_INPUTS help Enable support for nrfx SAADC driver for nRF52 MCU series. diff --git a/drivers/adc/Kconfig.sam_afec b/drivers/adc/Kconfig.sam_afec index 18396a0f31467..d6100161c1a6d 100644 --- a/drivers/adc/Kconfig.sam_afec +++ b/drivers/adc/Kconfig.sam_afec @@ -9,7 +9,6 @@ menuconfig ADC_SAM_AFEC bool "SAM ADC Driver" depends on SOC_FAMILY_SAM - select HAS_DTS_ADC help Enable Atmel SAM MCU Family Analog-to-Digital Converter (ADC) driver based on AFEC module. From ab926d6436a552170cb7bc48622a72ab2552fd40 Mon Sep 17 00:00:00 2001 From: Maureen Helm Date: Mon, 6 Aug 2018 15:53:10 -0500 Subject: [PATCH 07/21] adc: Convert mcux adc16 driver to the new adc api Major rework of the mcux adc16 driver to convert it to the new adc api. Currently supports a subset of the api features including synchronous and asynchronous reads, and consecutive reads triggered by the kernel timer. Does not yet support some of the channel configuration options such as gain and reference voltage because the hardware only allows these options to be configured by peripheral instance rather than by channel. The values are currently hardcoded in the driver, but in the future we could introduce some flexibility per instance via device tree attributes. Does not yet support consecutive reads triggered by a hardware timer. Signed-off-by: Maureen Helm --- drivers/adc/adc_mcux_adc16.c | 195 ++++++++++++++++++++++++++++------- 1 file changed, 158 insertions(+), 37 deletions(-) diff --git a/drivers/adc/adc_mcux_adc16.c b/drivers/adc/adc_mcux_adc16.c index c13cd2c6b6395..0d62499ef87b8 100644 --- a/drivers/adc/adc_mcux_adc16.c +++ b/drivers/adc/adc_mcux_adc16.c @@ -1,69 +1,170 @@ /* - * Copyright (c) 2017, NXP + * Copyright (c) 2017-2018, NXP * * SPDX-License-Identifier: Apache-2.0 */ #include #include -#include #include +#define SYS_LOG_LEVEL CONFIG_SYS_LOG_ADC_LEVEL +#include + +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" + struct mcux_adc16_config { ADC_Type *base; void (*irq_config_func)(struct device *dev); }; struct mcux_adc16_data { - struct k_sem sync; - u32_t channel_group; - u32_t result; + struct device *dev; + struct adc_context ctx; + u16_t *buffer; + u16_t *repeat_buffer; + u32_t channels; + u8_t channel_id; }; -static void mcux_adc16_enable(struct device *dev) +static int mcux_adc16_channel_setup(struct device *dev, + const struct adc_channel_cfg *channel_cfg) +{ + u8_t channel_id = channel_cfg->channel_id; + + if (channel_id > (ADC_SC1_ADCH_MASK >> ADC_SC1_ADCH_SHIFT)) { + SYS_LOG_ERR("Channel %d is not valid", channel_id); + return -EINVAL; + } + + if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) { + SYS_LOG_ERR("Invalid channel acquisition time"); + return -EINVAL; + } + + if (channel_cfg->differential) { + SYS_LOG_ERR("Differential channels are not supported"); + return -EINVAL; + } + + if (channel_cfg->gain != ADC_GAIN_1) { + SYS_LOG_ERR("Invalid channel gain"); + return -EINVAL; + } + + if (channel_cfg->reference != ADC_REF_INTERNAL) { + SYS_LOG_ERR("Invalid channel reference"); + return -EINVAL; + } + + return 0; +} + +static int start_read(struct device *dev, const struct adc_sequence *sequence) +{ + const struct mcux_adc16_config *config = dev->config->config_info; + struct mcux_adc16_data *data = dev->driver_data; + adc16_hardware_average_mode_t mode; + int error; + + if (sequence->resolution != 12) { + SYS_LOG_ERR("Invalid resolution"); + return -EINVAL; + } + + switch (sequence->oversampling) { + case 0: + mode = kADC16_HardwareAverageDisabled; + break; + case 2: + mode = kADC16_HardwareAverageCount4; + break; + case 3: + mode = kADC16_HardwareAverageCount8; + break; + case 4: + mode = kADC16_HardwareAverageCount16; + break; + case 5: + mode = kADC16_HardwareAverageCount32; + break; + default: + SYS_LOG_ERR("Invalid oversampling"); + return -EINVAL; + } + ADC16_SetHardwareAverage(config->base, mode); + + data->buffer = sequence->buffer; + data->repeat_buffer = sequence->buffer; + + adc_context_start_read(&data->ctx, sequence); + error = adc_context_wait_for_completion(&data->ctx); + adc_context_release(&data->ctx, error); + + return error; +} + +static int mcux_adc16_read(struct device *dev, + const struct adc_sequence *sequence) { - ARG_UNUSED(dev); + struct mcux_adc16_data *data = dev->driver_data; + + adc_context_lock(&data->ctx, false, NULL); + return start_read(dev, sequence); } -static void mcux_adc16_disable(struct device *dev) +#ifdef CONFIG_ADC_ASYNC +static int mcux_adc16_read_async(struct device *dev, + const struct adc_sequence *sequence, + struct k_poll_signal *async) { - ARG_UNUSED(dev); + struct mcux_adc16_data *data = dev->driver_data; + + adc_context_lock(&data->ctx, true, async); + return start_read(dev, sequence); } +#endif -static int mcux_adc16_read(struct device *dev, struct adc_seq_table *seq_table) +static void mcux_adc16_start_channel(struct device *dev) { const struct mcux_adc16_config *config = dev->config->config_info; struct mcux_adc16_data *data = dev->driver_data; - ADC_Type *base = config->base; - struct adc_seq_entry *entry = seq_table->entries; adc16_channel_config_t channel_config; u32_t channel_group = 0; - int i; - channel_config.enableInterruptOnConversionCompleted = true; + data->channel_id = find_lsb_set(data->channels) - 1; + + SYS_LOG_DBG("Starting channel %d", data->channel_id); + #if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE channel_config.enableDifferentialConversion = false; #endif + channel_config.enableInterruptOnConversionCompleted = true; + channel_config.channelNumber = data->channel_id; + ADC16_SetChannelConfig(config->base, channel_group, &channel_config); +} - for (i = 0; i < seq_table->num_entries; i++) { - if (entry->buffer_length < sizeof(data->result)) { - return -EINVAL; - } - - channel_config.channelNumber = entry->channel_id; - ADC16_SetChannelConfig(base, channel_group, &channel_config); +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct mcux_adc16_data *data = + CONTAINER_OF(ctx, struct mcux_adc16_data, ctx); - data->channel_group = channel_group; + data->channels = ctx->sequence->channels; - k_sem_take(&data->sync, K_FOREVER); + mcux_adc16_start_channel(data->dev); +} - memcpy(entry->buffer, &data->result, sizeof(data->result)); +static void adc_context_update_buffer_pointer(struct adc_context *ctx, + bool repeat_sampling) +{ + struct mcux_adc16_data *data = + CONTAINER_OF(ctx, struct mcux_adc16_data, ctx); - entry++; + if (repeat_sampling) { + data->buffer = data->repeat_buffer; } - - return 0; } static void mcux_adc16_isr(void *arg) @@ -72,11 +173,21 @@ static void mcux_adc16_isr(void *arg) const struct mcux_adc16_config *config = dev->config->config_info; struct mcux_adc16_data *data = dev->driver_data; ADC_Type *base = config->base; - u32_t channel_group = data->channel_group; + u32_t channel_group = 0; + u16_t result; + + result = ADC16_GetChannelConversionValue(base, channel_group); + SYS_LOG_DBG("Finished channel %d. Result is 0x%04x", + data->channel_id, result); - data->result = ADC16_GetChannelConversionValue(base, channel_group); + *data->buffer++ = result; + data->channels &= ~BIT(data->channel_id); - k_sem_give(&data->sync); + if (data->channels) { + mcux_adc16_start_channel(dev); + } else { + adc_context_on_sampling_done(&data->ctx, dev); + } } static int mcux_adc16_init(struct device *dev) @@ -86,23 +197,25 @@ static int mcux_adc16_init(struct device *dev) ADC_Type *base = config->base; adc16_config_t adc_config; - k_sem_init(&data->sync, 0, UINT_MAX); - ADC16_GetDefaultConfig(&adc_config); ADC16_Init(base, &adc_config); ADC16_EnableHardwareTrigger(base, false); - ADC16_SetHardwareAverage(base, kADC16_HardwareAverageCount4); config->irq_config_func(dev); + data->dev = dev; + + adc_context_unlock_unconditionally(&data->ctx); return 0; } static const struct adc_driver_api mcux_adc16_driver_api = { - .enable = mcux_adc16_enable, - .disable = mcux_adc16_disable, + .channel_setup = mcux_adc16_channel_setup, .read = mcux_adc16_read, +#ifdef CONFIG_ADC_ASYNC + .read_async = mcux_adc16_read_async, +#endif }; #if CONFIG_ADC_0 @@ -113,7 +226,11 @@ static const struct mcux_adc16_config mcux_adc16_config_0 = { .irq_config_func = mcux_adc16_config_func_0, }; -static struct mcux_adc16_data mcux_adc16_data_0; +static struct mcux_adc16_data mcux_adc16_data_0 = { + ADC_CONTEXT_INIT_TIMER(mcux_adc16_data_0, ctx), + ADC_CONTEXT_INIT_LOCK(mcux_adc16_data_0, ctx), + ADC_CONTEXT_INIT_SYNC(mcux_adc16_data_0, ctx), +}; DEVICE_AND_API_INIT(mcux_adc16_0, CONFIG_ADC_0_NAME, &mcux_adc16_init, &mcux_adc16_data_0, &mcux_adc16_config_0, @@ -137,7 +254,11 @@ static const struct mcux_adc16_config mcux_adc16_config_1 = { .irq_config_func = mcux_adc16_config_func_1, }; -static struct mcux_adc16_data mcux_adc16_data_1; +static struct mcux_adc16_data mcux_adc16_data_1 = { + ADC_CONTEXT_INIT_TIMER(mcux_adc16_data_1, ctx), + ADC_CONTEXT_INIT_LOCK(mcux_adc16_data_1, ctx), + ADC_CONTEXT_INIT_SYNC(mcux_adc16_data_1, ctx), +}; DEVICE_AND_API_INIT(mcux_adc16_1, CONFIG_ADC_1_NAME, &mcux_adc16_init, &mcux_adc16_data_1, &mcux_adc16_config_1, From c371d6df74346f0414f2e408d153837449c567c7 Mon Sep 17 00:00:00 2001 From: Maureen Helm Date: Mon, 6 Aug 2018 16:22:13 -0500 Subject: [PATCH 08/21] tests: adc_api: Add support for kinetis boards Adds board-specific macros to enable the adc_api test to run on kinetis boards. This restores the test to support all the nxp boards that were supported before the new adc api was introduced. Signed-off-by: Maureen Helm --- tests/drivers/adc/adc_api/src/test_adc.c | 50 ++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tests/drivers/adc/adc_api/src/test_adc.c b/tests/drivers/adc/adc_api/src/test_adc.c index 167d2158ac12f..b8c2c3b391c28 100644 --- a/tests/drivers/adc/adc_api/src/test_adc.c +++ b/tests/drivers/adc/adc_api/src/test_adc.c @@ -44,6 +44,56 @@ #define ADC_2ND_CHANNEL_ID 2 #define ADC_2ND_CHANNEL_INPUT NRF_SAADC_INPUT_AIN2 +#elif defined(CONFIG_BOARD_FRDM_K64F) + +#define ADC_DEVICE_NAME CONFIG_ADC_1_NAME +#define ADC_RESOLUTION 12 +#define ADC_GAIN ADC_GAIN_1 +#define ADC_REFERENCE ADC_REF_INTERNAL +#define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT +#define ADC_1ST_CHANNEL_ID 14 +#define ADC_1ST_CHANNEL_INPUT 0 + +#elif defined(CONFIG_BOARD_FRDM_KL25Z) + +#define ADC_DEVICE_NAME CONFIG_ADC_0_NAME +#define ADC_RESOLUTION 12 +#define ADC_GAIN ADC_GAIN_1 +#define ADC_REFERENCE ADC_REF_INTERNAL +#define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT +#define ADC_1ST_CHANNEL_ID 12 +#define ADC_1ST_CHANNEL_INPUT 0 + +#elif defined(CONFIG_BOARD_FRDM_KW41Z) + +#define ADC_DEVICE_NAME CONFIG_ADC_0_NAME +#define ADC_RESOLUTION 12 +#define ADC_GAIN ADC_GAIN_1 +#define ADC_REFERENCE ADC_REF_INTERNAL +#define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT +#define ADC_1ST_CHANNEL_ID 3 +#define ADC_1ST_CHANNEL_INPUT 0 + +#elif defined(CONFIG_BOARD_HEXIWEAR_K64) + +#define ADC_DEVICE_NAME CONFIG_ADC_0_NAME +#define ADC_RESOLUTION 12 +#define ADC_GAIN ADC_GAIN_1 +#define ADC_REFERENCE ADC_REF_INTERNAL +#define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT +#define ADC_1ST_CHANNEL_ID 16 +#define ADC_1ST_CHANNEL_INPUT 0 + +#elif defined(CONFIG_BOARD_HEXIWEAR_KW40Z) + +#define ADC_DEVICE_NAME CONFIG_ADC_0_NAME +#define ADC_RESOLUTION 12 +#define ADC_GAIN ADC_GAIN_1 +#define ADC_REFERENCE ADC_REF_INTERNAL +#define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT +#define ADC_1ST_CHANNEL_ID 1 +#define ADC_1ST_CHANNEL_INPUT 0 + #else #error "Unsupported board." #endif From b465ef3c3e48ff353ebf1489b273bb70926a6e1e Mon Sep 17 00:00:00 2001 From: Justin Watson Date: Wed, 15 Aug 2018 15:01:57 -0700 Subject: [PATCH 09/21] sam: adc: Updated SAM ADC driver. Updated to work with new ADC API. Signed-off-by: Justin Watson --- arch/arm/soc/atmel_sam/same70/dts.fixup | 2 + .../sam_e70_xplained/doc/sam_e70_xplained.rst | 2 + .../sam_e70_xplained/sam_e70_xplained.yaml | 1 + drivers/adc/adc_sam_afec.c | 466 ++++++++++++------ .../adc/adc_api/boards/sam_e70_xplained.conf | 3 + tests/drivers/adc/adc_api/src/test_adc.c | 10 + 6 files changed, 322 insertions(+), 162 deletions(-) create mode 100644 tests/drivers/adc/adc_api/boards/sam_e70_xplained.conf diff --git a/arch/arm/soc/atmel_sam/same70/dts.fixup b/arch/arm/soc/atmel_sam/same70/dts.fixup index b8f25469ea1c7..0e2a449cdfb3a 100644 --- a/arch/arm/soc/atmel_sam/same70/dts.fixup +++ b/arch/arm/soc/atmel_sam/same70/dts.fixup @@ -95,10 +95,12 @@ #define CONFIG_ADC_0_IRQ ATMEL_SAM_AFEC_4003C000_IRQ_0 #define CONFIG_ADC_0_IRQ_PRI ATMEL_SAM_AFEC_4003C000_IRQ_0_PRIORITY #define CONFIG_ADC_0_NAME ATMEL_SAM_AFEC_4003C000_LABEL +#define CONFIG_ADC_0_PERIPHERAL_ID ATMEL_SAM_AFEC_4003C000_PERIPHERAL_ID #define CONFIG_ADC_1_BASE_ADDRESS ATMEL_SAM_AFEC_40064000_BASE_ADDRESS #define CONFIG_ADC_1_IRQ ATMEL_SAM_AFEC_40064000_IRQ_0 #define CONFIG_ADC_1_IRQ_PRI ATMEL_SAM_AFEC_40064000_IRQ_0_PRIORITY #define CONFIG_ADC_1_NAME ATMEL_SAM_AFEC_40064000_LABEL +#define CONFIG_ADC_1_PERIPHERAL_ID ATMEL_SAM_AFEC_40064000_PERIPHERAL_ID /* End of SoC Level DTS fixup file */ diff --git a/boards/arm/sam_e70_xplained/doc/sam_e70_xplained.rst b/boards/arm/sam_e70_xplained/doc/sam_e70_xplained.rst index c1bf6166b058b..6cbd63f1d1cea 100644 --- a/boards/arm/sam_e70_xplained/doc/sam_e70_xplained.rst +++ b/boards/arm/sam_e70_xplained/doc/sam_e70_xplained.rst @@ -56,6 +56,8 @@ features: +-----------+------------+-------------------------------------+ | GPIO | on-chip | gpio | +-----------+------------+-------------------------------------+ +| ADC | on-chip | ADC via AFEC | ++-----------+------------+-------------------------------------+ Other hardware features are not currently supported by Zephyr. diff --git a/boards/arm/sam_e70_xplained/sam_e70_xplained.yaml b/boards/arm/sam_e70_xplained/sam_e70_xplained.yaml index 5081c27112e52..178547051ac89 100644 --- a/boards/arm/sam_e70_xplained/sam_e70_xplained.yaml +++ b/boards/arm/sam_e70_xplained/sam_e70_xplained.yaml @@ -7,3 +7,4 @@ toolchain: - gnuarmemb supported: - netif:eth + - adc diff --git a/drivers/adc/adc_sam_afec.c b/drivers/adc/adc_sam_afec.c index 6450857aebeaa..21d68e2de180d 100644 --- a/drivers/adc/adc_sam_afec.c +++ b/drivers/adc/adc_sam_afec.c @@ -1,11 +1,15 @@ /* * Copyright (c) 2017 comsuisse AG + * Copyright (c) 2018 Justin Watson * * SPDX-License-Identifier: Apache-2.0 */ /** @file * @brief Atmel SAM MCU family ADC (AFEC) driver. + * + * This is an implementation of the Zephyr ADC driver using the SAM Analog + * Front-End Controller (AFEC) peripheral. */ #include @@ -16,143 +20,254 @@ #include #include +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" + #define SYS_LOG_DOMAIN "dev/adc_sam_afec" #define SYS_LOG_LEVEL CONFIG_SYS_LOG_ADC_LEVEL #include -#define ADC_CHANNELS 12 +#define NUM_CHANNELS 12 -struct adc_sam_dev_cfg { - Afec *regs; - const struct soc_gpio_pin *pin_trigger; - void (*irq_config)(void); - u8_t irq_id; - u8_t periph_id; -}; +#define CONF_ADC_PRESCALER ((SOC_ATMEL_SAM_MCK_FREQ_HZ / 15000000) - 1) + +typedef void (*cfg_func_t)(struct device *dev); + +struct adc_sam_data { + struct adc_context ctx; + struct device *dev; -struct channel_samples { + /* Pointer to the buffer in the sequence. */ u16_t *buffer; - u32_t length; -}; -struct adc_sam_dev_data { - struct k_sem sem_meas; - struct k_sem mutex_thread; - u16_t active_channels; - u16_t measured_channels; - u16_t active_chan_last; - struct channel_samples samples[ADC_CHANNELS]; + /* Pointer to the beginning of a sample. Consider the number of + * channels in the sequence: this buffer changes by that amount + * so all the channels would get repeated. + */ + u16_t *repeat_buffer; + + /* Bit mask of the channels to be sampled. */ + u32_t channels; + + /* Index of the channel being sampled. */ + u8_t channel_id; }; -#define CONF_ADC_PRESCALER ((SOC_ATMEL_SAM_MCK_FREQ_HZ / 15000000) - 1) +struct adc_sam_cfg { + Afec *regs; + cfg_func_t cfg_func; + u32_t periph_id; + struct soc_gpio_pin afec_trg_pin; +}; -#define DEV_NAME(dev) ((dev)->config->name) #define DEV_CFG(dev) \ - ((const struct adc_sam_dev_cfg *const)(dev)->config->config_info) + ((const struct adc_sam_cfg *const)(dev)->config->config_info) + #define DEV_DATA(dev) \ - ((struct adc_sam_dev_data *const)(dev)->driver_data) + ((struct adc_sam_data *)(dev)->driver_data) -static void adc_sam_isr(void *arg) +static int adc_sam_channel_setup(struct device *dev, + const struct adc_channel_cfg *channel_cfg) { - struct device *dev = (struct device *)arg; - const struct adc_sam_dev_cfg *const dev_cfg = DEV_CFG(dev); - struct adc_sam_dev_data *const dev_data = DEV_DATA(dev); - Afec *const afec = dev_cfg->regs; - struct channel_samples *samples = dev_data->samples; - u32_t isr_status; - u16_t value; - - isr_status = afec->AFEC_ISR; - for (int i = 0; i < ADC_CHANNELS; i++) { - if (isr_status & BIT(i)) { - /* Channel i has been sampled */ - afec->AFEC_CSELR = AFEC_CSELR_CSEL(i); - value = (u16_t)(afec->AFEC_CDR); - - if (samples[i].length > 0) { - /* Save sample */ - *samples[i].buffer = value; - samples[i].length--; - samples[i].buffer++; - - dev_data->measured_channels |= BIT(i); - } - if (samples[i].length == 0) { - afec->AFEC_CHDR |= BIT(i); - afec->AFEC_IDR |= BIT(i); - dev_data->active_channels &= ~BIT(i); - } - } + const struct adc_sam_cfg * const cfg = DEV_CFG(dev); + Afec *const afec = cfg->regs; + + u8_t channel_id = channel_cfg->channel_id; + + /* Clear the gain bits for the channel. */ + afec->AFEC_CGR &= ~(3 << channel_id * 2); + + switch (channel_cfg->gain) { + case ADC_GAIN_1: + /* A value of 0 in this register is a gain of 1. */ + break; + case ADC_GAIN_1_2: + afec->AFEC_CGR |= (1 << (channel_id * 2)); + break; + case ADC_GAIN_1_4: + afec->AFEC_CGR |= (2 << (channel_id * 2)); + break; + default: + SYS_LOG_ERR("Selected ADC gain is not valid"); + return -EINVAL; } - if (dev_data->active_chan_last == dev_data->measured_channels) { - if (!dev_data->active_channels) { - /* No more conversions needed */ - k_sem_give(&dev_data->sem_meas); - } else { - /* Start another conversion with remaining channels */ - dev_data->measured_channels = 0; - dev_data->active_chan_last = dev_data->active_channels; - afec->AFEC_CR = AFEC_CR_START; - } + if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) { + SYS_LOG_ERR("Selected ADC acquisition time is not valid"); + return -EINVAL; + } + + if (channel_cfg->reference != ADC_REF_EXTERNAL0) { + SYS_LOG_ERR("Selected reference is not valid"); + return -EINVAL; + } + + if (channel_cfg->differential) { + SYS_LOG_ERR("Differential input is not supported"); + return -EINVAL; } + + /* Set single ended channels to unsigned and differential channels + * to signed conversions. + */ + afec->AFEC_EMR &= ~(AFEC_EMR_SIGNMODE( + AFEC_EMR_SIGNMODE_SE_UNSG_DF_SIGN_Val)); + + return 0; } -static int adc_sam_read(struct device *dev, struct adc_seq_table *seq_tbl) +static void adc_sam_start_conversion(struct device *dev) { - const struct adc_sam_dev_cfg *dev_cfg = DEV_CFG(dev); - struct adc_sam_dev_data *const dev_data = DEV_DATA(dev); - Afec *const afec = dev_cfg->regs; - u8_t channel; - u32_t num_samples; + const struct adc_sam_cfg *const cfg = DEV_CFG(dev); + struct adc_sam_data *data = DEV_DATA(dev); + Afec *const afec = cfg->regs; - k_sem_take(&dev_data->mutex_thread, K_FOREVER); + data->channel_id = find_lsb_set(data->channels) - 1; - dev_data->active_channels = 0; + SYS_LOG_DBG("Starting channel %d", data->channel_id); - /* Enable chosen channels */ - for (int i = 0; i < seq_tbl->num_entries; i++) { - channel = seq_tbl->entries[i].channel_id; - if (channel >= ADC_CHANNELS) { - return -EINVAL; - } + /* Disable all channels. */ + afec->AFEC_CHDR = 0xfff; + afec->AFEC_IDR = 0xfff; - /* Check and set number of requested samples */ - num_samples = seq_tbl->entries[i].buffer_length / sizeof(u16_t); - if (!num_samples) { - return -EINVAL; - } - dev_data->samples[channel].length = num_samples; + /* Enable the ADC channel. This also enables/selects the channel pin as + * an input to the AFEC (50.5.1 SAM E70 datasheet). + */ + afec->AFEC_CHER = (1 << data->channel_id); - /* Set start of sample buffer */ - dev_data->samples[channel].buffer = - (u16_t *)seq_tbl->entries[i].buffer; + /* Enable the interrupt for the channel. */ + afec->AFEC_IER = (1 << data->channel_id); - /* Enable channel */ - dev_data->active_channels |= BIT(channel); - } + /* Start the conversions. */ + afec->AFEC_CR = AFEC_CR_START; +} + +/** + * This is only called once at the beginning of all the conversions, + * all channels as a group. + */ +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct adc_sam_data *data = CONTAINER_OF(ctx, struct adc_sam_data, ctx); - /* Enable chosen channels and their interrupts */ - afec->AFEC_CHER = dev_data->active_channels; - afec->AFEC_IER = dev_data->active_channels; + data->channels = ctx->sequence->channels; - /* Start conversions */ - dev_data->measured_channels = 0; - dev_data->active_chan_last = dev_data->active_channels; - afec->AFEC_CR = AFEC_CR_START; - k_sem_take(&dev_data->sem_meas, K_FOREVER); + adc_sam_start_conversion(data->dev); +} + +static void adc_context_update_buffer_pointer(struct adc_context *ctx, + bool repeat_sampling) +{ + struct adc_sam_data *data = CONTAINER_OF(ctx, struct adc_sam_data, ctx); - k_sem_give(&dev_data->mutex_thread); + if (repeat_sampling) { + data->buffer = data->repeat_buffer; + } +} +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) { + SYS_LOG_ERR("Provided buffer is too small (%u/%u)", + sequence->buffer_size, needed_buffer_size); + return -ENOMEM; + } return 0; } -static void adc_sam_configure(struct device *dev) +static int start_read(struct device *dev, const struct adc_sequence *sequence) { - const struct adc_sam_dev_cfg *dev_cfg = DEV_CFG(dev); - Afec *const afec = dev_cfg->regs; + struct adc_sam_data *data = DEV_DATA(dev); + int error = 0; + u32_t channels = sequence->channels; + + data->channels = 0; + + /* Signal an error if the channel selection is invalid (no channels or + * a non-existing one is selected). + */ + if (channels == 0 || + (channels & (~0UL << NUM_CHANNELS))) { + SYS_LOG_ERR("Invalid selection of channels"); + return -EINVAL; + } + + if (sequence->oversampling != 0) { + SYS_LOG_ERR("Oversampling is not supported"); + return -EINVAL; + } + + if (sequence->resolution != 12) { + /* TODO JKW: Support the Enhanced Resolution Mode 50.6.3 page + * 1544. + */ + SYS_LOG_ERR("ADC resolution value %d is not valid", + sequence->resolution); + return -EINVAL; + } + + if (sequence->options->interval_us != 0) { + SYS_LOG_ERR("Spaced intervals not supported"); + return -EINVAL; + } - /* Reset the AFEC */ + u8_t num_active_channels = 0; + u8_t channel = 0; + + while (channels > 0) { + if (channels & 1) { + ++num_active_channels; + } + channels >>= 1; + ++channel; + } + + error = check_buffer_size(sequence, num_active_channels); + if (error) { + return error; + } + + /* In the context you have a pointer to the adc_sam_data structure + * only. + */ + data->buffer = sequence->buffer; + data->repeat_buffer = sequence->buffer; + + /* At this point we allow the scheduler to do other things while + * we wait for the conversions to complete. This is provided by the + * adc_context functions. However, the caller of this function is + * blocked until the results are in. + */ + adc_context_start_read(&data->ctx, sequence); + + error = adc_context_wait_for_completion(&data->ctx); + adc_context_release(&data->ctx, error); + + return error; +} + +static int adc_sam_read(struct device *dev, + const struct adc_sequence *sequence) +{ + struct adc_sam_data *data = DEV_DATA(dev); + + adc_context_lock(&data->ctx, false, NULL); + return start_read(dev, sequence); +} + +static int adc_sam_init(struct device *dev) +{ + const struct adc_sam_cfg *const cfg = DEV_CFG(dev); + struct adc_sam_data *data = DEV_DATA(dev); + Afec *const afec = cfg->regs; + + /* Reset the AFEC. */ afec->AFEC_CR = AFEC_CR_SWRST; afec->AFEC_MR = AFEC_MR_TRGEN_DIS @@ -164,100 +279,127 @@ static void adc_sam_configure(struct device *dev) | AFEC_MR_ONE | AFEC_MR_USEQ_NUM_ORDER; - /* Set all channels CM voltage to Vrefp/2 (512) */ - for (int i = 0; i < ADC_CHANNELS; i++) { + /* Set all channels CM voltage to Vrefp/2 (512). */ + for (int i = 0; i < NUM_CHANNELS; i++) { afec->AFEC_CSELR = i; afec->AFEC_COCR = 512; } - /* Enable PGA and Current Bias */ + /* Enable PGA and Current Bias. */ afec->AFEC_ACR = AFEC_ACR_PGA0EN | AFEC_ACR_PGA1EN | AFEC_ACR_IBCTL(1); + + soc_pmc_peripheral_enable(cfg->periph_id); + + cfg->cfg_func(dev); + + data->dev = dev; + + adc_context_unlock_unconditionally(&data->ctx); + + return 0; } -static int adc_sam_initialize(struct device *dev) +#ifdef CONFIG_ADC_ASYNC +static int adc_sam_read_async(struct device *dev, + const struct adc_sequence *sequence, + struct k_poll_signal *async) { - const struct adc_sam_dev_cfg *dev_cfg = DEV_CFG(dev); - struct adc_sam_dev_data *const dev_data = DEV_DATA(dev); + struct adc_sam_data *data = DEV_DATA(dev); - /* Initialize semaphores */ - k_sem_init(&dev_data->sem_meas, 0, 1); - k_sem_init(&dev_data->mutex_thread, 1, 1); + adc_context_lock(&data->ctx, true, async); + return start_read(dev, sequence); +} +#endif - /* Configure interrupts */ - dev_cfg->irq_config(); +static const struct adc_driver_api adc_sam_api = { + .channel_setup = adc_sam_channel_setup, + .read = adc_sam_read, +#ifdef CONFIG_ADC_ASYNC + .read_async = adc_sam_read_async, +#endif +}; - /* Enable module's clock */ - soc_pmc_peripheral_enable(dev_cfg->periph_id); +static void adc_sam_isr(void *arg) +{ + struct device *dev = (struct device *)arg; + struct adc_sam_data *data = DEV_DATA(dev); + const struct adc_sam_cfg *const cfg = DEV_CFG(dev); + Afec *const afec = cfg->regs; + u16_t result; - /* Configure ADC */ - adc_sam_configure(dev); + afec->AFEC_CHDR |= BIT(data->channel_id); + afec->AFEC_IDR |= BIT(data->channel_id); - /* Enable module interrupt */ - irq_enable(dev_cfg->irq_id); + afec->AFEC_CSELR = AFEC_CSELR_CSEL(data->channel_id); + result = (u16_t)(afec->AFEC_CDR); - SYS_LOG_INF("Device %s initialized", DEV_NAME(dev)); + *data->buffer++ = result; + data->channels &= ~BIT(data->channel_id); - return 0; + if (data->channels) { + adc_sam_start_conversion(dev); + } else { + /* Called once all conversions have completed.*/ + adc_context_on_sampling_done(&data->ctx, dev); + } } -static const struct adc_driver_api adc_sam_driver_api = { - .read = adc_sam_read, +#ifdef CONFIG_ADC_0 +static void adc0_sam_cfg_func(struct device *dev); + +static const struct adc_sam_cfg adc0_sam_cfg = { + .regs = (Afec *)CONFIG_ADC_0_BASE_ADDRESS, + .cfg_func = adc0_sam_cfg_func, + .periph_id = CONFIG_ADC_0_PERIPHERAL_ID, + .afec_trg_pin = PIN_AFE0_ADTRG, }; -/* ADC_0 */ +static struct adc_sam_data adc0_sam_data = { + ADC_CONTEXT_INIT_TIMER(adc0_sam_data, ctx), + ADC_CONTEXT_INIT_LOCK(adc0_sam_data, ctx), + ADC_CONTEXT_INIT_SYNC(adc0_sam_data, ctx), +}; -#ifdef CONFIG_ADC_0 -static struct device DEVICE_NAME_GET(adc0_sam); +DEVICE_AND_API_INIT(adc0_sam, CONFIG_ADC_0_NAME, adc_sam_init, + &adc0_sam_data, &adc0_sam_cfg, POST_KERNEL, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &adc_sam_api); -static void adc0_irq_config(void) +static void adc0_sam_cfg_func(struct device *dev) { - IRQ_CONNECT(AFEC0_IRQn, CONFIG_ADC_0_IRQ_PRI, adc_sam_isr, + IRQ_CONNECT(CONFIG_ADC_0_IRQ, CONFIG_ADC_0_IRQ_PRI, adc_sam_isr, DEVICE_GET(adc0_sam), 0); + irq_enable(CONFIG_ADC_0_IRQ); } -static const struct soc_gpio_pin pin_adc0 = PIN_AFE0_ADTRG; +#endif /* CONFIG_ADC_0 */ -static const struct adc_sam_dev_cfg adc0_sam_config = { - .regs = AFEC0, - .pin_trigger = &pin_adc0, - .periph_id = ID_AFEC0, - .irq_config = adc0_irq_config, - .irq_id = AFEC0_IRQn, -}; - -static struct adc_sam_dev_data adc0_sam_data; +#ifdef CONFIG_ADC_1 +static void adc1_sam_cfg_func(struct device *dev); -DEVICE_AND_API_INIT(adc0_sam, CONFIG_ADC_0_NAME, &adc_sam_initialize, - &adc0_sam_data, &adc0_sam_config, POST_KERNEL, - CONFIG_ADC_INIT_PRIORITY, &adc_sam_driver_api); -#endif +static const struct adc_sam_cfg adc1_sam_cfg = { + .regs = (Afec *)CONFIG_ADC_1_BASE_ADDRESS, + .cfg_func = adc1_sam_cfg_func, + .periph_id = CONFIG_ADC_1_PERIPHERAL_ID, + .afec_trg_pin = PIN_AFE1_ADTRG, +}; -/* ADC_1 */ +static struct adc_sam_data adc1_sam_data = { + ADC_CONTEXT_INIT_TIMER(adc1_sam_data, ctx), + ADC_CONTEXT_INIT_LOCK(adc1_sam_data, ctx), + ADC_CONTEXT_INIT_SYNC(adc1_sam_data, ctx), +}; -#ifdef CONFIG_ADC_1 -static struct device DEVICE_NAME_GET(adc1_sam); +DEVICE_AND_API_INIT(adc1_sam, CONFIG_ADC_1_NAME, adc_sam_init, + &adc1_sam_data, &adc1_sam_cfg, POST_KERNEL, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &adc_sam_api); -static void adc1_irq_config(void) +static void adc1_sam_cfg_func(struct device *dev) { - IRQ_CONNECT(AFEC1_IRQn, CONFIG_ADC_1_IRQ_PRI, adc_sam_isr, + IRQ_CONNECT(CONFIG_ADC_1_IRQ, CONFIG_ADC_1_IRQ_PRI, adc_sam_isr, DEVICE_GET(adc1_sam), 0); + irq_enable(CONFIG_ADC_1_IRQ); } -static const struct soc_gpio_pin pin_adc1 = PIN_AFE1_ADTRG; - -static const struct adc_sam_dev_cfg adc1_sam_config = { - .regs = AFEC1, - .pin_trigger = &pin_adc1, - .periph_id = ID_AFEC1, - .irq_config = adc1_irq_config, - .irq_id = AFEC1_IRQn, -}; - -static struct adc_sam_dev_data adc1_sam_data; - -DEVICE_AND_API_INIT(adc1_sam, CONFIG_ADC_1_NAME, &adc_sam_initialize, - &adc1_sam_data, &adc1_sam_config, POST_KERNEL, - CONFIG_ADC_INIT_PRIORITY, &adc_sam_driver_api); -#endif +#endif /* CONFIG_ADC_1 */ diff --git a/tests/drivers/adc/adc_api/boards/sam_e70_xplained.conf b/tests/drivers/adc/adc_api/boards/sam_e70_xplained.conf new file mode 100644 index 0000000000000..9cc28af15bc55 --- /dev/null +++ b/tests/drivers/adc/adc_api/boards/sam_e70_xplained.conf @@ -0,0 +1,3 @@ +CONFIG_ADC=y +CONFIG_ADC_SAM_AFEC=y +CONFIG_ADC_0=y diff --git a/tests/drivers/adc/adc_api/src/test_adc.c b/tests/drivers/adc/adc_api/src/test_adc.c index b8c2c3b391c28..48316f26f5b6e 100644 --- a/tests/drivers/adc/adc_api/src/test_adc.c +++ b/tests/drivers/adc/adc_api/src/test_adc.c @@ -94,6 +94,16 @@ #define ADC_1ST_CHANNEL_ID 1 #define ADC_1ST_CHANNEL_INPUT 0 +#elif defined(CONFIG_BOARD_SAM_E70_XPLAINED) + +#define ADC_DEVICE_NAME CONFIG_ADC_0_NAME +#define ADC_RESOLUTION 12 +#define ADC_GAIN ADC_GAIN_1 +#define ADC_REFERENCE ADC_REF_EXTERNAL0 +#define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT +#define ADC_1ST_CHANNEL_ID 0 +#define ADC_1ST_CHANNEL_INPUT 0 + #else #error "Unsupported board." #endif From d623676c9b0d20aa98f1b9c72c827b5e97911ae8 Mon Sep 17 00:00:00 2001 From: Punit Vara Date: Fri, 17 Aug 2018 11:35:17 +0530 Subject: [PATCH 10/21] drivers: Use Designware driver for sensor subsystem Remove adc_qmsi_ss to use designware driver for sensor subsystem Signed-off-by: Punit Vara --- .../soc/quark_se_c1000_ss/Kconfig.defconfig | 2 +- drivers/adc/CMakeLists.txt | 1 - drivers/adc/Kconfig.qmsi | 29 +- drivers/adc/adc_qmsi_ss.c | 345 ------------------ 4 files changed, 3 insertions(+), 374 deletions(-) delete mode 100644 drivers/adc/adc_qmsi_ss.c diff --git a/arch/arc/soc/quark_se_c1000_ss/Kconfig.defconfig b/arch/arc/soc/quark_se_c1000_ss/Kconfig.defconfig index a42c46c7f4790..63260aac6976c 100644 --- a/arch/arc/soc/quark_se_c1000_ss/Kconfig.defconfig +++ b/arch/arc/soc/quark_se_c1000_ss/Kconfig.defconfig @@ -126,7 +126,7 @@ endif endif # I2C if ADC -config ADC_QMSI_SS +config ADC_DW def_bool y config ADC_0_IRQ_PRI default 0 diff --git a/drivers/adc/CMakeLists.txt b/drivers/adc/CMakeLists.txt index cc21a323ce115..fc371eb1da86f 100644 --- a/drivers/adc/CMakeLists.txt +++ b/drivers/adc/CMakeLists.txt @@ -3,7 +3,6 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_ADC_DW adc_dw.c) zephyr_library_sources_ifdef(CONFIG_ADC_MCUX_ADC16 adc_mcux_adc16.c) zephyr_library_sources_ifdef(CONFIG_ADC_QMSI adc_qmsi.c) -zephyr_library_sources_ifdef(CONFIG_ADC_QMSI_SS adc_qmsi_ss.c) zephyr_library_sources_ifdef(CONFIG_ADC_SAM_AFEC adc_sam_afec.c) zephyr_library_sources_ifdef(CONFIG_ADC_TI_ADC108S102 adc_ti_adc108s102.c) zephyr_library_sources_ifdef(CONFIG_ADC_NRFX_ADC adc_nrfx_adc.c) diff --git a/drivers/adc/Kconfig.qmsi b/drivers/adc/Kconfig.qmsi index 98d9592ac703b..c9debde634603 100644 --- a/drivers/adc/Kconfig.qmsi +++ b/drivers/adc/Kconfig.qmsi @@ -13,14 +13,7 @@ menuconfig ADC_QMSI help Enable the driver implementation of the QMSI ADC IP. -menuconfig ADC_QMSI_SS - bool "QMSI ADC Driver for the Sensor Subsystem" - depends on QMSI - select ADC_0 - help - Enable the driver implementation of the QMSI ADC IP. - -if ADC_QMSI || ADC_QMSI_SS +if ADC_QMSI choice prompt "Capturing Mode" @@ -59,7 +52,6 @@ config ADC_QMSI_SERIAL_DELAY the serial output is delayed after the conversion has started. -if ADC_QMSI config ADC_QMSI_SAMPLE_WIDTH int "Sample Width" default 3 @@ -73,22 +65,5 @@ config ADC_QMSI_SAMPLE_WIDTH - 2 = 10 bits resolution - 3 = 12 bits resolution -endif - -if ADC_QMSI_SS -config ADC_QMSI_SAMPLE_WIDTH - int "Sample Width" - default 11 - help - Defines ADC device data sample width (resolution): - - - 5 = 6 bits resolution - - - 7 = 8 bits resolution - - - 9 = 10 bits resolution - - - 11 = 12 bits resolution -endif -endif # ADC_QMSI || ADC_QMSI_SS +endif # ADC_QMSI diff --git a/drivers/adc/adc_qmsi_ss.c b/drivers/adc/adc_qmsi_ss.c deleted file mode 100644 index 599d2eb23c7f0..0000000000000 --- a/drivers/adc/adc_qmsi_ss.c +++ /dev/null @@ -1,345 +0,0 @@ -/* adc_qmsi.c - QMSI ADC Sensor Subsystem driver */ - -/* - * Copyright (c) 2016 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "qm_ss_isr.h" -#include "qm_ss_adc.h" -#include "ss_clk.h" - -enum { - ADC_STATE_IDLE, - ADC_STATE_BUSY, - ADC_STATE_ERROR -}; - -struct adc_info { - atomic_t state; - struct k_sem device_sync_sem; - struct k_sem sem; -#ifdef CONFIG_DEVICE_POWER_MANAGEMENT - u32_t device_power_state; - qm_ss_adc_context_t adc_ctx; -#endif -}; - -static void adc_config_irq(void); -static qm_ss_adc_config_t cfg; - -#if (CONFIG_ADC_QMSI_INTERRUPT) - -static void complete_callback(void *data, int error, qm_ss_adc_status_t status, - qm_ss_adc_cb_source_t source) -{ - ARG_UNUSED(status); - ARG_UNUSED(source); - - struct device *dev = data; - - struct adc_info *info = dev->driver_data; - - if (info) { - if (error) { - info->state = ADC_STATE_ERROR; - } - k_sem_give(&info->device_sync_sem); - } -} - -#endif - -static void adc_lock(struct adc_info *data) -{ - k_sem_take(&data->sem, K_FOREVER); - data->state = ADC_STATE_BUSY; - -} -static void adc_unlock(struct adc_info *data) -{ - k_sem_give(&data->sem); - data->state = ADC_STATE_IDLE; - -} -#if (CONFIG_ADC_QMSI_CALIBRATION) -static void adc_qmsi_ss_enable(struct device *dev) -{ - struct adc_info *info = dev->driver_data; - - adc_lock(info); - qm_ss_adc_set_mode(QM_SS_ADC_0, QM_SS_ADC_MODE_NORM_CAL); - qm_ss_adc_calibrate(QM_SS_ADC_0); - adc_unlock(info); -} - -#else -static void adc_qmsi_ss_enable(struct device *dev) -{ - struct adc_info *info = dev->driver_data; - - adc_lock(info); - qm_ss_adc_set_mode(QM_SS_ADC_0, QM_SS_ADC_MODE_NORM_NO_CAL); - adc_unlock(info); -} -#endif /* CONFIG_ADC_QMSI_CALIBRATION */ - -static void adc_qmsi_ss_disable(struct device *dev) -{ - struct adc_info *info = dev->driver_data; - - adc_lock(info); - /* Go to deep sleep */ - qm_ss_adc_set_mode(QM_SS_ADC_0, QM_SS_ADC_MODE_DEEP_PWR_DOWN); - adc_unlock(info); -} - -#if (CONFIG_ADC_QMSI_POLL) -static int adc_qmsi_ss_read(struct device *dev, struct adc_seq_table *seq_tbl) -{ - int i, ret = 0; - qm_ss_adc_xfer_t xfer; - qm_ss_adc_status_t status; - - struct adc_info *info = dev->driver_data; - - - for (i = 0; i < seq_tbl->num_entries; i++) { - - xfer.ch = (qm_ss_adc_channel_t *)&seq_tbl->entries[i].channel_id; - /* Just one channel at the time using the Zephyr sequence table - */ - xfer.ch_len = 1; - xfer.samples = (qm_ss_adc_sample_t *)seq_tbl->entries[i].buffer; - - /* buffer length (bytes) the number of samples, the QMSI Driver - * does not allow more than QM_ADC_FIFO_LEN samples at the time - * in polling mode, if that happens, the qm_adc_convert api will - * return with an error - */ - xfer.samples_len = - (seq_tbl->entries[i].buffer_length)/sizeof(qm_ss_adc_sample_t); - - xfer.callback = NULL; - xfer.callback_data = NULL; - - cfg.window = seq_tbl->entries[i].sampling_delay; - - adc_lock(info); - - if (qm_ss_adc_set_config(QM_SS_ADC_0, &cfg) != 0) { - ret = -EINVAL; - adc_unlock(info); - break; - } - - /* Run the conversion, here the function will poll for the - * samples. The function will constantly read the status - * register to check if the number of samples required has been - * captured - */ - if (qm_ss_adc_convert(QM_SS_ADC_0, &xfer, &status) != 0) { - ret = -EIO; - adc_unlock(info); - break; - } - - /* Successful Analog to Digital conversion */ - adc_unlock(info); - } - - return ret; -} -#else -static int adc_qmsi_ss_read(struct device *dev, struct adc_seq_table *seq_tbl) -{ - int i, ret = 0; - qm_ss_adc_xfer_t xfer; - - struct adc_info *info = dev->driver_data; - - for (i = 0; i < seq_tbl->num_entries; i++) { - - xfer.ch = (qm_ss_adc_channel_t *)&seq_tbl->entries[i].channel_id; - /* Just one channel at the time using the Zephyr sequence table */ - xfer.ch_len = 1; - xfer.samples = - (qm_ss_adc_sample_t *)seq_tbl->entries[i].buffer; - - xfer.samples_len = - (seq_tbl->entries[i].buffer_length)/sizeof(qm_ss_adc_sample_t); - - xfer.callback = complete_callback; - xfer.callback_data = dev; - - cfg.window = seq_tbl->entries[i].sampling_delay; - - adc_lock(info); - - if (qm_ss_adc_set_config(QM_SS_ADC_0, &cfg) != 0) { - ret = -EINVAL; - adc_unlock(info); - break; - } - - /* This is the interrupt driven API, will generate and interrupt and - * call the complete_callback function once the samples have been - * obtained - */ - if (qm_ss_adc_irq_convert(QM_SS_ADC_0, &xfer) != 0) { - ret = -EIO; - adc_unlock(info); - break; - } - - /* Wait for the interrupt to finish */ - k_sem_take(&info->device_sync_sem, K_FOREVER); - - if (info->state == ADC_STATE_ERROR) { - ret = -EIO; - adc_unlock(info); - break; - } - /* Successful Analog to Digital conversion */ - adc_unlock(info); - } - - return ret; -} -#endif /* CONFIG_ADC_QMSI_POLL */ - -static void adc_qmsi_ss_rx_isr(void *arg) -{ - ARG_UNUSED(arg); - qm_ss_adc_0_isr(NULL); -} - -static void adc_qmsi_ss_err_isr(void *arg) -{ - ARG_UNUSED(arg); - qm_ss_adc_0_error_isr(NULL); -} - -static const struct adc_driver_api api_funcs = { - .enable = adc_qmsi_ss_enable, - .disable = adc_qmsi_ss_disable, - .read = adc_qmsi_ss_read, -}; - -#ifdef CONFIG_DEVICE_POWER_MANAGEMENT -static void adc_qmsi_ss_set_power_state(struct device *dev, - u32_t power_state) -{ - struct adc_info *context = dev->driver_data; - - context->device_power_state = power_state; -} - -static u32_t adc_qmsi_ss_get_power_state(struct device *dev) -{ - struct adc_info *context = dev->driver_data; - - return context->device_power_state; -} - -static int adc_qmsi_ss_suspend_device(struct device *dev) -{ - struct adc_info *context = dev->driver_data; - - qm_ss_adc_save_context(QM_SS_ADC_0, &context->adc_ctx); - - adc_qmsi_ss_set_power_state(dev, DEVICE_PM_SUSPEND_STATE); - - return 0; -} - -static int adc_qmsi_ss_resume_device_from_suspend(struct device *dev) -{ - struct adc_info *context = dev->driver_data; - - qm_ss_adc_restore_context(QM_SS_ADC_0, &context->adc_ctx); - - adc_qmsi_ss_set_power_state(dev, DEVICE_PM_ACTIVE_STATE); - - return 0; -} - -static int adc_qmsi_ss_device_ctrl(struct device *dev, u32_t ctrl_command, - void *context) -{ - if (ctrl_command == DEVICE_PM_SET_POWER_STATE) { - if (*((u32_t *)context) == DEVICE_PM_SUSPEND_STATE) { - return adc_qmsi_ss_suspend_device(dev); - } else if (*((u32_t *)context) == DEVICE_PM_ACTIVE_STATE) { - return adc_qmsi_ss_resume_device_from_suspend(dev); - } - } else if (ctrl_command == DEVICE_PM_GET_POWER_STATE) { - *((u32_t *)context) = adc_qmsi_ss_get_power_state(dev); - } - - return 0; -} -#else -#define adc_qmsi_ss_set_power_state(...) -#endif /* CONFIG_DEVICE_POWER_MANAGEMENT */ -static int adc_qmsi_ss_init(struct device *dev) -{ - struct adc_info *info = dev->driver_data; - - /* Set up config */ - /* Clock cycles between the start of each sample */ - cfg.window = CONFIG_ADC_QMSI_SERIAL_DELAY; - cfg.resolution = CONFIG_ADC_QMSI_SAMPLE_WIDTH; - - qm_ss_adc_set_config(QM_SS_ADC_0, &cfg); - - ss_clk_adc_enable(); - ss_clk_adc_set_div(CONFIG_ADC_QMSI_CLOCK_RATIO); - k_sem_init(&info->device_sync_sem, 0, UINT_MAX); - - k_sem_init(&info->sem, 1, UINT_MAX); - info->state = ADC_STATE_IDLE; - - adc_config_irq(); - - adc_qmsi_ss_set_power_state(dev, DEVICE_PM_ACTIVE_STATE); - - return 0; -} - -static struct adc_info adc_info_dev; - -DEVICE_DEFINE(adc_qmsi_ss, CONFIG_ADC_0_NAME, &adc_qmsi_ss_init, - adc_qmsi_ss_device_ctrl, &adc_info_dev, NULL, POST_KERNEL, - CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &api_funcs); - -static void adc_config_irq(void) -{ - u32_t *scss_intmask; - - IRQ_CONNECT(IRQ_ADC_IRQ, CONFIG_ADC_0_IRQ_PRI, - adc_qmsi_ss_rx_isr, DEVICE_GET(adc_qmsi_ss), 0); - irq_enable(IRQ_ADC_IRQ); - - IRQ_CONNECT(IRQ_ADC_ERR, CONFIG_ADC_0_IRQ_PRI, - adc_qmsi_ss_err_isr, DEVICE_GET(adc_qmsi_ss), 0); - irq_enable(IRQ_ADC_ERR); - - scss_intmask = - (u32_t *)&QM_INTERRUPT_ROUTER->ss_adc_0_error_int_mask; - *scss_intmask &= ~BIT(8); - - scss_intmask = (u32_t *)&QM_INTERRUPT_ROUTER->ss_adc_0_int_mask; - *scss_intmask &= ~BIT(8); -} From c0f499b6694ab703b12d5407831cbb5b12027c6f Mon Sep 17 00:00:00 2001 From: Punit Vara Date: Fri, 17 Aug 2018 14:22:24 +0530 Subject: [PATCH 11/21] dts: arc: Use dts tree for designware driver Get required data from dts tree. Signed-off-by: Punit Vara --- .../soc/quark_se_c1000_ss/Kconfig.defconfig | 2 -- arch/arc/soc/quark_se_c1000_ss/dts.fixup | 6 ++++ .../arc/arduino_101_sss/arduino_101_sss.dts | 4 +++ dts/arc/quark_se_c1000_ss.dtsi | 13 +++++++ dts/bindings/iio/adc/snps,dw-adc.yaml | 35 +++++++++++++++++++ 5 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 dts/bindings/iio/adc/snps,dw-adc.yaml diff --git a/arch/arc/soc/quark_se_c1000_ss/Kconfig.defconfig b/arch/arc/soc/quark_se_c1000_ss/Kconfig.defconfig index 63260aac6976c..21403cf2eba17 100644 --- a/arch/arc/soc/quark_se_c1000_ss/Kconfig.defconfig +++ b/arch/arc/soc/quark_se_c1000_ss/Kconfig.defconfig @@ -128,8 +128,6 @@ endif # I2C if ADC config ADC_DW def_bool y -config ADC_0_IRQ_PRI - default 0 endif if BT_H4 diff --git a/arch/arc/soc/quark_se_c1000_ss/dts.fixup b/arch/arc/soc/quark_se_c1000_ss/dts.fixup index 8d7c477495dc8..3c215e699b85b 100644 --- a/arch/arc/soc/quark_se_c1000_ss/dts.fixup +++ b/arch/arc/soc/quark_se_c1000_ss/dts.fixup @@ -68,4 +68,10 @@ #define CONFIG_GPIO_QMSI_1_IRQ INTEL_QMSI_GPIO_B0800B00_IRQ_0 #define CONFIG_GPIO_QMSI_1_IRQ_PRI INTEL_QMSI_GPIO_B0800B00_IRQ_0_PRIORITY +#define CONFIG_ADC_0_IRQ SNPS_DW_ADC_80015000_IRQ_NORMAL +#define CONFIG_ADC_IRQ_ERR SNPS_DW_ADC_80015000_IRQ_ERROR +#define CONFIG_ADC_0_IRQ_PRI SNPS_DW_ADC_80015000_IRQ_0_PRIORITY +#define CONFIG_ADC_0_NAME SNPS_DW_ADC_80015000_LABEL +#define CONFIG_ADC_0_BASE_ADDRESS SNPS_DW_ADC_80015000_BASE_ADDRESS + /* End of SoC Level DTS fixup file */ diff --git a/boards/arc/arduino_101_sss/arduino_101_sss.dts b/boards/arc/arduino_101_sss/arduino_101_sss.dts index 2f26717eee505..d28c2f8879ec5 100644 --- a/boards/arc/arduino_101_sss/arduino_101_sss.dts +++ b/boards/arc/arduino_101_sss/arduino_101_sss.dts @@ -44,3 +44,7 @@ &i2c3 { status = "ok"; }; + +&adc0 { + status = "ok"; +}; diff --git a/dts/arc/quark_se_c1000_ss.dtsi b/dts/arc/quark_se_c1000_ss.dtsi index a79b0f50416d8..2c74f9bc334b9 100644 --- a/dts/arc/quark_se_c1000_ss.dtsi +++ b/dts/arc/quark_se_c1000_ss.dtsi @@ -176,5 +176,18 @@ status = "disabled"; }; + + adc0: adc@80015000 { + compatible = "snps,dw-adc"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x80015000 0x05>; + interrupts = <19 0>, <18 0>; + interrupt-names = "normal", "error"; + interrupt-parent = <&core_intc>; + label = "ADC_0"; + + status = "disabled"; + }; }; }; diff --git a/dts/bindings/iio/adc/snps,dw-adc.yaml b/dts/bindings/iio/adc/snps,dw-adc.yaml new file mode 100644 index 0000000000000..ea34c5eeb6a03 --- /dev/null +++ b/dts/bindings/iio/adc/snps,dw-adc.yaml @@ -0,0 +1,35 @@ +# +# Copyright (c) 2018 Intel Corporation. +# +# SPDX-License-Identifier: Apache-2.0 +# +--- +title: DesignWare ADC +id: snps,dw-adc +version: 0.1 + +description: > + This is a representation of the DesignWare ADC node + +inherits: + !include adc.yaml + +properties: + compatible: + type: string + category: required + description: compatible strings + constraint: "snps,dw-adc" + + reg: + type: array + description: mmio register space + generation: define + category: required + + interrupts: + type: array + category: required + description: required interrupts + generation: define +... From 49d26d76cb9f804e99fb6cae0a32cdd1c5a3f459 Mon Sep 17 00:00:00 2001 From: Punit Vara Date: Fri, 24 Aug 2018 12:23:55 +0530 Subject: [PATCH 12/21] boards: quark_se_c1000_ss_devboard: Enable ADC node Enable ADC node in dts. Signed-off-by: Punit Vara --- .../quark_se_c1000_ss_devboard/quark_se_c1000_ss_devboard.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/boards/arc/quark_se_c1000_ss_devboard/quark_se_c1000_ss_devboard.dts b/boards/arc/quark_se_c1000_ss_devboard/quark_se_c1000_ss_devboard.dts index 91ce23be886e3..1bfa1a71956f5 100644 --- a/boards/arc/quark_se_c1000_ss_devboard/quark_se_c1000_ss_devboard.dts +++ b/boards/arc/quark_se_c1000_ss_devboard/quark_se_c1000_ss_devboard.dts @@ -44,3 +44,7 @@ &i2c3 { status = "ok"; }; + +&adc0 { + status = "ok"; +}; From 0c35d44f3cd4caf1c79cdb681ad6ae209d032eb8 Mon Sep 17 00:00:00 2001 From: Punit Vara Date: Fri, 17 Aug 2018 18:31:51 +0530 Subject: [PATCH 13/21] drivers: adc: Update new ADC APIs Replace new ADC apis for designware driver Signed-off-by: Punit Vara --- drivers/adc/adc_dw.c | 417 ++++++++++++++++++++++--------------------- drivers/adc/adc_dw.h | 13 +- 2 files changed, 223 insertions(+), 207 deletions(-) diff --git a/drivers/adc/adc_dw.c b/drivers/adc/adc_dw.c index 295aca1a488fa..f2e3212428460 100644 --- a/drivers/adc/adc_dw.c +++ b/drivers/adc/adc_dw.c @@ -15,9 +15,14 @@ #include #include #include + +#define ADC_CONTEXT_USES_KERNEL_TIMER +#include "adc_context.h" #include "adc_dw.h" +#include #define ADC_CLOCK_GATE (1 << 31) +#define ADC_DEEP_POWER_DOWN 0x01 #define ADC_POWER_DOWN 0x01 #define ADC_STANDBY 0x02 #define ADC_NORMAL_WITH_CALIB 0x03 @@ -51,6 +56,17 @@ #endif static void adc_config_irq(void); + +struct adc_info adc_info_dev = { + ADC_CONTEXT_INIT_TIMER(adc_info_dev, ctx), + ADC_CONTEXT_INIT_LOCK(adc_info_dev, ctx), + ADC_CONTEXT_INIT_SYNC(adc_info_dev, ctx), + .state = ADC_STATE_IDLE, +#ifdef CONFIG_ADC_DW_CALIBRATION + .calibration_value = ADC_NONE_CALIBRATION, +#endif +}; + #ifdef CONFIG_ADC_DW_CALIBRATION static void calibration_command(u8_t command) { @@ -66,7 +82,7 @@ static void calibration_command(u8_t command) /*Poll waiting for command*/ do { reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_SLV0); - } while ((reg_value & 0x10) == 0); + } while ((reg_value & BIT(4)) == 0); /*Clear Calibration Request*/ reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_MST0); @@ -83,7 +99,7 @@ static void adc_goto_normal_mode(struct device *dev) reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_SLV0); - if (((reg_value & 0xE) >> 1) != ADC_NORMAL_WITH_CALIB) { + if ((reg_value & ADC_MODE_MASK) != ADC_NORMAL_WITH_CALIB) { state = irq_lock(); /*Request Normal With Calibration Mode*/ @@ -96,7 +112,7 @@ static void adc_goto_normal_mode(struct device *dev) /*Poll waiting for normal mode*/ do { reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_SLV0); - } while ((reg_value & 0x1) == 0); + } while ((reg_value & BIT(3)) == 0); if (info->calibration_value == ADC_NONE_CALIBRATION) { /*Reset Calibration*/ @@ -123,10 +139,9 @@ static void adc_goto_normal_mode(struct device *dev) u32_t state; ARG_UNUSED(dev); - reg_value = sys_in32( - PERIPH_ADDR_BASE_CREG_SLV0 + SLV_OBSR); + reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_SLV0); - if (((reg_value & 0xE) >> 1) == ADC_NORMAL_WO_CALIB) { + if ((reg_value & ADC_MODE_MASK) == ADC_NORMAL_WO_CALIB) { state = irq_lock(); /*Request Power Down*/ reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_MST0); @@ -139,7 +154,7 @@ static void adc_goto_normal_mode(struct device *dev) do { reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_SLV0); - } while ((reg_value & 0x1) == 0); + } while ((reg_value & BIT(3)) == 0); } /*Request Normal With Calibration Mode*/ @@ -153,31 +168,39 @@ static void adc_goto_normal_mode(struct device *dev) /*Poll waiting for normal mode*/ do { reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_SLV0); - } while ((reg_value & 0x1) == 0); + } while ((reg_value & BIT(3)) == 0); } #endif -static void adc_goto_deep_power_down(void) +static int set_resolution(struct device *dev, + const struct adc_sequence *sequence) { - u32_t reg_value; - u32_t state; - - reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_SLV0); - if ((reg_value & 0xE >> 1) != 0) { - state = irq_lock(); - - reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_MST0); + u32_t tmp_val; + const struct adc_config *config = dev->config->config_info; + u32_t adc_base = config->reg_base; - reg_value &= ~(ADC_MODE_MASK); + tmp_val = sys_in32(adc_base + ADC_SET); + tmp_val &= ~FIVE_BITS_SET; + + switch (sequence->resolution) { + case 6: + break; + case 8: + tmp_val |= 1 & FIVE_BITS_SET; + break; + case 10: + tmp_val |= 2 & FIVE_BITS_SET; + break; + case 12: + tmp_val |= 3 & FIVE_BITS_SET; + break; + default: + return -EINVAL; + } - reg_value |= 0 | ADC_CLOCK_GATE; - sys_out32(reg_value, PERIPH_ADDR_BASE_CREG_MST0); + sys_out32(tmp_val, adc_base + ADC_SET); - irq_unlock(state); - do { - reg_value = sys_in32(PERIPH_ADDR_BASE_CREG_SLV0); - } while ((reg_value & 0x1) == 0); - } + return 0; } static void adc_dw_enable(struct device *dev) @@ -200,43 +223,125 @@ static void adc_dw_enable(struct device *dev) info->state = ADC_STATE_IDLE; } -static void adc_dw_disable(struct device *dev) +/* Implementation of the ADC driver API function: adc_channel_setup. */ +static int adc_dw_channel_setup(struct device *dev, + const struct adc_channel_cfg *channel_cfg) { - u32_t saved; + u8_t channel_id = channel_cfg->channel_id; struct adc_info *info = dev->driver_data; - const struct adc_config *config = dev->config->config_info; - u32_t adc_base = config->reg_base; - sys_out32(ADC_INT_DSB|ENABLE_ADC, adc_base + ADC_CTRL); - adc_goto_deep_power_down(); - sys_out32(ADC_INT_DSB|ADC_SEQ_PTR_RST, adc_base + ADC_CTRL); + if (channel_id >= DW_CHANNEL_COUNT) { + SYS_LOG_ERR("Invalid channel id"); + return -EINVAL; + } - saved = irq_lock(); + if (channel_cfg->gain != ADC_GAIN_1) { + SYS_LOG_ERR("Invalid channel gain"); + return -EINVAL; + } - sys_out32(sys_in32(adc_base + ADC_SET)|ADC_FLUSH_RX, adc_base + ADC_SET); - irq_unlock(saved); + if (channel_cfg->reference != ADC_REF_INTERNAL) { + SYS_LOG_ERR("Invalid channel reference"); + return -EINVAL; + } - info->state = ADC_STATE_DISABLED; + if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) { + SYS_LOG_ERR("Invalid channel acquisition time"); + return -EINVAL; + } + + if (info->state != ADC_STATE_IDLE) { + SYS_LOG_ERR("ADC is busy or in error state"); + return -EAGAIN; + } + + info->active_channels |= 1 << channel_id; + return 0; } -static int adc_dw_read_request(struct device *dev, struct adc_seq_table *seq_tbl) +static int adc_dw_read_request(struct device *dev, + const struct adc_sequence *seq_tbl) { - u32_t i; - u32_t ctrl; - u32_t tmp_val; - u32_t num_iters; - u32_t saved; - struct adc_seq_entry *entry; struct adc_info *info = dev->driver_data; - const struct adc_config *config = dev->config->config_info; - u32_t adc_base = config->reg_base; + int error = 0; + u32_t saved; - if (info->state != ADC_STATE_IDLE) { - return 1; + /*hardware requires minimum 10 us delay between consecutive samples*/ + if (seq_tbl->options && + seq_tbl->options->extra_samplings && + seq_tbl->options->interval_us < 10) { + return -EINVAL; + } + + info->channels = seq_tbl->channels & info->active_channels; + + if (seq_tbl->channels != info->channels) { + return -EINVAL; + } + + error = set_resolution(dev, seq_tbl); + if (error) { + return error; } saved = irq_lock(); - info->seq_size = seq_tbl->num_entries; + info->entries = seq_tbl; + info->buffer = (u16_t *)seq_tbl->buffer; + + if (seq_tbl->options) { + info->seq_size = seq_tbl->options->extra_samplings + 1; + } else { + info->seq_size = 1; + } + + info->state = ADC_STATE_SAMPLING; + irq_unlock(saved); + + adc_context_start_read(&info->ctx, seq_tbl); + error = adc_context_wait_for_completion(&info->ctx); + adc_context_release(&info->ctx, error); + + if (info->state == ADC_STATE_ERROR) { + info->state = ADC_STATE_IDLE; + return -EIO; + } + + return 0; +} + +static int adc_dw_read(struct device *dev, const struct adc_sequence *seq_tbl) +{ + struct adc_info *info = dev->driver_data; + int ret; + + adc_context_lock(&info->ctx, false, NULL); + + ret = adc_dw_read_request(dev, seq_tbl); + return ret; +} + +#ifdef CONFIG_ADC_ASYNC +/* Implementation of the ADC driver API function: adc_read_async. */ +static int adc_dw_read_async(struct device *dev, + const struct adc_sequence *sequence, + struct k_poll_signal *async) +{ + struct adc_info *info = dev->driver_data; + + adc_context_lock(&info->ctx, true, async); + return adc_dw_read_request(dev, sequence); +} +#endif + +static void adc_dw_start_conversion(struct device *dev) +{ + struct adc_info *info = dev->driver_data; + const struct adc_config *config = info->dev->config->config_info; + const struct adc_sequence *entry = info->ctx.sequence; + u32_t adc_base = config->reg_base; + u32_t ctrl, tmp_val, interval_us = 0; + + info->channel_id = find_lsb_set(info->channels) - 1; ctrl = sys_in32(adc_base + ADC_CTRL); ctrl |= ADC_SEQ_PTR_RST; @@ -244,72 +349,41 @@ static int adc_dw_read_request(struct device *dev, struct adc_seq_table *seq_tbl tmp_val = sys_in32(adc_base + ADC_SET); tmp_val &= ADC_SEQ_SIZE_SET_MASK; - tmp_val |= (((seq_tbl->num_entries - 1) & SIX_BITS_SET) - << SEQ_ENTRIES_POS); - tmp_val |= ((seq_tbl->num_entries - 1) << THRESHOLD_POS); sys_out32(tmp_val, adc_base + ADC_SET); - irq_unlock(saved); - - num_iters = seq_tbl->num_entries/2; - - for (i = 0, entry = seq_tbl->entries; - i < num_iters; i++, entry += 2) { - tmp_val = ((entry[1].sampling_delay & ELEVEN_BITS_SET) - << SEQ_DELAY_ODD_POS); - tmp_val |= ((entry[1].channel_id & FIVE_BITS_SET) - << SEQ_MUX_ODD_POS); - tmp_val |= ((entry[0].sampling_delay & ELEVEN_BITS_SET) - << SEQ_DELAY_EVEN_POS); - tmp_val |= (entry[0].channel_id & FIVE_BITS_SET); - sys_out32(tmp_val, adc_base + ADC_SEQ); + if (entry->options) { + interval_us = entry->options->interval_us; } - - if ((seq_tbl->num_entries % 2) != 0) { - tmp_val = ((entry[0].sampling_delay & ELEVEN_BITS_SET) + tmp_val = ((interval_us & ELEVEN_BITS_SET) << SEQ_DELAY_EVEN_POS); - tmp_val |= (entry[0].channel_id & FIVE_BITS_SET); - sys_out32(tmp_val, adc_base + ADC_SEQ); - } + tmp_val |= (info->channel_id & FIVE_BITS_SET); + sys_out32(tmp_val, adc_base + ADC_SEQ); sys_out32(ctrl | ADC_SEQ_PTR_RST, adc_base + ADC_CTRL); - info->entries = seq_tbl->entries; -#ifdef CONFIG_ADC_DW_REPETITIVE - memset(info->index, 0, seq_tbl->num_entries); -#endif - info->state = ADC_STATE_SAMPLING; sys_out32(START_ADC_SEQ, adc_base + ADC_CTRL); +} - k_sem_take(&info->device_sync_sem, K_FOREVER); +static void adc_context_start_sampling(struct adc_context *ctx) +{ + struct adc_info *info = CONTAINER_OF(ctx, struct adc_info, ctx); - if (info->state == ADC_STATE_ERROR) { - info->state = ADC_STATE_IDLE; - return -EIO; - } + info->channels = ctx->sequence->channels; - return 0; + adc_dw_start_conversion(info->dev); } -static int adc_dw_read(struct device *dev, struct adc_seq_table *seq_tbl) +static void adc_context_update_buffer_pointer(struct adc_context *ctx, + bool repeat) { - struct adc_info *info = dev->driver_data; + struct adc_info *info = CONTAINER_OF(ctx, struct adc_info, ctx); + const struct adc_sequence *entry = ctx->sequence; -#ifdef CONFIG_ADC_DW_DUMMY_CONVERSION - if (info->dummy_conversion == ADC_NONE_DUMMY) { - adc_dw_read_request(dev, seq_tbl); - info->dummy_conversion = ADC_DONE_DUMMY; + if (repeat) { + info->buffer = (u16_t *)entry->buffer; } -#endif - return adc_dw_read_request(dev, seq_tbl); } -static struct adc_driver_api api_funcs = { - .enable = adc_dw_enable, - .disable = adc_dw_disable, - .read = adc_dw_read, -}; - int adc_dw_init(struct device *dev) { u32_t tmp_val; @@ -322,12 +396,11 @@ int adc_dw_init(struct device *dev) tmp_val = sys_in32(adc_base + ADC_SET); tmp_val &= ADC_CONFIG_SET_MASK; - val = (config->sample_width) & FIVE_BITS_SET; - val &= ~(1 << INPUT_MODE_POS); - val |= ((config->capture_mode & ONE_BIT_SET) << CAPTURE_MODE_POS); + val = ((config->capture_mode & ONE_BIT_SET) << CAPTURE_MODE_POS); val |= ((config->out_mode & ONE_BIT_SET) << OUTPUT_MODE_POS); val |= ((config->serial_dly & FIVE_BITS_SET) << SERIAL_DELAY_POS); val |= ((config->seq_mode & ONE_BIT_SET) << SEQUENCE_MODE_POS); + val &= ~(1 << INPUT_MODE_POS); sys_out32(tmp_val|val, adc_base + ADC_SET); sys_out32(config->clock_ratio & ADC_CLK_RATIO_MASK, @@ -338,154 +411,91 @@ int adc_dw_init(struct device *dev) config->config_func(); - k_sem_init(&info->device_sync_sem, 0, UINT_MAX); - int_unmask(config->reg_irq_mask); int_unmask(config->reg_err_mask); + info->dev = dev; + + adc_dw_enable(dev); + adc_context_unlock_unconditionally(&info->ctx); return 0; } -#ifdef CONFIG_ADC_DW_SINGLESHOT static void adc_dw_rx_isr(void *arg) { struct device *dev = (struct device *)arg; - struct device_config *dev_config = dev->config; - const struct adc_config *config = dev_config->config_info; struct adc_info *info = dev->driver_data; + const struct adc_config *config = dev->config->config_info; u32_t adc_base = config->reg_base; - struct adc_seq_entry *entries = info->entries; u32_t reg_val; - u32_t seq_index; - for (seq_index = 0; seq_index < info->seq_size; seq_index++) { - u32_t *adc_buffer; - - reg_val = sys_in32(adc_base + ADC_SET); - sys_out32(reg_val|ADC_POP_SAMPLE, adc_base + ADC_SET); - adc_buffer = (u32_t *)entries[seq_index].buffer; - *adc_buffer = sys_in32(adc_base + ADC_SAMPLE); - } + reg_val = sys_in32(adc_base + ADC_SET); + sys_out32(reg_val|ADC_POP_SAMPLE, adc_base + ADC_SET); + *info->buffer++ = sys_in32(adc_base + ADC_SAMPLE); /*Resume ADC state to continue new conversions*/ sys_out32(RESUME_ADC_CAPTURE, adc_base + ADC_CTRL); reg_val = sys_in32(adc_base + ADC_SET); sys_out32(reg_val | ADC_FLUSH_RX, adc_base + ADC_SET); - info->state = ADC_STATE_IDLE; /*Clear data A register*/ reg_val = sys_in32(adc_base + ADC_CTRL); sys_out32(reg_val | ADC_CLR_DATA_A, adc_base + ADC_CTRL); - k_sem_give(&info->device_sync_sem); -} -#else /*CONFIG_ADC_DW_REPETITIVE*/ -static void adc_dw_rx_isr(void *arg) -{ - struct device *dev = (struct device *)arg; - struct device_config *dev_config = dev->config; - const struct adc_config *config = dev_config->config_info; - struct adc_info *info = dev->driver_data; - u32_t adc_base = config->reg_base; - struct adc_seq_entry *entries = info->entries; - u32_t reg_val; - u32_t sequence_index; - u8_t full_buffer_flag = 0; - - for (sequence_index = 0; sequence_index < info->seq_size; sequence_index++) { - u32_t *adc_buffer; - u32_t repetitive_index; - - repetitive_index = info->index[sequence_index]; - /*API array is 8 bits array but ADC reads blocks of 32 bits with every sample.*/ - if (repetitive_index >= (entries[sequence_index].buffer_length >> 2)) { - full_buffer_flag = 1; - continue; - } - - reg_val = sys_in32(adc_base + ADC_SET); - sys_out32(reg_val|ADC_POP_SAMPLE, adc_base + ADC_SET); - adc_buffer = (u32_t *)entries[sequence_index].buffer; - adc_buffer[repetitive_index] = sys_in32(adc_base + ADC_SAMPLE); - repetitive_index++; - info->index[sequence_index] = repetitive_index; - } - - if (full_buffer_flag == 1) { - /*Resume ADC state to continue new conversions*/ - sys_out32(RESUME_ADC_CAPTURE, adc_base + ADC_CTRL); - reg_val = sys_in32(adc_base + ADC_SET); - sys_out32(reg_val | ADC_FLUSH_RX, adc_base + ADC_SET); - info->state = ADC_STATE_IDLE; - /*Clear data A register*/ - reg_val = sys_in32(adc_base + ADC_CTRL); - sys_out32(reg_val | ADC_CLR_DATA_A, adc_base + ADC_CTRL); + info->state = ADC_STATE_IDLE; + info->channels &= ~BIT(info->channel_id); - k_sem_give(&info->device_sync_sem); - return; + if (info->channels) { + adc_dw_start_conversion(dev); + } else { + adc_context_on_sampling_done(&info->ctx, dev); } - - /*Clear data A register*/ - reg_val = sys_in32(adc_base + ADC_CTRL); - sys_out32(reg_val | ADC_CLR_DATA_A, adc_base + ADC_CTRL); } -#endif - static void adc_dw_err_isr(void *arg) { struct device *dev = (struct device *) arg; - const struct adc_config *config = dev->config->config_info; - struct adc_info *info = dev->driver_data; + const struct adc_config *config = dev->config->config_info; + struct adc_info *info = dev->driver_data; u32_t adc_base = config->reg_base; u32_t reg_val = sys_in32(adc_base + ADC_SET); - sys_out32(RESUME_ADC_CAPTURE, adc_base + ADC_CTRL); sys_out32(reg_val | ADC_FLUSH_RX, adc_base + ADC_CTRL); sys_out32(FLUSH_ADC_ERRORS, adc_base + ADC_CTRL); info->state = ADC_STATE_ERROR; - - k_sem_give(&info->device_sync_sem); + adc_context_on_sampling_done(&info->ctx, dev); } -#ifdef CONFIG_ADC_DW - -struct adc_info adc_info_dev = { - .state = ADC_STATE_IDLE, -#ifdef CONFIG_ADC_DW_CALIBRATION - .calibration_value = ADC_NONE_CALIBRATION, +static const struct adc_driver_api api_funcs = { + .channel_setup = adc_dw_channel_setup, + .read = adc_dw_read, +#ifdef CONFIG_ADC_ASYNC + .read_async = adc_dw_read_async, #endif -#ifdef CONFIG_ADC_DW_DUMMY_CONVERSION - .dummy_conversion = ADC_NONE_DUMMY, -#endif - }; +}; -static struct adc_config adc_config_dev = { - .reg_base = PERIPH_ADDR_BASE_ADC, - .reg_irq_mask = SCSS_REGISTER_BASE + INT_SS_ADC_IRQ_MASK, - .reg_err_mask = SCSS_REGISTER_BASE + INT_SS_ADC_ERR_MASK, +const static struct adc_config adc_config_dev = { + .reg_base = CONFIG_ADC_0_BASE_ADDRESS, + .reg_irq_mask = SCSS_REGISTER_BASE + INT_SS_ADC_IRQ_MASK, + .reg_err_mask = SCSS_REGISTER_BASE + INT_SS_ADC_ERR_MASK, #ifdef CONFIG_ADC_DW_SERIAL - .out_mode = 0, + .out_mode = 0, #elif CONFIG_ADC_DW_PARALLEL - .out_mode = 1, -#endif -#ifdef CONFIG_ADC_DW_SINGLESHOT - .seq_mode = 0, -#elif CONFIG_ADC_DW_REPETITIVE - .seq_mode = 1, + .out_mode = 1, #endif + .seq_mode = 0, + #ifdef CONFIG_ADC_DW_RISING_EDGE - .capture_mode = 0, + .capture_mode = 0, #elif CONFIG_ADC_DW_FALLING_EDGE - .capture_mode = 1, + .capture_mode = 1, #endif - .sample_width = CONFIG_ADC_DW_SAMPLE_WIDTH, - .clock_ratio = CONFIG_ADC_DW_CLOCK_RATIO, - .serial_dly = CONFIG_ADC_DW_SERIAL_DELAY, - .config_func = adc_config_irq, - }; + .clock_ratio = CONFIG_ADC_DW_CLOCK_RATIO, + .serial_dly = CONFIG_ADC_DW_SERIAL_DELAY, + .config_func = adc_config_irq, +}; DEVICE_AND_API_INIT(adc_dw, CONFIG_ADC_0_NAME, &adc_dw_init, &adc_info_dev, &adc_config_dev, @@ -494,12 +504,11 @@ DEVICE_AND_API_INIT(adc_dw, CONFIG_ADC_0_NAME, &adc_dw_init, static void adc_config_irq(void) { - IRQ_CONNECT(IRQ_ADC_IRQ, CONFIG_ADC_0_IRQ_PRI, adc_dw_rx_isr, + IRQ_CONNECT(CONFIG_ADC_0_IRQ, CONFIG_ADC_0_IRQ_PRI, adc_dw_rx_isr, DEVICE_GET(adc_dw), 0); - irq_enable(IRQ_ADC_IRQ); + irq_enable(CONFIG_ADC_0_IRQ); - IRQ_CONNECT(IRQ_ADC_ERR, CONFIG_ADC_0_IRQ_PRI, + IRQ_CONNECT(CONFIG_ADC_IRQ_ERR, CONFIG_ADC_0_IRQ_PRI, adc_dw_err_isr, DEVICE_GET(adc_dw), 0); - irq_enable(IRQ_ADC_ERR); + irq_enable(CONFIG_ADC_IRQ_ERR); } -#endif diff --git a/drivers/adc/adc_dw.h b/drivers/adc/adc_dw.h index cdd5e2a5e04e5..797755da73d4e 100644 --- a/drivers/adc/adc_dw.h +++ b/drivers/adc/adc_dw.h @@ -135,6 +135,8 @@ extern "C" { #define RESUME_ADC_CAPTURE (ADC_INT_DSB|ADC_CLK_ENABLE|ADC_SEQ_PTR_RST) #define FLUSH_ADC_ERRORS (ADC_INT_DSB|ADC_CLK_ENABLE|ADC_CLR_OVERFLOW|ADC_CLR_UNDRFLOW) +#define DW_CHANNEL_COUNT 19 + /** mV = 3.3V*/ #define ADC_VREF 3300 @@ -188,13 +190,19 @@ struct adc_config { * during driver execution. */ struct adc_info { - struct k_sem device_sync_sem; + struct device *dev; + struct adc_context ctx; + u16_t *buffer; + u32_t active_channels; + u32_t channels; + u32_t channel_id; + #ifdef CONFIG_ADC_DW_REPETITIVE /**Current reception buffer index*/ u8_t index[BUFS_NUM]; #endif /**Sequence entries' array*/ - struct adc_seq_entry *entries; + const struct adc_sequence *entries; /**State of execution of the driver*/ u8_t state; /**Sequence size*/ @@ -209,7 +217,6 @@ struct adc_info { }; - /** * * @brief ADC Initialization function. From f211236c8a4347d61f330ea36e2449aff288d203 Mon Sep 17 00:00:00 2001 From: Punit Vara Date: Fri, 24 Aug 2018 10:36:40 +0530 Subject: [PATCH 14/21] drivers: Kconfig.dw: Remove unnecessary Kconfig Remove Kconfig which are replaced by dts and unnecessary macros which is not useful anymore. Signed-off-by: Punit Vara --- drivers/adc/Kconfig.dw | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/drivers/adc/Kconfig.dw b/drivers/adc/Kconfig.dw index 370ef7e575841..1c235d91f3fb6 100644 --- a/drivers/adc/Kconfig.dw +++ b/drivers/adc/Kconfig.dw @@ -25,15 +25,6 @@ config ADC_DW_CALIBRATION If disabled, the ADC will require the application/system-integrator to provide a calibration method. -config ADC_DW_DUMMY_CONVERSION - bool "Enable dummy conversion" - default y - help - After awaking from low power state a dummy - conversion must be performed and discarded. - If disabled the user will have to discard the first - sample after a resume from a low power state. - choice prompt "Output Mode" default ADC_DW_SERIAL @@ -48,20 +39,6 @@ config ADC_DW_PARALLEL endchoice -choice - prompt "Sequence Mode" - default ADC_DW_SINGLESHOT - help - ADC sequence mode - single run/repetitive - -config ADC_DW_SINGLESHOT - bool "Single Ended" - -config ADC_DW_REPETITIVE - bool "Differential" - -endchoice - choice prompt "Capture Mode" default ADC_DW_RISING_EDGE @@ -77,20 +54,6 @@ config ADC_DW_FALLING_EDGE endchoice -config ADC_DW_SAMPLE_WIDTH - int "Sample Width" - default 31 - help - Defines ADC device data sample width (resolution): - - - 0 = 6 bits resolution - - - 1 = 8 bits resolution - - - 2 = 10 bits resolution - - - 3 = 12 bits resolution - config ADC_DW_SERIAL_DELAY int "Serial Delay" default 1 From 9c4852adc7f2419e3e0e8777003e22179df5b74e Mon Sep 17 00:00:00 2001 From: Punit Vara Date: Tue, 14 Aug 2018 14:54:57 +0530 Subject: [PATCH 15/21] drivers: grove: Modify light sensor Replace old ADC apis with new ones. Signed-off-by: Punit Vara --- drivers/grove/light_sensor.c | 39 ++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/drivers/grove/light_sensor.c b/drivers/grove/light_sensor.c index 1c176aaead716..3e39a0f0a6dad 100644 --- a/drivers/grove/light_sensor.c +++ b/drivers/grove/light_sensor.c @@ -16,16 +16,26 @@ struct gls_data { struct device *adc; - struct adc_seq_entry sample; - struct adc_seq_table adc_table; + struct adc_channel_cfg ch10_cfg; u8_t adc_buffer[4]; }; +static struct adc_sequence_options options = { + .interval_us = 12, + .extra_samplings = 0, +}; + +static struct adc_sequence adc_table = { + .options = &options, +}; + +#define ADC_RESOLUTION 8 + static int gls_sample_fetch(struct device *dev, enum sensor_channel chan) { struct gls_data *drv_data = dev->driver_data; - return adc_read(drv_data->adc, &drv_data->adc_table); + return adc_read(drv_data->adc, &adc_table); } static int gls_channel_get(struct device *dev, @@ -44,7 +54,7 @@ static int gls_channel_get(struct device *dev, /* * The formula for converting the analog value to lux is taken from * the UPM project: - * https://github.com/intel-iot-devkit/upm/blob/master/src/grove/grove.cxx#L161 + * https://github.com/intel-iot-devkit/upm/blob/master/src/grove/grove.cxx#L161 */ ldr_val = (1023.0 - analog_val) * 10.0 / analog_val; dval = 10000.0 / pow(ldr_val * 15.0, 4.0/3.0); @@ -71,15 +81,18 @@ static int gls_init(struct device *dev) return -EINVAL; } - drv_data->sample.sampling_delay = 12; - drv_data->sample.channel_id = CONFIG_GROVE_LIGHT_SENSOR_ADC_CHANNEL; - drv_data->sample.buffer = drv_data->adc_buffer; - drv_data->sample.buffer_length = 4; - - drv_data->adc_table.entries = &drv_data->sample; - drv_data->adc_table.num_entries = 1; - - adc_enable(drv_data->adc); + /*Change following parameters according to board if necessary*/ + drv_data->ch10_cfg.channel_id = CONFIG_GROVE_LIGHT_SENSOR_ADC_CHANNEL; + drv_data->ch10_cfg.differential = false; + drv_data->ch10_cfg.gain = ADC_GAIN_1, + drv_data->ch10_cfg.reference = ADC_REF_INTERNAL; + drv_data->ch10_cfg.acquisition_time = ADC_ACQ_TIME_DEFAULT; + adc_table.buffer = drv_data->adc_buffer; + adc_table.channels = BIT(CONFIG_GROVE_LIGHT_SENSOR_ADC_CHANNEL); + adc_table.resolution = ADC_RESOLUTION; + adc_table.buffer_size = 4; + + adc_channel_setup(drv_data->adc, &drv_data->ch10_cfg); dev->driver_api = &gls_api; From 21f2efc0e4ed93ab312ad7356153b660a60ed8f8 Mon Sep 17 00:00:00 2001 From: Punit Vara Date: Wed, 15 Aug 2018 09:49:50 +0530 Subject: [PATCH 16/21] drivers: grove: Update temperature driver Replace old ADC driver APIs with new ones. Signed-off-by: Punit Vara --- drivers/grove/temperature_sensor.c | 38 ++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/drivers/grove/temperature_sensor.c b/drivers/grove/temperature_sensor.c index 919bd6a9872ec..574d8f20e577c 100644 --- a/drivers/grove/temperature_sensor.c +++ b/drivers/grove/temperature_sensor.c @@ -21,18 +21,28 @@ #define B_CONST 4250 #endif +#define ADC_RESOLUTION 10 + struct gts_data { struct device *adc; - struct adc_seq_entry sample; - struct adc_seq_table adc_table; + struct adc_channel_cfg ch10_cfg; u8_t adc_buffer[4]; }; +static struct adc_sequence_options options = { + .extra_samplings = 0, + .interval_us = 15, +}; + +static struct adc_sequence adc_table = { + .options = &options, +}; + static int gts_sample_fetch(struct device *dev, enum sensor_channel chan) { struct gts_data *drv_data = dev->driver_data; - return adc_read(drv_data->adc, &drv_data->adc_table); + return adc_read(drv_data->adc, &adc_table); } static int gts_channel_get(struct device *dev, @@ -78,16 +88,18 @@ static int gts_init(struct device *dev) return -EINVAL; } - drv_data->sample.sampling_delay = 12; - drv_data->sample.channel_id = - CONFIG_GROVE_TEMPERATURE_SENSOR_ADC_CHANNEL; - drv_data->sample.buffer = drv_data->adc_buffer; - drv_data->sample.buffer_length = 4; - - drv_data->adc_table.entries = &drv_data->sample; - drv_data->adc_table.num_entries = 1; - - adc_enable(drv_data->adc); + /*Change following parameters according to board if necessary*/ + drv_data->ch10_cfg.channel_id = CONFIG_GROVE_TEMPERATURE_SENSOR_ADC_CHANNEL; + drv_data->ch10_cfg.differential = false; + drv_data->ch10_cfg.gain = ADC_GAIN_1, + drv_data->ch10_cfg.reference = ADC_REF_INTERNAL; + drv_data->ch10_cfg.acquisition_time = ADC_ACQ_TIME_DEFAULT; + adc_table.buffer = drv_data->adc_buffer; + adc_table.resolution = ADC_RESOLUTION; + adc_table.buffer_size = 4; + adc_table.channels = BIT(CONFIG_GROVE_TEMPERATURE_SENSOR_ADC_CHANNEL); + + adc_channel_setup(drv_data->adc, &drv_data->ch10_cfg); dev->driver_api = >s_api; From 92dc94e1dd21a2053dd27524c7644b4e5516f8f6 Mon Sep 17 00:00:00 2001 From: Punit Vara Date: Fri, 24 Aug 2018 10:25:19 +0530 Subject: [PATCH 17/21] tests: adc_api: Add ARC related parameters for ADC Add ARC related parameters and modified test case to work this test case on arc sensor subsystem. Signed-off-by: Punit Vara --- tests/drivers/adc/adc_api/src/test_adc.c | 37 ++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/drivers/adc/adc_api/src/test_adc.c b/tests/drivers/adc/adc_api/src/test_adc.c index 48316f26f5b6e..cc88e3e7593ce 100644 --- a/tests/drivers/adc/adc_api/src/test_adc.c +++ b/tests/drivers/adc/adc_api/src/test_adc.c @@ -104,6 +104,16 @@ #define ADC_1ST_CHANNEL_ID 0 #define ADC_1ST_CHANNEL_INPUT 0 +#elif defined(CONFIG_BOARD_QUARK_SE_C1000_DEVBOARD_SS) || \ + defined(CONFIG_BOARD_ARDUINO_101_SSS) +#define ADC_DEVICE_NAME CONFIG_ADC_0_NAME +#define ADC_RESOLUTION 10 +#define ADC_GAIN ADC_GAIN_1 +#define ADC_REFERENCE ADC_REF_INTERNAL +#define ADC_ACQUISITION_TIME ADC_ACQ_TIME_DEFAULT +#define ADC_1ST_CHANNEL_ID 10 +#define ADC_2ND_CHANNEL_ID 11 + #else #error "Unsupported board." #endif @@ -180,7 +190,19 @@ static void check_samples(int expected_count) static int test_task_one_channel(void) { int ret; + +#if defined(CONFIG_BOARD_QUARK_SE_C1000_DEVBOARD_SS) || \ + defined(CONFIG_BOARD_ARDUINO_101_SSS) + const struct adc_sequence_options options = { + .interval_us = 10, + .extra_samplings = 0, + }; +#endif const struct adc_sequence sequence = { +#if defined(CONFIG_BOARD_QUARK_SE_C1000_DEVBOARD_SS) || \ + defined(CONFIG_BOARD_ARDUINO_101_SSS) + .options = &options, +#endif .channels = BIT(ADC_1ST_CHANNEL_ID), .buffer = m_sample_buffer, .buffer_size = sizeof(m_sample_buffer), @@ -212,7 +234,19 @@ void test_adc_sample_one_channel(void) static int test_task_two_channels(void) { int ret; + +#if defined(CONFIG_BOARD_QUARK_SE_C1000_DEVBOARD_SS) || \ + defined(CONFIG_BOARD_ARDUINO_101_SSS) + const struct adc_sequence_options options = { + .interval_us = 30, + .extra_samplings = 0, + }; +#endif const struct adc_sequence sequence = { +#if defined(CONFIG_BOARD_QUARK_SE_C1000_DEVBOARD_SS) || \ + defined(CONFIG_BOARD_ARDUINO_101_SSS) + .options = &options, +#endif .channels = BIT(ADC_1ST_CHANNEL_ID) | BIT(ADC_2ND_CHANNEL_ID), .buffer = m_sample_buffer, @@ -234,6 +268,7 @@ static int test_task_two_channels(void) return TC_PASS; } #endif /* defined(ADC_2ND_CHANNEL_ID) */ + void test_adc_sample_two_channels(void) { #if defined(ADC_2ND_CHANNEL_ID) @@ -253,6 +288,7 @@ static int test_task_asynchronous_call(void) int ret; const struct adc_sequence_options options = { .extra_samplings = 4, + .interval_us = 10, }; const struct adc_sequence sequence = { .options = &options, @@ -392,6 +428,7 @@ static int test_task_repeated_samplings(void) * Hence, the third sampling will not take place. */ .extra_samplings = 2, + .interval_us = 15, }; const struct adc_sequence sequence = { .options = &options, From 735b709e1e1eb70dd6aa94b1c1d8cb397b8c04e2 Mon Sep 17 00:00:00 2001 From: Punit Vara Date: Sat, 25 Aug 2018 15:01:16 +0530 Subject: [PATCH 18/21] samples: grove_light: Provide device name from Kconfig check return value for sample fetch. Conditional printk added to print adc value. Signed-off-by: Punit Vara --- samples/sensor/grove_light/src/main.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/samples/sensor/grove_light/src/main.c b/samples/sensor/grove_light/src/main.c index 8541bf931e5da..e10b42b6f645b 100644 --- a/samples/sensor/grove_light/src/main.c +++ b/samples/sensor/grove_light/src/main.c @@ -14,20 +14,29 @@ void main(void) { - struct device *dev = device_get_binding("GROVE_LIGHT_SENSOR"); + struct device *dev = device_get_binding(CONFIG_GROVE_LIGHT_SENSOR_NAME); if (dev == NULL) { printk("device not found. aborting test.\n"); return; } while (1) { + int read; struct sensor_value lux; - sensor_sample_fetch(dev); - sensor_channel_get(dev, SENSOR_CHAN_LIGHT, &lux); + read = sensor_sample_fetch(dev); + if (read) { + printk("sample fetch error %d\n", read); + continue; + } - printf("lux: %f\n", sensor_value_to_double(&lux)); + sensor_channel_get(dev, SENSOR_CHAN_LIGHT, &lux); +#ifdef CONFIG_NEWLIB_LIBC_FLOAT_PRINTF + printk("lux: %d\n", sensor_value_to_double(&lux)); +#else + printk("lux: %d\n", lux.val1); +#endif k_sleep(SLEEP_TIME); } } From 6766f3f7eacf9c562e955b2e975e33e2190f0875 Mon Sep 17 00:00:00 2001 From: Punit Vara Date: Sat, 25 Aug 2018 18:10:51 +0530 Subject: [PATCH 19/21] samples: grove_temperature: Use device name from Kconfig Use Kconfig to get device name. Make LIBC conditional to get output. Signed-off-by: Punit Vara --- samples/sensor/grove_temperature/src/main.c | 22 +++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/samples/sensor/grove_temperature/src/main.c b/samples/sensor/grove_temperature/src/main.c index 1f803e706e88a..0b8a52eee373e 100644 --- a/samples/sensor/grove_temperature/src/main.c +++ b/samples/sensor/grove_temperature/src/main.c @@ -19,7 +19,9 @@ void main(void) { - struct device *dev = device_get_binding("GROVE_TEMPERATURE_SENSOR"); + struct device *dev = device_get_binding(CONFIG_GROVE_TEMPERATURE_SENSOR_NAME); + struct sensor_value temp; + int read; if (dev == NULL) { printf("device not found. aborting test.\n"); @@ -41,9 +43,12 @@ void main(void) #endif while (1) { - struct sensor_value temp; - sensor_sample_fetch(dev); + read = sensor_sample_fetch(dev); + if (read) { + printk("sample fetch error\n"); + continue; + } sensor_channel_get(dev, SENSOR_CHAN_AMBIENT_TEMP, &temp); #ifdef CONFIG_GROVE_LCD_RGB char row[16]; @@ -57,14 +62,23 @@ void main(void) /* display temperature on LCD */ glcd_cursor_pos_set(glcd, 0, 0); +#ifdef CONFIG_NEWLIB_LIBC_FLOAT_PRINTF sprintf(row, "T:%.2f%cC", sensor_value_to_double(&temp), 223 /* degree symbol */); +#else + sprintf(row, "T:%d%cC", temp.val1, + 223 /* degree symbol */); +#endif glcd_print(glcd, row, strlen(row)); #endif - printf("Temperature: %.2f C\n", sensor_value_to_double(&temp)); +#ifdef CONFIG_NEWLIB_LIBC_FLOAT_PRINTF + printf("Temperature: %.2f C\n", sensor_value_to_double(&temp)); +#else + printk("Temperature: %d\n", temp.val1); +#endif k_sleep(SLEEP_TIME); } } From 642e23446b6544b45a484f18fafd070b959c500d Mon Sep 17 00:00:00 2001 From: Punit Vara Date: Mon, 27 Aug 2018 00:13:07 +0530 Subject: [PATCH 20/21] boards: quark_d2000_crb: Remove adc support Remove ADC support from d2000 as it is not migrated to new ADC apis. Signed-off-by: Punit Vara --- boards/x86/quark_d2000_crb/quark_d2000_crb.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/boards/x86/quark_d2000_crb/quark_d2000_crb.yaml b/boards/x86/quark_d2000_crb/quark_d2000_crb.yaml index a63eeb8ac54e2..8f5e4a4ad7acb 100644 --- a/boards/x86/quark_d2000_crb/quark_d2000_crb.yaml +++ b/boards/x86/quark_d2000_crb/quark_d2000_crb.yaml @@ -9,7 +9,6 @@ toolchain: ram: 8 flash: 32 supported: - - adc - i2c - spi - gpio From 47dfd811de96163278979516e695bedd5fdc406b Mon Sep 17 00:00:00 2001 From: Punit Vara Date: Mon, 27 Aug 2018 00:16:25 +0530 Subject: [PATCH 21/21] tests: adc_api: Remove sample width test scenario Remove unnecessary sample width scenario. Signed-off-by: Punit Vara --- samples/sensor/grove_light/sample.yaml | 3 +-- samples/sensor/grove_temperature/sample.yaml | 3 +-- tests/drivers/adc/adc_api/testcase.yaml | 20 -------------------- 3 files changed, 2 insertions(+), 24 deletions(-) diff --git a/samples/sensor/grove_light/sample.yaml b/samples/sensor/grove_light/sample.yaml index f033adf0f4bc8..9b6c8ef6deeb0 100644 --- a/samples/sensor/grove_light/sample.yaml +++ b/samples/sensor/grove_light/sample.yaml @@ -2,8 +2,7 @@ sample: name: Grove Light Sensor tests: test: - platform_whitelist: arduino_101_sss quark_d2000_crb - arduino_due + platform_whitelist: arduino_101_sss arduino_due tags: drivers sensor grove light harness: grove depends_on: adc diff --git a/samples/sensor/grove_temperature/sample.yaml b/samples/sensor/grove_temperature/sample.yaml index 792834275dbe5..5fe3e660c93d6 100644 --- a/samples/sensor/grove_temperature/sample.yaml +++ b/samples/sensor/grove_temperature/sample.yaml @@ -3,8 +3,7 @@ sample: tests: test: min_flash: 33 - platform_whitelist: arduino_101_sss quark_d2000_crb - arduino_due + platform_whitelist: arduino_101_sss arduino_due tags: drivers sensor grove temperature harness: grove depends_on: adc diff --git a/tests/drivers/adc/adc_api/testcase.yaml b/tests/drivers/adc/adc_api/testcase.yaml index 35eed63ca447a..7f5dc25c9eba4 100644 --- a/tests/drivers/adc/adc_api/testcase.yaml +++ b/tests/drivers/adc/adc_api/testcase.yaml @@ -3,23 +3,3 @@ common: tests: peripheral.adc: depends_on: adc - peripheral.adc.poll_mode: - extra_configs: - - CONFIG_ADC_QMSI_POLL=y - platform_whitelist: quark_se_c1000_ss_devboard - peripheral.adc.resolution_10: - extra_configs: - - CONFIG_ADC_QMSI_SAMPLE_WIDTH=10 - platform_whitelist: quark_se_c1000_ss_devboard - peripheral.adc.resolution_12: - extra_configs: - - CONFIG_ADC_QMSI_SAMPLE_WIDTH=12 - platform_whitelist: quark_se_c1000_ss_devboard - peripheral.adc.resolution_6: - extra_configs: - - CONFIG_ADC_QMSI_SAMPLE_WIDTH=6 - platform_whitelist: quark_se_c1000_ss_devboard - peripheral.adc.resolution_8: - extra_configs: - - CONFIG_ADC_QMSI_SAMPLE_WIDTH=8 - platform_whitelist: quark_se_c1000_ss_devboard