Espressif analogbufio implementation
This commit is contained in:
parent
cd0ff5196a
commit
5635077853
283
ports/espressif/common-hal/analogbufio/BufferedIn.c
Normal file
283
ports/espressif/common-hal/analogbufio/BufferedIn.c
Normal file
@ -0,0 +1,283 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2023 Milind Movasha
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "common-hal/analogbufio/BufferedIn.h"
|
||||
#include "shared-bindings/analogbufio/BufferedIn.h"
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
#include "shared/runtime/interrupt_char.h"
|
||||
#include "py/runtime.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "driver/adc.h"
|
||||
|
||||
//#define DEBUG_ANALOGBUFIO
|
||||
|
||||
#define NUM_SAMPLES_PER_INTERRUPT 256
|
||||
#define NUM_ADC_CHANNELS 1
|
||||
#define DMA_BUFFER_SIZE 1024
|
||||
#define ATTENUATION ADC_ATTEN_DB_0
|
||||
#define ADC_READ_TIMEOUT_MS 2000
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32)
|
||||
#define ADC_RESULT_BYTE 2
|
||||
#define ADC_CONV_LIMIT_EN 1 //For ESP32, this should always be set to 1
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
#define ADC_RESULT_BYTE 2
|
||||
#define ADC_CONV_LIMIT_EN 0
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32H2)
|
||||
#define ADC_RESULT_BYTE 4
|
||||
#define ADC_CONV_LIMIT_EN 0
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
#define ADC_RESULT_BYTE 4
|
||||
#define ADC_CONV_LIMIT_EN 0
|
||||
#endif
|
||||
|
||||
static adc_digi_convert_mode_t convert_mode = ADC_CONV_SINGLE_UNIT_2;
|
||||
static adc_digi_output_format_t output_format = ADC_DIGI_OUTPUT_FORMAT_TYPE1;
|
||||
static uint8_t adc_channel = 0;
|
||||
|
||||
void common_hal_analogbufio_bufferedin_construct(analogbufio_bufferedin_obj_t *self, const mcu_pin_obj_t *pin, uint32_t sample_rate) {
|
||||
uint16_t adc1_chan_mask = 0;
|
||||
uint16_t adc2_chan_mask = 0;
|
||||
|
||||
if( self->pin != NULL) {
|
||||
mp_raise_ValueError(translate("ADC DMA already initialized"));
|
||||
}
|
||||
|
||||
output_format = ADC_DIGI_OUTPUT_FORMAT_TYPE1;
|
||||
if(pin->adc_index == ADC_UNIT_1) {
|
||||
convert_mode = ADC_CONV_SINGLE_UNIT_1;
|
||||
} else {
|
||||
convert_mode = ADC_CONV_SINGLE_UNIT_2;
|
||||
}
|
||||
|
||||
if (pin->adc_index == NO_ADC || pin->adc_channel == NO_ADC_CHANNEL) {
|
||||
raise_ValueError_invalid_pin();
|
||||
}
|
||||
|
||||
adc_channel = pin->adc_channel;
|
||||
|
||||
/*
|
||||
* Chip version Conversion Mode Output Format Type
|
||||
* ESP32 1 TYPE1
|
||||
* ESP32S2 1,2,BOTH,ALTER TYPE1, TYPE2
|
||||
* ESP32C3 ALTER TYPE2
|
||||
* ESP32S3 1,2,BOTH,ALTER TYPE2
|
||||
* ESP32H3 1,2,BOTH,ALTER TYPE2
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32)
|
||||
if(pin->adc_index != ADC_UNIT_1) {
|
||||
mp_raise_ValueError(translate("ESP32 only supports ADC1 unit"));
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
#endif
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
//ESP32C3 only supports alter mode
|
||||
convert_mode = ADC_CONV_ALTER_UNIT;
|
||||
output_format = ADC_DIGI_OUTPUT_FORMAT_TYPE2;
|
||||
#endif
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
#endif
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32H2)
|
||||
#endif
|
||||
|
||||
self->pin = pin;
|
||||
common_hal_mcu_pin_claim(pin);
|
||||
|
||||
if(pin->adc_index == ADC_UNIT_1) {
|
||||
adc1_chan_mask = 1 << pin->adc_channel;
|
||||
} else {
|
||||
adc2_chan_mask = 1 << pin->adc_channel;
|
||||
}
|
||||
|
||||
adc_digi_init_config_t adc_dma_config = {
|
||||
.max_store_buf_size = DMA_BUFFER_SIZE,
|
||||
.conv_num_each_intr = NUM_SAMPLES_PER_INTERRUPT,
|
||||
.adc1_chan_mask = adc1_chan_mask,
|
||||
.adc2_chan_mask = adc2_chan_mask,
|
||||
};
|
||||
|
||||
#if defined(DEBUG_ANALOGBUFIO)
|
||||
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);
|
||||
#endif //DEBUG_ANALOGBUFIO
|
||||
esp_err_t err = adc_digi_initialize(&adc_dma_config);
|
||||
if(ESP_OK != err) {
|
||||
common_hal_analogbufio_bufferedin_deinit(self);
|
||||
mp_raise_ValueError_varg(translate("Unable to initialize ADC DMA controller, ErrorCode:%d"),err);
|
||||
}
|
||||
|
||||
adc_digi_configuration_t dig_cfg = {
|
||||
.conv_limit_en = ADC_CONV_LIMIT_EN,
|
||||
.conv_limit_num = 250,
|
||||
.pattern_num = NUM_ADC_CHANNELS,
|
||||
.sample_freq_hz = sample_rate,
|
||||
.conv_mode = convert_mode,
|
||||
.format = output_format,
|
||||
};
|
||||
|
||||
#if defined(DEBUG_ANALOGBUFIO)
|
||||
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);
|
||||
#endif //DEBUG_ANALOGBUFIO
|
||||
|
||||
adc_digi_pattern_config_t adc_pattern[NUM_ADC_CHANNELS] = {0};
|
||||
adc_pattern[0].atten = ATTENUATION;
|
||||
adc_pattern[0].channel = pin->adc_channel;
|
||||
if(pin->adc_index == ADC_UNIT_1) {
|
||||
adc_pattern[0].unit = 0;
|
||||
} else {
|
||||
adc_pattern[0].unit = 1;
|
||||
}
|
||||
adc_pattern[0].bit_width = SOC_ADC_DIGI_MAX_BITWIDTH;
|
||||
|
||||
dig_cfg.adc_pattern = adc_pattern;
|
||||
#if defined(DEBUG_ANALOGBUFIO)
|
||||
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);
|
||||
#endif //DEBUG_ANALOGBUFIO
|
||||
|
||||
err = adc_digi_controller_configure(&dig_cfg);
|
||||
if(ESP_OK != err) {
|
||||
common_hal_analogbufio_bufferedin_deinit(self);
|
||||
mp_raise_ValueError_varg(translate("Unable to configure ADC DMA controller, ErrorCode:%d"),err);
|
||||
}
|
||||
err = adc_digi_start();
|
||||
if(ESP_OK != err) {
|
||||
common_hal_analogbufio_bufferedin_deinit(self);
|
||||
mp_raise_ValueError_varg(translate("Unable to start ADC DMA controller, ErrorCode:%d"),err);
|
||||
}
|
||||
}
|
||||
|
||||
bool common_hal_analogbufio_bufferedin_deinited(analogbufio_bufferedin_obj_t *self) {
|
||||
return self->pin == NULL;
|
||||
}
|
||||
|
||||
void common_hal_analogbufio_bufferedin_deinit(analogbufio_bufferedin_obj_t *self) {
|
||||
if (common_hal_analogbufio_bufferedin_deinited(self)) {
|
||||
return;
|
||||
}
|
||||
|
||||
adc_digi_stop();
|
||||
adc_digi_deinitialize();
|
||||
|
||||
// Release ADC Pin
|
||||
reset_pin_number(self->pin->number);
|
||||
self->pin = NULL;
|
||||
}
|
||||
|
||||
static bool check_valid_data(const adc_digi_output_data_t *data)
|
||||
{
|
||||
unsigned int unit = data->type2.unit;
|
||||
if(output_format == ADC_DIGI_OUTPUT_FORMAT_TYPE2) {
|
||||
if (data->type2.channel >= SOC_ADC_CHANNEL_NUM(unit)) return false;
|
||||
if (adc_channel != data->type2.channel) return false;
|
||||
} else {
|
||||
if( convert_mode == ADC_CONV_SINGLE_UNIT_1 ) {
|
||||
unit = 0;
|
||||
} else {
|
||||
unit = 1;
|
||||
}
|
||||
if (data->type1.channel >= SOC_ADC_CHANNEL_NUM(unit)) return false;
|
||||
if (adc_channel != data->type1.channel) return false;
|
||||
}
|
||||
if (unit > 2) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint32_t common_hal_analogbufio_bufferedin_readinto(analogbufio_bufferedin_obj_t *self, uint8_t *buffer, uint32_t len, uint8_t bytes_per_sample) {
|
||||
uint8_t result[NUM_SAMPLES_PER_INTERRUPT] __attribute__ ((aligned (4))) = {0};
|
||||
uint32_t captured_samples = 0;
|
||||
uint32_t captured_bytes = 0;
|
||||
esp_err_t ret;
|
||||
uint32_t ret_num = 0;
|
||||
|
||||
#if defined(DEBUG_ANALOGBUFIO)
|
||||
mp_printf(&mp_plat_print,"Required bytes: %d\n",len);
|
||||
#endif //DEBUG_ANALOGBUFIO
|
||||
|
||||
while(captured_bytes < len) {
|
||||
ret_num = 0;
|
||||
ret = adc_digi_read_bytes(result, NUM_SAMPLES_PER_INTERRUPT, &ret_num, ADC_READ_TIMEOUT_MS);
|
||||
|
||||
if (ret == ESP_OK) {
|
||||
for(uint32_t i=0; i<ret_num; i+=ADC_RESULT_BYTE) {
|
||||
if(check_valid_data((adc_digi_output_data_t *) (void *)&result[i])) {
|
||||
if(captured_bytes < len) {
|
||||
if(ADC_RESULT_BYTE == 2) {
|
||||
if(output_format == ADC_DIGI_OUTPUT_FORMAT_TYPE1) {
|
||||
*(uint16_t *)(void *)&buffer[captured_bytes] = ((adc_digi_output_data_t *) (void *)&result[i])->type1.data;
|
||||
} else {
|
||||
*(uint16_t *)(void *)&buffer[captured_bytes] = ((adc_digi_output_data_t *) (void *)&result[i])->type2.data;
|
||||
}
|
||||
} else {
|
||||
if(output_format == ADC_DIGI_OUTPUT_FORMAT_TYPE1) {
|
||||
*(uint32_t *)(void *)&buffer[captured_bytes] = ((adc_digi_output_data_t *) (void *)&result[i])->type1.data;
|
||||
} else {
|
||||
*(uint32_t *)(void *)&buffer[captured_bytes] = ((adc_digi_output_data_t *) (void *)&result[i])->type2.data;
|
||||
}
|
||||
}
|
||||
captured_bytes += ADC_RESULT_BYTE;
|
||||
captured_samples++;
|
||||
} else {
|
||||
return captured_samples;
|
||||
}
|
||||
} else {
|
||||
#if defined(DEBUG_ANALOGBUFIO)
|
||||
if(ADC_RESULT_BYTE == 2) {
|
||||
mp_printf(&mp_plat_print,"Invalid sample received: 0x%0x\n",*(uint16_t *)(void *)&result[i]);
|
||||
} else {
|
||||
mp_printf(&mp_plat_print,"Invalid sample received: 0x%0x\n",*(uint32_t *)(void *)&result[i]);
|
||||
}
|
||||
#endif //DEBUG_ANALOGBUFIO
|
||||
return captured_samples;
|
||||
}
|
||||
}
|
||||
} else if (ret == ESP_ERR_TIMEOUT) {
|
||||
#if defined(DEBUG_ANALOGBUFIO)
|
||||
mp_printf(&mp_plat_print,"ADC Timeout\n");
|
||||
#endif //DEBUG_ANALOGBUFIO
|
||||
return captured_samples;
|
||||
} else {
|
||||
#if defined(DEBUG_ANALOGBUFIO)
|
||||
mp_printf(&mp_plat_print,"adc_digi_read_bytes failed error code:%d\n",ret);
|
||||
#endif //DEBUG_ANALOGBUFIO
|
||||
return captured_samples;
|
||||
}
|
||||
}
|
||||
#if defined(DEBUG_ANALOGBUFIO)
|
||||
mp_printf(&mp_plat_print,"Captured bytes: %d\n",captured_bytes);
|
||||
#endif //DEBUG_ANALOGBUFIO
|
||||
return captured_samples;
|
||||
}
|
42
ports/espressif/common-hal/analogbufio/BufferedIn.h
Normal file
42
ports/espressif/common-hal/analogbufio/BufferedIn.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2023 Milind Movasha
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MICROPY_INCLUDED_ESP32_COMMON_HAL_ANALOGBUFIO_BUFFEREDIN_H
|
||||
#define MICROPY_INCLUDED_ESP32_COMMON_HAL_ANALOGBUFIO_BUFFEREDIN_H
|
||||
|
||||
#include "common-hal/microcontroller/Pin.h"
|
||||
#include "py/obj.h"
|
||||
|
||||
// This is the analogbufio object
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
const mcu_pin_obj_t *pin;
|
||||
uint8_t chan;
|
||||
} analogbufio_bufferedin_obj_t;
|
||||
|
||||
#endif // MICROPY_INCLUDED_ESP32_COMMON_HAL_ANALOGBUFIO_BUFFEREDIN_H
|
1
ports/espressif/common-hal/analogbufio/__init__.c
Normal file
1
ports/espressif/common-hal/analogbufio/__init__.c
Normal file
@ -0,0 +1 @@
|
||||
// No analogbufio module functions.
|
@ -13,6 +13,7 @@ CIRCUITPY_FULL_BUILD ?= 1
|
||||
# These modules are implemented in ports/<port>/common-hal:
|
||||
CIRCUITPY_ALARM ?= 1
|
||||
CIRCUITPY_AUDIOBUSIO ?= 1
|
||||
CIRCUITPY_ANALOGBUFIO ?= 1
|
||||
CIRCUITPY_AUDIOBUSIO_I2SOUT ?= 1
|
||||
CIRCUITPY_AUDIOBUSIO_PDMIN ?= 0
|
||||
CIRCUITPY_AUDIOCORE ?= 1
|
||||
|
Loading…
Reference in New Issue
Block a user