[PATCH v6 10/10] bsps/arm/stm32f4: ADC API implementation
Duc Doan
dtbpkmte at gmail.com
Sun Aug 7 10:58:22 UTC 2022
---
bsps/arm/stm32f4/adc/adc.c | 495 ++++++++++++++++++
bsps/arm/stm32f4/include/bsp/stm32f4_adc.h | 198 +++++++
spec/build/bsps/arm/stm32f4/grp.yml | 2 +
spec/build/bsps/arm/stm32f4/obj.yml | 3 +
spec/build/bsps/arm/stm32f4/optnumadcctrl.yml | 16 +
5 files changed, 714 insertions(+)
create mode 100644 bsps/arm/stm32f4/adc/adc.c
create mode 100644 bsps/arm/stm32f4/include/bsp/stm32f4_adc.h
create mode 100644 spec/build/bsps/arm/stm32f4/optnumadcctrl.yml
diff --git a/bsps/arm/stm32f4/adc/adc.c b/bsps/arm/stm32f4/adc/adc.c
new file mode 100644
index 0000000000..61ced0f4c9
--- /dev/null
+++ b/bsps/arm/stm32f4/adc/adc.c
@@ -0,0 +1,495 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup stm32f4_adc
+ */
+
+/*
+ * 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/stm32f4_adc.h>
+#include <stdlib.h>
+
+#if defined(ADC3)
+#define NUM_ADC 3
+#elif defined(ADC2)
+#define NUM_ADC 2
+#else
+#define NUM_ADC 1
+#endif
+
+/************** Helpers *****************/
+/**
+ * @brief Macro to get stm32f4_gpio object from a base rtems_gpio
+ * object.
+ *
+ * This is a wrapper of RTEMS_CONTAINER_OF macro
+ *
+ * @param base The pointer to a rtems_gpio object
+ * @retval The pointer to the stm32f4_gpio object owning
+ * the specified rtems_gpio object
+ */
+#define stm32f4_adc_get_adc_from_base(_base) \
+ RTEMS_CONTAINER_OF(_base, stm32f4_adc, base)
+
+void adc_irq_handler(void *arg);
+
+/**
+ * @brief Data structure for non-blocking read.
+ */
+typedef struct {
+ uint32_t adc_value;
+ rtems_adc_status status;
+} stm32f4_adc_data;
+static stm32f4_adc_data adc_data[NUM_ADC] = {0};
+
+/**
+ * @brief Configure the ADC channel to be the specified one.
+ * An ADC contains multiple channels, so before each operation, we should
+ * select the wanted channel.
+ */
+static rtems_status_code stm32f4_adc_select_channel(
+ rtems_adc *base
+);
+
+/***************/
+/**
+ * ADC objects that have simple lock for mutex.
+ */
+#ifdef ADC1
+static ADC_TypeDef_Protected _ADC1_protected = { ADC1, false };
+ADC_TypeDef_Protected *const ADC1_protected = &_ADC1_protected;
+
+static rtems_status_code stm32f4_adc_get_adc1(uint32_t id, rtems_adc **out);
+#endif
+#ifdef ADC2
+static ADC_TypeDef_Protected _ADC2_protected = { ADC2, false };
+ADC_TypeDef_Protected *const ADC2_protected = &_ADC2_protected;
+
+static rtems_status_code stm32f4_adc_get_adc2(uint32_t id, rtems_adc **out);
+#endif
+#ifdef ADC3
+static ADC_TypeDef_Protected _ADC3_protected = { ADC3, false };
+ADC_TypeDef_Protected *const ADC3_protected = &_ADC3_protected;
+
+static rtems_status_code stm32f4_adc_get_adc3(uint32_t id, rtems_adc **out);
+#endif
+
+/* Helpers */
+#define STM32F4_GET_ADC_NUMBER(ADCx) \
+ ( (uintptr_t) ( ADCx ) == (uintptr_t) ADC1 ? 1 : \
+ (uintptr_t) ( ADCx ) == (uintptr_t) ADC2 ? 2 : \
+ (uintptr_t) ( ADCx ) == (uintptr_t) ADC3 ? 3 : \
+ 0 )
+#define STM32F4_GET_ADCx_FROM_NUMBER(num) (\
+ ( num ) == 1 ? ADC1 : \
+ ( num ) == 2 && NUM_ADC >= 2 ? ADC2 : \
+ ( num ) == 3 && NUM_ADC == 3 ? ADC3 : \
+ NULL)
+#define STM32F4_GET_ADCx_PROTECTED_FROM_NUMBER(num) (\
+ ( num ) == 1 ? ADC1_protected : \
+ ( num ) == 2 && NUM_ADC >= 2 ? ADC2_protected : \
+ ( num ) == 3 && NUM_ADC == 3 ? ADC3_protected : \
+ NULL)
+#define STM32F4_GET_LL_ADC_CHANNEL(num) (\
+ ( num ) == 0 ? LL_ADC_CHANNEL_0 : \
+ ( num ) == 1 ? LL_ADC_CHANNEL_1 : \
+ ( num ) == 2 ? LL_ADC_CHANNEL_2 : \
+ ( num ) == 3 ? LL_ADC_CHANNEL_3 : \
+ ( num ) == 4 ? LL_ADC_CHANNEL_4 : \
+ ( num ) == 5 ? LL_ADC_CHANNEL_5 : \
+ ( num ) == 6 ? LL_ADC_CHANNEL_6 : \
+ ( num ) == 7 ? LL_ADC_CHANNEL_7 : \
+ ( num ) == 8 ? LL_ADC_CHANNEL_8 : \
+ ( num ) == 9 ? LL_ADC_CHANNEL_9 : \
+ ( num ) == 10 ? LL_ADC_CHANNEL_10 : \
+ ( num ) == 11 ? LL_ADC_CHANNEL_11 : \
+ ( num ) == 12 ? LL_ADC_CHANNEL_12 : \
+ ( num ) == 13 ? LL_ADC_CHANNEL_13 : \
+ ( num ) == 14 ? LL_ADC_CHANNEL_14 : \
+ ( num ) == 15 ? LL_ADC_CHANNEL_15 : \
+ 0xffffffff)
+
+static const rtems_adc_handlers stm32f4_adc_handlers = {
+ stm32f4_adc_init,
+ stm32f4_adc_read_raw,
+ stm32f4_adc_start_read_raw_nb,
+ stm32f4_adc_read_raw_nb,
+ stm32f4_adc_set_channel,
+ stm32f4_adc_set_resolution,
+ stm32f4_adc_set_alignment
+};
+
+#ifdef ADC1
+static rtems_status_code stm32f4_adc_get_adc1(
+ uint32_t id,
+ rtems_adc **out
+)
+{
+ return stm32f4_adc_get(1, id, out);
+}
+#endif /* ADC1 */
+#ifdef ADC2
+static rtems_status_code stm32f4_adc_get_adc2(
+ uint32_t id,
+ rtems_adc **out
+)
+{
+ return stm32f4_adc_get(2, id, out);
+}
+#endif /* ADC2 */
+#ifdef ADC3
+static rtems_status_code stm32f4_adc_get_adc3(
+ uint32_t id,
+ rtems_adc **out
+)
+{
+ return stm32f4_adc_get(3, id, out);
+}
+#endif /* ADC3 */
+
+rtems_status_code stm32f4_adc_get(
+ uint32_t adc_num,
+ uint32_t id,
+ rtems_adc **out
+)
+{
+ // First allocate space for stm32f4_adc object
+ stm32f4_adc *adc = malloc(sizeof(stm32f4_adc));
+ if (adc == NULL) {
+ return RTEMS_NO_MEMORY;
+ }
+
+ *(uint32_t *) &adc->base.id = id;
+ *(const rtems_adc_handlers **) &adc->base.handlers = &stm32f4_adc_handlers;
+
+ adc->adc_config.ADCx = STM32F4_GET_ADCx_PROTECTED_FROM_NUMBER(adc_num);
+ adc->adc_config.resolution = STM32F4_ADC_DEFAULT_RESOLUTION;
+ adc->adc_config.alignment = STM32F4_ADC_DEFAULT_ALIGNMENT;
+ adc->adc_config.locked = false;
+ *out = (rtems_adc *) adc;
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code stm32f4_adc_destroy(
+ rtems_adc *pin
+)
+{
+ if (pin != NULL) {
+ free(pin);
+ return RTEMS_SUCCESSFUL;
+ }
+ return RTEMS_UNSATISFIED;
+}
+
+static rtems_status_code stm32f4_adc_select_channel(
+ rtems_adc *base
+)
+{
+ stm32f4_adc *adc = stm32f4_adc_get_adc_from_base(base);
+ stm32f4_adc_config *adc_config = &adc->adc_config;
+ if (!STM32F4_IS_LOCKED(adc_config) &&
+ !STM32F4_IS_LOCKED(adc_config->ADCx)) {
+ STM32F4_LOCK(adc_config);
+ STM32F4_LOCK(adc_config->ADCx);
+
+ LL_ADC_Disable(adc_config->ADCx->ADCx);
+
+ LL_ADC_SetResolution(adc_config->ADCx->ADCx, adc_config->resolution);
+ LL_ADC_SetDataAlignment(adc_config->ADCx->ADCx, adc_config->alignment);
+ LL_ADC_REG_SetSequencerRanks(
+ adc_config->ADCx->ADCx,
+ LL_ADC_REG_RANK_1,
+ adc_config->channel
+ );
+ LL_ADC_SetChannelSamplingTime(
+ adc_config->ADCx->ADCx,
+ adc_config->channel,
+ STM32F4_ADC_DEFAULT_SAMPLINGTIME
+ );
+
+ LL_ADC_Enable(adc_config->ADCx->ADCx);
+ /* Delay for ADC stabilization time */
+ /* Compute number of CPU cycles to wait for */
+ volatile uint32_t counter =
+ (ADC_STAB_DELAY_US * (SystemCoreClock / 1000000U));
+ while(counter != 0U)
+ {
+ counter--;
+ }
+
+ STM32F4_UNLOCK(adc_config);
+ STM32F4_UNLOCK(adc_config->ADCx);
+ return RTEMS_SUCCESSFUL;
+ }
+ return RTEMS_UNSATISFIED;
+}
+
+static void stm32f4_adc_start(
+ void
+)
+{
+ // Install ISR for non-blocking read
+ rtems_status_code sc = rtems_interrupt_handler_install(
+ ADC_IRQn,
+ NULL,
+ RTEMS_INTERRUPT_SHARED,
+ adc_irq_handler,
+ NULL
+ );
+ while (sc != RTEMS_SUCCESSFUL);
+
+ // Registers with ADC API
+#ifdef ADC1
+ rtems_adc_register(stm32f4_adc_get_adc1, stm32f4_adc_destroy);
+#endif /* ADC1 */
+#ifdef ADC2
+ rtems_adc_register(stm32f4_adc_get_adc2, stm32f4_adc_destroy);
+#endif /* ADC2 */
+#ifdef ADC3
+ rtems_adc_register(stm32f4_adc_get_adc3, stm32f4_adc_destroy);
+#endif /* ADC3 */
+}
+RTEMS_SYSINIT_ITEM(
+ stm32f4_adc_start,
+ RTEMS_SYSINIT_BSP_PRE_DRIVERS,
+ RTEMS_SYSINIT_ORDER_LAST
+);
+
+void stm32f4_adc_init(
+ rtems_adc *base
+)
+{
+ stm32f4_adc *adc = stm32f4_adc_get_adc_from_base(base);
+ stm32f4_adc_config *adc_config = &adc->adc_config;
+ if (!LL_ADC_IsEnabled(adc_config->ADCx->ADCx)) {
+ // Enable clock
+ switch ((uintptr_t) adc_config->ADCx->ADCx) {
+#ifdef ADC1
+ case (uintptr_t) ADC1:
+ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC1);
+ break;
+#endif
+#ifdef ADC2
+ case (uintptr_t) ADC2:
+ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC2);
+ break;
+#endif
+#ifdef ADC3
+ case (uintptr_t) ADC3:
+ LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC3);
+ break;
+#endif
+ default:
+ return;
+ }
+
+ // ADC common setup
+ LL_ADC_SetSequencersScanMode(adc_config->ADCx->ADCx, LL_ADC_SEQ_SCAN_DISABLE);
+ LL_ADC_REG_SetTriggerSource(adc_config->ADCx->ADCx, LL_ADC_REG_TRIG_SOFTWARE);
+ LL_ADC_REG_SetSequencerLength(adc_config->ADCx->ADCx, LL_ADC_REG_SEQ_SCAN_DISABLE);
+ LL_ADC_REG_SetSequencerDiscont(adc_config->ADCx->ADCx, LL_ADC_REG_SEQ_DISCONT_DISABLE);
+ LL_ADC_REG_SetContinuousMode(adc_config->ADCx->ADCx, LL_ADC_REG_CONV_SINGLE);
+ LL_ADC_REG_SetDMATransfer(adc_config->ADCx->ADCx, LL_ADC_REG_DMA_TRANSFER_NONE);
+
+ LL_ADC_REG_SetFlagEndOfConversion(adc_config->ADCx->ADCx, LL_ADC_REG_FLAG_EOC_UNITARY_CONV);
+
+ LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(adc_config->ADCx->ADCx), LL_ADC_CLOCK_SYNC_PCLK_DIV2);
+ LL_ADC_SetMultimode(__LL_ADC_COMMON_INSTANCE(adc_config->ADCx->ADCx), LL_ADC_MULTI_INDEPENDENT);
+
+ LL_ADC_Enable(adc_config->ADCx->ADCx);
+ /* Delay for ADC stabilization time */
+ /* Compute number of CPU cycles to wait for */
+ volatile uint32_t counter = (ADC_STAB_DELAY_US * (SystemCoreClock / 1000000U));
+ while(counter != 0U)
+ {
+ counter--;
+ }
+ }
+}
+
+rtems_status_code stm32f4_adc_read_raw(
+ rtems_adc *base,
+ uint32_t *result,
+ uint32_t timeout
+)
+{
+ uint32_t tickstart = 0U;
+ rtems_status_code sc = stm32f4_adc_select_channel(base);
+ if (sc != RTEMS_SUCCESSFUL) {
+ return sc;
+ }
+ stm32f4_adc *adc = stm32f4_adc_get_adc_from_base(base);
+ stm32f4_adc_config *adc_config = &adc->adc_config;
+ STM32F4_LOCK(adc_config->ADCx);
+ STM32F4_LOCK(adc_config);
+ LL_ADC_REG_StartConversionSWStart(adc_config->ADCx->ADCx);
+ while (!LL_ADC_IsActiveFlag_EOCS(adc_config->ADCx->ADCx)) {
+ if (timeout != RTEMS_ADC_NO_TIMEOUT) {
+ if (timeout == 0U || ((HAL_GetTick() - tickstart) > timeout)) {
+ if (!LL_ADC_IsActiveFlag_EOCS(adc_config->ADCx->ADCx)) {
+ return RTEMS_TIMEOUT;
+ }
+ }
+ }
+ }
+ *result = LL_ADC_REG_ReadConversionData32(adc_config->ADCx->ADCx);
+ STM32F4_UNLOCK(adc_config->ADCx);
+ STM32F4_UNLOCK(adc_config);
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code stm32f4_adc_start_read_raw_nb(
+ rtems_adc *base
+)
+{
+ stm32f4_adc *adc = stm32f4_adc_get_adc_from_base(base);
+ stm32f4_adc_config *adc_config = &adc->adc_config;
+ unsigned int adc_idx = STM32F4_GET_ADC_NUMBER(adc_config->ADCx->ADCx) - 1;
+ if (adc_data[adc_idx].status == RTEMS_ADC_NOT_STARTED) {
+ // start conversion here
+ rtems_status_code sc = stm32f4_adc_select_channel(base);
+ if (sc != RTEMS_SUCCESSFUL) {
+ return sc;
+ }
+ STM32F4_LOCK(adc_config);
+ STM32F4_LOCK(adc_config->ADCx);
+ LL_ADC_EnableIT_EOCS(adc_config->ADCx->ADCx);
+ LL_ADC_REG_StartConversionSWStart(adc_config->ADCx->ADCx);
+ adc_data[adc_idx].status = RTEMS_ADC_NOT_READY;
+
+ return RTEMS_SUCCESSFUL;
+ }
+ return RTEMS_UNSATISFIED;
+}
+
+rtems_adc_status stm32f4_adc_read_raw_nb(
+ rtems_adc *base,
+ uint32_t *result
+)
+{
+ stm32f4_adc *adc = stm32f4_adc_get_adc_from_base(base);
+ stm32f4_adc_config *adc_config = &adc->adc_config;
+ unsigned int adc_idx = STM32F4_GET_ADC_NUMBER(adc_config->ADCx->ADCx) - 1;
+ rtems_adc_status ret = adc_data[adc_idx].status;
+ if (ret == RTEMS_ADC_READY) {
+ *result = adc_data[adc_idx].adc_value;
+ adc_data[adc_idx].status = RTEMS_ADC_NOT_STARTED;
+
+ STM32F4_UNLOCK(adc_config->ADCx);
+ STM32F4_UNLOCK(adc_config);
+ }
+ return ret;
+}
+
+rtems_status_code stm32f4_adc_set_channel(
+ rtems_adc *base,
+ uint32_t channel
+)
+{
+ stm32f4_adc *adc = stm32f4_adc_get_adc_from_base(base);
+ adc->adc_config.channel = STM32F4_GET_LL_ADC_CHANNEL(channel);
+ if (adc->adc_config.channel == 0xffffffff)
+ return RTEMS_UNSATISFIED;
+ return RTEMS_SUCCESSFUL;
+}
+
+rtems_status_code stm32f4_adc_set_resolution(
+ rtems_adc *base,
+ unsigned int bits
+)
+{
+ stm32f4_adc *adc = stm32f4_adc_get_adc_from_base(base);
+ stm32f4_adc_config *adc_config = &adc->adc_config;
+ if (!STM32F4_IS_LOCKED(adc_config)) {
+ STM32F4_LOCK(adc_config);
+ switch (bits) {
+ case 12:
+ adc_config->resolution = LL_ADC_RESOLUTION_12B;
+ break;
+ case 10:
+ adc_config->resolution = LL_ADC_RESOLUTION_10B;
+ break;
+ case 8:
+ adc_config->resolution = LL_ADC_RESOLUTION_8B;
+ break;
+ case 6:
+ adc_config->resolution = LL_ADC_RESOLUTION_6B;
+ break;
+ default:
+ return RTEMS_UNSATISFIED;
+ }
+ STM32F4_UNLOCK(adc_config);
+ return RTEMS_SUCCESSFUL;
+ }
+ return RTEMS_RESOURCE_IN_USE;
+}
+
+rtems_status_code stm32f4_adc_set_alignment(
+ rtems_adc *base,
+ rtems_adc_align align
+)
+{
+ stm32f4_adc *adc = stm32f4_adc_get_adc_from_base(base);
+ stm32f4_adc_config *adc_config = &adc->adc_config;
+ if (!STM32F4_IS_LOCKED(adc_config)) {
+ STM32F4_LOCK(adc_config);
+ switch (align) {
+ case RTEMS_ADC_ALIGN_LEFT:
+ adc_config->alignment = LL_ADC_DATA_ALIGN_LEFT;
+ break;
+ case RTEMS_ADC_ALIGN_RIGHT:
+ adc_config->alignment = LL_ADC_DATA_ALIGN_RIGHT;
+ break;
+ default:
+ return RTEMS_UNSATISFIED;
+ }
+ STM32F4_UNLOCK(adc_config);
+ return RTEMS_SUCCESSFUL;
+ }
+ return RTEMS_RESOURCE_IN_USE;
+}
+
+void adc_irq_handler(void *arg) {
+ rtems_interrupt_level level;
+ rtems_interrupt_disable( level );
+ unsigned int i;
+ for (i = 0; i < NUM_ADC; ++i) {
+ ADC_TypeDef *adcx = STM32F4_GET_ADCx_FROM_NUMBER(i+1);
+ if (LL_ADC_IsActiveFlag_EOCS(adcx)) {
+ if (adc_data[i].status == RTEMS_ADC_NOT_READY) {
+ LL_ADC_DisableIT_EOCS(adcx);
+ adc_data[i].adc_value = LL_ADC_REG_ReadConversionData32(adcx);
+ adc_data[i].status = RTEMS_ADC_READY;
+ }
+ break;
+ }
+ }
+ rtems_interrupt_enable( level );
+}
+
+RTEMS_ADC_LINK();
diff --git a/bsps/arm/stm32f4/include/bsp/stm32f4_adc.h b/bsps/arm/stm32f4/include/bsp/stm32f4_adc.h
new file mode 100644
index 0000000000..b228e959fd
--- /dev/null
+++ b/bsps/arm/stm32f4/include/bsp/stm32f4_adc.h
@@ -0,0 +1,198 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup stm32f4_adc
+ *
+ * STM32F4 BSP implementation of ADC.
+ */
+
+/*
+ * 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_ARM_STM32F4_BSP_ADC
+#define LIBBSP_ARM_STM32F4_BSP_ADC
+
+#include <rtems/sysinit.h>
+#include <bsp/adc.h>
+#include <stm32f4xx_ll_bus.h>
+#include <stm32f4xx_ll_adc.h>
+#include <bsp/stm32f4_gpio.h>
+
+#define STM32F4_ADC_DEFAULT_RESOLUTION LL_ADC_RESOLUTION_10B
+#define STM32F4_ADC_DEFAULT_ALIGNMENT LL_ADC_DATA_ALIGN_RIGHT
+#define STM32F4_ADC_DEFAULT_SAMPLINGTIME LL_ADC_SAMPLINGTIME_3CYCLES
+
+#define STM32F4_ADC_DEFAULT_RESOLUTION_RTEMS 10
+#define STM32F4_ADC_DEFAULT_ALIGNMENT_RTEMS RTEMS_ADC_ALIGN_RIGHT
+
+/**
+ * Macros for simple locking of shared objects.
+ * Structs must have a bool member named "locked"
+ */
+#define STM32F4_LOCK(obj) \
+ do { \
+ ( obj )->locked = true; \
+ } while (0)
+
+#define STM32F4_UNLOCK(obj) \
+ do { \
+ ( obj )->locked = false; \
+ } while (0)
+
+#define STM32F4_IS_LOCKED(obj) \
+ (( obj )->locked)
+
+/**
+ * @brief Wrapper of ADC_TypeDef with a simple lock.
+ */
+typedef struct {
+ ADC_TypeDef *ADCx;
+ bool locked;
+} ADC_TypeDef_Protected;
+
+/**
+ * @brief Structure containing ADC configuration for an
+ * ADC pin.
+ */
+typedef struct {
+ /**
+ * @brief Locks ADC configuration change on this pin
+ * if set to true.
+ */
+ bool locked;
+ /**
+ * @brief STM32F4-defined ADCx.
+ */
+ ADC_TypeDef_Protected *ADCx;
+ /**
+ * @brief ADC channel of the pin.
+ * This can be LL_ADC_CHANNEL_n defined by STM32F4 LL
+ * driver, where 0 <= n <= 18.
+ */
+ uint32_t channel;
+ /**
+ * @brief Resolution of the ADC pin.
+ * This can be one of the following values:
+ * @ref LL_ADC_RESOLUTION_12B
+ * @ref LL_ADC_RESOLUTION_10B
+ * @ref LL_ADC_RESOLUTION_8B
+ * @ref LL_ADC_RESOLUTION_6B
+ */
+ uint32_t resolution;
+ /**
+ * @brief Data alignment of the ADC pin.
+ * This can be one of the following values:
+ * @ref LL_ADC_DATA_ALIGN_RIGHT
+ * @ref LL_ADC_DATA_ALIGN_LEFT
+ */
+ uint32_t alignment;
+} stm32f4_adc_config;
+
+/**
+ * @brief STM32F4 wrapper of peripherals API.
+ */
+typedef struct {
+ rtems_adc base;
+ stm32f4_adc_config adc_config;
+} stm32f4_adc;
+
+const rtems_adc_handlers *stm32f4_get_adc_handlers(
+ void
+);
+
+/**
+ * @brief Get the HAL-defined ADCx pointer.
+ * @note This function should not be called. Use
+ * @see stm32f4_get_ADCx_protected() instead.
+ */
+ADC_TypeDef *stm32f4_get_ADCx(
+ GPIO_TypeDef *gpiox
+);
+
+ADC_TypeDef_Protected *stm32f4_get_ADCx_protected(
+ GPIO_TypeDef *gpiox
+);
+
+rtems_status_code stm32f4_get_LL_ADC_CHANNEL(
+ stm32f4_gpio *gpio,
+ uint32_t *channel
+);
+
+bool stm32f4_is_adc_pin(
+ stm32f4_gpio *gpio
+);
+
+rtems_status_code stm32f4_adc_get(
+ uint32_t id,
+ uint32_t adc_num,
+ rtems_adc **out
+);
+
+rtems_status_code stm32f4_adc_destroy(
+ rtems_adc *adc
+);
+
+/***/
+
+/**
+ * @brief Performs initialization for an ADC pin
+ */
+void stm32f4_adc_init(
+ rtems_adc *base
+);
+
+rtems_status_code stm32f4_adc_read_raw(
+ rtems_adc *base,
+ uint32_t *result,
+ uint32_t timeout
+);
+
+rtems_status_code stm32f4_adc_start_read_raw_nb(
+ rtems_adc *base
+);
+
+rtems_adc_status stm32f4_adc_read_raw_nb(
+ rtems_adc *base,
+ uint32_t *result
+);
+
+rtems_status_code stm32f4_adc_set_channel(
+ rtems_adc *base,
+ uint32_t channel
+);
+
+rtems_status_code stm32f4_adc_set_resolution(
+ rtems_adc *base,
+ unsigned int bits
+);
+
+rtems_status_code stm32f4_adc_set_alignment(
+ rtems_adc *base,
+ rtems_adc_align align
+);
+
+#endif /* LIBBSP_ARM_STM32F4_BSP_ADC */
diff --git a/spec/build/bsps/arm/stm32f4/grp.yml b/spec/build/bsps/arm/stm32f4/grp.yml
index 1cb14c7ae6..bba1afb728 100644
--- a/spec/build/bsps/arm/stm32f4/grp.yml
+++ b/spec/build/bsps/arm/stm32f4/grp.yml
@@ -26,6 +26,8 @@ links:
uid: optusehse
- role: build-dependency
uid: optnumgpioctrl
+- role: build-dependency
+ uid: optnumadcctrl
- role: build-dependency
uid: opteni2c1
- role: build-dependency
diff --git a/spec/build/bsps/arm/stm32f4/obj.yml b/spec/build/bsps/arm/stm32f4/obj.yml
index f05c072fec..c477e35628 100644
--- a/spec/build/bsps/arm/stm32f4/obj.yml
+++ b/spec/build/bsps/arm/stm32f4/obj.yml
@@ -153,6 +153,7 @@ install:
- bsps/arm/stm32f4/include/bsp/stm32f10xxx_rcc.h
- bsps/arm/stm32f4/include/bsp/stm32f4.h
- bsps/arm/stm32f4/include/bsp/stm32f4_gpio.h
+ - bsps/arm/stm32f4/include/bsp/stm32f4_adc.h
- bsps/arm/stm32f4/include/bsp/stm32f4xxxx_adc.h
- bsps/arm/stm32f4/include/bsp/stm32f4xxxx_exti.h
- bsps/arm/stm32f4/include/bsp/stm32f4xxxx_flash.h
@@ -262,6 +263,7 @@ source:
- bsps/arm/stm32f4/hal/stm32f4xx_ll_utils.c
- bsps/arm/stm32f4/hal/system_stm32f4xx.c
- bsps/arm/stm32f4/gpio/gpio.c
+- bsps/arm/stm32f4/adc/adc.c
- bsps/arm/shared/irq/irq-armv7m.c
- bsps/arm/shared/irq/irq-dispatch-armv7m.c
- bsps/arm/shared/start/bsp-start-memcpy.S
@@ -277,6 +279,7 @@ source:
- bsps/arm/stm32f4/start/start-config-io.c
- bsps/shared/cache/nocache.c
- bsps/shared/dev/gpio/gpio2.c
+- bsps/shared/dev/adc/adc.c
- bsps/shared/dev/btimer/btimer-cpucounter.c
- bsps/shared/dev/cpucounter/cpucounterfrequency.c
- bsps/shared/dev/cpucounter/cpucounterread.c
diff --git a/spec/build/bsps/arm/stm32f4/optnumadcctrl.yml b/spec/build/bsps/arm/stm32f4/optnumadcctrl.yml
new file mode 100644
index 0000000000..d3a1ee7345
--- /dev/null
+++ b/spec/build/bsps/arm/stm32f4/optnumadcctrl.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: 1
+default-by-variant: []
+description: |
+ Number of ADC controllers of this BSP.
+enabled-by: true
+format: '{}'
+links: []
+name: BSP_ADC_NUM_CONTROLLERS
+type: build
--
2.37.1
More information about the devel
mailing list