From b451de05e4a6799d5cd403d3ac97a44a5d705fa6 Mon Sep 17 00:00:00 2001 From: Hauke Petersen Date: Thu, 17 Jul 2014 00:57:19 +0200 Subject: [PATCH] cpu/board: added ADC driver for stm32f4discovery --- boards/stm32f4discovery/include/periph_conf.h | 67 +++---- cpu/stm32f4/periph/adc.c | 185 ++++++++++++++++++ 2 files changed, 209 insertions(+), 43 deletions(-) create mode 100644 cpu/stm32f4/periph/adc.c diff --git a/boards/stm32f4discovery/include/periph_conf.h b/boards/stm32f4discovery/include/periph_conf.h index bf41fe09c..47c5694ce 100644 --- a/boards/stm32f4discovery/include/periph_conf.h +++ b/boards/stm32f4discovery/include/periph_conf.h @@ -109,57 +109,38 @@ * @name ADC configuration * @{ */ -#define ADC_NUMOF (0U) -#define ADC_0_EN 0 -#define ADC_1_EN 0 +#define ADC_NUMOF (2U) +#define ADC_0_EN 1 +#define ADC_1_EN 1 +#define ADC_MAX_CHANNELS 2 /* ADC 0 configuration */ -#define ADC_0_DEV ADC1 /* TODO !!!!!!! */ -#define ADC_0_SAMPLE_TIMER +#define ADC_0_DEV ADC1 +#define ADC_0_CHANNELS 2 +#define ADC_0_CLKEN() (RCC->APB2ENR |= RCC_APB2ENR_ADC1EN) +#define ADC_0_CLKDIS() (RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN)) +#define ADC_0_PORT GPIOA +#define ADC_0_PORT_CLKEN() (RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN) /* ADC 0 channel 0 pin config */ -#define ADC_0_C0_PORT -#define ADC_0_C0_PIN -#define ADC_0_C0_CLKEN() -#define ADC_0_C0_AFCFG() +#define ADC_0_CH0 1 +#define ADC_0_CH0_PIN 1 /* ADC 0 channel 1 pin config */ -#define ADC_0_C1_PORT -#define ADC_0_C1_PIN -#define ADC_0_C1_CLKEN() -#define ADC_0_C1_AFCFG() -/* ADC 0 channel 2 pin config */ -#define ADC_0_C2_PORT -#define ADC_0_C2_PIN -#define ADC_0_C2_CLKEN() -#define ADC_0_C2_AFCFG() -/* ADC 0 channel 3 pin config */ -#define ADC_0_C3_PORT -#define ADC_0_C3_PIN -#define ADC_0_C3_CLKEN() -#define ADC_0_C3_AFCFG() +#define ADC_0_CH1 4 +#define ADC_0_CH1_PIN 4 /* ADC 0 configuration */ -#define ADC_1_DEV ADC2 /* TODO !!!!!!! */ -#define ADC_1_SAMPLE_TIMER +#define ADC_1_DEV ADC2 +#define ADC_1_CHANNELS 2 +#define ADC_1_CLKEN() (RCC->APB2ENR |= RCC_APB2ENR_ADC2EN) +#define ADC_1_CLKDIS() (RCC->APB2ENR &= ~(RCC_APB2ENR_ADC2EN)) +#define ADC_1_PORT GPIOC +#define ADC_1_PORT_CLKEN() (RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN) /* ADC 0 channel 0 pin config */ -#define ADC_1_C0_PORT -#define ADC_1_C0_PIN -#define ADC_1_C0_CLKEN() -#define ADC_1_C0_AFCFG() +#define ADC_1_CH0 11 +#define ADC_1_CH0_PIN 1 /* ADC 0 channel 1 pin config */ -#define ADC_1_C1_PORT -#define ADC_1_C1_PIN -#define ADC_1_C1_CLKEN() -#define ADC_1_C1_AFCFG() -/* ADC 0 channel 2 pin config */ -#define ADC_1_C2_PORT -#define ADC_1_C2_PIN -#define ADC_1_C2_CLKEN() -#define ADC_1_C2_AFCFG() -/* ADC 0 channel 3 pin config */ -#define ADC_1_C3_PORT -#define ADC_1_C3_PIN -#define ADC_1_C3_CLKEN() -#define ADC_1_C3_AFCFG() +#define ADC_1_CH1 12 +#define ADC_1_CH1_PIN 2 /** @} */ diff --git a/cpu/stm32f4/periph/adc.c b/cpu/stm32f4/periph/adc.c new file mode 100644 index 000000000..03e38614c --- /dev/null +++ b/cpu/stm32f4/periph/adc.c @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2014 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. + */ + +/** + * @ingroup cpu_stm32f4 + * @{ + * + * @file + * @brief Low-level ADC driver implementation + * + * @author Hauke Petersen + * + * @} + */ + +#include "cpu.h" +#include "periph/adc.h" +#include "periph_conf.h" + +/* guard in case that no ADC device is defined */ +#if ADC_NUMOF + +typedef struct { + int max_value; +} adc_config_t; + +adc_config_t adc_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 * 2) | 3 << (ADC_0_CH1_PIN * 2)); + break; +#endif +#if ADC_1_EN + case ADC_1: + adc = ADC_1_DEV; + ADC_1_PORT_CLKEN(); + ADC_1_PORT->MODER |= (3 << (ADC_1_CH0_PIN * 2) | 3 << (ADC_1_CH1_PIN * 2)); + break; +#endif + default: + return -1; + } + + /* reset control registers */ + adc->CR1 = 0; + adc->CR2 = 0; + adc->SQR1 = 0; + + /* set precision */ + + switch (precision) { + case ADC_RES_6BIT: + adc->CR1 |= ADC_CR1_RES_0 | ADC_CR1_RES_1; + adc_config[dev].max_value = 0x3f; + break; + case ADC_RES_8BIT: + adc->CR1 |= ADC_CR1_RES_1; + adc_config[dev].max_value = 0xff; + break; + case ADC_RES_10BIT: + adc->CR1 |= ADC_CR1_RES_0; + adc_config[dev].max_value = 0x3ff; + break; + case ADC_RES_12BIT: + adc_config[dev].max_value = 0xfff; + break; + case ADC_RES_14BIT: + case ADC_RES_16BIT: + adc_poweroff(dev); + return -1; + break; + } + + /* set clock prescaler */ + ADC->CCR = (3 << 16); /* ADC clock = 10,5MHz */ + + /* enable the ADC module */ + adc->CR2 |= ADC_CR2_ADON; + + return 0; +} + +int adc_sample(adc_t dev, int channel) +{ + ADC_TypeDef *adc = 0; + + switch (dev) { +#if ADC_0_EN + case ADC_0: + adc = ADC_0_DEV; + switch (channel) { + case 0: + adc->SQR3 = ADC_0_CH0 & 0x1f; + break; + case 1: + adc->SQR3 = ADC_0_CH1 & 0x1f; + break; + default: + return -1; + } + break; +#endif +#if ADC_1_EN + case ADC_1: + adc = ADC_1_DEV; + switch (channel) { + case 0: + adc->SQR3 = ADC_1_CH0 & 0x1f; + break; + case 1: + adc->SQR3 = ADC_1_CH1 & 0x1f; + break; + default: + return -1; + } + break; +#endif + } + + /* start single conversion */ + adc->CR2 |= ADC_CR2_SWSTART; + /* wait until conversion is complete */ + while (!(adc->SR & ADC_SR_EOC)); + /* read and return result */ + return (int)adc->DR; +} + +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 + } +} + +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 + } +} + +int adc_map(adc_t dev, int value, int min, int max) +{ + return (int)adc_mapf(dev, value, (float)min, (float)max); +} + +float adc_mapf(adc_t dev, int value, float min, float max) +{ + return ((max - min) / ((float)adc_config[dev].max_value)) * value; +} + +#endif /* ADC_NUMOF */