Skip to content

ADC Multi-sampling #9315

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

Closed
wants to merge 31 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
96d9f7a
ADC now init externally and accepts samples keyword
bill88t Jun 6, 2024
6365dd7
Implement finalizers
bill88t Jun 9, 2024
23f6d48
Implement ADC sampling for rp2
bill88t Jun 9, 2024
d70f279
Do ADC sampling for SAMD and increase maximum sample size to uint16_t
bill88t Jun 10, 2024
c2253cb
Some forgotten uint8_t's -> uint16_t's
bill88t Jun 10, 2024
39d26d6
Do ADC sampling on cxd56
bill88t Jun 10, 2024
3bd040f
mimxrt10xx ADC sampling
bill88t Jun 10, 2024
1aed286
nordic ADC sampling
bill88t Jun 10, 2024
c7ec52f
Update check condition
bill88t Jun 12, 2024
5a074f3
Do silabs adc sampling
bill88t Jun 12, 2024
456af9f
Add stm adc sampling
bill88t Jun 12, 2024
d5da363
fix nordic
bill88t Jun 12, 2024
5136dae
uint everythin
bill88t Jun 12, 2024
e4cb4d1
more type fixes
bill88t Jun 12, 2024
94dfd55
Fix one more type
bill88t Jun 12, 2024
e1e7a70
types types types
bill88t Jun 12, 2024
8d32a53
... Types.
bill88t Jun 12, 2024
15ad471
getset sample_size
bill88t Jun 12, 2024
7bec349
Add input validation for setting sample_size
bill88t Jun 12, 2024
17f8f9e
Add the setters/getters to all
bill88t Jun 12, 2024
0bb84f3
Fix dupe "}"?
bill88t Jun 12, 2024
95f78dd
Merge remote-tracking branch 'adafruit/main' into adc_paranoia
bill88t Jun 20, 2024
17607fb
Improve espressif adc looping logic
bill88t Jun 20, 2024
dfa4e72
Improve documentation a bit
bill88t Jun 20, 2024
e3e2b0f
Improve the looping logic a lot more for espressif
bill88t Jun 20, 2024
ea8275f
Merge remote-tracking branch 'adafruit/main' into adc_paranoia
bill88t Jul 5, 2024
7498a61
Merge remote-tracking branch 'adafruit/main' into adc_paranoia
bill88t Aug 8, 2024
bae5bc5
Merge remote-tracking branch 'adafruit/main' into adc_paranoia
bill88t Aug 9, 2024
7e0a82d
Merge remote-tracking branch 'adafruit/main' into adc_paranoia
bill88t Aug 11, 2024
d2bdba6
Switch message to reduce flash space usage
bill88t Aug 11, 2024
ad44262
Merge remote-tracking branch 'adafruit/main' into adc_paranoia
bill88t Aug 13, 2024
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
2 changes: 1 addition & 1 deletion locale/circuitpython.pot
Original file line number Diff line number Diff line change
Expand Up @@ -4275,7 +4275,7 @@ msgstr ""
msgid "usecols keyword must be specified"
msgstr ""

#: py/objint.c
#: py/objint.c shared-bindings/analogio/AnalogIn.c
#, c-format
msgid "value must fit in %d byte(s)"
msgstr ""
Expand Down
23 changes: 20 additions & 3 deletions ports/atmel-samd/common-hal/analogio/AnalogIn.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
#endif

void common_hal_analogio_analogin_construct(analogio_analogin_obj_t *self,
const mcu_pin_obj_t *pin) {
const mcu_pin_obj_t *pin, uint16_t sample_size) {
uint8_t adc_index;
uint8_t adc_channel = 0xff;
for (adc_index = 0; adc_index < NUM_ADC_PER_PIN; adc_index++) {
Expand All @@ -50,6 +50,7 @@ void common_hal_analogio_analogin_construct(analogio_analogin_obj_t *self,
self->instance = adc_insts[adc_index];
self->channel = adc_channel;
self->pin = pin;
self->sample_size = sample_size;
}

bool common_hal_analogio_analogin_deinited(analogio_analogin_obj_t *self) {
Expand Down Expand Up @@ -99,13 +100,29 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) {

uint16_t value;
adc_sync_read_channel(&adc, self->channel, ((uint8_t *)&value), 2);
adc_sync_read_channel(&adc, self->channel, ((uint8_t *)&value), 2);

uint32_t avg_value = 0;
for (int i = 0; i < self->sample_size; i++) {
adc_sync_read_channel(&adc, self->channel, ((uint8_t *)&value), 2);
avg_value += value;
}

adc_sync_deinit(&adc);

avg_value /= self->sample_size;

// Stretch 12-bit ADC reading to 16-bit range
return (value << 4) | (value >> 8);
return (avg_value << 4) | (avg_value >> 8);
}

float common_hal_analogio_analogin_get_reference_voltage(analogio_analogin_obj_t *self) {
return 3.3f;
}

uint16_t common_hal_analogio_analogin_get_sample_size(analogio_analogin_obj_t *self) {
return self->sample_size;
}

void common_hal_analogio_analogin_set_sample_size(analogio_analogin_obj_t *self, uint16_t sample_size) {
self->sample_size = sample_size;
}
1 change: 1 addition & 0 deletions ports/atmel-samd/common-hal/analogio/AnalogIn.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ typedef struct {
const mcu_pin_obj_t *pin;
Adc *instance;
uint8_t channel;
uint8_t sample_size;
} analogio_analogin_obj_t;

void analogin_reset(void);
24 changes: 18 additions & 6 deletions ports/cxd56/common-hal/analogio/AnalogIn.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ static analogin_dev_t analogin_dev[] = {
{"/dev/hpadc1", &pin_HPADC1, -1},
};

void common_hal_analogio_analogin_construct(analogio_analogin_obj_t *self, const mcu_pin_obj_t *pin) {
void common_hal_analogio_analogin_construct(analogio_analogin_obj_t *self, const mcu_pin_obj_t *pin, uint16_t sample_size) {
if (!pin->analog) {
raise_ValueError_invalid_pin();
}
Expand Down Expand Up @@ -66,6 +66,7 @@ void common_hal_analogio_analogin_construct(analogio_analogin_obj_t *self, const
ioctl(analogin_dev[self->number].fd, ANIOC_CXD56_START, 0);

self->pin = pin;
self->sample_size = sample_size;
}

void common_hal_analogio_analogin_deinit(analogio_analogin_obj_t *self) {
Expand All @@ -86,11 +87,14 @@ bool common_hal_analogio_analogin_deinited(analogio_analogin_obj_t *self) {
}

uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) {
int16_t value = 0;

read(analogin_dev[self->number].fd, &value, sizeof(value));

return (uint16_t)32768 + (uint16_t)value;
uint32_t avg_value = 0;
for (uint16_t i = 0; i < self->sample_size; i++) {
int16_t value = 0;
read(analogin_dev[self->number].fd, &value, sizeof(value));
avg_value += (uint16_t)32768 + (uint16_t)value;
}
avg_value /= self->sample_size;
return avg_value;
}

// Reference voltage is a fixed value which is depending on the board.
Expand Down Expand Up @@ -119,3 +123,11 @@ void analogin_reset(void) {
}
}
}

uint16_t common_hal_analogio_analogin_get_sample_size(analogio_analogin_obj_t *self) {
return self->sample_size;
}

void common_hal_analogio_analogin_set_sample_size(analogio_analogin_obj_t *self, uint16_t sample_size) {
self->sample_size = sample_size;
}
1 change: 1 addition & 0 deletions ports/cxd56/common-hal/analogio/AnalogIn.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ typedef struct {
mp_obj_base_t base;
const mcu_pin_obj_t *pin;
int8_t number;
uint16_t sample_size;
} analogio_analogin_obj_t;

void analogin_reset(void);
129 changes: 67 additions & 62 deletions ports/espressif/common-hal/analogio/AnalogIn.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#include <string.h>

#define DEFAULT_VREF 1100
#define NO_OF_SAMPLES 2
#define ATTENUATION ADC_ATTEN_DB_11
#if defined(CONFIG_IDF_TARGET_ESP32)
#define DATA_WIDTH ADC_BITWIDTH_12
Expand All @@ -43,7 +42,7 @@
#endif

void common_hal_analogio_analogin_construct(analogio_analogin_obj_t *self,
const mcu_pin_obj_t *pin) {
const mcu_pin_obj_t *pin, uint16_t sample_size) {
if (pin->adc_index == NO_ADC || pin->adc_channel == NO_ADC_CHANNEL) {
raise_ValueError_invalid_pin();
}
Expand All @@ -53,104 +52,110 @@ void common_hal_analogio_analogin_construct(analogio_analogin_obj_t *self,
// Turn off the pull-up as soon as we know the pin will be used for analog reads,
// since it may take a while for the voltage to stabilize if the input is high-impedance.
gpio_pullup_dis(pin->number);
}

bool common_hal_analogio_analogin_deinited(analogio_analogin_obj_t *self) {
return self->pin == NULL;
}

void common_hal_analogio_analogin_deinit(analogio_analogin_obj_t *self) {
if (common_hal_analogio_analogin_deinited(self)) {
return;
}
reset_pin_number(self->pin->number);
self->pin = NULL;
}

uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) {
adc_oneshot_unit_handle_t adc_handle;
self->sample_size = sample_size;
adc_oneshot_unit_init_cfg_t adc_config = {
.unit_id = self->pin->adc_index,
.ulp_mode = ADC_ULP_MODE_DISABLE
};
CHECK_ESP_RESULT(adc_oneshot_new_unit(&adc_config, &adc_handle));
CHECK_ESP_RESULT(adc_oneshot_new_unit(&adc_config, &(self->adc_handle)));

adc_oneshot_chan_cfg_t channel_config = {
.atten = ATTENUATION,
.bitwidth = DATA_WIDTH
};
adc_channel_t channel = (adc_channel_t)self->pin->adc_channel;
adc_oneshot_config_channel(adc_handle, channel, &channel_config);
self->channel = (adc_channel_t)self->pin->adc_channel;
adc_oneshot_config_channel(self->adc_handle, self->channel, &channel_config);

adc_cali_scheme_ver_t supported_schemes;
adc_cali_check_scheme(&supported_schemes);
adc_cali_scheme_ver_t calibration_scheme = 0;
adc_cali_handle_t calibration;
self->calibration_scheme = 0;

#if defined(ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED) && ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
adc_cali_curve_fitting_config_t config = {
.unit_id = self->pin->adc_index,
.chan = channel,
.atten = ATTENUATION,
.bitwidth = DATA_WIDTH
};
if (adc_cali_create_scheme_curve_fitting(&config, &calibration) == ESP_OK) {
calibration_scheme = ADC_CALI_SCHEME_VER_CURVE_FITTING;
self->config.unit_id = self->pin->adc_index;
self->config.chan = self->channel;
self->config.atten = ATTENUATION;
self->config.bitwidth = DATA_WIDTH;
if (adc_cali_create_scheme_curve_fitting(&(self->config), &(self->calibration)) == ESP_OK) {
self->calibration_scheme = ADC_CALI_SCHEME_VER_CURVE_FITTING;
}
#endif
#if defined(ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED) && ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
if (calibration_scheme == 0) {
adc_cali_line_fitting_config_t config = {
.unit_id = self->pin->adc_index,
.atten = ATTENUATION,
.bitwidth = DATA_WIDTH,
#ifdef CONFIG_IDF_TARGET_ESP32
.default_vref = DEFAULT_VREF,
#endif
};
if (adc_cali_create_scheme_line_fitting(&config, &calibration) == ESP_OK) {
calibration_scheme = ADC_CALI_SCHEME_VER_LINE_FITTING;
}
if (self->calibration_scheme == 0) {
self->config.unit_id = self->pin->adc_index;
self->config.atten = ATTENUATION;
self->config.bitwidth = DATA_WIDTH;
#ifdef CONFIG_IDF_TARGET_ESP32
self->config.default_vref = DEFAULT_VREF;
#endif
}
;
if (adc_cali_create_scheme_line_fitting(&(self->config), &(self->calibration)) == ESP_OK) {
self->calibration_scheme = ADC_CALI_SCHEME_VER_LINE_FITTING;
}
#endif
}

bool common_hal_analogio_analogin_deinited(analogio_analogin_obj_t *self) {
return self->pin == NULL;
}

void common_hal_analogio_analogin_deinit(analogio_analogin_obj_t *self) {
if (common_hal_analogio_analogin_deinited(self)) {
return;
}
#if defined(ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED) && ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
if (self->calibration_scheme == ADC_CALI_SCHEME_VER_CURVE_FITTING) {
adc_cali_delete_scheme_curve_fitting(self->calibration);
}
#endif
#if defined(ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED) && ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
if (self->calibration_scheme == ADC_CALI_SCHEME_VER_LINE_FITTING) {
adc_cali_delete_scheme_line_fitting(self->calibration);
}
#endif
adc_oneshot_del_unit(self->adc_handle);
reset_pin_number(self->pin->number);
self->pin = NULL;
}

uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) {
uint32_t adc_reading = 0;
size_t sample_count = 0;
uint16_t sample_count = 0;
uint8_t retries_left = 20;
// Multisampling
esp_err_t ret = ESP_OK;
for (int i = 0; i < NO_OF_SAMPLES; i++) {
while ((sample_count < self->sample_size) && retries_left) {
int raw;
ret = adc_oneshot_read(adc_handle, channel, &raw);
ret = adc_oneshot_read(self->adc_handle, self->channel, &raw);
if (ret != ESP_OK) {
continue;
retries_left--;
} else {
adc_reading += raw;
sample_count += 1;
}
adc_reading += raw;
sample_count += 1;
}
if (sample_count == 0) {
if (sample_count < self->sample_size) {
// 20 read failures, returns the final error
raise_esp_error(ret);
}
adc_reading /= sample_count;

// This corrects non-linear regions of the ADC range with a LUT, so it's a better reading than raw
int voltage;
adc_cali_raw_to_voltage(calibration, adc_reading, &voltage);

adc_cali_raw_to_voltage(self->calibration, adc_reading, &voltage);

#if defined(ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED) && ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
if (calibration_scheme == ADC_CALI_SCHEME_VER_CURVE_FITTING) {
adc_cali_delete_scheme_curve_fitting(calibration);
}
#endif
#if defined(ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED) && ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
if (calibration_scheme == ADC_CALI_SCHEME_VER_LINE_FITTING) {
adc_cali_delete_scheme_line_fitting(calibration);
}
#endif
adc_oneshot_del_unit(adc_handle);
return voltage * ((1 << 16) - 1) / 3300;
}

float common_hal_analogio_analogin_get_reference_voltage(analogio_analogin_obj_t *self) {
return 3.3f;
}

uint16_t common_hal_analogio_analogin_get_sample_size(analogio_analogin_obj_t *self) {
return self->sample_size;
}

void common_hal_analogio_analogin_set_sample_size(analogio_analogin_obj_t *self, uint16_t sample_size) {
self->sample_size = sample_size;
}
18 changes: 18 additions & 0 deletions ports/espressif/common-hal/analogio/AnalogIn.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,26 @@
#include "FreeRTOS.h"
#include "freertos/semphr.h"
#include "py/obj.h"
#include "adc_cali_schemes.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_adc/adc_cali.h"
#include "driver/gpio.h"
#include "hal/adc_types.h"


typedef struct {
mp_obj_base_t base;
const mcu_pin_obj_t *pin;
uint16_t sample_size;
adc_oneshot_unit_handle_t adc_handle;
adc_channel_t channel;
#if defined(ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED) && ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
adc_cali_curve_fitting_config_t config;
#endif
#if defined(ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED) && ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED
adc_cali_line_fitting_config_t config;
#endif
adc_cali_scheme_ver_t calibration_scheme;
adc_cali_handle_t calibration;

} analogio_analogin_obj_t;
17 changes: 15 additions & 2 deletions ports/mimxrt10xx/common-hal/analogio/AnalogIn.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#define ADC_CHANNEL_GROUP 0

void common_hal_analogio_analogin_construct(analogio_analogin_obj_t *self,
const mcu_pin_obj_t *pin) {
const mcu_pin_obj_t *pin, uint16_t sample_size) {
adc_config_t config = {0};

if (pin->adc == NULL) {
Expand All @@ -37,6 +37,7 @@ void common_hal_analogio_analogin_construct(analogio_analogin_obj_t *self,
claim_pin(pin);

self->pin = pin;
self->sample_size = sample_size;
}

bool common_hal_analogio_analogin_deinited(analogio_analogin_obj_t *self) {
Expand All @@ -61,7 +62,11 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) {

}

uint16_t value = ADC_GetChannelConversionValue(self->pin->adc, ADC_CHANNEL_GROUP);
uint32_t value = 0;
for (uint16_t i = 0; i < self->sample_size; i++) {
value += ADC_GetChannelConversionValue(self->pin->adc, ADC_CHANNEL_GROUP);
}
value /= self->sample_size;

// Stretch 12-bit ADC reading to 16-bit range
return (value << 4) | (value >> 8);
Expand All @@ -70,3 +75,11 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) {
float common_hal_analogio_analogin_get_reference_voltage(analogio_analogin_obj_t *self) {
return 3.3f;
}

uint16_t common_hal_analogio_analogin_get_sample_size(analogio_analogin_obj_t *self) {
return self->sample_size;
}

void common_hal_analogio_analogin_set_sample_size(analogio_analogin_obj_t *self, uint16_t sample_size) {
self->sample_size = sample_size;
}
1 change: 1 addition & 0 deletions ports/mimxrt10xx/common-hal/analogio/AnalogIn.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@
typedef struct {
mp_obj_base_t base;
const mcu_pin_obj_t *pin;
uint16_t sample_size;
} analogio_analogin_obj_t;
Loading
Loading