From 470bee59a7508565ecc87e6011a39e15ce8363f7 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Wed, 18 Jan 2023 01:41:41 +0100 Subject: [PATCH] cpu/sam0_common: implement 16 bit mode by oversampling --- cpu/sam0_common/include/periph_cpu_common.h | 15 +++++++++-- cpu/sam0_common/periph/adc.c | 30 ++++++++++++++------- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/cpu/sam0_common/include/periph_cpu_common.h b/cpu/sam0_common/include/periph_cpu_common.h index 9e992b18438b..758f80497f51 100644 --- a/cpu/sam0_common/include/periph_cpu_common.h +++ b/cpu/sam0_common/include/periph_cpu_common.h @@ -821,9 +821,20 @@ typedef enum { ADC_RES_10BIT = ADC_CTRLC_RESSEL_10BIT_Val, /**< ADC resolution: 10 bit */ ADC_RES_12BIT = ADC_CTRLC_RESSEL_12BIT_Val, /**< ADC resolution: 12 bit */ #endif - ADC_RES_14BIT = 0xfe, /**< not supported */ - ADC_RES_16BIT = 0xfd /**< not supported */ + ADC_RES_16BIT_2SAMPL = ( 0x1 << 2) | 0x1, /**< sum of 2 12 bit samples */ + ADC_RES_16BIT_4SAMPL = ( 0x2 << 2) | 0x1, /**< sum of 4 12 bit samples */ + ADC_RES_16BIT_8SAMPL = ( 0x3 << 2) | 0x1, /**< sum of 8 12 bit samples */ + ADC_RES_16BIT_16SAMPL = ( 0x4 << 2) | 0x1, /**< sum of 16 12 bit samples */ + ADC_RES_16BIT_32SAMPL = ( 0x5 << 2) | 0x1, /**< sum of 32 12 bit samples */ + ADC_RES_16BIT_64SAMPL = ( 0x6 << 2) | 0x1, /**< sum of 64 12 bit samples */ + ADC_RES_16BIT_128SAMPL = ( 0x7 << 2) | 0x1, /**< sum of 128 12 bit samples */ + ADC_RES_16BIT_256SAMPL = ( 0x8 << 2) | 0x1, /**< sum of 256 12 bit samples */ + ADC_RES_16BIT_512SAMPL = ( 0x9 << 2) | 0x1, /**< sum of 512 12 bit samples */ + ADC_RES_16BIT_1024SAMPL = ( 0xA << 2) | 0x1, /**< sum of 1024 12 bit samples */ + ADC_RES_14BIT = 0xfe, /**< not supported */ } adc_res_t; + +#define ADC_RES_16BIT ADC_RES_16BIT_16SAMPL /**< default to 16x oversampling */ #endif /* DOXYGEN */ /** diff --git a/cpu/sam0_common/periph/adc.c b/cpu/sam0_common/periph/adc.c index 3c906842b03c..59c236a7e811 100644 --- a/cpu/sam0_common/periph/adc.c +++ b/cpu/sam0_common/periph/adc.c @@ -23,6 +23,7 @@ #include "periph/gpio.h" #include "periph/adc.h" #include "periph_conf.h" +#include "macros/utils.h" #include "mutex.h" #define ENABLE_DEBUG 0 @@ -181,11 +182,7 @@ static void _setup_calibration(Adc *dev) static int _adc_configure(Adc *dev, adc_res_t res) { - /* Individual comparison necessary because ADC Resolution Bits are not - * numerically in order and 16Bit (averaging - not currently supported) - * falls between 12bit and 10bit. See datasheet for details */ - if (!((res == ADC_RES_8BIT) || (res == ADC_RES_10BIT) || - (res == ADC_RES_12BIT))){ + if ((res == ADC_RES_6BIT) || (res == ADC_RES_14BIT)) { return -1; } @@ -203,10 +200,10 @@ static int _adc_configure(Adc *dev, adc_res_t res) /* Set ADC resolution */ #ifdef ADC_CTRLC_RESSEL /* Reset resolution bits in CTRLC */ - dev->CTRLC.bit.RESSEL = res; + dev->CTRLC.bit.RESSEL = res & 0x3; #else /* Reset resolution bits in CTRLB */ - dev->CTRLB.bit.RESSEL = res; + dev->CTRLB.bit.RESSEL = res & 0x3; #endif /* Set Voltage Reference */ @@ -241,6 +238,12 @@ static int _adc_configure(Adc *dev, adc_res_t res) } #endif + if ((res & 0x3) == 1) { + dev->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM(res >> 2); + } else { + dev->AVGCTRL.reg = 0; + } + /* Enable ADC Module */ dev->CTRLA.reg |= ADC_CTRLA_ENABLE; _wait_syncbusy(dev); @@ -325,14 +328,23 @@ int32_t adc_sample(adc_t line, adc_res_t res) /* Wait for the result */ while (!(dev->INTFLAG.reg & ADC_INTFLAG_RESRDY)) {} - int16_t result = dev->RESULT.reg; + uint16_t sample = dev->RESULT.reg; + int result; _adc_poweroff(dev); _done(); /* in differential mode we lose one bit for the sign */ if (diffmode) { - result *= 2; + result = 2 * (int16_t)sample; + } else { + result = sample; + } + + /* 16 bit mode is implemented as oversampling */ + if ((res & 0x3) == 1) { + /* ADC does automatic right shifts beyond 16 samples */ + result <<= (4 - MIN(4, res >> 2)); } return result;