From 539d1b45f61700c11a97151cd246b4b3983f5c07 Mon Sep 17 00:00:00 2001 From: Silvano Seva Date: Tue, 30 Apr 2024 08:40:46 +0200 Subject: [PATCH] STM32F4xx: driver for ADC peripherals --- meson.build | 1 + platform/mcu/STM32F4xx/drivers/adc_stm32.c | 116 +++++++++++++++++++++ platform/mcu/STM32F4xx/drivers/adc_stm32.h | 66 ++++++++++++ 3 files changed, 183 insertions(+) create mode 100644 platform/mcu/STM32F4xx/drivers/adc_stm32.c create mode 100644 platform/mcu/STM32F4xx/drivers/adc_stm32.h diff --git a/meson.build b/meson.build index ae53579f..7162ea64 100644 --- a/meson.build +++ b/meson.build @@ -214,6 +214,7 @@ stm32f405_src = ['platform/mcu/STM32F4xx/boot/startup.cpp', 'platform/mcu/STM32F4xx/drivers/rng.c', 'platform/mcu/STM32F4xx/drivers/i2c_stm32.c', 'platform/mcu/STM32F4xx/drivers/spi_stm32.c', + 'platform/mcu/STM32F4xx/drivers/adc_stm32.c', 'platform/drivers/audio/stm32_dac.cpp', 'platform/drivers/audio/stm32_adc.cpp', 'platform/drivers/audio/stm32_pwm.cpp', diff --git a/platform/mcu/STM32F4xx/drivers/adc_stm32.c b/platform/mcu/STM32F4xx/drivers/adc_stm32.c new file mode 100644 index 00000000..44c55936 --- /dev/null +++ b/platform/mcu/STM32F4xx/drivers/adc_stm32.c @@ -0,0 +1,116 @@ +/*************************************************************************** + * Copyright (C) 2020 - 2023 by Silvano Seva IU2KWO * + * and Niccolò Izzo IU2KIN * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, see * + ***************************************************************************/ + +#include +#include +#include +#include "adc_stm32.h" + +int adcStm32_init(const struct Adc *adc) +{ + switch((uint32_t) adc->priv) + { + case ADC1_BASE: + RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; + __DSB(); + break; + + case ADC2_BASE: + RCC->APB2ENR |= RCC_APB2ENR_ADC2EN; + __DSB(); + break; + + case ADC3_BASE: + RCC->APB2ENR |= RCC_APB2ENR_ADC3EN; + __DSB(); + break; + + default: + return -EINVAL; + break; + } + + ADC_TypeDef *pAdc = ((ADC_TypeDef *) adc->priv); + + /* + * ADC clock is APB2 frequency divided by 8, giving 10.5MHz. + * We set the sample time of each channel to 84 ADC cycles and we have that + * a conversion takes 12 cycles: total conversion time is then of ~9us. + */ + ADC->CCR |= ADC_CCR_ADCPRE; + pAdc->SMPR2 = 0x4924924; + pAdc->SMPR1 = 0x24924924; + + /* + * Convert one channel, no overrun interrupt, 12-bit resolution, + * no analog watchdog, discontinuous mode, no end of conversion interrupts, + * turn on ADC. + */ + pAdc->SQR1 = 0; + pAdc->CR2 = ADC_CR2_ADON; + + if(adc->mutex != NULL) + pthread_mutex_init((pthread_mutex_t *) adc->mutex, NULL); + + return 0; +} + +void adcStm32_terminate(const struct Adc *adc) +{ + /* A conversion may be in progress, wait until it finishes */ + if(adc->mutex != NULL) + pthread_mutex_lock((pthread_mutex_t *) adc->mutex); + + ((ADC_TypeDef *) adc->priv)->CR2 = 0; + + switch((uint32_t) adc->priv) + { + case ADC1_BASE: + RCC->APB2ENR &= ~RCC_APB2ENR_ADC1EN; + __DSB(); + break; + + case ADC2_BASE: + RCC->APB2ENR &= ~RCC_APB2ENR_ADC2EN; + __DSB(); + break; + + case ADC3_BASE: + RCC->APB2ENR &= ~RCC_APB2ENR_ADC3EN; + __DSB(); + break; + } + + if(adc->mutex != NULL) + pthread_mutex_destroy((pthread_mutex_t *) adc->mutex); +} + +uint16_t adcStm32_sample(const struct Adc *adc, const uint32_t channel) +{ + if(channel > 19) + return 0; + + ADC_TypeDef *pAdc = ((ADC_TypeDef *) adc->priv); + + pAdc->SQR3 = channel; + pAdc->CR2 |= ADC_CR2_SWSTART; + + while((pAdc->SR & ADC_SR_EOC) == 0) ; + + return pAdc->DR; +} diff --git a/platform/mcu/STM32F4xx/drivers/adc_stm32.h b/platform/mcu/STM32F4xx/drivers/adc_stm32.h new file mode 100644 index 00000000..9764cc1c --- /dev/null +++ b/platform/mcu/STM32F4xx/drivers/adc_stm32.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2024 by Silvano Seva IU2KWO * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, see * + ***************************************************************************/ + +#ifndef ADC_STM32_H +#define ADC_STM32_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Define an instance of an STM32 ADC device driver. + * + * @param name: instance name. + * @param periph: pointer to hardware peripheral. + * @param mutx: pointer to mutex for concurrent access, can be NULL. + * @param vref: ADC reference voltage, in uV. + */ +#define ADC_STM32_DEVICE_DEFINE(name, periph, mutx, vref) \ +extern uint16_t adcStm32_sample(const struct Adc *adc, \ + const uint32_t channel); \ +const struct Adc name = \ +{ \ + .sample = &adcStm32_sample, \ + .priv = periph, \ + .mutex = mutx, \ + .countsTouV = ADC_COUNTS_TO_UV(vref, 12) \ +}; + +/** + * Initialize an STM32 ADC peripheral. + * + * @param adc: pointer to ADC device handle. + * @return zero on success, a negative error code otherwise. + */ +int adcStm32_init(const struct Adc *adc); + +/** + * Shut down an STM32 ADC peripheral. + * + * @param adc: pointer to ADC device handle. + * @return zero on success, a negative error code otherwise. + */ +void adcStm32_terminate(const struct Adc *adc); + +#ifdef __cplusplus +} +#endif + +#endif /* ADC_STM32_H */