diff --git a/boards/airfy-beacon/include/periph_conf.h b/boards/airfy-beacon/include/periph_conf.h index df2f613bfb..cce1947844 100644 --- a/boards/airfy-beacon/include/periph_conf.h +++ b/boards/airfy-beacon/include/periph_conf.h @@ -95,19 +95,13 @@ static const timer_conf_t timer_config[] = { /** @} */ /** - * @name ADC configuration + * @brief ADC configuration + * + * The configuration consists simply of a list of channels that should be used * @{ */ -#define ADC_NUMOF (1U) -#define ADC_0_EN 1 -#define ADC_MAX_CHANNELS 4 - -/* ADC 0 device configuration */ -#define ADC_0_CHANNELS 4 -#define ADC_0_CH0 ADC_CONFIG_PSEL_AnalogInput3 -#define ADC_0_CH1 ADC_CONFIG_PSEL_AnalogInput4 -#define ADC_0_CH2 ADC_CONFIG_PSEL_AnalogInput5 -#define ADC_0_CH3 ADC_CONFIG_PSEL_AnalogInput6 +#define ADC_CONFIG {3, 4, 5, 6} +#define ADC_NUMOF (4) /** @} */ /** diff --git a/boards/ek-lm4f120xl/include/periph_conf.h b/boards/ek-lm4f120xl/include/periph_conf.h index 83e9634545..537e3e6d4b 100644 --- a/boards/ek-lm4f120xl/include/periph_conf.h +++ b/boards/ek-lm4f120xl/include/periph_conf.h @@ -93,12 +93,11 @@ extern "C" { /** @} */ /** - * @name ADC configuration + * @brief ADC configuration * @{ */ -#define ADC_NUMOF 1 -#define ADC_0_EN 1 -#define ADC_MAX_CHANNELS 12 +#define ADC_NUMOF (12) +/** @} */ #ifdef __cplusplus } diff --git a/boards/f4vi1/include/periph_conf.h b/boards/f4vi1/include/periph_conf.h index 4b596fe916..858cb098fe 100644 --- a/boards/f4vi1/include/periph_conf.h +++ b/boards/f4vi1/include/periph_conf.h @@ -104,6 +104,13 @@ static const uart_conf_t uart_config[] = { #define UART_NUMOF (sizeof(uart_config) / sizeof(uart_config[0])) /** @} */ +/** + * @brief ADC configuration + * @{ + */ +#define ADC_NUMOF (0) +/** @} */ + #ifdef __cplusplus } #endif diff --git a/boards/frdm-k64f/include/periph_conf.h b/boards/frdm-k64f/include/periph_conf.h index 10269e0053..871a5ebe6c 100644 --- a/boards/frdm-k64f/include/periph_conf.h +++ b/boards/frdm-k64f/include/periph_conf.h @@ -20,7 +20,7 @@ #ifndef PERIPH_CONF_H #define PERIPH_CONF_H -#include "cpu_conf.h" +#include "periph_cpu.h" #ifdef __cplusplus extern "C" @@ -45,6 +45,7 @@ extern "C" #define KINETIS_MCG_PLL_FREQ 60000000 #define CLOCK_CORECLOCK KINETIS_MCG_PLL_FREQ +#define CLOCK_BUSCLOCK (CLOCK_CORECLOCK / 2) /** @} */ @@ -102,47 +103,17 @@ extern "C" * @name ADC configuration * @{ */ -#define ADC_NUMOF (1U) -#define ADC_0_EN 1 -#define ADC_MAX_CHANNELS 6 +static const adc_conf_t adc_config[] = { + /* dev, pin, channel */ + { ADC0, GPIO_PIN(PORT_B, 10), 14 }, + { ADC0, GPIO_PIN(PORT_B, 11), 15 }, + { ADC0, GPIO_PIN(PORT_C, 11), 7 }, + { ADC0, GPIO_PIN(PORT_C, 10), 6 }, + { ADC0, GPIO_PIN(PORT_C, 8), 4 }, + { ADC0, GPIO_PIN(PORT_C, 9), 5 }, +}; -/* ADC 0 configuration */ -#define ADC_0_DEV ADC1 -#define ADC_0_MODULE_CLOCK CLOCK_CORECLOCK -#define ADC_0_CHANNELS 6 -#define ADC_0_CLKEN() (SIM->SCGC3 |= (SIM_SCGC3_ADC1_MASK)) -#define ADC_0_CLKDIS() (SIM->SCGC3 &= ~(SIM_SCGC3_ADC1_MASK)) -#define ADC_0_PORT_CLKEN() (SIM->SCGC5 |= (SIM_SCGC5_PORTB_MASK | SIM_SCGC5_PORTC_MASK)) -/* ADC 0 channel 0 pin config */ -#define ADC_0_CH0_PORT PORTB -#define ADC_0_CH0_PIN 10 -#define ADC_0_CH0_PIN_AF 0 -#define ADC_0_CH0 14 -/* ADC 0 channel 1 pin config */ -#define ADC_0_CH1_PORT PORTB -#define ADC_0_CH1_PIN 11 -#define ADC_0_CH1_PIN_AF 0 -#define ADC_0_CH1 15 -/* ADC 0 channel 2 pin config */ -#define ADC_0_CH2_PORT PORTC -#define ADC_0_CH2_PIN 11 -#define ADC_0_CH2_PIN_AF 0 -#define ADC_0_CH2 7 -/* ADC 0 channel 3 pin config */ -#define ADC_0_CH3_PORT PORTC -#define ADC_0_CH3_PIN 10 -#define ADC_0_CH3_PIN_AF 0 -#define ADC_0_CH3 6 -/* ADC 0 channel 4 pin config */ -#define ADC_0_CH4_PORT PORTC -#define ADC_0_CH4_PIN 8 -#define ADC_0_CH4_PIN_AF 0 -#define ADC_0_CH4 4 -/* ADC 0 channel 5 pin config */ -#define ADC_0_CH5_PORT PORTC -#define ADC_0_CH5_PIN 9 -#define ADC_0_CH5_PIN_AF 0 -#define ADC_0_CH5 5 +#define ADC_NUMOF (sizeof(adc_config) / sizeof(adc_config[0])) /** @} */ /** diff --git a/boards/msbiot/include/periph_conf.h b/boards/msbiot/include/periph_conf.h index f3cb437f0e..2ff330ae23 100644 --- a/boards/msbiot/include/periph_conf.h +++ b/boards/msbiot/include/periph_conf.h @@ -100,25 +100,17 @@ extern "C" { /** * @name ADC configuration + * + * We need to define the following fields: + * PIN, device (ADCx), channel * @{ */ -#define ADC_NUMOF (1U) -#define ADC_0_EN 1 -#define ADC_MAX_CHANNELS 2 +#define ADC_CONFIG { \ + {GPIO_PIN(PORT_B, 0), 0, 8}, \ + {GPIO_PIN(PORT_B, 1), 0, 9} \ +} -/* ADC 0 configuration */ -#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 GPIOB -#define ADC_0_PORT_CLKEN() (RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN) -/* ADC 0 channel 0 pin config */ -#define ADC_0_CH0 8 -#define ADC_0_CH0_PIN 0 -/* ADC 0 channel 1 pin config */ -#define ADC_0_CH1 9 -#define ADC_0_CH1_PIN 1 +#define ADC_NUMOF (2) /** @} */ /** diff --git a/boards/mulle/include/periph_conf.h b/boards/mulle/include/periph_conf.h index 4f11c05e1a..ad05843e96 100644 --- a/boards/mulle/include/periph_conf.h +++ b/boards/mulle/include/periph_conf.h @@ -20,6 +20,8 @@ #ifndef MULLE_PERIPH_CONF_H_ #define MULLE_PERIPH_CONF_H_ +#include "periph_cpu.h" + #ifdef __cplusplus extern "C" { @@ -50,6 +52,9 @@ extern "C" #define CPU_INT_FAST_CLK_HZ 4000000u /** Default System clock value */ #define DEFAULT_SYSTEM_CLOCK (CPU_XTAL32k_CLK_HZ * 2929u) + +/* bus clock for the peripherals */ +#define CLOCK_BUSCLOCK (DEFAULT_SYSTEM_CLOCK / 2) /** @} */ /** @@ -135,89 +140,19 @@ extern "C" * @name ADC configuration * @{ */ -#define ADC_NUMOF (2U) -#define ADC_0_EN 1 -#define ADC_1_EN 1 -#define ADC_MAX_CHANNELS 6 +static const adc_conf_t adc_config[] = { + /* dev, pin, channel */ + { ADC0, GPIO_UNDEF, 26 }, /* internal: temperature sensor */ + { ADC0, GPIO_UNDEF, 27 }, /* internal: band gap */ + { ADC0, GPIO_UNDEF, 29 }, /* internal: V_REFSH */ + { ADC0, GPIO_UNDEF, 30 }, /* internal: V_REFSL */ + { ADC1, GPIO_UNDEF, 0 }, /* connected to Mulle Vbat/2 on PGA1_DP */ + { ADC1, GPIO_UNDEF, 19 }, /* connected to Mulle Vchr/2 on PGA1_DM */ +}; -/* ADC 0 configuration */ -#define ADC_0_DEV ADC0 -#define ADC_0_CHANNELS 4 -#define ADC_0_CLKEN() (BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_ADC0_SHIFT) = 1) -#define ADC_0_CLKDIS() (BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_ADC0_SHIFT) = 0) -#define ADC_0_PORT_CLKEN() /* no PORT pins configured */ -#define ADC_0_MODULE_CLOCK SystemBusClock -/* ADC 0 channel 0 pin config */ -#define ADC_0_CH0 26 /* Temp sensor channel */ -#define ADC_0_CH0_PORT 0 /* this channel is not part of the pin mux on this CPU */ -#define ADC_0_CH0_PIN 0 -#define ADC_0_CH0_PIN_AF 0 -/* ADC 0 channel 1 pin config */ -#define ADC_0_CH1 27 /* Band gap channel */ -#define ADC_0_CH1_PORT 0 /* this channel is not part of the pin mux on this CPU */ -#define ADC_0_CH1_PIN 0 -#define ADC_0_CH1_PIN_AF 0 -/* ADC 0 channel 2 pin config */ -#define ADC_0_CH2 29 /* V_REFSH */ -#define ADC_0_CH2_PORT 0 /* this channel is not part of the pin mux on this CPU */ -#define ADC_0_CH2_PIN 0 -#define ADC_0_CH2_PIN_AF 0 -/* ADC 0 channel 3 pin config */ -#define ADC_0_CH3 30 /* V_REFSL */ -#define ADC_0_CH3_PORT 0 /* this channel is not part of the pin mux on this CPU */ -#define ADC_0_CH3_PIN 0 -#define ADC_0_CH3_PIN_AF 0 -/* ADC 0 channel 4 pin config */ -#define ADC_0_CH4 4 -#define ADC_0_CH4_PORT 0 -#define ADC_0_CH4_PIN 0 -#define ADC_0_CH4_PIN_AF 0 -/* ADC 0 channel 5 pin config */ -#define ADC_0_CH5 5 -#define ADC_0_CH5_PORT 0 -#define ADC_0_CH5_PIN 0 -#define ADC_0_CH5_PIN_AF 0 - -/* ADC 1 configuration */ -#define ADC_1_DEV ADC1 -#define ADC_1_CHANNELS 2 -#define ADC_1_CLKEN() (BITBAND_REG32(SIM->SCGC3, SIM_SCGC3_ADC1_SHIFT) = 1) -#define ADC_1_CLKDIS() (BITBAND_REG32(SIM->SCGC3, SIM_SCGC3_ADC1_SHIFT) = 0) -#define ADC_1_PORT_CLKEN() /* no PORT pins configured */ -#define ADC_1_MODULE_CLOCK SystemBusClock -/* ADC 1 channel 0 pin config */ -#define ADC_1_CH0 0 /* DADP0, connected externally to Mulle Vbat/2 on PGA1_DP */ -#define ADC_1_CH0_PORT 0 /* this channel is not part of the pin mux on this CPU */ -#define ADC_1_CH0_PIN 0 -#define ADC_1_CH0_PIN_AF 0 -/* ADC 1 channel 1 pin config */ -#define ADC_1_CH1 19 /* AD19, connected externally to Mulle Vchr/2 on PGA1_DM */ -#define ADC_1_CH1_PORT 0 /* this channel is not part of the pin mux on this CPU */ -#define ADC_1_CH1_PIN 0 -#define ADC_1_CH1_PIN_AF 0 -/* ADC 1 channel 2 pin config */ -#define ADC_1_CH2 12 -#define ADC_1_CH2_PIN 0 -#define ADC_1_CH2_PIN_AF 0 -#define ADC_1_CH2_PORT 0 -/* ADC 1 channel 3 pin config */ -#define ADC_1_CH3 13 -#define ADC_1_CH3_PIN 0 -#define ADC_1_CH3_PIN_AF 0 -#define ADC_1_CH3_PORT 0 -/* ADC 1 channel 4 pin config */ -#define ADC_1_CH4 14 -#define ADC_1_CH4_PIN 0 -#define ADC_1_CH4_PIN_AF 0 -#define ADC_1_CH4_PORT 0 -/* ADC 1 channel 5 pin config */ -#define ADC_1_CH5 15 -#define ADC_1_CH5_PIN 0 -#define ADC_1_CH5_PIN_AF 0 -#define ADC_1_CH5_PORT 0 +#define ADC_NUMOF (sizeof(adc_config) / sizeof(adc_config[0])) /** @} */ - /** * @name PWM configuration * @{ diff --git a/boards/nrf51dongle/include/periph_conf.h b/boards/nrf51dongle/include/periph_conf.h index 2fca29fb0b..165e1f8c50 100644 --- a/boards/nrf51dongle/include/periph_conf.h +++ b/boards/nrf51dongle/include/periph_conf.h @@ -80,6 +80,15 @@ static const timer_conf_t timer_config[] = { #define UART_PIN_CTS 10 /** @} */ +/** + * @brief ADC configuration + * + * The configuration consists simply of a list of channels that should be used + * @{ + */ +#define ADC_NUMOF (0) +/** @} */ + /** * @name Radio device configuration * diff --git a/boards/nrf6310/include/periph_conf.h b/boards/nrf6310/include/periph_conf.h index 35b7873344..636b4e0f05 100644 --- a/boards/nrf6310/include/periph_conf.h +++ b/boards/nrf6310/include/periph_conf.h @@ -118,6 +118,16 @@ static const timer_conf_t timer_config[] = { #define SPI_1_PIN_MOSI 18 /** @} */ +/** + * @brief ADC configuration + * + * The configuration consists simply of a list of channels that should be used + * @{ + */ +#define ADC_NUMOF (0) +/** @} */ + + #ifdef __cplusplus } #endif diff --git a/boards/nucleo-f091/include/periph_conf.h b/boards/nucleo-f091/include/periph_conf.h index 7c43f01d13..9415101da4 100644 --- a/boards/nucleo-f091/include/periph_conf.h +++ b/boards/nucleo-f091/include/periph_conf.h @@ -19,6 +19,8 @@ #ifndef PERIPH_CONF_H_ #define PERIPH_CONF_H_ +#include "periph_cpu.h" + #ifdef __cplusplus extern "C" { #endif @@ -100,6 +102,13 @@ extern "C" { #define RTC_NUMOF (1U) /** @} */ +/** + * @brief ADC configuration + * @{ + */ +#define ADC_NUMOF (0) +/** @} */ + #ifdef __cplusplus } #endif diff --git a/boards/nucleo-f401/include/periph_conf.h b/boards/nucleo-f401/include/periph_conf.h index 7464475841..06e1cf6ae6 100644 --- a/boards/nucleo-f401/include/periph_conf.h +++ b/boards/nucleo-f401/include/periph_conf.h @@ -161,6 +161,12 @@ static const uart_conf_t uart_config[] = { #define I2C_0_SDA_CLKEN() (RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN) /** @} */ +/** + * @brief ADC configuration + * @{ + */ +#define ADC_NUMOF (0) +/** @} */ #ifdef __cplusplus } diff --git a/boards/pba-d-01-kw2x/include/periph_conf.h b/boards/pba-d-01-kw2x/include/periph_conf.h index 0ba5cef4be..d3aa4460f3 100644 --- a/boards/pba-d-01-kw2x/include/periph_conf.h +++ b/boards/pba-d-01-kw2x/include/periph_conf.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Freie Universität Berlin + * Copyright (C) 2014-2016 Freie Universität Berlin * Copyright (C) 2014 PHYTEC Messtechnik GmbH * * This file is subject to the terms and conditions of the GNU Lesser General @@ -22,7 +22,7 @@ #ifndef PERIPH_CONF_H_ #define PERIPH_CONF_H_ -#include "cpu_conf.h" +#include "periph_cpu.h" #ifdef __cplusplus extern "C" @@ -47,6 +47,7 @@ extern "C" #define KINETIS_MCG_PLL_FREQ 48000000 #define CLOCK_CORECLOCK KINETIS_MCG_PLL_FREQ +#define CLOCK_BUSCLOCK CLOCK_CORECLOCK /** @} */ @@ -115,55 +116,23 @@ extern "C" #define UART_1_AF 3 /** @} */ - /** * @name ADC configuration * @{ */ -#define ADC_NUMOF (1U) -#define ADC_0_EN 1 -#define ADC_MAX_CHANNELS 6 +static const adc_conf_t adc_config[] = { + /* dev, pin, channel */ + { ADC0, GPIO_PIN(PORT_E, 2), 1 }, + { ADC0, GPIO_PIN(PORT_E, 3), 1 }, + { ADC0, GPIO_PIN(PORT_D, 7), 22 }, + { ADC0, GPIO_PIN(PORT_D, 5), 6 }, + { ADC0, GPIO_PIN(PORT_E, 0), 10 }, + { ADC0, GPIO_PIN(PORT_E, 1), 11 }, +}; -/* ADC 0 configuration */ -#define ADC_0_DEV ADC0 -#define ADC_0_MODULE_CLOCK CLOCK_CORECLOCK -#define ADC_0_CHANNELS 6 -#define ADC_0_CLKEN() (SIM->SCGC6 |= (SIM_SCGC6_ADC0_MASK)) -#define ADC_0_CLKDIS() (SIM->SCGC6 &= ~(SIM_SCGC6_ADC0_MASK)) -#define ADC_0_PORT_CLKEN() (SIM->SCGC5 |= (SIM_SCGC5_PORTD_MASK | SIM_SCGC5_PORTE_MASK)) -/* ADC 0 channel 0 pin config */ -#define ADC_0_CH0 1 -#define ADC_0_CH0_PIN 2 -#define ADC_0_CH0_PIN_AF 0 -#define ADC_0_CH0_PORT PORTE -/* ADC 0 channel 1 pin config */ -#define ADC_0_CH1 1 /* PTE3 uses the same ADC_CH as PTE2, in single channel mode only one of them can be selected */ -#define ADC_0_CH1_PIN 3 -#define ADC_0_CH1_PIN_AF 0 -#define ADC_0_CH1_PORT PORTE -/* ADC 0 channel 2 pin config */ -#define ADC_0_CH2 22 -#define ADC_0_CH2_PIN 7 -#define ADC_0_CH2_PIN_AF 0 -#define ADC_0_CH2_PORT PORTD -/* ADC 0 channel 3 pin config */ -#define ADC_0_CH3 6 -#define ADC_0_CH3_PIN 5 -#define ADC_0_CH3_PIN_AF 0 -#define ADC_0_CH3_PORT PORTD -/* ADC 0 channel 4 pin config */ -#define ADC_0_CH4 10 -#define ADC_0_CH4_PIN 0 -#define ADC_0_CH4_PIN_AF 0 -#define ADC_0_CH4_PORT PORTE -/* ADC 0 channel 5 pin config */ -#define ADC_0_CH5 11 -#define ADC_0_CH5_PIN 1 -#define ADC_0_CH5_PIN_AF 0 -#define ADC_0_CH5_PORT PORTE +#define ADC_NUMOF (sizeof(adc_config) / sizeof(adc_config[0])) /** @} */ - /** * @name PWM configuration * @{ diff --git a/boards/pca10000/include/periph_conf.h b/boards/pca10000/include/periph_conf.h index b00406327b..08cfd5b789 100644 --- a/boards/pca10000/include/periph_conf.h +++ b/boards/pca10000/include/periph_conf.h @@ -82,6 +82,15 @@ static const timer_conf_t timer_config[] = { #define UART_PIN_CTS 10 /** @} */ +/** + * @brief ADC configuration + * + * The configuration consists simply of a list of channels that should be used + * @{ + */ +#define ADC_NUMOF (0) +/** @} */ + /** * @name Radio device configuration * diff --git a/boards/pca10005/include/periph_conf.h b/boards/pca10005/include/periph_conf.h index 02187a417a..f4db32da4f 100644 --- a/boards/pca10005/include/periph_conf.h +++ b/boards/pca10005/include/periph_conf.h @@ -102,19 +102,13 @@ static const timer_conf_t timer_config[] = { /** @} */ /** - * @name ADC configuration + * @brief ADC configuration + * + * The configuration consists simply of a list of channels that should be used * @{ */ -#define ADC_NUMOF (1U) -#define ADC_0_EN 1 -#define ADC_MAX_CHANNELS 4 - -/* ADC 0 device configuration */ -#define ADC_0_CHANNELS 4 -#define ADC_0_CH0 ADC_CONFIG_PSEL_AnalogInput0 -#define ADC_0_CH1 ADC_CONFIG_PSEL_AnalogInput1 -#define ADC_0_CH2 ADC_CONFIG_PSEL_AnalogInput2 -#define ADC_0_CH3 ADC_CONFIG_PSEL_AnalogInput3 +#define ADC_CONFIG {0, 1, 2, 3} +#define ADC_NUMOF (4) /** @} */ /** diff --git a/boards/stm32f0discovery/include/periph_conf.h b/boards/stm32f0discovery/include/periph_conf.h index b668a9850d..35cedddd3b 100644 --- a/boards/stm32f0discovery/include/periph_conf.h +++ b/boards/stm32f0discovery/include/periph_conf.h @@ -19,6 +19,8 @@ #ifndef PERIPH_CONF_H_ #define PERIPH_CONF_H_ +#include "periph_cpu.h" + #ifdef __cplusplus extern "C" { #endif @@ -89,38 +91,22 @@ extern "C" { /** @} */ /** - * @name ADC configuration + * @brief ADC configuration + * + * We need to configure the following values: + * [ pin, channel ] * @{ */ -#define ADC_NUMOF (1U) -#define ADC_0_EN 1 -#define ADC_MAX_CHANNELS 6 +#define ADC_CONFIG { \ + { GPIO_PIN(PORT_C, 0), 10 },\ + { GPIO_PIN(PORT_C, 1), 11 },\ + { GPIO_PIN(PORT_C, 2), 12 },\ + { GPIO_PIN(PORT_C, 3), 13 },\ + { GPIO_PIN(PORT_C, 4), 14 },\ + { GPIO_PIN(PORT_C, 5), 15 } \ +} -/* ADC 0 configuration */ -#define ADC_0_DEV ADC1 -#define ADC_0_CHANNELS 6 -#define ADC_0_CLKEN() (RCC->APB2ENR |= RCC_APB2ENR_ADCEN) -#define ADC_0_CLKDIS() (RCC->APB2ENR &= ~(RCC_APB2ENR_ADCEN)) -#define ADC_0_PORT GPIOC -#define ADC_0_PORT_CLKEN() (RCC->AHBENR |= RCC_AHBENR_GPIOCEN) -/* ADC 0 channel 0 pin config */ -#define ADC_0_CH0 10 -#define ADC_0_CH0_PIN 0 -/* ADC 0 channel 1 pin config */ -#define ADC_0_CH1 11 -#define ADC_0_CH1_PIN 1 -/* ADC 0 channel 2 pin config */ -#define ADC_0_CH2 12 -#define ADC_0_CH2_PIN 2 -/* ADC 0 channel 3 pin config */ -#define ADC_0_CH3 13 -#define ADC_0_CH3_PIN 3 -/* ADC 0 channel 4 pin config */ -#define ADC_0_CH4 14 -#define ADC_0_CH4_PIN 4 -/* ADC 0 channel 5 pin config */ -#define ADC_0_CH5 15 -#define ADC_0_CH5_PIN 5 +#define ADC_NUMOF (6) /** @} */ /** diff --git a/boards/stm32f4discovery/include/periph_conf.h b/boards/stm32f4discovery/include/periph_conf.h index b8086a61de..9b84eab4d0 100644 --- a/boards/stm32f4discovery/include/periph_conf.h +++ b/boards/stm32f4discovery/include/periph_conf.h @@ -116,42 +116,20 @@ static const uart_conf_t uart_config[] = { /** @} */ /** - * @name ADC configuration + * @brief ADC configuration + * + * We need to define the following fields: + * PIN, device (ADCx), channel * @{ */ -#define ADC_NUMOF (2U) -#define ADC_0_EN 1 -#define ADC_1_EN 1 -#define ADC_MAX_CHANNELS 2 +#define ADC_CONFIG { \ + {GPIO_PIN(PORT_A, 1), 0, 1}, \ + {GPIO_PIN(PORT_A, 4), 0, 4}, \ + {GPIO_PIN(PORT_C, 1), 1, 11}, \ + {GPIO_PIN(PORT_C, 2), 1, 12} \ +} -/* ADC 0 configuration */ -#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_CH0 1 -#define ADC_0_CH0_PIN 1 -/* ADC 0 channel 1 pin config */ -#define ADC_0_CH1 4 -#define ADC_0_CH1_PIN 4 - -/* ADC 1 configuration */ -#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 1 channel 0 pin config */ -#define ADC_1_CH0 11 -#define ADC_1_CH0_PIN 1 -/* ADC 1 channel 1 pin config */ -#define ADC_1_CH1 12 -#define ADC_1_CH1_PIN 2 +#define ADC_NUMOF (4) /** @} */ /** diff --git a/boards/weio/include/periph_conf.h b/boards/weio/include/periph_conf.h index f1a293ea3d..a111eba5f8 100644 --- a/boards/weio/include/periph_conf.h +++ b/boards/weio/include/periph_conf.h @@ -266,15 +266,6 @@ extern "C" { #define PWM_1_CH2_AF 0x81 /* @} */ -/** - * @brief ADC configuration - * @{ - */ -#define ADC_NUMOF (1U) -#define ADC_0_EN 1 -#define ADC_MAX_CHANNELS 8 -/* @} */ - #ifdef __cplusplus } #endif diff --git a/boards/yunjia-nrf51822/include/periph_conf.h b/boards/yunjia-nrf51822/include/periph_conf.h index ba5043c49d..0cfea3433e 100644 --- a/boards/yunjia-nrf51822/include/periph_conf.h +++ b/boards/yunjia-nrf51822/include/periph_conf.h @@ -100,19 +100,13 @@ static const timer_conf_t timer_config[] = { /** @} */ /** - * @name ADC configuration + * @brief ADC configuration + * + * The configuration consists simply of a list of channels that should be used * @{ */ -#define ADC_NUMOF (1U) -#define ADC_0_EN 1 -#define ADC_MAX_CHANNELS 4 - -/* ADC 0 device configuration */ -#define ADC_0_CHANNELS 4 -#define ADC_0_CH0 ADC_CONFIG_PSEL_AnalogInput4 -#define ADC_0_CH1 ADC_CONFIG_PSEL_AnalogInput5 -#define ADC_0_CH2 ADC_CONFIG_PSEL_AnalogInput6 -#define ADC_0_CH3 ADC_CONFIG_PSEL_AnalogInput7 +#define ADC_CONFIG {4, 5, 6, 7} +#define ADC_NUMOF (4) /** @} */ /** diff --git a/cpu/k64f/cpu.c b/cpu/k64f/cpu.c index 7bd91f931d..567ce64e42 100644 --- a/cpu/k64f/cpu.c +++ b/cpu/k64f/cpu.c @@ -21,6 +21,7 @@ #include #include "cpu.h" +#include "mcg.h" #include "cpu_conf.h" #define SIM_CLKDIV1_60MHZ (SIM_CLKDIV1_OUTDIV1(0) | \ diff --git a/cpu/k64f/include/cpu_conf.h b/cpu/k64f/include/cpu_conf.h index 3abb2381bd..15cef19607 100644 --- a/cpu/k64f/include/cpu_conf.h +++ b/cpu/k64f/include/cpu_conf.h @@ -32,8 +32,6 @@ #error "undefined CPU_MODEL" #endif -#include "mcg.h" - #ifdef __cplusplus extern "C" { diff --git a/cpu/kinetis_common/include/mcg.h b/cpu/kinetis_common/include/mcg.h index 7f32e952d4..034fb6f0e0 100644 --- a/cpu/kinetis_common/include/mcg.h +++ b/cpu/kinetis_common/include/mcg.h @@ -100,7 +100,6 @@ #ifndef __MCG_CPU_H #define __MCG_CPU_H -#include "cpu_conf.h" #include "periph_conf.h" #if KINETIS_CPU_USE_MCG diff --git a/cpu/kinetis_common/include/periph_cpu.h b/cpu/kinetis_common/include/periph_cpu.h index 79a48fed8f..794d953041 100644 --- a/cpu/kinetis_common/include/periph_cpu.h +++ b/cpu/kinetis_common/include/periph_cpu.h @@ -109,6 +109,31 @@ enum { GPIO_PORTS_NUMOF /**< overall number of available ports */ }; +/** + * @brief Override default ADC resolution values + * @{ + */ +#define HAVE_ADC_RES_T +typedef enum { + ADC_RES_6BIT = (0xfe), /**< not supported */ + ADC_RES_8BIT = ADC_CFG1_MODE(0), /**< ADC resolution: 8 bit */ + ADC_RES_10BIT = ADC_CFG1_MODE(2), /**< ADC resolution: 10 bit */ + ADC_RES_12BIT = ADC_CFG1_MODE(1), /**< ADC resolution: 12 bit */ + ADC_RES_14BIT = (0xff), /**< ADC resolution: 14 bit */ + ADC_RES_16BIT = ADC_CFG1_MODE(3) /**< ADC resolution: 16 bit */ +} adc_res_t; +/** @} */ + +/** + * @brief CPU specific ADC configuration + */ +typedef struct { + ADC_Type *dev; /**< ADC device */ + gpio_t pin; /**< pin to use, set to GPIO_UNDEF for internal + * channels */ + uint8_t chan; /**< ADC channel */ +} adc_conf_t; + /** * @brief CPU internal function for initializing PORTs * diff --git a/cpu/kinetis_common/periph/adc.c b/cpu/kinetis_common/periph/adc.c index e2967d13b4..72bc6c8846 100644 --- a/cpu/kinetis_common/periph/adc.c +++ b/cpu/kinetis_common/periph/adc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Freie Universität Berlin + * Copyright (C) 2014-2016 Freie Universität Berlin * Copyright (C) 2014 PHYTEC Messtechnik GmbH * Copyright (C) 2015 Eistec AB * @@ -25,18 +25,68 @@ #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 clock speed + * + * The ADC clock speed must be configured to be >2MHz and <12MHz in order for + * the ADC to work. For ADC calibration to work as intended, the ADC clock speed + * must further no be >4MHz, so we target a ADC clock speed > 2 and <4MHz. + */ +#define ADC_MAX_CLK (4000000U) -typedef struct { - int max_value; - int bits; -} adc_config_t; +static mutex_t locks[] = { + MUTEX_INIT, +#ifdef ADC1 + MUTEX_INIT, +#endif +}; -adc_config_t adc_config[ADC_NUMOF]; +static inline ADC_Type *dev(adc_t line) +{ + return adc_config[line].dev; +} + +static inline int dev_num(adc_t line) +{ + if (dev(line) == ADC0) { + return 0; + } +#ifdef ADC1 + else if (dev(line) == ADC1) { + return 1; + } +#endif + return -1; +} + +static inline void prep(adc_t line) +{ + if (dev(line) == ADC0) { + BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_ADC0_SHIFT) = 1; + } +#ifdef ADC1 + else { + BITBAND_REG32(SIM->SCGC3, SIM_SCGC3_ADC1_SHIFT) = 1; + } +#endif + mutex_lock(&locks[dev_num(line)]); +} + +static inline void done(adc_t line) +{ + if (dev(line) == ADC0) { + BITBAND_REG32(SIM->SCGC6, SIM_SCGC6_ADC0_SHIFT) = 0; + } +#ifdef ADC1 + else { + BITBAND_REG32(SIM->SCGC3, SIM_SCGC3_ADC1_SHIFT) = 0; + } +#endif + mutex_unlock(&locks[dev_num(line)]); +} /** * @brief Perform ADC calibration routine. @@ -44,34 +94,31 @@ adc_config_t adc_config[ADC_NUMOF]; * This is a recipe taken straight from the Kinetis K60 reference manual. It has * been tested on MK60DN512VLL10. * - * @param[in] ADC_ptr Pointer to ADC device to operate on. + * @param[in] dev Pointer to ADC device to operate on. * * @return 0 on success * @return <0 on errors */ -int kinetis_adc_calibrate(ADC_Type *ADC_ptr) +int kinetis_adc_calibrate(ADC_Type *dev) { uint16_t cal; - ADC_ptr->SC3 |= ADC_SC3_CAL_MASK; + dev->SC3 |= ADC_SC3_CAL_MASK; - while (ADC_ptr->SC3 & ADC_SC3_CAL_MASK); /* wait for calibration to finish */ + while (dev->SC3 & ADC_SC3_CAL_MASK) {} /* wait for calibration to finish */ - while (!(ADC_ptr->SC1[0] & ADC_SC1_COCO_MASK)); + while (!(dev->SC1[0] & ADC_SC1_COCO_MASK)) {} - if (ADC_ptr->SC3 & ADC_SC3_CALF_MASK) { + if (dev->SC3 & ADC_SC3_CALF_MASK) { /* calibration failed for some reason, possibly SC2[ADTRG] is 1 ? */ return -1; } - /* - * Following the steps in the reference manual: - */ + /* From the reference manual */ /* 1. Initialize or clear a 16-bit variable in RAM. */ - /* 2. Add the plus-side calibration results CLP0, CLP1, CLP2, CLP3, CLP4, and - * CLPS to the variable. */ - cal = ADC_ptr->CLP0 + ADC_ptr->CLP1 + ADC_ptr->CLP2 + ADC_ptr->CLP3 + - ADC_ptr->CLP4 + ADC_ptr->CLPS; + /* 2. Add the plus-side calibration results CLP0, CLP1, CLP2, CLP3, CLP4, + * and CLPS to the variable. */ + cal = dev->CLP0 + dev->CLP1 + dev->CLP2 + dev->CLP3 + dev->CLP4 + dev->CLPS; /* 3. Divide the variable by two. */ cal /= 2; /* 4. Set the MSB of the variable. */ @@ -82,345 +129,88 @@ int kinetis_adc_calibrate(ADC_Type *ADC_ptr) * We ignore the above optimization suggestion, we most likely only perform * this calibration on startup and it will only save nanoseconds. */ /* 6. Store the value in the plus-side gain calibration register PG. */ - ADC_ptr->PG = cal; - + dev->PG = cal; /* 7. Repeat the procedure for the minus-side gain calibration value. */ - cal = ADC_ptr->CLM0 + ADC_ptr->CLM1 + ADC_ptr->CLM2 + ADC_ptr->CLM3 + - ADC_ptr->CLM4 + ADC_ptr->CLMS; + cal = dev->CLM0 + dev->CLM1 + dev->CLM2 + dev->CLM3 + dev->CLM4 + dev->CLMS; cal /= 2; cal |= (1 << 15); - ADC_ptr->MG = cal; + dev->MG = cal; return 0; } - -int adc_init(adc_t dev, adc_precision_t precision) +int adc_init(adc_t line) { - ADC_Type *adc = 0; - PORT_Type *port[ADC_MAX_CHANNELS]; - uint8_t pins[ADC_MAX_CHANNELS]; - uint8_t af[ADC_MAX_CHANNELS]; - int channels = 0; - uint32_t mode = 0; - uint32_t div = 0; - int i = 0; - uint32_t clock = 0; - - adc_poweron(dev); - - switch (dev) { -#if ADC_0_EN - - case ADC_0: - adc = ADC_0_DEV; - port[0] = ADC_0_CH0_PORT; - port[1] = ADC_0_CH1_PORT; - port[2] = ADC_0_CH2_PORT; - port[3] = ADC_0_CH3_PORT; - port[4] = ADC_0_CH4_PORT; - port[5] = ADC_0_CH5_PORT; - pins[0] = ADC_0_CH0_PIN; - pins[1] = ADC_0_CH1_PIN; - pins[2] = ADC_0_CH2_PIN; - pins[3] = ADC_0_CH3_PIN; - pins[4] = ADC_0_CH4_PIN; - pins[5] = ADC_0_CH5_PIN; - af[0] = ADC_0_CH0_PIN_AF; - af[1] = ADC_0_CH1_PIN_AF; - af[2] = ADC_0_CH2_PIN_AF; - af[3] = ADC_0_CH3_PIN_AF; - af[4] = ADC_0_CH4_PIN_AF; - af[5] = ADC_0_CH5_PIN_AF; - channels = ADC_0_CHANNELS; - clock = ADC_0_MODULE_CLOCK; - ADC_0_PORT_CLKEN(); - break; -#endif -#if ADC_1_EN - - case ADC_1: - adc = ADC_1_DEV; - port[0] = ADC_1_CH0_PORT; - port[1] = ADC_1_CH1_PORT; - port[2] = ADC_1_CH2_PORT; - port[3] = ADC_1_CH3_PORT; - port[4] = ADC_1_CH4_PORT; - port[5] = ADC_1_CH5_PORT; - pins[0] = ADC_1_CH0_PIN; - pins[1] = ADC_1_CH1_PIN; - pins[2] = ADC_1_CH2_PIN; - pins[3] = ADC_1_CH3_PIN; - pins[4] = ADC_1_CH4_PIN; - pins[5] = ADC_1_CH5_PIN; - af[0] = ADC_1_CH0_PIN_AF; - af[1] = ADC_1_CH1_PIN_AF; - af[2] = ADC_1_CH2_PIN_AF; - af[3] = ADC_1_CH3_PIN_AF; - af[4] = ADC_1_CH4_PIN_AF; - af[5] = ADC_1_CH5_PIN_AF; - channels = ADC_1_CHANNELS; - clock = ADC_1_MODULE_CLOCK; - ADC_1_PORT_CLKEN(); - break; -#endif - - default: - return -1; - } - - if (channels > ADC_MAX_CHANNELS) { + /* make sure the given line is valid */ + if (line >= ADC_NUMOF) { return -1; } - /* set precision, these numbers are valid for the K60 */ - switch (precision) { - case ADC_RES_6BIT: - /* Not supported by hardware, use 8 bit mode. */ - mode = ADC_CFG1_MODE(0); - adc_config[dev].bits = 8; - break; + /* prepare the device: lock and power on */ + prep(line); - case ADC_RES_8BIT: - mode = ADC_CFG1_MODE(0); - adc_config[dev].bits = 8; - break; - - case ADC_RES_10BIT: - mode = ADC_CFG1_MODE(2); - adc_config[dev].bits = 10; - break; - - case ADC_RES_12BIT: - mode = ADC_CFG1_MODE(1); - adc_config[dev].bits = 12; - break; - - case ADC_RES_14BIT: - /* Not supported by hardware, use 16 bit mode. */ - mode = ADC_CFG1_MODE(3); - adc_config[dev].bits = 16; - break; - - case ADC_RES_16BIT: - mode = ADC_CFG1_MODE(3); - adc_config[dev].bits = 16; - break; - } - - adc_config[dev].max_value = (1 << adc_config[dev].bits) - 1; - - for (i = 0; i < channels; i++) { - /* Check whether we need to set the pin mux for this channel. */ - if (port[i] != NULL) { - port[i]->PCR[pins[i]] = PORT_PCR_MUX(af[i]); - } + /* configure the connected pin mux */ + if (adc_config[line].pin != GPIO_UNDEF) { + gpio_init_port(adc_config[line].pin, GPIO_AF_ANALOG); } /* The ADC requires at least 2 MHz module clock for full accuracy, and less * than 12 MHz */ /* For the calibration it is important that the ADC clock is <= 4 MHz */ - if (clock > 4000000 * 8) { - /* Need to divide by 16, we set the clock input to BusClock/2 and - * divide clock by 8 (the maximum divider) */ - div = ADC_CFG1_ADIV(3) | ADC_CFG1_ADICLK(1); - } - else if (clock > 4000000 * 4) { - /* divide clock by 8 */ - div = ADC_CFG1_ADIV(3); - } - else if (clock > 4000000 * 2) { - /* divide clock by 4 */ - div = ADC_CFG1_ADIV(2); - } - else if (clock > 4000000 * 1) { - /* divide clock by 2 */ - div = ADC_CFG1_ADIV(1); + uint32_t adiv; + int i = 4; + if (CLOCK_BUSCLOCK > (ADC_MAX_CLK * 8)) { + adiv = ADC_CFG1_ADIV(3) | ADC_CFG1_ADICLK(1); } else { - /* no clock divider */ - div = ADC_CFG1_ADIV(0); + while ((i > 0) && (CLOCK_BUSCLOCK < (ADC_MAX_CLK * i))) { + i--; + } + adiv = ADC_CFG1_ADIV(i - 1); } /* set configuration register 1: clocking and precision */ /* Set long sample time */ - adc->CFG1 = ADC_CFG1_ADLSMP_MASK | mode | div; - + dev(line)->CFG1 = ADC_CFG1_ADLSMP_MASK | adiv; /* select ADxxb channels, longest sample time (20 extra ADC cycles) */ - adc->CFG2 = ADC_CFG2_MUXSEL_MASK | ADC_CFG2_ADLSTS(0); - + dev(line)->CFG2 = ADC_CFG2_MUXSEL_MASK | ADC_CFG2_ADLSTS(0); /* select software trigger, external ref pins */ - adc->SC2 = ADC_SC2_REFSEL(0); - + dev(line)->SC2 = ADC_SC2_REFSEL(0); /* select hardware average over 32 samples */ - adc->SC3 = ADC_SC3_AVGE_MASK | ADC_SC3_AVGS(3); - + dev(line)->SC3 = ADC_SC3_AVGE_MASK | ADC_SC3_AVGS(3); /* set an (arbitrary) input channel, single-ended mode */ - adc->SC1[0] = ADC_SC1_ADCH(ADC_0_CH0); - adc->SC1[1] = ADC_SC1_ADCH(ADC_0_CH0); + dev(line)->SC1[0] = ADC_SC1_ADCH(0); /* perform calibration routine */ - if (kinetis_adc_calibrate(adc) != 0) { + int res = kinetis_adc_calibrate(dev(line)); + done(line); + return res; +} + +int adc_sample(adc_t line, adc_res_t res) +{ + int sample; + + /* check if resolution is applicable */ + if (res > 0xf0) { return -1; } - return 0; -} - -int adc_sample(adc_t dev, int channel) -{ - ADC_Type *adc = 0; - - switch (dev) { -#if ADC_0_EN - - case ADC_0: - adc = ADC_0_DEV; - - /* start single conversion on corresponding channel */ - switch (channel) { - case 0: - adc->SC1[0] = ADC_SC1_ADCH(ADC_0_CH0); - break; - - case 1: - adc->SC1[0] = ADC_SC1_ADCH(ADC_0_CH1); - break; - - case 2: - adc->SC1[0] = ADC_SC1_ADCH(ADC_0_CH2); - break; - - case 3: - adc->SC1[0] = ADC_SC1_ADCH(ADC_0_CH3); - break; - - case 4: - adc->SC1[0] = ADC_SC1_ADCH(ADC_0_CH4); - break; - - case 5: - adc->SC1[0] = ADC_SC1_ADCH(ADC_0_CH5); - break; - - default: - return -1; - } - - break; -#endif -#if ADC_1_EN - - case ADC_1: - adc = ADC_1_DEV; - - /* start single conversion on corresponding channel */ - switch (channel) { - case 0: - adc->SC1[0] = ADC_SC1_ADCH(ADC_1_CH0); - break; - - case 1: - adc->SC1[0] = ADC_SC1_ADCH(ADC_1_CH1); - break; - - case 2: - adc->SC1[0] = ADC_SC1_ADCH(ADC_1_CH2); - break; - - case 3: - adc->SC1[0] = ADC_SC1_ADCH(ADC_1_CH3); - break; - - case 4: - adc->SC1[0] = ADC_SC1_ADCH(ADC_1_CH4); - break; - - case 5: - adc->SC1[0] = ADC_SC1_ADCH(ADC_1_CH5); - break; - - default: - return -1; - } - - break; -#endif - } + /* lock and power on the device */ + prep(line); + /* set resolution */ + dev(line)->CFG1 &= ~(ADC_CFG1_MODE_MASK); + dev(line)->CFG1 |= (res); + /* select the channel that is sampled */ + dev(line)->SC1[0] = adc_config[line].chan; /* wait until conversion is complete */ - /* TODO: Use interrupts and yield the thread */ - while (!(adc->SC1[0] & ADC_SC1_COCO_MASK)); - + while (!(dev(line)->SC1[0] & ADC_SC1_COCO_MASK)) {} /* read and return result */ - return (int)adc->R[0]; + sample = (int)dev(line)->R[0]; + + /* power off and unlock the device */ + done(line); + + return sample; } - -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) -{ - int scale = max - min; - - /* NB: There is additional room for the multiplication result if using the - * actual precision setting of the ADC as the limit in this if statement: */ - if (scale < (1 << 16)) { - /* The ADCs on these CPUs are limited to 16 bits, the result of - * value x scale will be 31 bits long or less. We use the upper part - * of a 32 bit word when scaling */ - int32_t tmp = value * scale; - /* Divide by ADC range to get the scaled result */ - return (tmp / (1 << adc_config[dev].bits)); - } - else { - /* Target scale is too large to use int32_t as an in between result */ - int64_t tmp = scale; - /* Make sure the compiler does not generate code which will truncate the - * result. */ - tmp *= value; - /* Divide by ADC range to get the scaled result */ - tmp /= (1 << adc_config[dev].bits); - return tmp; - } -} - -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 */ diff --git a/cpu/kw2x/cpu.c b/cpu/kw2x/cpu.c index 1844e1312f..41f95e6c16 100644 --- a/cpu/kw2x/cpu.c +++ b/cpu/kw2x/cpu.c @@ -21,6 +21,7 @@ #include #include "cpu.h" +#include "mcg.h" #include "cpu_conf.h" #define FLASH_BASE (0x00000000) diff --git a/cpu/kw2x/include/cpu_conf.h b/cpu/kw2x/include/cpu_conf.h index c6f46f20ba..01d1baa731 100644 --- a/cpu/kw2x/include/cpu_conf.h +++ b/cpu/kw2x/include/cpu_conf.h @@ -37,8 +37,6 @@ #error "undefined CPU_MODEL" #endif -#include "mcg.h" - #ifdef __cplusplus extern "C" { diff --git a/cpu/lm4f120/include/periph_cpu.h b/cpu/lm4f120/include/periph_cpu.h index e2ca77bb5f..901f580e81 100644 --- a/cpu/lm4f120/include/periph_cpu.h +++ b/cpu/lm4f120/include/periph_cpu.h @@ -52,7 +52,6 @@ typedef enum { } gpio_pp_t; /** @} */ - /** * @brief Override values for pin direction configuration * @{ @@ -88,6 +87,19 @@ enum { PORT_F = 5, /**< port F */ }; +/** + * @brief Override resolution options + */ +#define HAVE_ADC_RES_T +typedef enum { + ADC_RES_6BIT = 0xa00, /**< not supported by hardware */ + ADC_RES_8BIT = 0xb00, /**< not supported by hardware */ + ADC_RES_10BIT = ADC_RES_10BIT_S, /**< ADC resolution: 10 bit */ + ADC_RES_12BIT = ADC_RES_12BIT_S, /**< ADC resolution: 12 bit */ + ADC_RES_14BIT = 0xc00, /**< not supported by hardware */ + ADC_RES_16BIT = 0xd00, /**< not supported by hardware */ +} adc_res_t; + #ifdef __cplusplus } #endif diff --git a/cpu/lm4f120/periph/adc.c b/cpu/lm4f120/periph/adc.c index 24b58b1bd5..c8abdcd385 100644 --- a/cpu/lm4f120/periph/adc.c +++ b/cpu/lm4f120/periph/adc.c @@ -13,6 +13,8 @@ * @file * @brief Low-level ADC driver implementation * + * The current ADC driver implementation only supports ADC0. + * * @author Marc Poulhiès * * @} @@ -22,152 +24,109 @@ #include #include "cpu.h" +#include "mutex.h" #include "periph/adc.h" -#include "periph_conf.h" -#if ADC_NUMOF +/* + * @brief ADC sequence used by this driver and oversampling settings + * @{ + */ +#define SEQ (3) +#define OVERSAMPLE (64) +/** @} */ +/** + * @brief pin configuration parameters + */ struct adc_gpio_cfg_s { unsigned long gpio_base; unsigned long gpio_sysctl; unsigned short gpio_pin; }; -static const struct adc_gpio_cfg_s adc0_gpio[ADC_MAX_CHANNELS] = { - { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOE, GPIO_PIN_3 }, // AIN0 - { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOE, GPIO_PIN_2 }, // AIN1 - { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOE, GPIO_PIN_1 }, // AIN2 - { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOE, GPIO_PIN_0 }, // AIN3 - { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOD, GPIO_PIN_3 }, // AIN4 - { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOD, GPIO_PIN_2 }, // AIN5 - { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOD, GPIO_PIN_1 }, // AIN6 - { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOD, GPIO_PIN_0 }, // AIN7 - { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOE, GPIO_PIN_5 }, // AIN8 - { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOE, GPIO_PIN_4 }, // AIN9 - { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOB, GPIO_PIN_4 }, // AIN10 - { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOB, GPIO_PIN_5 }, // AIN11 +/** + * @brief Fixed ADC pin configuration + */ +static const struct adc_gpio_cfg_s adc0_gpio[ADC_NUMOF] = { + { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOE, GPIO_PIN_3 }, /**< AIN0 */ + { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOE, GPIO_PIN_2 }, /**< AIN1 */ + { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOE, GPIO_PIN_1 }, /**< AIN2 */ + { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOE, GPIO_PIN_0 }, /**< AIN3 */ + { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOD, GPIO_PIN_3 }, /**< AIN4 */ + { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOD, GPIO_PIN_2 }, /**< AIN5 */ + { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOD, GPIO_PIN_1 }, /**< AIN6 */ + { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOD, GPIO_PIN_0 }, /**< AIN7 */ + { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOE, GPIO_PIN_5 }, /**< AIN8 */ + { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOE, GPIO_PIN_4 }, /**< AIN9 */ + { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOB, GPIO_PIN_4 }, /**< AIN10 */ + { GPIO_PORTE_BASE, SYSCTL_PERIPH_GPIOB, GPIO_PIN_5 }, /**< AIN11 */ }; -/* - * We only support ADC0 for now +/** + * @brief Lock to prevent concurrent access to the ADC */ -#define ADC_0_SYSCTL SYSCTL_PERIPH_ADC0 -#define ADC_0_GPIO adc0_gpio -#define ADC_0_BASE ADC0_BASE -#define ADC_0_SEQ 3 +static mutex_t lock = MUTEX_INIT; -int adc_init(adc_t dev, adc_precision_t precision) +static inline void prep(void) { - unsigned long adc_base; - unsigned long adc_seq; - - switch (dev) { -#if ADC_0_EN - case ADC_0: - adc_base = ADC_0_BASE; - adc_seq = ADC_0_SEQ; - break; -#endif - } - ROM_SysCtlADCSpeedSet(SYSCTL_ADCSPEED_125KSPS); - adc_poweron(dev); - - ROM_ADCHardwareOversampleConfigure(adc_base, 64); - ROM_ADCSequenceDisable(adc_base, adc_seq); - - return 0; + mutex_lock(&lock); + ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); } -int adc_sample(adc_t dev, int channel) +static inline void done(void) { - int value[2]; - unsigned long adc_base; - unsigned long adc_seq; - unsigned long adc_gpio_port = 0; - unsigned long adc_gpio_pin = 0; - unsigned long adc_gpio_sysctl = 0; + ROM_SysCtlPeripheralDisable(SYSCTL_PERIPH_ADC0); + mutex_unlock(&lock); +} - if (channel >= ADC_MAX_CHANNELS) { +int adc_init(adc_t line) +{ + /* make sure the given ADC line is valid */ + if (line >= ADC_NUMOF) { return -1; } - switch (dev) { -#if ADC_0_EN - case ADC_0: - adc_base = ADC_0_BASE; - adc_seq = ADC_0_SEQ; + prep(); - adc_gpio_port = ADC_0_GPIO[channel].gpio_base; - adc_gpio_sysctl = ADC_0_GPIO[channel].gpio_sysctl; - adc_gpio_pin = ADC_0_GPIO[channel].gpio_pin; - break; -#endif - } - ROM_SysCtlPeripheralEnable(adc_gpio_sysctl); - ROM_GPIOPinTypeADC(adc_gpio_port, adc_gpio_pin); + ROM_SysCtlADCSpeedSet(SYSCTL_ADCSPEED_125KSPS); + ROM_ADCHardwareOversampleConfigure(ADC0_BASE, OVERSAMPLE); - ROM_ADCSequenceDisable(adc_base, adc_seq); - ROM_ADCIntClear(adc_base, adc_seq); + ROM_SysCtlPeripheralEnable(adc0_gpio[line].gpio_sysctl); + ROM_GPIOPinTypeADC(adc0_gpio[line].gpio_base, adc0_gpio[line].gpio_pin); - ROM_ADCSequenceConfigure(adc_base, adc_seq, ADC_TRIGGER_PROCESSOR, 0); + done(); - ROM_ADCSequenceStepConfigure(adc_base, adc_seq, 0, channel | ADC_CTL_IE | ADC_CTL_END); - ROM_ADCSequenceEnable(adc_base, adc_seq); - - ROM_ADCIntClear(adc_base, adc_seq); - - ROM_ADCProcessorTrigger(adc_base, adc_seq); - while (!ROM_ADCIntStatus(adc_base, adc_seq, false)) { - } - ROM_ADCIntClear(adc_base, adc_seq); - ROM_ADCSequenceDataGet(adc_base, adc_seq, (unsigned long *) value); - - return value[0]; -} - -void adc_poweron(adc_t dev) -{ - unsigned long adc_sysctl; - - switch (dev) { -#if ADC_0_EN - case ADC_0: - adc_sysctl = ADC_0_SYSCTL; - break; -#endif - } - ROM_SysCtlPeripheralEnable(adc_sysctl); -} - -void adc_poweroff(adc_t dev) -{ - unsigned long adc_sysctl; - - switch (dev) { -#if ADC_0_EN - case ADC_0: - adc_sysctl = ADC_0_SYSCTL; - break; -#endif - } - ROM_SysCtlPeripheralDisable(adc_sysctl); -} - - -/* - * Currently not supported - */ -int adc_map(adc_t dev, int value, int min, int max) -{ return 0; } -/* - * Currently not supported - */ -float adc_mapf(adc_t dev, int value, float min, float max) +int adc_sample(adc_t line, adc_res_t res) { - return 0.0; -} + int value[2]; -#endif /* ADC_NUMOF */ + if ((res != ADC_RES_10BIT) && (res != ADC_RES_12BIT)) { + return -1; + } + + prep(); + + /* set channel */ + ROM_ADCSequenceConfigure(ADC0_BASE, SEQ, ADC_TRIGGER_PROCESSOR, 0); + ROM_ADCSequenceStepConfigure(ADC0_BASE, SEQ, 0, line | ADC_CTL_IE | ADC_CTL_END); + /* set resolution */ + ROM_ADCResolutionSet(ADC0_BASE, (unsigned long)res); + + /* start conversion and wait for results */ + ROM_ADCSequenceEnable(ADC0_BASE, SEQ); + ROM_ADCIntClear(ADC0_BASE, SEQ); + ROM_ADCProcessorTrigger(ADC0_BASE, SEQ); + while (!ROM_ADCIntStatus(ADC0_BASE, SEQ, false)) {} + + /* get results */ + ROM_ADCSequenceDataGet(ADC0_BASE, SEQ, (unsigned long *) value); + + /* disable device again */ + ROM_ADCSequenceDisable(ADC0_BASE, SEQ); + done(); + + return value[0]; +} diff --git a/cpu/lpc11u34/include/periph_cpu.h b/cpu/lpc11u34/include/periph_cpu.h index 84c6864fae..29d988398c 100644 --- a/cpu/lpc11u34/include/periph_cpu.h +++ b/cpu/lpc11u34/include/periph_cpu.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 Freie Universität Berlin + * Copyright (C) 2015-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 @@ -14,6 +14,7 @@ * @brief CPU specific definitions for internal peripheral handling * * @author Paul RATHGEB + * @author Hauke Petersen */ #ifndef PERIPH_CPU_H_ @@ -39,6 +40,28 @@ extern "C" { */ #define CPUID_LEN (16U) +/** + * @brief Define number of available ADC lines + * + * TODO: check this value + */ +#define ADC_NUMOF (10U) + +/** + * @brief Override the ADC resolution settings + * @{ + */ +#define HAVE_ADC_RES_T +typedef enum { + ADC_RES_6BIT = 0, /**< ADC resolution: 6 bit */ + ADC_RES_8BIT, /**< ADC resolution: 8 bit */ + ADC_RES_10BIT, /**< ADC resolution: 10 bit */ + ADC_RES_12BIT, /**< ADC resolution: 12 bit */ + ADC_RES_14BIT, /**< ADC resolution: 14 bit */ + ADC_RES_16BIT, /**< ADC resolution: 16 bit */ +} adc_res_t; +/** @} */ + #ifdef __cplusplus } #endif diff --git a/cpu/lpc11u34/periph/adc.c b/cpu/lpc11u34/periph/adc.c index 6bd3ec4b3d..4144f5c0b5 100644 --- a/cpu/lpc11u34/periph/adc.c +++ b/cpu/lpc11u34/periph/adc.c @@ -1,9 +1,9 @@ /* - * Copyright (C) 2015 Freie Universität Berlin + * Copyright (C) 2015-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. */ /** @@ -13,114 +13,91 @@ * @file * @brief Low-level ADC driver implementation * - * @author Paul RATHGEB + * @author Paul Rathgeb + * @author Hauke Petersen * * @} */ #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 Mutex to synchronize ADC access from different threads + */ +static mutex_t lock = MUTEX_INIT; -static inline uint32_t *_adc_channel_to_pin(int channel) +static inline uint32_t *pincfg_reg(adc_t line) { - return (channel < 6) ? ((uint32_t*)(LPC_IOCON) + (11 + channel)) - : ((uint32_t*)(LPC_IOCON) + (16 + channel)); + int offset = (line < 6) ? (11 + line) : (16 + line); + return ((uint32_t *)(LPC_IOCON) + offset); } -int adc_init(adc_t dev, adc_precision_t precision) +static inline void prep(void) { - adc_poweron(dev); + mutex_lock(&lock); + LPC_SYSCON->PDRUNCFG &= ~(1 << 4); + LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 13); +} - /* Set resolution */ - switch (precision) { - case ADC_RES_6BIT: - LPC_ADC->CR |= (0x04 << 17); - break; - case ADC_RES_8BIT: - LPC_ADC->CR |= (0x02 << 17); - break; - case ADC_RES_10BIT: - LPC_ADC->CR |= (0x0 << 17); - break; - case ADC_RES_12BIT: - case ADC_RES_14BIT: - case ADC_RES_16BIT: - /* Resolution > 10 bits unsupported */ - adc_poweroff(dev); - return -1; - break; - } +static inline void done(void) +{ + LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 13); + LPC_SYSCON->PDRUNCFG |= (1 << 4); + mutex_unlock(&lock); +} + +int adc_init(adc_t line) +{ + uint32_t *pincfg; + + prep(); /* ADC frequency : 3MHz */ - LPC_ADC->CR |= (15 << 8); + LPC_ADC->CR = (15 << 8); + /* configure the connected pin */ + pincfg = pincfg_reg(line); + /* Put the pin in its ADC alternate function */ + if (line < 5) { + *pincfg |= 2; + } + else { + *pincfg |= 1; + } + /* Configure ADMODE in analog input */ + *pincfg &= ~(1 << 7); + + done(); return 0; } -int adc_sample(adc_t dev, int channel) +int adc_sample(adc_t line, adc_res_t res) { - if (channel > ADC_MAX_CHANNELS) { + int sample; + + /* check if resolution is valid */ + if (res < 0xff) { return -1; } - /* Compute the IOCON register for the channel */ - uint32_t *cfg = _adc_channel_to_pin(channel); - /* Put the pin in its ADC alternate function */ - if (channel < 5) { - *cfg |= 2; - } - else { - *cfg |= 1; - } - /* Configure ADMODE in analog input */ - *cfg &= ~(1 << 7); + /* prepare the device */ + prep(); + + /* set resolution */ + LPC_ADC->CR &= ~(0x7 << 17); + LPC_ADC->CR |= res; /* Start a conversion */ - LPC_ADC->CR |= (1 << channel) | (1 << 24); + LPC_ADC->CR |= (1 << line) | (1 << 24); /* Wait for the end of the conversion */ - while (!(LPC_ADC->DR[channel] & (1 << 31))); + while (!(LPC_ADC->DR[line] & (1 << 31))) {} /* Read and return result */ - return (LPC_ADC->DR[channel] >> 6); -} + sample = (LPC_ADC->DR[line] >> 6); -void adc_poweron(adc_t dev) -{ - switch (dev) { -#if ADC_0_EN - case ADC_0: - LPC_SYSCON->PDRUNCFG &= ~(1 << 4); - LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 13); - break; -#endif - } -} + done(); -void adc_poweroff(adc_t dev) -{ - switch (dev) { -#if ADC_0_EN - case ADC_0: - LPC_SYSCON->PDRUNCFG |= (1 << 4); - LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 13); - break; -#endif - } + return sample; } - -int adc_map(adc_t dev, int value, int min, int max) -{ - return 0; -} - -float adc_mapf(adc_t dev, int value, float min, float max) -{ - return 0.0; -} - -#endif /* ADC_NUMOF */ diff --git a/cpu/nrf51/periph/adc.c b/cpu/nrf51/periph/adc.c index 263c7a416d..6b6080b0f0 100644 --- a/cpu/nrf51/periph/adc.c +++ b/cpu/nrf51/periph/adc.c @@ -1,10 +1,10 @@ /* - * Copyright (C) 2014 Freie Universität Berlin - * Copyright (C) 2015 Ludwig Knüpfer + * Copyright (C) 2014-2016 Freie Universität Berlin + * 2015 Ludwig Knüpfer * - * 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. */ /** @@ -12,7 +12,7 @@ * @{ * * @file - * @brief Low-level UART driver implementation + * @brief Low-level ADC driver implementation * * @author Hauke Petersen * @author Ludwig Knüpfer @@ -21,114 +21,73 @@ */ #include "cpu.h" +#include "mutex.h" #include "periph/adc.h" #include "periph_conf.h" -/* guard file in case no ADC device is defined */ -#if ADC_NUMOF +/** + * @brief Load the ADC configuration + * @{ + */ +#ifdef ADC_CONFIG +static const uint8_t adc_config[] = ADC_CONFIG; +#else +static const uint8_t adc_config[] = {}; +#endif -/* save the maximum value configured for the ADC */ -int adc_max_value; +/** + * @brief Lock to prevent concurrency issues when used from different threads + */ +static mutex_t lock; -int adc_init(adc_t dev, adc_precision_t precision) +static inline void prep(void) { - /* the NRF51822 only supports one ADC... */ - if (dev != ADC_0) { - return -2; - } - - /* power on ADC */ + mutex_lock(&lock); NRF_ADC->POWER = 1; + NRF_ADC->ENABLE = 1; +} - /* disable ADC interrupts */ - NRF_ADC->INTENSET = (ADC_INTENSET_END_Disabled << ADC_INTENSET_END_Pos); +static inline void done(void) +{ + NRF_ADC->ENABLE = 0; + NRF_ADC->POWER = 0; + mutex_unlock(&lock); +} - /* configure ADC, set precision, internal reference to VBG */ - switch (precision) { - case ADC_RES_8BIT: - adc_max_value = 255; - NRF_ADC->CONFIG = (ADC_CONFIG_RES_8bit << ADC_CONFIG_RES_Pos); - break; - case ADC_RES_10BIT: - adc_max_value = 1023; - NRF_ADC->CONFIG = (ADC_CONFIG_RES_10bit << ADC_CONFIG_RES_Pos); - break; - default: - NRF_ADC->POWER = 0; - return -1; +int adc_init(adc_t line) +{ + if (line >= ADC_NUMOF) { + return -1; } - - /* select the reference voltage / prescaler */ - NRF_ADC->CONFIG |= (ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos); - NRF_ADC->CONFIG |= (ADC_CONFIG_REFSEL_VBG << ADC_CONFIG_REFSEL_Pos); - NRF_ADC->CONFIG |= (ADC_CONFIG_INPSEL_AnalogInputOneThirdPrescaling << ADC_CONFIG_INPSEL_Pos); - - /* enable the ADC */ - NRF_ADC->ENABLE = (ADC_ENABLE_ENABLE_Enabled << ADC_ENABLE_ENABLE_Pos); - return 0; } -int adc_sample(adc_t dev, int channel) +int adc_sample(adc_t line, adc_res_t res) { - if (dev != ADC_0) { - return -2; + int val; + + /* check if resolution is valid */ + if (res > 2) { + return -1; } - /* set channel */ - NRF_ADC->CONFIG &= ~(ADC_CONFIG_PSEL_Msk); - NRF_ADC->CONFIG |= (ADC_CONFIG_PSEL_Disabled << ADC_CONFIG_PSEL_Pos); - switch (channel) { - case 0: - NRF_ADC->CONFIG |= (ADC_0_CH0 << ADC_CONFIG_PSEL_Pos); - break; - case 1: - NRF_ADC->CONFIG |= (ADC_0_CH1 << ADC_CONFIG_PSEL_Pos); - break; - case 2: - NRF_ADC->CONFIG |= (ADC_0_CH2 << ADC_CONFIG_PSEL_Pos); - break; - case 3: - NRF_ADC->CONFIG |= (ADC_0_CH3 << ADC_CONFIG_PSEL_Pos); - break; - default: - return -1; - } + /* prepare device */ + prep(); + /* set resolution, line, and use 1/3 input and ref voltage scaling */ + NRF_ADC->CONFIG = ((ADC_CONFIG_REFSEL_SupplyOneThirdPrescaling << 5) | + (ADC_CONFIG_INPSEL_AnalogInputOneThirdPrescaling << 2) | + (1 << (adc_config[line] + 8)) | + res); /* start conversion */ NRF_ADC->TASKS_START = 1; - /* wait for conversion to be complete */ - while (((NRF_ADC->BUSY & ADC_BUSY_BUSY_Msk) >> ADC_BUSY_BUSY_Pos) == ADC_BUSY_BUSY_Busy) {} - NRF_ADC->EVENTS_END = 1; + while (NRF_ADC->BUSY == 1) {} + /* get result */ + val = (int)NRF_ADC->RESULT; - /* return result */ - return (int)NRF_ADC->RESULT; + /* free device */ + done(); + + return val; } - -void adc_poweron(adc_t dev) -{ - if (dev == ADC_0) { - NRF_ADC->POWER = 1; - } -} - -void adc_poweroff(adc_t dev) -{ - if (dev == ADC_0) { - NRF_ADC->POWER = 0; - } -} - -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) -{ - (void) dev; - return ((max - min) / ((float)adc_max_value)) * value; -} - -#endif /* ADC_NUMOF */ diff --git a/cpu/nrf5x_common/include/periph_cpu.h b/cpu/nrf5x_common/include/periph_cpu.h index 63b7d49384..d287e0febf 100644 --- a/cpu/nrf5x_common/include/periph_cpu.h +++ b/cpu/nrf5x_common/include/periph_cpu.h @@ -77,6 +77,21 @@ typedef enum { } gpio_flank_t; /** @} */ +/** + * @brief Override ADC resolution values + * @{ + */ +#define HAVE_ADC_RES_T +typedef enum { + ADC_RES_6BIT = 0xf0, /**< ADC resolution: 6 bit */ + ADC_RES_8BIT = 0x00, /**< ADC resolution: 8 bit */ + ADC_RES_10BIT = 0x02, /**< ADC resolution: 10 bit */ + ADC_RES_12BIT = 0xf1, /**< ADC resolution: 12 bit */ + ADC_RES_14BIT = 0xf2, /**< ADC resolution: 14 bit */ + ADC_RES_16BIT = 0xf3 /**< ADC resolution: 16 bit */ +} adc_res_t; +/** @} */ + /** * @brief Timer configuration options */ 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 */ diff --git a/cpu/stm32f4/include/periph_cpu.h b/cpu/stm32f4/include/periph_cpu.h index 70f404cec4..120ac79eca 100644 --- a/cpu/stm32f4/include/periph_cpu.h +++ b/cpu/stm32f4/include/periph_cpu.h @@ -25,6 +25,15 @@ extern "C" { #endif +/** + * @brief Available number of ADC devices + */ +#if defined(CPU_MODEL_STM32F401RE) +#define ADC_DEVS (1U) +#elif defined(CPU_MODEL_STM32F407VG) || defined(CPU_MODEL_STM32F415RG) +#define ADC_DEVS (3U) +#endif + /** * @brief Overwrite the default gpio_t type definition * @{ @@ -43,6 +52,30 @@ typedef uint32_t gpio_t; */ #define GPIO_PIN(x, y) ((GPIOA_BASE + (x << 10)) | y) +/** + * @brief declare needed generic SPI functions + * @{ + */ +#define PERIPH_SPI_NEEDS_TRANSFER_BYTES +#define PERIPH_SPI_NEEDS_TRANSFER_REG +#define PERIPH_SPI_NEEDS_TRANSFER_REGS +/** @} */ + +/** + * @brief Override the ADC resolution configuration + * @{ + */ +#define HAVE_ADC_RES_T +typedef enum { + ADC_RES_6BIT = 0x03000000, /**< ADC resolution: 6 bit */ + ADC_RES_8BIT = 0x02000000, /**< ADC resolution: 8 bit */ + ADC_RES_10BIT = 0x01000000, /**< ADC resolution: 10 bit */ + ADC_RES_12BIT = 0x00000000, /**< ADC resolution: 12 bit */ + ADC_RES_14BIT = 1, /**< ADC resolution: 14 bit (not supported) */ + ADC_RES_16BIT = 2 /**< ADC resolution: 16 bit (not supported)*/ +} adc_res_t; +/** @} */ + /** * @brief Available ports on the STM32F4 family */ @@ -95,6 +128,16 @@ typedef struct { } uart_conf_t; /** @} */ +/** + * @brief ADC channel configuration data + */ +typedef struct { + gpio_t pin; /**< pin connected to the channel */ + uint8_t dev; /**< ADCx - 1 device used for the channel */ + uint8_t chan; /**< CPU ADC channel connected to the pin */ + uint8_t rcc; /**< bit in the RCC APB2 enable register */ +} adc_conf_t; + /** * @brief Configure the alternate function for the given pin * @@ -105,6 +148,13 @@ typedef struct { */ void gpio_init_af(gpio_t pin, gpio_af_t af); +/** + * @brief Configure the given pin to be used as ADC input + * + * @param[in] pin pin to configure + */ +void gpio_init_analog(gpio_t pin); + /** * @brief Power on the DMA device the given stream belongs to * diff --git a/cpu/stm32f4/periph/adc.c b/cpu/stm32f4/periph/adc.c index 12c1f47ceb..1ee863bc95 100644 --- a/cpu/stm32f4/periph/adc.c +++ b/cpu/stm32f4/periph/adc.c @@ -1,5 +1,5 @@ /* - * 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 @@ -19,167 +19,111 @@ */ #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 { - int max_value; -} adc_config_t; +/** + * @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 -adc_config_t adc_config[ADC_NUMOF]; +/** + * @brief Allocate locks for all three available ADC devices + */ +static mutex_t locks[] = { +#if ADC_DEVS > 1 + MUTEX_INIT, +#endif +#if ADC_DEVS > 2 + MUTEX_INIT, +#endif + MUTEX_INIT +}; -int adc_init(adc_t dev, adc_precision_t precision) +static inline ADC_TypeDef *dev(adc_t line) { - ADC_TypeDef *adc = 0; + return (ADC_TypeDef *)(ADC1_BASE + (adc_config[line].dev << 8)); +} - adc_poweron(dev); +static inline void prep(adc_t line) +{ + mutex_lock(&locks[adc_config[line].dev]); + RCC->APB2ENR |= (RCC_APB2ENR_ADC1EN << adc_config[line].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; +static inline void done(adc_t line) +{ + RCC->APB2ENR &= ~(RCC_APB2ENR_ADC1EN << adc_config[line].dev); + mutex_unlock(&locks[adc_config[line].dev]); +} + +int adc_init(adc_t line) +{ + uint32_t clk_div = 2; + + /* check if the line is valid */ + if (line >= ADC_NUMOF) { + return -1; } - /* reset control registers */ - adc->CR1 = 0; - adc->CR2 = 0; - adc->SQR1 = 0; + /* lock and power-on the device */ + prep(line); - /* 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; + /* configure the pin */ + gpio_init_analog(adc_config[line].pin); + /* set sequence length to 1 conversion and enable the ADC device */ + dev(line)->SQR1 = 0; + dev(line)->CR2 = ADC_CR2_ADON; + /* set clock prescaler to get the maximal possible ADC clock value */ + for (clk_div = 2; clk_div < 8; clk_div += 2) { + if ((CLOCK_CORECLOCK / clk_div) <= MAX_ADC_SPEED) { break; + } } + ADC->CCR = ((clk_div / 2) - 1) << 16; - /* set clock prescaler */ - ADC->CCR = (3 << 16); /* ADC clock = 10,5MHz */ - - /* enable the ADC module */ - adc->CR2 |= ADC_CR2_ADON; - + /* free the device again */ + done(line); 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->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 + /* check if resolution is applicable */ + if (res < 0xff) { + return -1; } - /* 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; -} + /* lock and power on the ADC device */ + prep(line); -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 - } -} + /* wait for any ongoing conversions to finish */ + while (dev(line)->SR & ADC_SR_STRT) {} + /* set resolution and conversion channel */ + dev(line)->CR1 = res; + dev(line)->SQR3 = adc_config[line].chan; + /* start conversion and wait for results */ + dev(line)->CR2 |= ADC_CR2_SWSTART; + while (!(dev(line)->SR & ADC_SR_EOC)) {} + /* finally read sample and reset the STRT bit in the status register */ + sample = (int)dev(line)->DR; + dev(line)->SR &= ~ADC_SR_STRT; -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 - } -} + /* power off and unlock device again */ + done(line); -int adc_map(adc_t dev, int value, int min, int max) -{ - return (int)adc_mapf(dev, value, (float)min, (float)max); + return sample; } - -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 */ diff --git a/cpu/stm32f4/periph/gpio.c b/cpu/stm32f4/periph/gpio.c index 7b49f3fc35..774a31acf8 100644 --- a/cpu/stm32f4/periph/gpio.c +++ b/cpu/stm32f4/periph/gpio.c @@ -148,6 +148,14 @@ void gpio_init_af(gpio_t pin, gpio_af_t af) port->AFR[(pin_num > 7) ? 1 : 0] |= (af << ((pin_num & 0x07) * 4)); } +void gpio_init_analog(gpio_t pin) +{ + /* enable clock */ + RCC->AHB1ENR |= (RCC_AHB1ENR_GPIOAEN << _port_num(pin)); + /* set to analog mode */ + _port(pin)->MODER |= (0x3 << (2 * _pin_num(pin))); +} + void gpio_irq_enable(gpio_t pin) { EXTI->IMR |= (1 << _pin_num(pin)); diff --git a/drivers/include/mq3.h b/drivers/include/mq3.h index 55dde35013..f10944e64d 100644 --- a/drivers/include/mq3.h +++ b/drivers/include/mq3.h @@ -33,8 +33,7 @@ extern "C" { * @brief device descriptor for a MQ-3 sensor */ typedef struct { - adc_t adc_dev; /**< the used ADC device */ - int adc_chan; /**< used channel of the ADC */ + adc_t adc_line; /**< the used ADC line */ } mq3_t; /** @@ -47,12 +46,11 @@ typedef struct { * * @param[out] dev device descriptor of an MQ-3 sensor * @param[in] adc the ADC device the sensor is connected to - * @param[in] channel the channel of the ADC device used * * @return 0 on success * @return -1 on error */ -int mq3_init(mq3_t *dev, adc_t adc, int channel); +int mq3_init(mq3_t *dev, adc_t adc_line); /** * @brief Read the RAW sensor value, can be between 0 and MQ3_MAX_RAW_VALUE diff --git a/drivers/include/periph/adc.h b/drivers/include/periph/adc.h index b009dc8129..6f60181f1a 100644 --- a/drivers/include/periph/adc.h +++ b/drivers/include/periph/adc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Freie Universität Berlin + * Copyright (C) 2014-2015 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 @@ -9,7 +9,29 @@ /** * @defgroup drivers_periph_adc ADC * @ingroup drivers_periph - * @brief Low-level ADC peripheral driver + * @brief Low-level ADC peripheral driver interface + * + * This is a very simple ADC interface to allow platform independent access to + * a MCU's ADC unit(s). This interface is intentionally designed as simple as + * possible, to allow for very easy implementation and maximal portability. + * + * As of now, the interface does not allow for any advanced ADC concepts (e.g. + * continuous mode, scan sequences, injections). It is to be determined, if + * these features will ever be integrated in this interface, or if it does make + * more sense to create a second, advanced ADC interface for this. + * + * The ADC driver interface is built around the concept of ADC lines. An ADC + * line in this context is a tuple consisting out of a hardware ADC device (an + * ADC functional unit on the MCU) and an ADC channel connected to pin. + * + * If a MCU has more than one hardware ADC unit, the ADC lines can be mapped in + * a way, that it is possible to sample multiple lines in parallel, given that + * the ADC implementation allows for interruption of the program flow while + * waiting for the result of a conversion (e.g. through putting the calling + * thread to sleep while waiting for the conversion results). + * + * @todo Extend interface for continuous mode? + * * @{ * * @file @@ -18,128 +40,99 @@ * @author Hauke Petersen */ -#ifndef ADC_H -#define ADC_H +#ifndef PERIPH_ADC_H +#define PERIPH_ADC_H +#include "periph_cpu.h" #include "periph_conf.h" #ifdef __cplusplus extern "C" { #endif -/* guard file in case no ADC device is defined */ -#if ADC_NUMOF - /** - * @brief Definition available ADC devices - * - * Each ADC device is based on a hardware ADC which can have one or more - * multiplexed channels. + * @brief Make sure the number of available ADC lines is defined + * @{ */ -typedef enum { -#if ADC_0_EN - ADC_0 = 0, /**< ADC device 0 */ +#ifndef ADC_NUMOF +#error "ADC_NUMOF undefined" #endif -#if ADC_1_EN - ADC_1, /**< ADC device 1 */ -#endif -#if ADC_2_EN - ADC_2, /**< ADC device 2 */ -#endif -#if ADC_3_EN - ADC_3, /**< ADC device 3 */ -#endif -} adc_t; +/** @} */ /** - * @brief Possible ADC precision settings + * @brief Define default ADC type identifier + * @{ */ -typedef enum { - ADC_RES_6BIT = 0, /**< ADC precision: 6 bit */ - ADC_RES_8BIT, /**< ADC precision: 8 bit */ - ADC_RES_10BIT, /**< ADC precision: 10 bit */ - ADC_RES_12BIT, /**< ADC precision: 12 bit */ - ADC_RES_14BIT, /**< ADC precision: 14 bit */ - ADC_RES_16BIT, /**< ADC precision: 16 bit */ -} adc_precision_t; +#ifndef HAVE_ADC_T +typedef unsigned int adc_t; +#endif +/** @} */ /** - * @brief Initialization of a given ADC device + * @brief Default ADC undefined value + * @{ + */ +#ifndef ADC_UNDEF +#define ADC_UNDEF (0xffff) +#endif +/** @} */ + +/** + * @brief Default ADC line access macro + * @{ + */ +#ifndef ADC_LINE +#define ADC_LINE(x) (x) +#endif +/** @} */ + +/** + * @brief Possible ADC resolution settings + * @{ + */ +#ifndef HAVE_ADC_RES_T +typedef enum { + ADC_RES_6BIT = 0, /**< ADC resolution: 6 bit */ + ADC_RES_8BIT, /**< ADC resolution: 8 bit */ + ADC_RES_10BIT, /**< ADC resolution: 10 bit */ + ADC_RES_12BIT, /**< ADC resolution: 12 bit */ + ADC_RES_14BIT, /**< ADC resolution: 14 bit */ + ADC_RES_16BIT, /**< ADC resolution: 16 bit */ +} adc_res_t; +#endif +/** @} */ + +/** + * @brief Initialize the given ADC line * - * The ADC will be initialized in synchronous, blocking mode, so no callbacks for finished - * conversions are required as conversions are presumed to be very fast (somewhere in the - * range of some us). + * The ADC line is initialized in synchronous, blocking mode. * - * @param[in] dev the device to initialize - * @param[in] precision the precision to use for conversion + * @param[in] line line to initialize * * @return 0 on success - * @return -1 on precision not available + * @return -1 on invalid ADC line */ -int adc_init(adc_t dev, adc_precision_t precision); +int adc_init(adc_t line); /** - * @brief Start a new conversion by using the given channel. + * @brief Sample a value from the given ADC line * - * If a conversion on any channel on the given ADC core is in progress, it is aborted. + * This function blocks until the conversion has finished. Please note, that if + * more than one line share the same ADC device, and if these lines are sampled + * at the same time (e.g. from different threads), the one called secondly waits + * for the first to finish before its conversion starts. * - * @param[in] dev the ADC device to use for the conversion - * @param[in] channel the channel to convert from + * @param[in] line line to sample + * @param[in] resolution resolution to use for conversion * - * @return the converted value - * @return -1 on invalid channel + * @return the sampled value on success + * @return -1 if resolution is not applicable */ -int adc_sample(adc_t dev, int channel); - -/** - * @brief Enable the power for the given ADC device - * - * @param[in] dev the ADC device to power up - */ -void adc_poweron(adc_t dev); - -/** - * @brief Disable the power for the given ADC device - * - * @param[in] dev the ADC device to power down - */ -void adc_poweroff(adc_t dev); - -/** - * @brief Helper function to map a converted value to the given integer range. - * - * This function is useful for converting sampled ADC values into their physical representation. - * - * The min value is asserted to be smaller than the max value. - * - * @param[in] dev the ADC device to read the precision value from (as input interval) - * @param[in] value the value to map - * @param[in] min the lower bound of the target interval - * @param[in] max the upper bound of the target interval - * - * @return the mapped value - */ -int adc_map(adc_t dev, int value, int min, int max); - -/** - * @brief Helper function to map a converted value to the given float range - * - * @see adc_map - * - * @param[in] dev the ADC device to read the precision value from (as input interval) - * @param[in] value the value to map - * @param[in] min the lower bound of the target interval - * @param[in] max the upper bound of the target interval - * - * @return the mapped value - */ -float adc_mapf(adc_t dev, int value, float min, float max); - -#endif /* ADC_NUMOF */ +int adc_sample(adc_t line, adc_res_t res); #ifdef __cplusplus } #endif -#endif /* ADC_H */ +#endif /* PERIPH_ADC_H */ /** @} */ diff --git a/drivers/mq3/mq3.c b/drivers/mq3/mq3.c index e3fe6285e7..1ad77a95c5 100644 --- a/drivers/mq3/mq3.c +++ b/drivers/mq3/mq3.c @@ -24,16 +24,15 @@ #define MIN (100U) /* TODO: calibrate to useful value */ #define FACTOR (2.33f) /* TODO: calibrate to useful value */ -int mq3_init(mq3_t *dev, adc_t adc, int channel) +int mq3_init(mq3_t *dev, adc_t adc_line) { - dev->adc_dev = adc; - dev->adc_chan = channel; - return adc_init(dev->adc_dev, PRECISION); + dev->adc_line = adc_line; + return adc_init(dev->adc_line); } int mq3_read_raw(mq3_t *dev) { - return adc_sample(dev->adc_dev, dev->adc_chan); + return adc_sample(dev->adc_line, PRECISION); } int mq3_read(mq3_t *dev) diff --git a/sys/adc_util/Makefile b/sys/adc_util/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/sys/adc_util/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/sys/adc_util/adc_util.c b/sys/adc_util/adc_util.c new file mode 100644 index 0000000000..1cd3293c30 --- /dev/null +++ b/sys/adc_util/adc_util.c @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2015 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 sys_adc_util + * @{ + * + * @file + * @brief ADC utility function implementation + * + * @author Hauke Petersen + * + * @} + */ + +#include "adc_util.h" + +/* keep a max value to ADC resolution mapping for quick access in the ROM */ +static const int val_max[] = { + [ADC_RES_6BIT] = 0x003f, + [ADC_RES_8BIT] = 0x00ff, + [ADC_RES_10BIT] = 0x03ff, + [ADC_RES_12BIT] = 0x0fff, + [ADC_RES_14BIT] = 0x3fff, + [ADC_RES_16BIT] = 0xffff +} + +int adc_util_map(int sample, adc_res_t res, int min, int max) +{ + return ((((max - min) * sample) / val_max[res]) + min); +} + +float adc_util_mapf(int sample, adc_res_t res, float min, float max) +{ + return ((((max - min) * sample) / val_max[res]) + min); +} diff --git a/sys/include/adc_util.h b/sys/include/adc_util.h new file mode 100644 index 0000000000..fc9d568b82 --- /dev/null +++ b/sys/include/adc_util.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2015 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. + */ + +/** + * @defgroup sys_adc_util ADC utilities + * @ingroup sys + * @brief Utility functions for handling ADC samples + * + * @{ + * @file + * @brief ADC utility function interfaces + * + * @author Hauke Petersen + */ + +#ifndef ADC_UTIL_H +#define ADC_UTIL_H + +#include "periph/adc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Map a sampled ADC value to a given range + * + * This function is useful for converting sampled ADC values into their physical + * representation. + * + * The min value is asserted to be smaller than the max value. + * + * @param[in] sample sampled ADC value + * @param[in] res ADC resolution + * @param[in] min the lower bound of the target interval + * @param[in] max the upper bound of the target interval + * + * @return the mapped value + */ +int adc_util_map(int sample, adc_res_t res, int min, int max); + +/** + * @brief Map a sampled ADC value to a given range (using floating point + * arithmetics) + * + * @see adc_util_map + * + * @param[in] sample sampled ADC value + * @param[in] res ADC resolution + * @param[in] min the lower bound of the target interval + * @param[in] max the upper bound of the target interval + * + * @return the mapped value + */ +float adc_util_mapf(int sample, adc_res_t res, float min, float max); + +#ifdef __cplusplus +} +#endif + +#endif /* ADC_UTIL_H */ +/** @} */ diff --git a/tests/driver_mq3/Makefile b/tests/driver_mq3/Makefile index 20135bd0e9..53b3707186 100644 --- a/tests/driver_mq3/Makefile +++ b/tests/driver_mq3/Makefile @@ -7,11 +7,9 @@ USEMODULE += mq3 USEMODULE += xtimer # set default device parameters in case they are undefined -MQ3_ADC ?= ADC_0 -MQ3_CHAN ?= 0 +MQ3_ADC_LINE ?= ADC_LINE\(0\) # export parameters -CFLAGS += -DMQ3_ADC=$(MQ3_ADC) -CFLAGS += -DMQ3_CHAN=$(MQ3_CHAN) +CFLAGS += -DMQ3_ADC_LINE=$(MQ3_ADC_LINE) include $(RIOTBASE)/Makefile.include diff --git a/tests/driver_mq3/main.c b/tests/driver_mq3/main.c index 1a18397518..aab1b9eb49 100644 --- a/tests/driver_mq3/main.c +++ b/tests/driver_mq3/main.c @@ -25,11 +25,8 @@ #include "periph_conf.h" #include "periph/adc.h" -#ifndef MQ3_ADC -#error "MQ3_ADC is not specified" -#endif -#ifndef MQ3_CHAN -#error "MQ3_CHAN is not specified" +#ifndef MQ3_ADC_LINE +#error "MQ3_ADC_LINE is not specified" #endif int main(void) @@ -38,8 +35,8 @@ int main(void) int res; puts("MQ-3 alcohol sensor test application\n"); - printf("Initializing MQ-3 sensor at ADC_%i, channel %i... ", MQ3_ADC, MQ3_CHAN); - res = mq3_init(&dev, MQ3_ADC, MQ3_CHAN); + printf("Initializing MQ-3 sensor at ADC_LINE(%i)... ", (int)MQ3_ADC_LINE); + res = mq3_init(&dev, MQ3_ADC_LINE); if (res == 0) { puts("[ok]\n"); } diff --git a/tests/periph_adc/README.md b/tests/periph_adc/README.md index 498ec155f0..7ad2990acf 100644 --- a/tests/periph_adc/README.md +++ b/tests/periph_adc/README.md @@ -1,11 +1,11 @@ Expected result =============== -When running this test, you should see the samples of all configured ADC channels +When running this test, you should see the samples of all configured ADC lines continuously streamed to std-out. Background ========== -This test application will initialize each configured ADC device to sample with +This test application will initialize each configured ADC lines to sample with 10-bit accuracy. Once configured the application will continuously convert each available channel and print the conversion results to std-out. diff --git a/tests/periph_adc/main.c b/tests/periph_adc/main.c index 3e07a87be2..5ba15d08c0 100644 --- a/tests/periph_adc/main.c +++ b/tests/periph_adc/main.c @@ -1,17 +1,17 @@ /* - * Copyright (C) 2014 Freie Universität Berlin + * Copyright (C) 2014-2015 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. */ /** - * @ingroup tests + * @ingroup tests * @{ * * @file - * @brief Test case for the low-level ADC driver + * @brief Test application for peripheral ADC drivers * * @author Hauke Petersen * @@ -20,64 +20,43 @@ #include -#include "cpu.h" -#include "board.h" #include "xtimer.h" #include "periph/adc.h" -#if ADC_NUMOF < 1 -#error "Please enable at least 1 ADC device to run this test" -#endif #define RES ADC_RES_10BIT #define DELAY (100 * 1000U) -static int values[ADC_NUMOF][ADC_MAX_CHANNELS]; int main(void) { - puts("\nRIOT ADC peripheral driver test\n"); - puts("This test simply converts each available ADC channel about every 10ms\n\n"); + uint32_t last = xtimer_now(); + int sample = 0; + puts("\nRIOT ADC peripheral driver test\n"); + puts("This test will sample all available ADC lines once every 100ms with\n" + "a 10-bit resolution and print the sampled results to STDIO\n\n"); + + /* initialize all available ADC lines */ for (int i = 0; i < ADC_NUMOF; i++) { - /* initialize result vector */ - for (int j = 0; j < ADC_MAX_CHANNELS; j++) { - values[i][j] = -1; - } - /* initialize ADC device */ - printf("Initializing ADC_%i @ %i bit resolution", i, (6 + (2* RES))); - if (adc_init(i, RES) == 0) { - puts(" ...[ok]"); - } - else { - puts(" ...[failed]"); + if (adc_init(ADC_LINE(i)) < 0) { + printf("Initialization of ADC_LINE(%i) failed\n", i); return 1; + } else { + printf("Successfully initialized ADC_LINE(%i)\n", i); } } - puts("\n"); - while (1) { - /* convert each channel for this ADC device */ for (int i = 0; i < ADC_NUMOF; i++) { - for (int j = 0; j < ADC_MAX_CHANNELS; j++) { - values[i][j] = adc_sample(i, j); + sample = adc_sample(ADC_LINE(i), RES); + if (sample < 0) { + printf("ADC_LINE(%i): 10-bit resolution not applicable\n", i); + } else { + printf("ADC_LINE(%i): %i\n", i, sample); } } - - /* print the results */ - printf("Values: "); - for (int i = 0; i < ADC_NUMOF; i++) { - for (int j = 0; j < ADC_MAX_CHANNELS; j++) { - if (values[i][j] >= 0) { - printf("ADC_%i-CH%i: %4i ", i, j, values[i][j]); - } - } - } - printf("\n"); - - /* sleep a little while */ - xtimer_usleep(DELAY); + xtimer_usleep_until(&last, DELAY); } return 0; diff --git a/tests/periph_dac/main.c b/tests/periph_dac/main.c index a3e5352d5f..7aa0f77296 100644 --- a/tests/periph_dac/main.c +++ b/tests/periph_dac/main.c @@ -32,6 +32,7 @@ #endif #define RES DAC_RES_10BIT +#define ADC_RES ADC_RES_10BIT #define DELAY (1000 * 1000U) #define MAX_VALUE_STEPS 1000 @@ -60,9 +61,9 @@ int main(void) return 1; } -#if ADC_NUMOF > 0 - printf("Initializing ADC_0 @ %i bit resolution", (6 + (2* RES))); - if (adc_init(0, RES) == 0) { +#ifdef ADC_NUMOF + printf("Initializing ADC_LINE(0)"); + if (adc_init(ADC_LINE(0)) == 0) { puts(" ...[ok]"); } else { @@ -82,9 +83,9 @@ int main(void) printf("%i: Something went wrong writing DAC\n", status_dac_write); return -1; } -#if ADC_NUMOF > 0 +#ifdef ADC_NUMOF /* Read values from ADC */ - int sample = adc_sample(ADC_0, 0); + int sample = adc_sample(ADC_LINE(0), ADC_RES); if (sample < 0) { printf("%i: Something went wrong sampling ADC\n", sample); return -1;