Skip to content

Commit 5f058e9

Browse files
purewackdpgeorge
authored andcommitted
esp32: Update ADC driver update to the new esp_adc API.
This commit updates the ADC to use the new driver `esp_adc/adc_oneshot.h`. There are several errata notes about not being able to change the bit-width of the ADCs certain chips. The only chip that can switch resolution to a lower one is the normal ESP32. ESP32 C2 and S3 are stuck at 12 bits, while S2 is at 13 bits. On the S2, you can change the resolution, but it has no effect on the resolution, rather, it prevents attenuation from working at all! The resolution is set to the maximum possible for each SoC, with the ESP32 being the only one not throwing errors when trying to set the bit-width to 9, 10, 11 or 12 bits using `ADC.width(bits)`. Signed-off-by: Damian Nowacki (purewack) [email protected]
1 parent 2c2f0b2 commit 5f058e9

File tree

8 files changed

+155
-113
lines changed

8 files changed

+155
-113
lines changed

docs/esp32/quickref.rst

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,14 +544,27 @@ Legacy methods:
544544

545545
Equivalent to ``ADC.block().init(bits=bits)``.
546546

547+
The only chip that can switch resolution to a lower one is the normal esp32.
548+
The C2 & S3 are stuck at 12 bits, while the S2 is at 13 bits.
549+
547550
For compatibility, the ``ADC`` object also provides constants matching the
548-
supported ADC resolutions:
551+
supported ADC resolutions, per chip:
549552

553+
ESP32:
550554
- ``ADC.WIDTH_9BIT`` = 9
551555
- ``ADC.WIDTH_10BIT`` = 10
552556
- ``ADC.WIDTH_11BIT`` = 11
553557
- ``ADC.WIDTH_12BIT`` = 12
554558

559+
ESP32 C3 & S3:
560+
- ``ADC.WIDTH_12BIT`` = 12
561+
562+
ESP32 S2:
563+
- ``ADC.WIDTH_13BIT`` = 13
564+
565+
.. method:: ADC.deinit()
566+
567+
Provided to deinit the adc driver.
555568

556569
Software SPI bus
557570
----------------

ports/esp32/adc.c

Lines changed: 42 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -26,83 +26,73 @@
2626
*/
2727

2828
#include "py/mphal.h"
29+
#include "py/mperrno.h"
2930
#include "adc.h"
30-
#include "driver/adc.h"
31+
#include "esp_adc/adc_oneshot.h"
3132
#include "esp_adc/adc_cali_scheme.h"
3233

33-
#define DEFAULT_VREF 1100
34+
static esp_err_t ensure_adc_calibration(machine_adc_block_obj_t *self, adc_atten_t atten);
3435

35-
void madcblock_bits_helper(machine_adc_block_obj_t *self, mp_int_t bits) {
36-
if (bits < SOC_ADC_RTC_MIN_BITWIDTH && bits > SOC_ADC_RTC_MAX_BITWIDTH) {
37-
// Invalid value for the current chip, raise exception in the switch below.
38-
bits = -1;
36+
void adc_is_init_guard(machine_adc_block_obj_t *self) {
37+
if (!self->handle) {
38+
mp_raise_OSError(MP_EPERM);
3939
}
40-
switch (bits) {
41-
case 9:
42-
self->width = ADC_BITWIDTH_9;
43-
break;
44-
case 10:
45-
self->width = ADC_BITWIDTH_10;
46-
break;
47-
case 11:
48-
self->width = ADC_BITWIDTH_11;
49-
break;
50-
case 12:
51-
self->width = ADC_BITWIDTH_12;
52-
break;
53-
case 13:
54-
self->width = ADC_BITWIDTH_13;
55-
break;
56-
default:
57-
mp_raise_ValueError(MP_ERROR_TEXT("invalid bits"));
58-
}
59-
self->bits = bits;
40+
}
6041

61-
if (self->unit_id == ADC_UNIT_1) {
62-
adc1_config_width(self->width);
63-
}
42+
esp_err_t apply_self_adc_channel_atten(const machine_adc_obj_t *self, uint8_t atten) {
43+
adc_is_init_guard(self->block);
44+
45+
adc_oneshot_chan_cfg_t config = {
46+
.atten = atten,
47+
.bitwidth = self->block->bitwidth,
48+
};
49+
esp_err_t ret = adc_oneshot_config_channel(self->block->handle, self->channel_id, &config);
50+
return ret;
6451
}
6552

6653
mp_int_t madcblock_read_helper(machine_adc_block_obj_t *self, adc_channel_t channel_id) {
67-
int raw = 0;
68-
if (self->unit_id == ADC_UNIT_1) {
69-
raw = adc1_get_raw(channel_id);
70-
} else {
71-
#if (SOC_ADC_PERIPH_NUM >= 2)
72-
check_esp_err(adc2_get_raw(channel_id, self->width, &raw));
73-
#endif
74-
}
75-
return raw;
54+
adc_is_init_guard(self);
55+
56+
int reading = 0;
57+
adc_oneshot_read(self->handle, channel_id, &reading);
58+
return reading;
59+
}
60+
61+
/*
62+
During testing, it turned out that the function `adc_cali_raw_to_voltage` does not account for the lower resolution,
63+
instead it expects the full resolution value as an argument, hence the scaling applied here
64+
*/
65+
mp_int_t madcblock_read_uv_helper(machine_adc_block_obj_t *self, adc_channel_t channel_id, adc_atten_t atten) {
66+
int raw = madcblock_read_helper(self, channel_id);
67+
int uv = 0;
68+
69+
check_esp_err(ensure_adc_calibration(self, atten));
70+
check_esp_err(adc_cali_raw_to_voltage(self->calib[atten], (raw << (ADC_WIDTH_MAX - self->bitwidth)), &uv));
71+
return (mp_int_t)uv * 1000;
7672
}
7773

7874
static esp_err_t ensure_adc_calibration(machine_adc_block_obj_t *self, adc_atten_t atten) {
79-
if (self->handle[atten] != NULL) {
75+
if (self->calib[atten] != NULL) {
8076
return ESP_OK;
8177
}
8278

79+
esp_err_t ret = ESP_OK;
80+
8381
#if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED
8482
adc_cali_curve_fitting_config_t cali_config = {
8583
.unit_id = self->unit_id,
8684
.atten = atten,
87-
.bitwidth = self->width,
85+
.bitwidth = self->bitwidth,
8886
};
89-
return adc_cali_create_scheme_curve_fitting(&cali_config, &self->handle[atten]);
87+
ret = adc_cali_create_scheme_curve_fitting(&cali_config, &self->calib[atten]);
9088
#else
9189
adc_cali_line_fitting_config_t cali_config = {
9290
.unit_id = self->unit_id,
9391
.atten = atten,
94-
.bitwidth = self->width,
92+
.bitwidth = self->bitwidth,
9593
};
96-
return adc_cali_create_scheme_line_fitting(&cali_config, &self->handle[atten]);
94+
ret = adc_cali_create_scheme_line_fitting(&cali_config, &self->calib[atten]);
9795
#endif
98-
}
9996

100-
mp_int_t madcblock_read_uv_helper(machine_adc_block_obj_t *self, adc_channel_t channel_id, adc_atten_t atten) {
101-
int raw = madcblock_read_helper(self, channel_id);
102-
int uv;
103-
104-
check_esp_err(ensure_adc_calibration(self, atten));
105-
check_esp_err(adc_cali_raw_to_voltage(self->handle[atten], raw, &uv));
106-
107-
return (mp_int_t)uv * 1000;
97+
return ret;
10898
}

ports/esp32/adc.h

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,45 @@
2929
#define MICROPY_INCLUDED_ESP32_ADC_H
3030

3131
#include "py/runtime.h"
32-
#include "esp_adc_cal.h"
32+
#include "esp_adc/adc_oneshot.h"
3333
#include "esp_adc/adc_cali_scheme.h"
3434

35-
#define ADC_ATTEN_MAX SOC_ADC_ATTEN_NUM
35+
#define ADC_ATTEN_COUNT SOC_ADC_ATTEN_NUM
36+
#define ADC_ATTEN_MIN ADC_ATTEN_DB_0
37+
#define ADC_ATTEN_MAX ADC_ATTEN_DB_11
38+
39+
/*
40+
https://github.com/espressif/esp-idf/issues/13128
41+
https://github.com/espressif/esp-idf/blob/release/v5.2/components/soc/esp32s3/include/soc/soc_caps.h
42+
https://docs.espressif.com/projects/esp-chip-errata/en/latest/esp32s2/03-errata-description/index.html
43+
https://docs.espressif.com/projects/esp-idf/en/v4.2/esp32/api-reference/peripherals/adc.html
44+
45+
Looks like only the original esp32 is capable of bitwidth adjustment, all others are stuck at 12 bits,
46+
except the S2, which is locked at 13 bits, otherwise attenuation doesn't work.
47+
*/
48+
#if CONFIG_IDF_TARGET_ESP32S2
49+
50+
#define ADC_WIDTH_MIN ADC_BITWIDTH_13
51+
#define ADC_WIDTH_MAX ADC_BITWIDTH_13
52+
53+
#elif CONFIG_IDF_TARGET_ESP32
54+
55+
#define ADC_WIDTH_MIN ADC_BITWIDTH_9
56+
#define ADC_WIDTH_MAX ADC_BITWIDTH_12
57+
58+
#else
59+
60+
#define ADC_WIDTH_MIN ADC_BITWIDTH_12
61+
#define ADC_WIDTH_MAX ADC_BITWIDTH_12
62+
63+
#endif
3664

3765
typedef struct _machine_adc_block_obj_t {
3866
mp_obj_base_t base;
3967
adc_unit_t unit_id;
40-
mp_int_t bits;
41-
adc_bits_width_t width;
42-
adc_cali_handle_t handle[ADC_ATTEN_MAX];
68+
adc_oneshot_unit_handle_t handle;
69+
adc_bitwidth_t bitwidth;
70+
adc_cali_handle_t calib[ADC_ATTEN_COUNT];
4371
} machine_adc_block_obj_t;
4472

4573
typedef struct _machine_adc_obj_t {
@@ -51,11 +79,18 @@ typedef struct _machine_adc_obj_t {
5179

5280
extern machine_adc_block_obj_t madcblock_obj[];
5381

54-
void madcblock_bits_helper(machine_adc_block_obj_t *self, mp_int_t bits);
82+
esp_err_t apply_self_adc_channel_atten(const machine_adc_obj_t *self, uint8_t atten);
83+
5584
mp_int_t madcblock_read_helper(machine_adc_block_obj_t *self, adc_channel_t channel_id);
5685
mp_int_t madcblock_read_uv_helper(machine_adc_block_obj_t *self, adc_channel_t channel_id, adc_atten_t atten);
5786

5887
const machine_adc_obj_t *madc_search_helper(machine_adc_block_obj_t *block, adc_channel_t channel_id, gpio_num_t gpio_id);
5988
void madc_init_helper(const machine_adc_obj_t *self, size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
6089

90+
mp_int_t mp_machine_adc_atten_get_helper(const machine_adc_obj_t *self);
91+
void mp_machine_adc_atten_set_helper(const machine_adc_obj_t *self, mp_int_t atten);
92+
93+
mp_int_t mp_machine_adc_width_get_helper(const machine_adc_obj_t *self);
94+
void mp_machine_adc_block_width_set_helper(machine_adc_block_obj_t *self, mp_int_t width);
95+
6196
#endif // MICROPY_INCLUDED_ESP32_ADC_H

ports/esp32/boards/sdkconfig.base

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,6 @@ CONFIG_ADC_CAL_LUT_ENABLE=y
117117
CONFIG_UART_ISR_IN_IRAM=y
118118

119119
# IDF 5 deprecated
120-
CONFIG_ADC_SUPPRESS_DEPRECATE_WARN=y
121120
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
122121

123122
CONFIG_ETH_USE_SPI_ETHERNET=y

ports/esp32/machine_adc.c

Lines changed: 52 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
#include "py/mphal.h"
3232
#include "adc.h"
33-
#include "driver/adc.h"
33+
#include "esp_adc/adc_oneshot.h"
3434

3535
#define ADCBLOCK1 (&madcblock_obj[0])
3636
#define ADCBLOCK2 (&madcblock_obj[1])
@@ -126,20 +126,8 @@ static const machine_adc_obj_t madc_obj[] = {
126126
#endif
127127
};
128128

129-
// These values are initialised to 0, which means the corresponding ADC channel is not initialised.
130-
// The madc_atten_get/madc_atten_set functions store (atten+1) here so that the uninitialised state
131-
// can be distinguished from the initialised state.
132129
static uint8_t madc_obj_atten[MP_ARRAY_SIZE(madc_obj)];
133130

134-
static inline adc_atten_t madc_atten_get(const machine_adc_obj_t *self) {
135-
uint8_t value = madc_obj_atten[self - &madc_obj[0]];
136-
return value == 0 ? ADC_ATTEN_MAX : value - 1;
137-
}
138-
139-
static inline void madc_atten_set(const machine_adc_obj_t *self, adc_atten_t atten) {
140-
madc_obj_atten[self - &madc_obj[0]] = atten + 1;
141-
}
142-
143131
const machine_adc_obj_t *madc_search_helper(machine_adc_block_obj_t *block, adc_channel_t channel_id, gpio_num_t gpio_id) {
144132
for (int i = 0; i < MP_ARRAY_SIZE(madc_obj); i++) {
145133
const machine_adc_obj_t *adc = &madc_obj[i];
@@ -152,22 +140,7 @@ const machine_adc_obj_t *madc_search_helper(machine_adc_block_obj_t *block, adc_
152140

153141
static void mp_machine_adc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
154142
const machine_adc_obj_t *self = MP_OBJ_TO_PTR(self_in);
155-
mp_printf(print, "ADC(Pin(%u), atten=%u)", self->gpio_id, madc_atten_get(self));
156-
}
157-
158-
static void madc_atten_helper(const machine_adc_obj_t *self, mp_int_t atten) {
159-
esp_err_t err = ESP_FAIL;
160-
if (self->block->unit_id == ADC_UNIT_1) {
161-
err = adc1_config_channel_atten(self->channel_id, atten);
162-
} else {
163-
#if SOC_ADC_PERIPH_NUM >= 2
164-
err = adc2_config_channel_atten(self->channel_id, atten);
165-
#endif
166-
}
167-
if (err != ESP_OK) {
168-
mp_raise_ValueError(MP_ERROR_TEXT("invalid atten"));
169-
}
170-
madc_atten_set(self, atten);
143+
mp_printf(print, "ADC(Pin(%u), atten=%u)", self->gpio_id, mp_machine_adc_atten_get_helper(self));
171144
}
172145

173146
void madc_init_helper(const machine_adc_obj_t *self, size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
@@ -182,18 +155,32 @@ void madc_init_helper(const machine_adc_obj_t *self, size_t n_pos_args, const mp
182155
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
183156
mp_arg_parse_all(n_pos_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
184157

185-
mp_int_t atten = args[ARG_atten].u_int;
186-
if (atten != -1) {
187-
madc_atten_helper(self, atten);
188-
} else if (madc_atten_get(self) == ADC_ATTEN_MAX) {
189-
madc_atten_helper(self, ADC_ATTEN_DB_0);
158+
159+
if (!self->block->handle) {
160+
adc_oneshot_unit_init_cfg_t init_config = {
161+
.unit_id = self->block->unit_id
162+
};
163+
check_esp_err(adc_oneshot_new_unit(&init_config, &self->block->handle));
190164
}
165+
166+
mp_int_t atten = args[ARG_atten].u_int;
167+
mp_machine_adc_atten_set_helper(self, atten != -1 ? atten : ADC_ATTEN_MAX);
168+
mp_machine_adc_block_width_set_helper(self->block, ADC_WIDTH_MAX);
169+
apply_self_adc_channel_atten(self, mp_machine_adc_atten_get_helper(self));
170+
191171
}
192172

193173
static void mp_machine_adc_init_helper(machine_adc_obj_t *self, size_t n_pos_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
194174
madc_init_helper(self, n_pos_args, pos_args, kw_args);
195175
}
196176

177+
static void mp_machine_adc_deinit(machine_adc_obj_t *self) {
178+
if (self->block->handle) {
179+
check_esp_err(adc_oneshot_del_unit(self->block->handle));
180+
self->block->handle = NULL;
181+
}
182+
}
183+
197184
static mp_obj_t mp_machine_adc_make_new(const mp_obj_type_t *type, size_t n_pos_args, size_t n_kw_args, const mp_obj_t *args) {
198185
mp_arg_check_num(n_pos_args, n_kw_args, 1, MP_OBJ_FUN_ARGS_MAX, true);
199186
gpio_num_t gpio_id = machine_pin_get_id(args[0]);
@@ -202,10 +189,6 @@ static mp_obj_t mp_machine_adc_make_new(const mp_obj_type_t *type, size_t n_pos_
202189
mp_raise_ValueError(MP_ERROR_TEXT("invalid pin"));
203190
}
204191

205-
if (self->block->width == -1) {
206-
madcblock_bits_helper(self->block, self->block->bits);
207-
}
208-
209192
mp_map_t kw_args;
210193
mp_map_init_fixed_table(&kw_args, n_kw_args, args + n_pos_args);
211194
madc_init_helper(self, n_pos_args - 1, args + 1, &kw_args);
@@ -225,20 +208,46 @@ static mp_int_t mp_machine_adc_read(machine_adc_obj_t *self) {
225208
static mp_int_t mp_machine_adc_read_u16(machine_adc_obj_t *self) {
226209
mp_uint_t raw = madcblock_read_helper(self->block, self->channel_id);
227210
// Scale raw reading to 16 bit value using a Taylor expansion (for 8 <= bits <= 16)
228-
mp_int_t bits = self->block->bits;
211+
mp_int_t bits = mp_machine_adc_width_get_helper(self);
229212
mp_uint_t u16 = raw << (16 - bits) | raw >> (2 * bits - 16);
230213
return u16;
231214
}
232215

233216
static mp_int_t mp_machine_adc_read_uv(machine_adc_obj_t *self) {
234-
adc_atten_t atten = madc_atten_get(self);
235-
return madcblock_read_uv_helper(self->block, self->channel_id, atten);
217+
return madcblock_read_uv_helper(self->block, self->channel_id, mp_machine_adc_atten_get_helper(self));
218+
}
219+
220+
mp_int_t mp_machine_adc_atten_get_helper(const machine_adc_obj_t *self) {
221+
uint8_t value = madc_obj_atten[self - &madc_obj[0]];
222+
return value == 0 ? ADC_ATTEN_MAX : value - 1;
223+
}
224+
225+
void mp_machine_adc_atten_set_helper(const machine_adc_obj_t *self, mp_int_t atten) {
226+
if (atten < ADC_ATTEN_MIN || atten > ADC_ATTEN_MAX) {
227+
mp_raise_ValueError(MP_ERROR_TEXT("invalid attenuation"));
228+
}
229+
230+
madc_obj_atten[self - &madc_obj[0]] = atten + 1;
236231
}
237232

238233
static void mp_machine_adc_atten_set(machine_adc_obj_t *self, mp_int_t atten) {
239-
madc_atten_helper(self, atten);
234+
mp_machine_adc_atten_set_helper(self, atten);
235+
apply_self_adc_channel_atten(self, mp_machine_adc_atten_get_helper(self));
236+
}
237+
238+
mp_int_t mp_machine_adc_width_get_helper(const machine_adc_obj_t *self) {
239+
return self->block->bitwidth;
240+
}
241+
242+
void mp_machine_adc_block_width_set_helper(machine_adc_block_obj_t *self, mp_int_t width) {
243+
if (width < ADC_WIDTH_MIN || width > ADC_WIDTH_MAX) {
244+
mp_raise_ValueError(MP_ERROR_TEXT("invalid bit-width"));
245+
}
246+
247+
self->bitwidth = width;
240248
}
241249

242250
static void mp_machine_adc_width_set(machine_adc_obj_t *self, mp_int_t width) {
243-
madcblock_bits_helper(self->block, width);
251+
mp_machine_adc_block_width_set_helper(self->block, width);
252+
apply_self_adc_channel_atten(self, mp_machine_adc_atten_get_helper(self));
244253
}

0 commit comments

Comments
 (0)