[PATCH v5 3/4] bsps: Add ADC API

Duc Doan dtbpkmte at gmail.com
Sun Jul 24 12:01:10 UTC 2022


---
 bsps/include/bsp/adc.h        | 292 ++++++++++++++++++++++++++++++++++
 bsps/shared/dev/adc/adc.c     | 200 +++++++++++++++++++++++
 spec/build/bsps/bspopts.yml   |   4 +
 spec/build/bsps/obj.yml       |   2 +
 spec/build/bsps/optenadc.yml  |  16 ++
 spec/build/bsps/optnumadc.yml |  16 ++
 6 files changed, 530 insertions(+)
 create mode 100644 bsps/include/bsp/adc.h
 create mode 100644 bsps/shared/dev/adc/adc.c
 create mode 100644 spec/build/bsps/optenadc.yml
 create mode 100644 spec/build/bsps/optnumadc.yml

diff --git a/bsps/include/bsp/adc.h b/bsps/include/bsp/adc.h
new file mode 100644
index 0000000000..d168e1b201
--- /dev/null
+++ b/bsps/include/bsp/adc.h
@@ -0,0 +1,292 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2022 Duc Doan (dtbpkmte at gmail.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIBBSP_BSP_ADC_H
+#define LIBBSP_BSP_ADC_H
+
+#include <bsp.h>
+#include <rtems.h>
+#include <bsp/periph_api.h>
+#include <bsp/gpio2.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef enum {
+    RTEMS_ADC_NOT_STARTED = 0,
+    RTEMS_ADC_NOT_READY,
+    RTEMS_ADC_READY
+} rtems_adc_status;
+
+typedef enum {
+    RTEMS_ADC_ALIGN_LEFT,
+    RTEMS_ADC_ALIGN_RIGHT
+} rtems_adc_align;
+
+typedef enum {
+    RTEMS_ADC_NB_INTERRUPT,
+    RTEMS_ADC_NB_DMA
+} rtems_adc_nb_mode;
+
+/**
+  * @brief Enumeration of reference voltages.
+  */
+typedef enum {
+    RTEMS_ADC_REF_DEFAULT = 0,
+    RTEMS_ADC_REF_INTERNAL,
+    RTEMS_ADC_REF_EXTERNAL
+} rtems_adc_ref;
+
+#define RTEMS_ADC_NO_TIMEOUT   0xFFFFFFFFU
+
+typedef void (*rtems_adc_isr)(void *);
+typedef double (*rtems_adc_tf) (void *params, uint32_t raw_value);
+typedef struct rtems_adc_handlers rtems_adc_handlers;
+typedef struct rtems_adc_api rtems_adc_api;
+
+/**
+  * @brief Macro to help creating a rtems_adc_api object.
+  *
+  * Each BSP/driver must define its own handlers and create an object 
+  * of this struct with pointers to those handlers.
+  */
+#define RTEMS_ADC_BUILD_API(                                    \
+        _init,                                                  \
+        _read_raw,                                              \
+        _start_read_raw_nb,                                     \
+        _read_raw_nb,                                           \
+        _set_resolution,                                        \
+        _set_alignment,                                         \
+        _configure_interrupt,                                   \
+        _remove_interrupt,                                      \
+        _enable_interrupt,                                      \
+        _disable_interrupt)                                     \
+    {                                                           \
+        .base = {                                               \
+            .api_type = RTEMS_PERIPH_API_TYPE_ADC,              \
+            .init = _init                                       \
+        },                                                      \
+        .read_raw = ( _read_raw ),                              \
+        .start_read_raw_nb = ( _start_read_raw_nb ),            \
+        .read_raw_nb = ( _read_raw_nb ),                        \
+        .set_resolution = ( _set_resolution ),                  \
+        .set_alignment = ( _set_alignment ),                    \
+        .configure_interrupt = ( _configure_interrupt ),        \
+        .remove_interrupt = ( _remove_interrupt ),              \
+        .enable_interrupt = ( _enable_interrupt ),              \
+        .disable_interrupt = ( _disable_interrupt ),            \
+    };
+
+struct rtems_adc_api {
+    /**
+      * @brief Contain base structure rtems_periph_api.
+      * @see rtems_periph_api
+      */
+    rtems_periph_api base;
+    /**
+      * @brief This member is a pointer to a transfer function
+      *        that will be assigned to this pin.
+      * If no transfer function assigned, it should remain NULL.
+      */
+    rtems_adc_tf tf;
+    void *tf_params;
+    /**
+      * @brief Pointer to a function that reads raw ADC value.
+      * This function is blocking and has a timeout parameter.
+      */
+    rtems_status_code (*read_raw) (rtems_gpio *, uint32_t *, uint32_t);
+    /**
+      * @brief Pointer to a function that starts ADC conversion
+      *        in non-blocking style.
+      */
+    rtems_status_code (*start_read_raw_nb) (rtems_gpio *);
+    /**
+      * @brief Pointer to a function that gets a raw ADC value when
+      *        available after a start_read_raw_nb() call. 
+      * If data is not available, the function should return a status
+      * to indicate that.
+      */
+    rtems_adc_status (*read_raw_nb) (rtems_gpio *, uint32_t *);
+    /**
+      * @brief Pointer to a function that sets the resolution of an
+      *        ADC controller associated with a pin.
+      *
+      * @note If a controller contains multiple pins, the resolution
+      *       setting may affect all of them.
+      */
+    rtems_status_code (*set_resolution) (rtems_gpio *, unsigned int);
+    /**
+      * @brief Pointer to a function that sets the alignment of an
+      *        ADC controller associated with a pin.
+      *
+      * @note If a controller contains multiple pins, the alignment
+      *       setting may affect all of them.
+      */
+    rtems_status_code (*set_alignment) (rtems_gpio *, rtems_adc_align);
+    /**
+      * @brief This member is the pointer to a handler for configuring
+      *        interrupt of a pin.
+      *
+      * This handler should register ISR and its arguments.
+      *
+      * @note Interrupt may occur when ADC conversion is completed.
+      * @note Enabling interrupt should be done in enable_interrupt()
+      *       handler.
+      */
+    rtems_status_code (*configure_interrupt) (rtems_gpio *, rtems_adc_isr, void *);
+    /**
+      * @brief This member is the pointer to a handler for removing
+      *        interrupt settings of a pin.
+      */
+    rtems_status_code (*remove_interrupt) (rtems_gpio *);
+    /**
+      * @brief This member is the pointer to a handler for enabling
+      *        interrupt functionality of a pin.
+      */
+    rtems_status_code (*enable_interrupt) (rtems_gpio *);
+    /**
+      * @brief This member is the pointer to a handler for disabling
+      *        interrupt of a pin.
+      */
+    rtems_status_code (*disable_interrupt) (rtems_gpio *);
+};
+
+/**
+  * @brief Read raw ADC value with infinite timeout.
+  *
+  * @param base[in]
+  * @param result[out]
+  *
+  * @retval
+  */
+extern rtems_status_code rtems_adc_read_raw(
+    rtems_gpio *base, 
+    uint32_t *result
+);
+extern rtems_status_code rtems_adc_read_raw_timeout(
+    rtems_gpio *base, 
+    uint32_t *result,
+    uint32_t timeout
+);
+
+/**
+  * @brief Starts a non-blocking ADC conversion.
+  *
+  * This function must be called before
+  * rtems_adc_read_raw_nb() or rtems_adc_read_nb()
+  *
+  * @param base
+  *
+  * @retval
+  */
+extern rtems_status_code rtems_adc_start_read_nb(
+    rtems_gpio *base
+);
+
+/**
+  * @brief Reads raw ADC value non-blocking.
+  */
+extern rtems_adc_status rtems_adc_read_raw_nb(
+    rtems_gpio *base, 
+    uint32_t *result
+);
+
+/**
+  * @brief Assigns a transfer function with parameters
+  *        to a pin.
+  */
+extern rtems_status_code rtems_adc_assign_tf(
+    rtems_gpio *base,
+    rtems_adc_tf tf, 
+    void *params
+);
+
+/**
+  * @brief Removes the assigned transfer function from
+  *        a pin.
+  */
+extern rtems_status_code rtems_adc_remove_tf(
+    rtems_gpio *base
+);
+
+/**
+  * @brief Reads an ADC value with infinite timeout.
+  *
+  * If no transfer function assigned, this will
+  * return the raw value via result pointer. Else, 
+  * it returns the calculated value using transfer
+  * function.
+  *
+  * @param base[in]
+  * @param result[out]
+  *
+  * @retval
+  */
+extern rtems_status_code rtems_adc_read(
+    rtems_gpio *base, 
+    double *result
+);
+extern rtems_status_code rtems_adc_read_timeout(
+    rtems_gpio *base, 
+    double *result,
+    uint32_t timeout
+);
+extern rtems_adc_status rtems_adc_read_nb(
+    rtems_gpio *base, 
+    double *result
+);
+
+extern rtems_status_code rtems_adc_set_resolution(
+    rtems_gpio *base,
+    unsigned int bits
+);
+extern rtems_status_code rtems_adc_set_alignment(
+    rtems_gpio *base,
+    rtems_adc_align align
+);
+
+extern rtems_status_code rtems_adc_configure_interrupt(
+    rtems_gpio *base,
+    rtems_adc_isr isr,
+    void *arg
+);
+extern rtems_status_code rtems_adc_remove_interrupt(
+    rtems_gpio *base
+);
+extern rtems_status_code rtems_adc_enable_interrupt(
+    rtems_gpio *base
+);
+extern rtems_status_code rtems_adc_disable_interrupt(
+    rtems_gpio *base
+);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* LIBBSP_BSP_ADC_H */
diff --git a/bsps/shared/dev/adc/adc.c b/bsps/shared/dev/adc/adc.c
new file mode 100644
index 0000000000..e288d35691
--- /dev/null
+++ b/bsps/shared/dev/adc/adc.c
@@ -0,0 +1,200 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2022 Duc Doan (dtbpkmte at gmail.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <bsp/adc.h>
+#include <stdbool.h>
+
+/**
+  * @brief Macro to check if an API pointer is ADC API.
+  * This only works if RTEMS_DEBUG is defined. This macro can
+  * only be called from functions. 
+  *
+  * @param _api_ptr A pointer to rtems_periph_api.
+  */ 
+#ifdef RTEMS_DEBUG
+#define RTEMS_ADC_API_TYPE_CHECK( _api_ptr )     \
+    do {                                                \
+        if ( *(rtems_periph_type *) ( _api_ptr ) != ( RTEMS_PERIPH_TYPE_ADC ) )               \
+            return RTEMS_UNSATISFIED;                   \
+    } while (0)
+#else
+#define RTEMS_ADC_API_TYPE_CHECK( _type )     \
+    ((void) ( _type ))
+#endif /* RTEMS_DEBUG */
+
+rtems_status_code rtems_adc_read_raw(
+    rtems_gpio *base,
+    uint32_t *result
+)
+{
+    RTEMS_ADC_API_TYPE_CHECK( base->api );
+    return ((rtems_adc_api *) (base->api))->read_raw(base, result, RTEMS_ADC_NO_TIMEOUT);
+}
+rtems_status_code rtems_adc_read_raw_timeout(
+    rtems_gpio *base,
+    uint32_t *result,
+    uint32_t timeout
+)
+{
+    RTEMS_ADC_API_TYPE_CHECK( base->api );
+    return ((rtems_adc_api *) (base->api))->read_raw(base, result, timeout);
+}
+
+rtems_adc_status rtems_adc_read_raw_nb(
+    rtems_gpio *base,
+    uint32_t *result
+)
+{
+    RTEMS_ADC_API_TYPE_CHECK( base->api );
+    return ((rtems_adc_api *) (base->api))->read_raw_nb(base, result);
+}
+
+rtems_status_code rtems_adc_assign_tf(
+    rtems_gpio *base,
+    rtems_adc_tf tf,
+    void *params
+)
+{
+    RTEMS_ADC_API_TYPE_CHECK( base->api );
+    ((rtems_adc_api *) (base->api))->tf = tf;
+    ((rtems_adc_api *) (base->api))->tf_params = params;
+    return RTEMS_SUCCESSFUL;
+}
+rtems_status_code rtems_adc_remove_tf(
+    rtems_gpio *base
+)
+{
+    RTEMS_ADC_API_TYPE_CHECK( base->api );
+    ((rtems_adc_api *) (base->api))->tf = NULL;
+    ((rtems_adc_api *) (base->api))->tf_params = NULL;
+    return RTEMS_SUCCESSFUL;
+}
+rtems_status_code rtems_adc_read(
+    rtems_gpio *base,
+    double *result
+)
+{
+    RTEMS_ADC_API_TYPE_CHECK( base->api );
+    uint32_t raw;
+    rtems_status_code sc = rtems_adc_read_raw(base, &raw);
+    if (sc == RTEMS_SUCCESSFUL) {
+        if (((rtems_adc_api *) (base->api))->tf == NULL)
+            *result = (double) raw;
+        else
+            *result = ((rtems_adc_api *) (base->api))->tf(((rtems_adc_api *) (base->api))->tf_params, raw);
+    }
+    return sc;
+}
+rtems_status_code rtems_adc_read_timeout(
+    rtems_gpio *base,
+    double *result,
+    uint32_t timeout
+)
+{
+    RTEMS_ADC_API_TYPE_CHECK( base->api );
+    uint32_t raw;
+    rtems_status_code sc = rtems_adc_read_raw_timeout(base, &raw, timeout);
+    if (sc == RTEMS_SUCCESSFUL) {
+        if (((rtems_adc_api *) (base->api))->tf == NULL)
+            *result = (double) raw;
+        else
+            *result = ((rtems_adc_api *) (base->api))->tf(((rtems_adc_api *) (base->api))->tf_params, raw);
+    }
+    return sc;
+}
+
+rtems_status_code rtems_adc_start_read_nb(
+    rtems_gpio *base
+)
+{
+    RTEMS_ADC_API_TYPE_CHECK( base->api );
+    return ((rtems_adc_api *) (base->api))->start_read_raw_nb(base);
+}
+rtems_adc_status rtems_adc_read_nb(
+    rtems_gpio *base,
+    double *result
+)
+{
+    RTEMS_ADC_API_TYPE_CHECK( base->api );
+    uint32_t raw;
+    rtems_adc_status sc = rtems_adc_read_raw_nb(base, &raw);
+    if (sc == RTEMS_ADC_READY) {
+        if (((rtems_adc_api *) (base->api))->tf == NULL)
+            *result = (double) raw;
+        else
+            *result = ((rtems_adc_api *) (base->api))->tf(((rtems_adc_api *) (base->api))->tf_params, raw);
+    }
+    return sc;
+}
+
+rtems_status_code rtems_adc_set_resolution(
+    rtems_gpio *base,
+    unsigned int bits
+)
+{
+    RTEMS_ADC_API_TYPE_CHECK( base->api );
+    return ((rtems_adc_api *) (base->api))->set_resolution(base, bits);
+}
+rtems_status_code rtems_adc_set_alignment(
+    rtems_gpio *base,
+    rtems_adc_align align
+)
+{
+    RTEMS_ADC_API_TYPE_CHECK( base->api );
+    return ((rtems_adc_api *) (base->api))->set_alignment(base, align);
+}
+
+rtems_status_code rtems_adc_configure_interrupt(
+    rtems_gpio *base,
+    rtems_adc_isr isr,
+    void *arg
+)
+{
+    RTEMS_ADC_API_TYPE_CHECK( base->api );
+    return ((rtems_adc_api *) (base->api))->configure_interrupt(base, isr, arg);
+}
+rtems_status_code rtems_adc_remove_interrupt(
+    rtems_gpio *base
+)
+{
+    RTEMS_ADC_API_TYPE_CHECK( base->api );
+    return ((rtems_adc_api *) (base->api))->remove_interrupt(base);
+}
+rtems_status_code rtems_adc_enable_interrupt(
+    rtems_gpio *base
+)
+{
+    RTEMS_ADC_API_TYPE_CHECK( base->api );
+    return ((rtems_adc_api *) (base->api))->enable_interrupt(base);
+}
+rtems_status_code rtems_adc_disable_interrupt(
+    rtems_gpio *base
+)
+{
+    RTEMS_ADC_API_TYPE_CHECK( base->api );
+    return ((rtems_adc_api *) (base->api))->disable_interrupt(base);
+}
diff --git a/spec/build/bsps/bspopts.yml b/spec/build/bsps/bspopts.yml
index 4a4c06d321..132259bc9e 100644
--- a/spec/build/bsps/bspopts.yml
+++ b/spec/build/bsps/bspopts.yml
@@ -7,6 +7,10 @@ guard: __BSP_OPTIONS_H
 include-headers: []
 install-path: ${BSP_INCLUDEDIR}
 links:
+- role: build-dependency
+  uid: optenadc
+- role: build-dependency
+  uid: optnumadc
 - role: build-dependency
   uid: optbspoptflags
 - role: build-dependency
diff --git a/spec/build/bsps/obj.yml b/spec/build/bsps/obj.yml
index 80736c197d..6c5e2536b3 100644
--- a/spec/build/bsps/obj.yml
+++ b/spec/build/bsps/obj.yml
@@ -18,6 +18,7 @@ install:
   - bsps/include/bsp/fdt.h
   - bsps/include/bsp/periph_api.h
   - bsps/include/bsp/gpio2.h
+  - bsps/include/bsp/adc.h
   - bsps/include/bsp/irq-default.h
   - bsps/include/bsp/irq-generic.h
   - bsps/include/bsp/irq-info.h
@@ -72,6 +73,7 @@ links:
   uid: objnosmp
 source:
 - bsps/shared/dev/gpio/gpio.c
+- bsps/shared/dev/adc/adc.c
 - bsps/shared/dev/periph_api/periph_api.c
 - bsps/shared/dev/display/disp_hcms29xx.c
 - bsps/shared/dev/display/font_hcms29xx.c
diff --git a/spec/build/bsps/optenadc.yml b/spec/build/bsps/optenadc.yml
new file mode 100644
index 0000000000..705a4236e4
--- /dev/null
+++ b/spec/build/bsps/optenadc.yml
@@ -0,0 +1,16 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+actions:
+- get-boolean: null
+- define-condition: null
+build-type: option
+copyrights:
+- Copyright (C) 2022 Duc Doan (dtbpkmte at gmail.com)
+default: false
+default-by-variant: []
+description: |
+  This option enables the BSP to use RTEMS ADC API.
+enabled-by: true
+format: '{}'
+links: []
+name: BSP_ENABLE_ADC
+type: build
diff --git a/spec/build/bsps/optnumadc.yml b/spec/build/bsps/optnumadc.yml
new file mode 100644
index 0000000000..f9564f9b47
--- /dev/null
+++ b/spec/build/bsps/optnumadc.yml
@@ -0,0 +1,16 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+actions:
+- get-integer: null
+- define: null
+build-type: option
+copyrights:
+- Copyright (C) 2022 Duc Doan (dtbpkmte at gmail.com)
+default: 0
+default-by-variant: []
+description: |
+  The number of external ADC used.
+enabled-by: true
+format: '{}'
+links: []
+name: BSP_NUM_ADC
+type: build
-- 
2.36.1



More information about the devel mailing list