diff --git a/cpu/nrf51/periph/adc.c b/cpu/nrf51/periph/adc.c index 263c7a416..6b6080b0f 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; - /* 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; + /* check if resolution is valid */ + if (res > 2) { + 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; - - /* return result */ - return (int)NRF_ADC->RESULT; -} + while (NRF_ADC->BUSY == 1) {} + /* get result */ + val = (int)NRF_ADC->RESULT; -void adc_poweron(adc_t dev) -{ - if (dev == ADC_0) { - NRF_ADC->POWER = 1; - } -} + /* free device */ + done(); -void adc_poweroff(adc_t dev) -{ - if (dev == ADC_0) { - NRF_ADC->POWER = 0; - } + return val; } - -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 63b7d4938..d287e0feb 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 */