Skip to content

Commit 5635077

Browse files
committed
Espressif analogbufio implementation
1 parent cd0ff51 commit 5635077

File tree

4 files changed

+327
-0
lines changed

4 files changed

+327
-0
lines changed
Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* SPDX-FileCopyrightText: Copyright (c) 2023 Milind Movasha
7+
*
8+
* SPDX-License-Identifier: BSD-3-Clause
9+
*
10+
*
11+
* Permission is hereby granted, free of charge, to any person obtaining a copy
12+
* of this software and associated documentation files (the "Software"), to deal
13+
* in the Software without restriction, including without limitation the rights
14+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15+
* copies of the Software, and to permit persons to whom the Software is
16+
* furnished to do so, subject to the following conditions:
17+
*
18+
* The above copyright notice and this permission notice shall be included in
19+
* all copies or substantial portions of the Software.
20+
*
21+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27+
* THE SOFTWARE.
28+
*/
29+
30+
#include <stdio.h>
31+
#include "common-hal/analogbufio/BufferedIn.h"
32+
#include "shared-bindings/analogbufio/BufferedIn.h"
33+
#include "shared-bindings/microcontroller/Pin.h"
34+
#include "shared/runtime/interrupt_char.h"
35+
#include "py/runtime.h"
36+
#include <string.h>
37+
#include <stdio.h>
38+
#include "sdkconfig.h"
39+
#include "freertos/FreeRTOS.h"
40+
#include "freertos/task.h"
41+
#include "freertos/semphr.h"
42+
#include "driver/adc.h"
43+
44+
//#define DEBUG_ANALOGBUFIO
45+
46+
#define NUM_SAMPLES_PER_INTERRUPT 256
47+
#define NUM_ADC_CHANNELS 1
48+
#define DMA_BUFFER_SIZE 1024
49+
#define ATTENUATION ADC_ATTEN_DB_0
50+
#define ADC_READ_TIMEOUT_MS 2000
51+
52+
#if defined(CONFIG_IDF_TARGET_ESP32)
53+
#define ADC_RESULT_BYTE 2
54+
#define ADC_CONV_LIMIT_EN 1 //For ESP32, this should always be set to 1
55+
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
56+
#define ADC_RESULT_BYTE 2
57+
#define ADC_CONV_LIMIT_EN 0
58+
#elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32H2)
59+
#define ADC_RESULT_BYTE 4
60+
#define ADC_CONV_LIMIT_EN 0
61+
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
62+
#define ADC_RESULT_BYTE 4
63+
#define ADC_CONV_LIMIT_EN 0
64+
#endif
65+
66+
static adc_digi_convert_mode_t convert_mode = ADC_CONV_SINGLE_UNIT_2;
67+
static adc_digi_output_format_t output_format = ADC_DIGI_OUTPUT_FORMAT_TYPE1;
68+
static uint8_t adc_channel = 0;
69+
70+
void common_hal_analogbufio_bufferedin_construct(analogbufio_bufferedin_obj_t *self, const mcu_pin_obj_t *pin, uint32_t sample_rate) {
71+
uint16_t adc1_chan_mask = 0;
72+
uint16_t adc2_chan_mask = 0;
73+
74+
if( self->pin != NULL) {
75+
mp_raise_ValueError(translate("ADC DMA already initialized"));
76+
}
77+
78+
output_format = ADC_DIGI_OUTPUT_FORMAT_TYPE1;
79+
if(pin->adc_index == ADC_UNIT_1) {
80+
convert_mode = ADC_CONV_SINGLE_UNIT_1;
81+
} else {
82+
convert_mode = ADC_CONV_SINGLE_UNIT_2;
83+
}
84+
85+
if (pin->adc_index == NO_ADC || pin->adc_channel == NO_ADC_CHANNEL) {
86+
raise_ValueError_invalid_pin();
87+
}
88+
89+
adc_channel = pin->adc_channel;
90+
91+
/*
92+
* Chip version Conversion Mode Output Format Type
93+
* ESP32 1 TYPE1
94+
* ESP32S2 1,2,BOTH,ALTER TYPE1, TYPE2
95+
* ESP32C3 ALTER TYPE2
96+
* ESP32S3 1,2,BOTH,ALTER TYPE2
97+
* ESP32H3 1,2,BOTH,ALTER TYPE2
98+
*/
99+
100+
#if defined(CONFIG_IDF_TARGET_ESP32)
101+
if(pin->adc_index != ADC_UNIT_1) {
102+
mp_raise_ValueError(translate("ESP32 only supports ADC1 unit"));
103+
}
104+
#endif
105+
#if defined(CONFIG_IDF_TARGET_ESP32S2)
106+
#endif
107+
#if defined(CONFIG_IDF_TARGET_ESP32C3)
108+
//ESP32C3 only supports alter mode
109+
convert_mode = ADC_CONV_ALTER_UNIT;
110+
output_format = ADC_DIGI_OUTPUT_FORMAT_TYPE2;
111+
#endif
112+
#if defined(CONFIG_IDF_TARGET_ESP32S3)
113+
#endif
114+
#if defined(CONFIG_IDF_TARGET_ESP32H2)
115+
#endif
116+
117+
self->pin = pin;
118+
common_hal_mcu_pin_claim(pin);
119+
120+
if(pin->adc_index == ADC_UNIT_1) {
121+
adc1_chan_mask = 1 << pin->adc_channel;
122+
} else {
123+
adc2_chan_mask = 1 << pin->adc_channel;
124+
}
125+
126+
adc_digi_init_config_t adc_dma_config = {
127+
.max_store_buf_size = DMA_BUFFER_SIZE,
128+
.conv_num_each_intr = NUM_SAMPLES_PER_INTERRUPT,
129+
.adc1_chan_mask = adc1_chan_mask,
130+
.adc2_chan_mask = adc2_chan_mask,
131+
};
132+
133+
#if defined(DEBUG_ANALOGBUFIO)
134+
mp_printf(&mp_plat_print,"pin:%d, ADC channel:%d, ADC index:%d, adc1_chan_mask:0x%x, adc2_chan_mask:0x%x\n",pin->number,pin->adc_channel,pin->adc_index,adc1_chan_mask,adc2_chan_mask);
135+
#endif //DEBUG_ANALOGBUFIO
136+
esp_err_t err = adc_digi_initialize(&adc_dma_config);
137+
if(ESP_OK != err) {
138+
common_hal_analogbufio_bufferedin_deinit(self);
139+
mp_raise_ValueError_varg(translate("Unable to initialize ADC DMA controller, ErrorCode:%d"),err);
140+
}
141+
142+
adc_digi_configuration_t dig_cfg = {
143+
.conv_limit_en = ADC_CONV_LIMIT_EN,
144+
.conv_limit_num = 250,
145+
.pattern_num = NUM_ADC_CHANNELS,
146+
.sample_freq_hz = sample_rate,
147+
.conv_mode = convert_mode,
148+
.format = output_format,
149+
};
150+
151+
#if defined(DEBUG_ANALOGBUFIO)
152+
mp_printf(&mp_plat_print,"conversion_mode:%d, format:%d, conv_limit_en:%d, sample_rate:%d\n",convert_mode,output_format,ADC_CONV_LIMIT_EN,sample_rate);
153+
#endif //DEBUG_ANALOGBUFIO
154+
155+
adc_digi_pattern_config_t adc_pattern[NUM_ADC_CHANNELS] = {0};
156+
adc_pattern[0].atten = ATTENUATION;
157+
adc_pattern[0].channel = pin->adc_channel;
158+
if(pin->adc_index == ADC_UNIT_1) {
159+
adc_pattern[0].unit = 0;
160+
} else {
161+
adc_pattern[0].unit = 1;
162+
}
163+
adc_pattern[0].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH;
164+
165+
dig_cfg.adc_pattern = adc_pattern;
166+
#if defined(DEBUG_ANALOGBUFIO)
167+
mp_printf(&mp_plat_print,"adc_pattern[0].channel:%d, adc_pattern[0].unit:%d, adc_pattern[0].atten:%d\n",adc_pattern[0].channel,adc_pattern[0].unit,adc_pattern[0].atten);
168+
#endif //DEBUG_ANALOGBUFIO
169+
170+
err = adc_digi_controller_configure(&dig_cfg);
171+
if(ESP_OK != err) {
172+
common_hal_analogbufio_bufferedin_deinit(self);
173+
mp_raise_ValueError_varg(translate("Unable to configure ADC DMA controller, ErrorCode:%d"),err);
174+
}
175+
err = adc_digi_start();
176+
if(ESP_OK != err) {
177+
common_hal_analogbufio_bufferedin_deinit(self);
178+
mp_raise_ValueError_varg(translate("Unable to start ADC DMA controller, ErrorCode:%d"),err);
179+
}
180+
}
181+
182+
bool common_hal_analogbufio_bufferedin_deinited(analogbufio_bufferedin_obj_t *self) {
183+
return self->pin == NULL;
184+
}
185+
186+
void common_hal_analogbufio_bufferedin_deinit(analogbufio_bufferedin_obj_t *self) {
187+
if (common_hal_analogbufio_bufferedin_deinited(self)) {
188+
return;
189+
}
190+
191+
adc_digi_stop();
192+
adc_digi_deinitialize();
193+
194+
// Release ADC Pin
195+
reset_pin_number(self->pin->number);
196+
self->pin = NULL;
197+
}
198+
199+
static bool check_valid_data(const adc_digi_output_data_t *data)
200+
{
201+
unsigned int unit = data->type2.unit;
202+
if(output_format == ADC_DIGI_OUTPUT_FORMAT_TYPE2) {
203+
if (data->type2.channel >= SOC_ADC_CHANNEL_NUM(unit)) return false;
204+
if (adc_channel != data->type2.channel) return false;
205+
} else {
206+
if( convert_mode == ADC_CONV_SINGLE_UNIT_1 ) {
207+
unit = 0;
208+
} else {
209+
unit = 1;
210+
}
211+
if (data->type1.channel >= SOC_ADC_CHANNEL_NUM(unit)) return false;
212+
if (adc_channel != data->type1.channel) return false;
213+
}
214+
if (unit > 2) return false;
215+
return true;
216+
}
217+
218+
219+
uint32_t common_hal_analogbufio_bufferedin_readinto(analogbufio_bufferedin_obj_t *self, uint8_t *buffer, uint32_t len, uint8_t bytes_per_sample) {
220+
uint8_t result[NUM_SAMPLES_PER_INTERRUPT] __attribute__ ((aligned (4))) = {0};
221+
uint32_t captured_samples = 0;
222+
uint32_t captured_bytes = 0;
223+
esp_err_t ret;
224+
uint32_t ret_num = 0;
225+
226+
#if defined(DEBUG_ANALOGBUFIO)
227+
mp_printf(&mp_plat_print,"Required bytes: %d\n",len);
228+
#endif //DEBUG_ANALOGBUFIO
229+
230+
while(captured_bytes < len) {
231+
ret_num = 0;
232+
ret = adc_digi_read_bytes(result, NUM_SAMPLES_PER_INTERRUPT, &ret_num, ADC_READ_TIMEOUT_MS);
233+
234+
if (ret == ESP_OK) {
235+
for(uint32_t i=0; i<ret_num; i+=ADC_RESULT_BYTE) {
236+
if(check_valid_data((adc_digi_output_data_t *) (void *)&result[i])) {
237+
if(captured_bytes < len) {
238+
if(ADC_RESULT_BYTE == 2) {
239+
if(output_format == ADC_DIGI_OUTPUT_FORMAT_TYPE1) {
240+
*(uint16_t *)(void *)&buffer[captured_bytes] = ((adc_digi_output_data_t *) (void *)&result[i])->type1.data;
241+
} else {
242+
*(uint16_t *)(void *)&buffer[captured_bytes] = ((adc_digi_output_data_t *) (void *)&result[i])->type2.data;
243+
}
244+
} else {
245+
if(output_format == ADC_DIGI_OUTPUT_FORMAT_TYPE1) {
246+
*(uint32_t *)(void *)&buffer[captured_bytes] = ((adc_digi_output_data_t *) (void *)&result[i])->type1.data;
247+
} else {
248+
*(uint32_t *)(void *)&buffer[captured_bytes] = ((adc_digi_output_data_t *) (void *)&result[i])->type2.data;
249+
}
250+
}
251+
captured_bytes += ADC_RESULT_BYTE;
252+
captured_samples++;
253+
} else {
254+
return captured_samples;
255+
}
256+
} else {
257+
#if defined(DEBUG_ANALOGBUFIO)
258+
if(ADC_RESULT_BYTE == 2) {
259+
mp_printf(&mp_plat_print,"Invalid sample received: 0x%0x\n",*(uint16_t *)(void *)&result[i]);
260+
} else {
261+
mp_printf(&mp_plat_print,"Invalid sample received: 0x%0x\n",*(uint32_t *)(void *)&result[i]);
262+
}
263+
#endif //DEBUG_ANALOGBUFIO
264+
return captured_samples;
265+
}
266+
}
267+
} else if (ret == ESP_ERR_TIMEOUT) {
268+
#if defined(DEBUG_ANALOGBUFIO)
269+
mp_printf(&mp_plat_print,"ADC Timeout\n");
270+
#endif //DEBUG_ANALOGBUFIO
271+
return captured_samples;
272+
} else {
273+
#if defined(DEBUG_ANALOGBUFIO)
274+
mp_printf(&mp_plat_print,"adc_digi_read_bytes failed error code:%d\n",ret);
275+
#endif //DEBUG_ANALOGBUFIO
276+
return captured_samples;
277+
}
278+
}
279+
#if defined(DEBUG_ANALOGBUFIO)
280+
mp_printf(&mp_plat_print,"Captured bytes: %d\n",captured_bytes);
281+
#endif //DEBUG_ANALOGBUFIO
282+
return captured_samples;
283+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* SPDX-FileCopyrightText: Copyright (c) 2023 Milind Movasha
7+
*
8+
* SPDX-License-Identifier: BSD-3-Clause
9+
*
10+
* Permission is hereby granted, free of charge, to any person obtaining a copy
11+
* of this software and associated documentation files (the "Software"), to deal
12+
* in the Software without restriction, including without limitation the rights
13+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14+
* copies of the Software, and to permit persons to whom the Software is
15+
* furnished to do so, subject to the following conditions:
16+
*
17+
* The above copyright notice and this permission notice shall be included in
18+
* all copies or substantial portions of the Software.
19+
*
20+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26+
* THE SOFTWARE.
27+
*/
28+
29+
#ifndef MICROPY_INCLUDED_ESP32_COMMON_HAL_ANALOGBUFIO_BUFFEREDIN_H
30+
#define MICROPY_INCLUDED_ESP32_COMMON_HAL_ANALOGBUFIO_BUFFEREDIN_H
31+
32+
#include "common-hal/microcontroller/Pin.h"
33+
#include "py/obj.h"
34+
35+
// This is the analogbufio object
36+
typedef struct {
37+
mp_obj_base_t base;
38+
const mcu_pin_obj_t *pin;
39+
uint8_t chan;
40+
} analogbufio_bufferedin_obj_t;
41+
42+
#endif // MICROPY_INCLUDED_ESP32_COMMON_HAL_ANALOGBUFIO_BUFFEREDIN_H
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// No analogbufio module functions.

ports/espressif/mpconfigport.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ CIRCUITPY_FULL_BUILD ?= 1
1313
# These modules are implemented in ports/<port>/common-hal:
1414
CIRCUITPY_ALARM ?= 1
1515
CIRCUITPY_AUDIOBUSIO ?= 1
16+
CIRCUITPY_ANALOGBUFIO ?= 1
1617
CIRCUITPY_AUDIOBUSIO_I2SOUT ?= 1
1718
CIRCUITPY_AUDIOBUSIO_PDMIN ?= 0
1819
CIRCUITPY_AUDIOCORE ?= 1

0 commit comments

Comments
 (0)