From da80af479ca187cf7523f4ff386b1a62ea2d4ec8 Mon Sep 17 00:00:00 2001 From: Hauke Petersen Date: Sun, 14 Feb 2016 13:28:05 +0100 Subject: [PATCH] cpu/stm32f0: reworked ADC driver --- cpu/stm32f0/include/periph_cpu.h | 23 ++++ cpu/stm32f0/periph/adc.c | 218 ++++++++++--------------------- 2 files changed, 95 insertions(+), 146 deletions(-) diff --git a/cpu/stm32f0/include/periph_cpu.h b/cpu/stm32f0/include/periph_cpu.h index 50e82c637f..5674f1ecb7 100644 --- a/cpu/stm32f0/include/periph_cpu.h +++ b/cpu/stm32f0/include/periph_cpu.h @@ -77,6 +77,29 @@ typedef enum { GPIO_AF3, /**< use alternate function 3 */ } gpio_af_t; +/** + * @brief Override ADC resolution values + * @{ + */ +#define HAVE_ADC_RES_T +typedef enum { + ADC_RES_6BIT = (0x3 << 3), /**< ADC resolution: 6 bit */ + ADC_RES_8BIT = (0x2 << 3), /**< ADC resolution: 8 bit */ + ADC_RES_10BIT = (0x1 << 3), /**< ADC resolution: 10 bit */ + ADC_RES_12BIT = (0x0 << 3), /**< ADC resolution: 12 bit */ + ADC_RES_14BIT = (0xfe), /**< not applicable */ + ADC_RES_16BIT = (0xff) /**< not applicable */ +} adc_res_t; +/** @} */ + +/** + * @brief ADC line configuration values + */ +typedef struct { + gpio_t pin; /**< pin to use */ + uint8_t chan; /**< internal channel the pin is connected to */ +} adc_conf_t; + /** * @brief Configure the alternate function for the given pin * diff --git a/cpu/stm32f0/periph/adc.c b/cpu/stm32f0/periph/adc.c index 08834b0a4d..d21b3625eb 100644 --- a/cpu/stm32f0/periph/adc.c +++ b/cpu/stm32f0/periph/adc.c @@ -1,9 +1,9 @@ /* - * Copyright (C) 2014 Freie Universität Berlin + * Copyright (C) 2014-2016 Freie Universität Berlin * - * This file is subject to the terms and conditions of the GNU Lesser General - * Public License v2.1. See the file LICENSE in the top level directory for more - * details. + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. */ /** @@ -18,164 +18,90 @@ * @} */ -#include -#include - #include "cpu.h" +#include "mutex.h" #include "periph/adc.h" -#include "periph_conf.h" -/* guard in case that no ADC device is defined */ -#if ADC_NUMOF +/** + * @brief Maximum allowed ADC clock speed + */ +#define MAX_ADC_SPEED (12000000U) - -typedef struct { - uint8_t precision; -} adc_config_t; - - -adc_config_t config[ADC_NUMOF]; - - -int adc_init(adc_t dev, adc_precision_t precision) -{ - ADC_TypeDef *adc = 0; - - adc_poweron(dev); - - switch (dev) { -#if ADC_0_EN - case ADC_0: - adc = ADC_0_DEV; - ADC_0_PORT_CLKEN(); - ADC_0_PORT->MODER |= ((3 << ADC_0_CH0_PIN) | (3 << ADC_0_CH1_PIN) | - (3 << ADC_0_CH2_PIN) | (3 << ADC_0_CH3_PIN) | - (3 << ADC_0_CH4_PIN) | (3 << ADC_0_CH5_PIN)); - break; +/** + * @brief Load the ADC configuration + * @{ + */ +#ifdef ADC_CONFIG +static const adc_conf_t adc_config[] = ADC_CONFIG; +#else +static const adc_conf_t adc_config[] = {}; #endif - default: - return -1; + +/** + * @brief Allocate locks for all three available ADC device + * + * All STM32F0 CPUs we support so far only come with a single ADC device. + */ +static mutex_t lock = MUTEX_INIT; + +static inline void prep(void) +{ + mutex_lock(&lock); + RCC->APB2ENR |= RCC_APB2ENR_ADCEN; +} + +static inline void done(void) +{ + RCC->APB2ENR &= ~(RCC_APB2ENR_ADCEN); + mutex_unlock(&lock); +} + +int adc_init(adc_t line) +{ + /* make sure the given line is valid */ + if (line >= ADC_NUMOF) { + return -1; } - /* reset control registers */ - adc->CR = 0; - adc->CFGR1 = 0; - adc->CFGR2 = 0; - - /* set resolution */ - config[dev].precision = (6 + (2 * precision)); - - switch (precision) { - case ADC_RES_6BIT: - adc->CFGR1 |= ADC_CFGR1_RES_0 | ADC_CFGR1_RES_1; - break; - case ADC_RES_8BIT: - adc->CFGR1 |= ADC_CFGR1_RES_1; - break; - case ADC_RES_10BIT: - adc->CFGR1 |= ADC_CFGR1_RES_0; - break; - case ADC_RES_12BIT: - break; - case ADC_RES_14BIT: - case ADC_RES_16BIT: - adc_poweroff(dev); - return -1; - } - - /* configure sampling time to 41.5 cycles */ - adc->SMPR = 4; - - /* enable the ADC module */ - adc->CR = ADC_CR_ADEN; + /* lock and power on the device */ + prep(); + /*configure the pin */ + gpio_init_analog(adc_config[line].pin); + /* reset configuration */ + ADC1->CFGR2 = 0; + /* enable device */ + ADC1->CR = ADC_CR_ADEN; + /* configure sampling time to save value */ + ADC1->SMPR = 0x3; /* 28.5 ADC clock cycles */ + /* power off an release device for now */ + done(); return 0; } -int adc_sample(adc_t dev, int channel) +int adc_sample(adc_t line, adc_res_t res) { - ADC_TypeDef *adc = 0; + int sample; - switch (dev) { -#if ADC_0_EN - case ADC_0: - adc = ADC_0_DEV; - switch (channel) { - case 0: - adc->CHSELR = (1 << ADC_0_CH0); - break; - case 1: - adc->CHSELR = (1 << ADC_0_CH1); - break; - case 2: - adc->CHSELR = (1 << ADC_0_CH2); - break; - case 3: - adc->CHSELR = (1 << ADC_0_CH3); - break; - case 4: - adc->CHSELR = (1 << ADC_0_CH4); - break; - case 5: - adc->CHSELR = (1 << ADC_0_CH5); - break; - default: - return -1; - } - break; -#endif - default: - return -1; + /* check if resolution is applicable */ + if (res > 0xf0) { + return -1; } - /* start single conversion */ - adc->CR |= ADC_CR_ADSTART; - /* wait until conversion is complete */ - while (!(adc->ISR & ADC_ISR_EOC)) {} - /* read and return result */ - return (int)adc->DR; -} + /* lock and power on the ADC device */ + prep(); -void adc_poweron(adc_t dev) -{ - switch (dev) { -#if ADC_0_EN - case ADC_0: - ADC_0_CLKEN(); - break; -#endif -#if ADC_1_EN - case ADC_1: - ADC_1_CLKEN(); - break; -#endif - } -} + /* set resolution and channel */ + ADC1->CFGR1 = res; + ADC1->CHSELR = (1 << adc_config[line].chan); + /* start conversion and wait for results */ + ADC1->CR |= ADC_CR_ADSTART; + while (!(ADC1->ISR & ADC_ISR_EOC)) {} + /* read result */ + sample = (int)ADC1->DR; -void adc_poweroff(adc_t dev) -{ - switch (dev) { -#if ADC_0_EN - case ADC_0: - ADC_0_CLKDIS(); - break; -#endif -#if ADC_1_EN - case ADC_1: - ADC_1_CLKDIS(); - break; -#endif - } -} + /* unlock and power off device again */ + done(); -int adc_map(adc_t dev, int value, int min, int max) -{ - return 0; + return sample; } - -float adc_mapf(adc_t dev, int value, float min, float max) -{ - return 0.0; -} - -#endif /* ADC_NUMOF */