From 42846549a57642baeaa2e09edea4aca96da569cf Mon Sep 17 00:00:00 2001 From: PeterKietzmann Date: Mon, 26 Oct 2015 13:17:21 +0100 Subject: [PATCH] import adc driver and test for moisture sensor --- boards/samr21-xpro/Makefile.features | 1 + boards/samr21-xpro/include/board.h | 2 +- boards/samr21-xpro/include/periph_conf.h | 123 ++++++++ cpu/samd21/periph/adc.c | 375 +++++++++++++++++++++++ tests/moisture/Makefile | 7 + tests/moisture/main.c | 80 +++++ 6 files changed, 587 insertions(+), 1 deletion(-) create mode 100644 cpu/samd21/periph/adc.c create mode 100644 tests/moisture/Makefile create mode 100644 tests/moisture/main.c diff --git a/boards/samr21-xpro/Makefile.features b/boards/samr21-xpro/Makefile.features index 6c981cf57080..d3531b1d4ef4 100644 --- a/boards/samr21-xpro/Makefile.features +++ b/boards/samr21-xpro/Makefile.features @@ -8,6 +8,7 @@ FEATURES_PROVIDED += periph_rtt FEATURES_PROVIDED += periph_spi FEATURES_PROVIDED += periph_timer FEATURES_PROVIDED += periph_uart +FEATURES_PROVIDED += periph_adc # Various other features (if any) FEATURES_PROVIDED += cpp diff --git a/boards/samr21-xpro/include/board.h b/boards/samr21-xpro/include/board.h index fd24914c288b..40e70d333fcd 100644 --- a/boards/samr21-xpro/include/board.h +++ b/boards/samr21-xpro/include/board.h @@ -70,7 +70,7 @@ extern "C" { * @name Define UART device and baudrate for stdio * @{ */ -#define STDIO UART_0 +#define STDIO UART_1 #define STDIO_BAUDRATE (115200U) #define STDIO_RX_BUFSIZE (64U) /** @} */ diff --git a/boards/samr21-xpro/include/periph_conf.h b/boards/samr21-xpro/include/periph_conf.h index ed1f1ad2d616..6560c53e606b 100644 --- a/boards/samr21-xpro/include/periph_conf.h +++ b/boards/samr21-xpro/include/periph_conf.h @@ -263,6 +263,129 @@ static const pwm_conf_t pwm_config[] = { #define RTT_RUNSTDBY (1) /* Keep RTT running in sleep states */ /** @} */ +/** @} */ + +/** + * @ ADC Configuration + * @{ + */ +typedef struct { + PortGroup *port; + uint8_t pin; + uint8_t muxpos; /* see datasheet sec 30.8.8 */ +} adc_conf_t; + +#define ADC_NUMOF (1U) +#define ADC_0_EN 1 +#define ADC_MAX_CHANNELS 8 + +/* ADC 0 device configuration */ +#define ADC_0_DEV ADC +#define ADC_0_PORT (PORT->Group[0]) +#define ADC_0_IRQ ADC_IRQn +#define ADC_0_CHANNELS 6 // ignore PA04 & PA05 due to EDBG UART conflict + +/* ADC 0 Default values */ +#define ADC_0_CLK_SOURCE 0 /* GCLK_GENERATOR_0 */ +#define ADC_0_PRESCALER ADC_CTRLB_PRESCALER_DIV512 +#define ADC_0_WINDOW_MODE ADC_WINCTRL_WINMODE_DISABLE +#define ADC_0_WINDOW_LOWER 0 +#define ADC_0_WINDOW_HIGHER 0 + +#define ADC_0_CORRECTION_EN 0 /* disabled */ +#define ADC_0_GAIN_CORRECTION ADC_GAINCORR_RESETVALUE +#define ADC_0_OFFSET_CORRECTION ADC_OFFSETCORR_RESETVALUE +#define ADC_0_SAMPLE_LENGTH 0 +#define ADC_0_PIN_SCAN_OFFSET_START 0 /* disabled */ +#define ADC_0_PIN_SCAN_INPUT_TO_SCAN 0 /* disabled */ +#define ADC_0_LEFT_ADJUST 0 /* disabled */ +#define ADC_0_DIFFERENTIAL_MODE 0 /* disabled */ +#define ADC_0_FREE_RUNNING 0 /* disabled */ +#define ADC_0_EVENT_ACTION 0 /* disabled */ +#define ADC_0_RUN_IN_STANDBY 0 /* disabled */ + +/* ADC 0 Module Status flags */ +#define ADC_0_STATUS_RESULT_READY (1UL << 0) +#define ADC_0_STATUS_WINDOW (1UL << 1) +#define ADC_0_STATUS_OVERRUN (1UL << 2) + +#if ADC_0_CHANNELS +#if ADC_0_DIFFERENTIAL_MODE +/* In differential mode, we can only pick one positive + * and one negative input. + */ +#define ADC_0_POS_INPUT ADC_INPUTCTRL_MUXPOS_PIN6 +#define ADC_0_NEG_INPUT ADC_INPUTCTRL_MUXNEG_PIN7 +#else +/* If we're not in differential mode, we can use any of + * ADC positive input pins the SAMR21-XPRO provides. Each pin is + * a separate ADC "channel". + */ +static const adc_conf_t adc_config[] = { + /* port, pin, muxpos */ + //{&PORT->Group[0], 4, 0x4}, // we cannot use these as well as use EDBG serial TX/RX + //{&PORT->Group[0], 5, 0x5}, // because PA04 & PA05 read/write directly to EDBG serial port. + {&PORT->Group[0], ADC_INPUTCTRL_MUXPOS_PIN6, 0x6}, // PA06 + {&PORT->Group[0], ADC_INPUTCTRL_MUXPOS_PIN7, 0x7}, // PA07 + {&PORT->Group[0], ADC_INPUTCTRL_MUXPOS_PIN16, 0x10}, // PA08 + {&PORT->Group[0], ADC_INPUTCTRL_MUXPOS_PIN17, 0x11}, // PA09 + {&PORT->Group[0], ADC_INPUTCTRL_MUXPOS_PIN10, 0xA}, // PB02 + {&PORT->Group[0], ADC_INPUTCTRL_MUXPOS_PIN11, 0xB}, // PB03 +}; +#endif +#endif + + +/* ADC 0 Gain Factor */ +#define ADC_0_GAIN_FACTOR_1X ADC_INPUTCTRL_GAIN_1X +#define ADC_0_GAIN_FACTOR_2X ADC_INPUTCTRL_GAIN_2X +#define ADC_0_GAIN_FACTOR_4X ADC_INPUTCTRL_GAIN_4X +#define ADC_0_GAIN_FACTOR_8X ADC_INPUTCTRL_GAIN_8X +#define ADC_0_GAIN_FACTOR_16X ADC_INPUTCTRL_GAIN_16X +/* Use this to define the value used */ +#define ADC_0_GAIN_FACTOR_DEFAULT ADC_0_GAIN_FACTOR_1X + +/* ADC 0 Resolutions */ +#define ADC_0_RES_8BIT ADC_CTRLB_RESSEL_8BIT +#define ADC_0_RES_10BIT ADC_CTRLB_RESSEL_10BIT +#define ADC_0_RES_12BIT ADC_CTRLB_RESSEL_12BIT +#define ADC_0_RES_16BIT ADC_CTRLB_RESSEL_16BIT + +/* ADC 0 Voltage reference */ +#define ADC_0_REF_INT_1V ADC_REFCTRL_REFSEL_INT1V +#define ADC_0_REF_EXT_B ADC_REFCTRL_REFSEL_AREFB +#define ADC_0_REF_COM_EN 1 +/* Use this to define the value used */ +#define ADC_0_REF_DEFAULT ADC_REFCTRL_REFSEL_AREFB//ADC_0_REF_INT_1V + +/* ADC 0 ACCUMULATE */ +#define ADC_0_ACCUM_DISABLE ADC_AVGCTRL_SAMPLENUM_1 +#define ADC_0_ACCUM_2 ADC_AVGCTRL_SAMPLENUM_2 +#define ADC_0_ACCUM_4 ADC_AVGCTRL_SAMPLENUM_4 +#define ADC_0_ACCUM_8 ADC_AVGCTRL_SAMPLENUM_8 +#define ADC_0_ACCUM_16 ADC_AVGCTRL_SAMPLENUM_16 +#define ADC_0_ACCUM_32 ADC_AVGCTRL_SAMPLENUM_32 +#define ADC_0_ACCUM_64 ADC_AVGCTRL_SAMPLENUM_64 +#define ADC_0_ACCUM_128 ADC_AVGCTRL_SAMPLENUM_128 +#define ADC_0_ACCUM_256 ADC_AVGCTRL_SAMPLENUM_256 +#define ADC_0_ACCUM_512 ADC_AVGCTRL_SAMPLENUM_512 +#define ADC_0_ACCUM_1024 ADC_AVGCTRL_SAMPLENUM_1024 +/* Use this to define the value used */ +#define ADC_0_ACCUM_DEFAULT ADC_0_ACCUM_DISABLE + +/* ADC 0 DIVIDE RESULT */ +#define ADC_0_DIV_RES_DISABLE 0 +#define ADC_0_DIV_RES_2 1 +#define ADC_0_DIV_RES_4 2 +#define ADC_0_DIV_RES_8 3 +#define ADC_0_DIV_RES_16 4 +#define ADC_0_DIV_RES_32 5 +#define ADC_0_DIV_RES_64 6 +#define ADC_0_DIV_RES_128 7 +/* Use this to define the value used */ +#define ADC_0_DIV_RES_DEFAULT ADC_0_DIV_RES_DISABLE +/** @} */ + #ifdef __cplusplus } #endif diff --git a/cpu/samd21/periph/adc.c b/cpu/samd21/periph/adc.c new file mode 100644 index 000000000000..b3ae5fed02b5 --- /dev/null +++ b/cpu/samd21/periph/adc.c @@ -0,0 +1,375 @@ +/* + * 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_samr21 + * @{ + * + * @file + * @brief ADC driver implementation + * + * @author Rane Balslev (SAMR21) + * + * @} + */ + +#include +#include "cpu.h" +#include "periph/adc.h" +#include "periph_conf.h" +#define ENABLE_DEBUG (0) +#include "debug.h" + +/* guard in case that no ADC device is defined */ +#if ADC_NUMOF + +/* Prototypes */ +bool adc_syncing(Adc*); +void adc_clear_status(Adc*, uint32_t); +uint32_t adc_get_status(Adc*); +int adc_configure_with_resolution(Adc*, uint32_t); + +int adc_init(adc_t dev, adc_precision_t precision) +{ + //adc_poweron(dev); + Adc *adc = 0; + int init = 0; + switch (dev) { + #if ADC_0_EN + case ADC_0: + adc = ADC_0_DEV; + while(adc_syncing(adc)); + /*Disable adc before init*/ + adc->CTRLA.reg &= ~ADC_CTRLA_ENABLE; + switch (precision) + { + case ADC_RES_8BIT: + init = adc_configure_with_resolution(adc, ADC_0_RES_8BIT); + break; + case ADC_RES_10BIT: + init = adc_configure_with_resolution(adc, ADC_0_RES_10BIT); + break; + case ADC_RES_12BIT: + init = adc_configure_with_resolution(adc, ADC_0_RES_12BIT); + break; + case ADC_RES_16BIT: + init = adc_configure_with_resolution(adc, ADC_0_RES_16BIT); + DEBUG("Init switch DONE\n"); + break; + default: + return -1; + } + while(adc_syncing(adc)); + if(init == -1) + return -1; + /* Enable bandgap if internal ref 1 volt */ + if(ADC_0_REF_DEFAULT == ADC_0_REF_INT_1V) + { + SYSCTRL->VREF.reg |= SYSCTRL_VREF_BGOUTEN; + } + /* Enable */ + adc->CTRLA.reg |= ADC_CTRLA_ENABLE; + break; + #endif + default: + return -1; + } + return 0; +} + +int adc_sample(adc_t dev, int channel) +{ + if (dev != ADC_0) { + return -2; + } + if (channel >= ADC_0_CHANNELS) { + return -1; + } + + // Select the inputs. + #if ADC_0_DIFFERENTIAL_MODE + /* In differential mode, use ADC_0_POS_INPUT & ADC_0_NEG_INPUT + */ + ADC->INPUTCTRL.reg = ADC_0_GAIN_FACTOR_DEFAULT + /*| (ADC_0_PIN_SCAN_OFFSET_START << ADC_INPUTCTRL_INPUTOFFSET_Pos) + | (ADC_0_PIN_SCAN_INPUT_TO_SCAN << ADC_INPUTCTRL_INPUTSCAN_Pos)*/ + | ADC_0_NEG_INPUT + | ADC_0_POS_INPUT; + #else + /* Otherwise, use the positive input corresponding to the provided arg + * "channel", and use GND as the negative input. + */ + ADC->INPUTCTRL.reg = ADC_0_GAIN_FACTOR_DEFAULT | adc_config[channel].muxpos | ADC_INPUTCTRL_MUXNEG_IOGND; + #endif + + // Wait for sync. + while (ADC->STATUS.reg & ADC_STATUS_SYNCBUSY); + + // Start the conversion. + ADC->SWTRIG.reg = ADC_SWTRIG_START; + + // Wait for the result. + while (!(ADC->INTFLAG.reg & ADC_INTFLAG_RESRDY)); + + // Read & return result. + return (int)ADC->RESULT.reg; +} + +void adc_poweron(adc_t dev) +{ + switch (dev) + { + #if ADC_0_EN + case ADC_0: + /* Setup generic clock mask for adc */ + PM->APBCMASK.reg |= PM_APBCMASK_ADC; + break; + #endif + default: + break; + } +} + +void adc_poweroff(adc_t dev) +{ + Adc *adc = 0; + + switch (dev) + { + #if ADC_0_EN + case ADC_0: + adc = ADC_0_DEV; + while(adc_syncing(adc)); + /* Disable */ + adc->CTRLA.reg &= ~ADC_CTRLA_ENABLE; + break; + #endif + default: + break; + } +} + +int adc_map(adc_t dev, int value, int min, int max) +{ + DEBUG("adc_map Not implemented!\n"); + return 0; +} + +float adc_mapf(adc_t dev, int value, float min, float max) +{ + DEBUG("adc_mapf Not implemented!\n"); + return 0.0; +} + +bool adc_syncing(Adc* adc) +{ + if(adc->STATUS.reg & ADC_STATUS_SYNCBUSY){ + return true; + } + return false; +} + +/* Configure ADC with defined Resolution */ +int adc_configure_with_resolution(Adc* adc, uint32_t precision) +{ + adc_poweron(ADC_0); + uint8_t divideResult = ADC_0_DIV_RES_DEFAULT; + uint32_t resolution = ADC_0_RES_16BIT; + uint32_t accumulate = ADC_0_ACCUM_DEFAULT; + if(adc->CTRLA.reg & ADC_CTRLA_SWRST) + return -1; + if(adc->CTRLA.reg & ADC_CTRLA_ENABLE) + return -1; + + /* GCLK Setup*/ + GCLK->CLKCTRL.reg = (uint32_t)((GCLK_CLKCTRL_CLKEN + | GCLK_CLKCTRL_GEN_GCLK0 + | (ADC_GCLK_ID << GCLK_CLKCTRL_ID_Pos))); + + /* Pin Muxing */ + #if ADC_0_DIFFERENTIAL_MODE + ADC_0_PORT.PINCFG[ ADC_0_POS_INPUT ].bit.PMUXEN = 1; + ADC_0_PORT.PMUX[ ADC_0_POS_INPUT / 2].bit.PMUXE = 1; + + /* ADC_0_POS_INPUT Input */ + ADC_0_PORT.DIRCLR.reg = (1 << ADC_0_POS_INPUT); + ADC_0_PORT.PINCFG[ADC_0_POS_INPUT].bit.INEN = true; + ADC_0_PORT.PINCFG[ADC_0_POS_INPUT].bit.PULLEN = false; + + if(ADC_0_NEG_INPUT != ADC_INPUTCTRL_MUXNEG_GND) + { + ADC_0_PORT.DIRCLR.reg = (1 << ADC_0_NEG_INPUT); + ADC_0_PORT.PINCFG[ADC_0_NEG_INPUT].bit.INEN = true; + ADC_0_PORT.PINCFG[ADC_0_NEG_INPUT].bit.PULLEN = false; + } + #else + for (int i = 0; i < ADC_0_CHANNELS; i++) { + PortGroup *port = adc_config[i].port; + int pin = adc_config[i].pin; + port->DIRCLR.reg = (1 << pin); + port->PINCFG[pin].reg = (PORT_PINCFG_PMUXEN | PORT_PINCFG_INEN); + port->PMUX[pin >> 1].reg = ~(0xf << (4 * (pin & 0x1))); + port->PMUX[pin >> 1].reg = (1 << (4 * (pin & 0x1))); + } + #endif + + + /* Set RUN_IN_STANDBY */ + adc->CTRLA.reg = (ADC_0_RUN_IN_STANDBY << ADC_CTRLA_RUNSTDBY_Pos); + + /* Set Voltage Reference */ + adc->REFCTRL.reg = (ADC_0_REF_COM_EN << ADC_REFCTRL_REFCOMP_Pos) | ADC_0_REF_DEFAULT; + + switch (precision) + { + case ADC_0_RES_8BIT: + resolution = ADC_0_RES_8BIT; + break; + case ADC_0_RES_10BIT: + resolution = ADC_0_RES_10BIT; + break; + case ADC_0_RES_12BIT: + resolution = ADC_0_RES_12BIT; + break; + case ADC_0_RES_16BIT: + divideResult = ADC_0_DIV_RES_DISABLE; + switch(ADC_0_ACCUM_DEFAULT) + { + case ADC_0_ACCUM_512: + accumulate = ADC_0_ACCUM_512; + break; + case ADC_0_ACCUM_1024: + accumulate = ADC_0_ACCUM_1024; + break; + default: + accumulate = ADC_0_ACCUM_256; + break; + } + resolution = ADC_0_RES_16BIT; + break; + default: + DEBUG("Invalid precision"); + return -1; + } + + /* Set the accumlation and devide result */ + adc->AVGCTRL.reg = ADC_AVGCTRL_ADJRES(divideResult) | accumulate; + + /* Set Sample length */ + adc->SAMPCTRL.reg = ADC_SAMPCTRL_SAMPLEN(ADC_0_SAMPLE_LENGTH);//(ADC_0_SAMPLE_LENGTH << ADC_SAMPCTRL_SAMPLEN_Pos); + while(adc_syncing(adc)); + + /* If external vref. Pin setup */ + if(ADC_0_REF_DEFAULT == ADC_0_REF_EXT_B) + { + ADC_0_PORT.DIRCLR.reg = (1 << ADC_0_REF_DEFAULT); + ADC_0_PORT.PINCFG[ADC_0_REF_DEFAULT].bit.INEN = true; + ADC_0_PORT.PINCFG[ADC_0_REF_DEFAULT].bit.PULLEN = false; + } + + /* Configure CTRLB Register HERE IS THE RESOLUTION SET!*/ + adc->CTRLB.reg = + ADC_0_PRESCALER | + resolution | + (ADC_0_CORRECTION_EN << ADC_CTRLB_CORREN_Pos) | + (ADC_0_FREE_RUNNING << ADC_CTRLB_FREERUN_Pos) | + (ADC_0_LEFT_ADJUST << ADC_CTRLB_LEFTADJ_Pos) | + (ADC_0_DIFFERENTIAL_MODE << ADC_CTRLB_DIFFMODE_Pos); + + + /* Configure Window Mode Register */ + /*adc->WINCTRL.reg = ADC_0_WINDOW_MODE; + while(adc_syncing(adc));*/ + + /* Configure lower threshold */ + adc->WINLT.reg = ADC_0_WINDOW_LOWER << ADC_WINLT_WINLT_Pos; + while(adc_syncing(adc)); + + /* Configure lower threshold */ + adc->WINUT.reg = ADC_0_WINDOW_HIGHER << ADC_WINUT_WINUT_Pos; + while(adc_syncing(adc)); + + /* Configure PIN SCAN MODE & positive & Negative Input Pins */ + /*adc->INPUTCTRL.reg = + ADC_0_GAIN_FACTOR_DEFAULT | + (ADC_0_PIN_SCAN_OFFSET_START << ADC_INPUTCTRL_INPUTOFFSET_Pos) | + (ADC_0_PIN_SCAN_INPUT_TO_SCAN << ADC_INPUTCTRL_INPUTSCAN_Pos) | + ADC_0_NEG_INPUT | + ADC_0_POS_INPUT;*/ + + /* Configure event action */ + adc->EVCTRL.reg = ADC_0_EVENT_ACTION; + + if (ADC_0_CORRECTION_EN) + { + if (ADC_0_GAIN_CORRECTION > ADC_GAINCORR_GAINCORR_Msk) + { + DEBUG("Invalid gain correction\n"); + return -1; + } + else + { + /* Set gain correction value */ + adc->GAINCORR.reg = (ADC_0_GAIN_CORRECTION << ADC_GAINCORR_GAINCORR_Pos); + } + if (ADC_0_OFFSET_CORRECTION > 2047 || ADC_0_OFFSET_CORRECTION < -2048) + { + DEBUG("Invalid offset correction\n"); + return -1; + } + else + { + /* Set offset correction value */ + adc->OFFSETCORR.reg = (ADC_0_OFFSET_CORRECTION << ADC_OFFSETCORR_OFFSETCORR_Pos); + } + } + + /* Disable all interrupts */ + adc->INTENCLR.reg = + (1 << ADC_INTENCLR_SYNCRDY_Pos) | (1 << ADC_INTENCLR_WINMON_Pos) | + (1 << ADC_INTENCLR_OVERRUN_Pos) | (1 << ADC_INTENCLR_RESRDY_Pos); + + /* Load the fixed device calibration constants*/ + adc->CALIB.reg = ADC_CALIB_BIAS_CAL((*(uint32_t*)ADC_FUSES_BIASCAL_ADDR >> ADC_FUSES_BIASCAL_Pos)) + | + ADC_CALIB_LINEARITY_CAL((*(uint64_t*)ADC_FUSES_LINEARITY_0_ADDR >> ADC_FUSES_LINEARITY_0_Pos)); + + return 1; +} + +/* Clear interrupt status flags */ +void adc_clear_status(Adc* adc, uint32_t status_flag) +{ + uint32_t interrupt_flags = 0; + + if(status_flag & ADC_0_STATUS_RESULT_READY) + interrupt_flags |= ADC_INTFLAG_RESRDY; + if(status_flag & ADC_0_STATUS_WINDOW) + interrupt_flags |= ADC_INTFLAG_WINMON; + if(status_flag & ADC_0_STATUS_OVERRUN) + interrupt_flags |= ADC_INTFLAG_OVERRUN; + /* Clear interrupt flag*/ + adc->INTFLAG.reg = interrupt_flags; +} + +/* Get ADC status */ +uint32_t adc_get_status(Adc* adc) +{ + uint32_t interrupt_flags = adc->INTFLAG.reg; + uint32_t status_flags = 0; + + if(interrupt_flags & ADC_INTFLAG_RESRDY) + status_flags |= ADC_0_STATUS_RESULT_READY; + if(interrupt_flags & ADC_INTFLAG_WINMON) + status_flags |= ADC_0_STATUS_WINDOW; + if(interrupt_flags & ADC_INTFLAG_OVERRUN) + status_flags |= ADC_0_STATUS_OVERRUN; + return status_flags; +} + +#endif /* ADC_NUMOF */ diff --git a/tests/moisture/Makefile b/tests/moisture/Makefile new file mode 100644 index 000000000000..38b786a8cd74 --- /dev/null +++ b/tests/moisture/Makefile @@ -0,0 +1,7 @@ +APPLICATION = moisture +include ../Makefile.tests_common + +FEATURES_REQUIRED = periph_adc periph_gpio +USEMODULE += xtimer + +include $(RIOTBASE)/Makefile.include diff --git a/tests/moisture/main.c b/tests/moisture/main.c new file mode 100644 index 000000000000..9a2a4d3588bf --- /dev/null +++ b/tests/moisture/main.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2015 HAW Hamburg + * + * 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 + * @{ + * + * @file + * @brief Test case for moisture sensor + * + * @author Peter Kietzmann + * + * @} + */ + +#include + +#include "cpu.h" +#include "board.h" +#include "xtimer.h" +#include "periph/adc.h" +#include "periph/gpio.h" + + +#if ADC_NUMOF < 1 +#error "Please enable at least 1 ADC device to run this test" +#endif + +#define ADC_NUM 0 +#define ADC_CH 0 +#define RES ADC_RES_12BIT +#define DELAY (100 * 1000U) + +#define GPIO_VCC_PORT 0 +#define GPIO_VCC_PIN 13 + +/* Compare http://www.watr.li/Sensing-moisture.html for setup */ + + +int main(void) +{ + int value; + + puts("\nRIOT ADC/moisture sensor test\n"); + + + /* initialize GPIO pin as power supply */ + gpio_init(GPIO_PIN(GPIO_VCC_PORT, GPIO_VCC_PIN), GPIO_DIR_OUT, 0); + + /* initialize ADC device */ + printf("Initializing ADC @ %i bit resolution", (6 + (2* RES))); + if (adc_init(ADC_NUM, RES) == 0) { + puts(" ...[ok]"); + } + else { + puts(" ...[failed]"); + return 1; + } + + puts("\n"); + + while (1) { + + gpio_set(GPIO_PIN(GPIO_VCC_PORT, GPIO_VCC_PIN)); + xtimer_usleep(1000); + value = adc_sample(ADC_NUM, ADC_CH); + gpio_clear(GPIO_PIN(GPIO_VCC_PORT, GPIO_VCC_PIN)); + + printf("ADC_%i-CH%i: %4i \n", ADC_NUM, ADC_CH, value); + /* sleep a little while */ + xtimer_usleep(DELAY); + } + + return 0; +}