--- 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 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel