From ab81e338f1d3a6c8103839c5fdfc284e62d1e7f0 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 | 8 +++++++- cpu/sam0_common/periph/adc.c | 21 ++++++++++++++------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/cpu/sam0_common/include/periph_cpu_common.h b/cpu/sam0_common/include/periph_cpu_common.h index 9e992b18438be..7e08b7bf756a1 100644 --- a/cpu/sam0_common/include/periph_cpu_common.h +++ b/cpu/sam0_common/include/periph_cpu_common.h @@ -821,11 +821,17 @@ 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_16BIT_2SAMPL = ( 1 << 2) | 0x1, /**< sum of 2 12 bit samples */ + ADC_RES_16BIT_4SAMPL = ( 2 << 2) | 0x1, /**< sum of 4 12 bit samples */ + ADC_RES_16BIT_8SAMPL = ( 3 << 2) | 0x1, /**< sum of 8 12 bit samples */ + ADC_RES_16BIT_16SAMPL = ( 4 << 2) | 0x1, /**< sum of 16 12 bit samples */ ADC_RES_14BIT = 0xfe, /**< not supported */ - ADC_RES_16BIT = 0xfd /**< not supported */ } adc_res_t; + +#define ADC_RES_16BIT ADC_RES_16BIT_16SAMPL /**< default to 16x oversampling */ #endif /* DOXYGEN */ + /** * @name Ethernet peripheral parameters * @{ diff --git a/cpu/sam0_common/periph/adc.c b/cpu/sam0_common/periph/adc.c index 3c906842b03c5..75c9d9da45e61 100644 --- a/cpu/sam0_common/periph/adc.c +++ b/cpu/sam0_common/periph/adc.c @@ -181,11 +181,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 +199,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 +237,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); @@ -335,5 +337,10 @@ int32_t adc_sample(adc_t line, adc_res_t res) result *= 2; } + /* 16 bit mode is implemented as oversampling */ + if ((res & 0x3) == 1) { + result <<= (4 - (res >> 2)); + } + return result; }