Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cpu/sam0_common: adc: implement 16 bit mode by oversampling #19165

Merged
merged 1 commit into from
Feb 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions cpu/sam0_common/include/periph_cpu_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
dylad marked this conversation as resolved.
Show resolved Hide resolved
} adc_res_t;

#define ADC_RES_16BIT ADC_RES_16BIT_16SAMPL /**< default to 16x oversampling */
#endif /* DOXYGEN */

/**
Expand Down
30 changes: 21 additions & 9 deletions cpu/sam0_common/periph/adc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}

Expand All @@ -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 */
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down