Update ADC and I2S APIs for 5.1
This fixes ESP32 because the BufferedIn used the old ADC API and I2S did too indirectly. Fixes #8429
This commit is contained in:
parent
1c0155c99b
commit
3fdfb9bd32
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -147,9 +147,6 @@
|
||||
[submodule "ports/espressif/esp-protocols"]
|
||||
path = ports/espressif/esp-protocols
|
||||
url = https://github.com/espressif/esp-protocols.git
|
||||
[submodule "ports/espressif/esp-iot-solution"]
|
||||
path = ports/espressif/esp-iot-solution
|
||||
url = https://github.com/espressif/esp-iot-solution.git
|
||||
[submodule "ports/espressif/esp-camera"]
|
||||
path = ports/espressif/esp-camera
|
||||
url = https://github.com/adafruit/esp32-camera.git
|
||||
|
@ -447,10 +447,6 @@ msgstr ""
|
||||
msgid "A hardware interrupt channel is already in use"
|
||||
msgstr ""
|
||||
|
||||
#: ports/espressif/common-hal/analogio/AnalogIn.c
|
||||
msgid "ADC2 is being used by WiFi"
|
||||
msgstr ""
|
||||
|
||||
#: ports/raspberrypi/common-hal/wifi/Radio.c
|
||||
msgid "AP could not be started"
|
||||
msgstr ""
|
||||
@ -2156,11 +2152,6 @@ msgstr ""
|
||||
msgid "Unable to allocate the heap."
|
||||
msgstr ""
|
||||
|
||||
#: ports/espressif/common-hal/analogbufio/BufferedIn.c
|
||||
#, c-format
|
||||
msgid "Unable to configure ADC DMA controller, ErrorCode:%d"
|
||||
msgstr ""
|
||||
|
||||
#: ports/espressif/common-hal/busio/I2C.c
|
||||
msgid "Unable to create lock"
|
||||
msgstr ""
|
||||
@ -2179,20 +2170,10 @@ msgstr ""
|
||||
msgid "Unable to init parser"
|
||||
msgstr ""
|
||||
|
||||
#: ports/espressif/common-hal/analogbufio/BufferedIn.c
|
||||
#, c-format
|
||||
msgid "Unable to initialize ADC DMA controller, ErrorCode:%d"
|
||||
msgstr ""
|
||||
|
||||
#: shared-module/displayio/OnDiskBitmap.c
|
||||
msgid "Unable to read color palette data"
|
||||
msgstr ""
|
||||
|
||||
#: ports/espressif/common-hal/analogbufio/BufferedIn.c
|
||||
#, c-format
|
||||
msgid "Unable to start ADC DMA controller, ErrorCode:%d"
|
||||
msgstr ""
|
||||
|
||||
#: ports/espressif/common-hal/mdns/Server.c
|
||||
#: ports/raspberrypi/common-hal/mdns/Server.c
|
||||
msgid "Unable to start mDNS query"
|
||||
@ -4207,7 +4188,8 @@ msgstr ""
|
||||
msgid "unexpected keyword argument"
|
||||
msgstr ""
|
||||
|
||||
#: py/bc.c py/objnamedtuple.c shared-bindings/traceback/__init__.c
|
||||
#: py/argcheck.c py/bc.c py/objnamedtuple.c
|
||||
#: shared-bindings/traceback/__init__.c
|
||||
msgid "unexpected keyword argument '%q'"
|
||||
msgstr ""
|
||||
|
||||
@ -4364,10 +4346,6 @@ msgstr ""
|
||||
msgid "wrong output type"
|
||||
msgstr ""
|
||||
|
||||
#: ports/espressif/common-hal/audiobusio/__init__.c
|
||||
msgid "xTaskCreate failed"
|
||||
msgstr ""
|
||||
|
||||
#: extmod/ulab/code/scipy/signal/signal.c
|
||||
msgid "zi must be an ndarray"
|
||||
msgstr ""
|
||||
|
2
main.c
2
main.c
@ -1190,7 +1190,9 @@ void NORETURN nlr_jump_fail(void *val) {
|
||||
|
||||
#ifndef NDEBUG
|
||||
static void NORETURN __fatal_error(const char *msg) {
|
||||
#if CIRCUITPY_DEBUG == 0
|
||||
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
|
||||
#endif
|
||||
while (true) {
|
||||
}
|
||||
}
|
||||
|
@ -304,17 +304,6 @@ ifneq ($(CIRCUITPY_BLEIO),0)
|
||||
SRC_C += common-hal/_bleio/ble_events.c
|
||||
endif
|
||||
|
||||
ifneq ($(CIRCUITPY_PARALLELDISPLAY),0)
|
||||
ifeq ($(IDF_TARGET),esp32s3)
|
||||
LCD_SRC = 8080_lcd_$(IDF_TARGET)
|
||||
else
|
||||
LCD_SRC = i2s_lcd_$(IDF_TARGET)_driver
|
||||
endif
|
||||
SRC_C += esp-iot-solution/components/bus/$(LCD_SRC).c
|
||||
$(BUILD)/esp-iot-solution/components/bus/$(LCD_SRC).o: CFLAGS += -Wno-sign-compare
|
||||
CFLAGS += -isystem esp-iot-solution/components/bus/include
|
||||
endif
|
||||
|
||||
ifneq ($(CIRCUITPY_DOTCLOCKFRAMEBUFFER),0)
|
||||
CFLAGS += -isystem esp-idf/components/esp_lcd/include
|
||||
CFLAGS += -isystem esp-idf/components/esp_lcd/interface
|
||||
|
@ -4,9 +4,9 @@ CIRCUITPY_CREATION_ID = 0x00320003
|
||||
IDF_TARGET = esp32
|
||||
|
||||
CIRCUITPY_ESP_FLASH_SIZE = 8MB
|
||||
CIRCUITPY_ESP_FLASH_MODE = dio
|
||||
CIRCUITPY_ESP_FLASH_FREQ = 40m
|
||||
CIRCUITPY_ESP_FLASH_MODE = qio
|
||||
CIRCUITPY_ESP_FLASH_FREQ = 80m
|
||||
|
||||
CIRCUITPY_ESP_PSRAM_SIZE = 2MB
|
||||
CIRCUITPY_ESP_PSRAM_MODE = qio
|
||||
CIRCUITPY_ESP_PSRAM_FREQ = 40m
|
||||
CIRCUITPY_ESP_PSRAM_FREQ = 80m
|
||||
|
@ -28,6 +28,7 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "bindings/espidf/__init__.h"
|
||||
#include "common-hal/analogbufio/BufferedIn.h"
|
||||
#include "shared-bindings/analogbufio/BufferedIn.h"
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
@ -39,7 +40,6 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "driver/adc.h"
|
||||
|
||||
// #define DEBUG_ANALOGBUFIO
|
||||
|
||||
@ -72,35 +72,10 @@ static void stop_dma(analogbufio_bufferedin_obj_t *self);
|
||||
void common_hal_analogbufio_bufferedin_construct(analogbufio_bufferedin_obj_t *self, const mcu_pin_obj_t *pin, uint32_t sample_rate) {
|
||||
self->pin = pin;
|
||||
self->sample_rate = sample_rate;
|
||||
}
|
||||
|
||||
static void start_dma(analogbufio_bufferedin_obj_t *self, adc_digi_convert_mode_t *convert_mode, adc_digi_output_format_t *output_format) {
|
||||
uint16_t adc1_chan_mask = 0;
|
||||
uint16_t adc2_chan_mask = 0;
|
||||
|
||||
const mcu_pin_obj_t *pin = self->pin;
|
||||
uint32_t sample_rate = self->sample_rate;
|
||||
|
||||
*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();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
/*
|
||||
@ -112,6 +87,36 @@ static void start_dma(analogbufio_bufferedin_obj_t *self, adc_digi_convert_mode_
|
||||
}
|
||||
#endif
|
||||
|
||||
// C3 and S3 have errata related to ADC2 and continuous mode.
|
||||
#if (defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3)) && !defined(CONFIG_ADC_CONTINUOUS_FORCE_USE_ADC2_ON_C3_S3)
|
||||
if (pin->adc_index != ADC_UNIT_1) {
|
||||
raise_ValueError_invalid_pin();
|
||||
}
|
||||
#endif
|
||||
|
||||
common_hal_mcu_pin_claim(pin);
|
||||
}
|
||||
|
||||
static void start_dma(analogbufio_bufferedin_obj_t *self, adc_digi_convert_mode_t *convert_mode, adc_digi_output_format_t *output_format) {
|
||||
const mcu_pin_obj_t *pin = self->pin;
|
||||
uint32_t sample_rate = self->sample_rate;
|
||||
|
||||
*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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_ESP32C3)
|
||||
/* ESP32C3 only supports alter mode */
|
||||
*convert_mode = ADC_CONV_ALTER_UNIT;
|
||||
@ -121,34 +126,21 @@ static void start_dma(analogbufio_bufferedin_obj_t *self, adc_digi_convert_mode_
|
||||
*output_format = ADC_DIGI_OUTPUT_FORMAT_TYPE2;
|
||||
#endif
|
||||
|
||||
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 = {
|
||||
adc_continuous_handle_cfg_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,
|
||||
.conv_frame_size = NUM_SAMPLES_PER_INTERRUPT * SOC_ADC_DIGI_DATA_BYTES_PER_CONV
|
||||
};
|
||||
|
||||
#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);
|
||||
esp_err_t err = adc_continuous_new_handle(&adc_dma_config, &self->handle);
|
||||
if (ESP_OK != err) {
|
||||
stop_dma(self);
|
||||
common_hal_analogbufio_bufferedin_deinit(self);
|
||||
mp_raise_ValueError_varg(translate("Unable to initialize ADC DMA controller, ErrorCode:%d"), err);
|
||||
CHECK_ESP_RESULT(err);
|
||||
}
|
||||
|
||||
adc_digi_configuration_t dig_cfg = {
|
||||
.conv_limit_en = ADC_CONV_LIMIT_EN,
|
||||
.conv_limit_num = 250,
|
||||
adc_continuous_config_t dig_cfg = {
|
||||
.pattern_num = NUM_ADC_CHANNELS,
|
||||
.sample_freq_hz = sample_rate,
|
||||
.conv_mode = *convert_mode,
|
||||
@ -174,25 +166,28 @@ static void start_dma(analogbufio_bufferedin_obj_t *self, adc_digi_convert_mode_
|
||||
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);
|
||||
err = adc_continuous_config(self->handle, &dig_cfg);
|
||||
if (ESP_OK != err) {
|
||||
stop_dma(self);
|
||||
common_hal_analogbufio_bufferedin_deinit(self);
|
||||
mp_raise_ValueError_varg(translate("Unable to configure ADC DMA controller, ErrorCode:%d"), err);
|
||||
CHECK_ESP_RESULT(err);
|
||||
}
|
||||
err = adc_digi_start();
|
||||
err = adc_continuous_start(self->handle);
|
||||
if (ESP_OK != err) {
|
||||
stop_dma(self);
|
||||
common_hal_analogbufio_bufferedin_deinit(self);
|
||||
mp_raise_ValueError_varg(translate("Unable to start ADC DMA controller, ErrorCode:%d"), err);
|
||||
CHECK_ESP_RESULT(err);
|
||||
}
|
||||
self->started = true;
|
||||
}
|
||||
|
||||
static void stop_dma(analogbufio_bufferedin_obj_t *self) {
|
||||
adc_digi_stop();
|
||||
adc_digi_deinitialize();
|
||||
// Release ADC Pin
|
||||
reset_pin_number(self->pin->number);
|
||||
if (self->started) {
|
||||
adc_continuous_stop(self->handle);
|
||||
self->started = false;
|
||||
}
|
||||
if (self->handle != NULL) {
|
||||
adc_continuous_deinit(self->handle);
|
||||
self->handle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool common_hal_analogbufio_bufferedin_deinited(analogbufio_bufferedin_obj_t *self) {
|
||||
@ -203,6 +198,8 @@ void common_hal_analogbufio_bufferedin_deinit(analogbufio_bufferedin_obj_t *self
|
||||
if (common_hal_analogbufio_bufferedin_deinited(self)) {
|
||||
return;
|
||||
}
|
||||
// Release ADC Pin
|
||||
reset_pin_number(self->pin->number);
|
||||
self->pin = NULL;
|
||||
}
|
||||
|
||||
@ -242,7 +239,7 @@ static bool check_valid_data(const adc_digi_output_data_t *data, const mcu_pin_o
|
||||
}
|
||||
|
||||
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};
|
||||
uint8_t result[NUM_SAMPLES_PER_INTERRUPT * SOC_ADC_DIGI_DATA_BYTES_PER_CONV] __attribute__ ((aligned(4))) = {0};
|
||||
uint32_t captured_samples = 0;
|
||||
uint32_t captured_bytes = 0;
|
||||
esp_err_t ret;
|
||||
@ -263,7 +260,7 @@ uint32_t common_hal_analogbufio_bufferedin_readinto(analogbufio_bufferedin_obj_t
|
||||
|
||||
while (captured_bytes < len) {
|
||||
ret_num = 0;
|
||||
ret = adc_digi_read_bytes(result, NUM_SAMPLES_PER_INTERRUPT, &ret_num, ADC_READ_TIMEOUT_MS);
|
||||
ret = adc_continuous_read(self->handle, result, NUM_SAMPLES_PER_INTERRUPT * SOC_ADC_DIGI_DATA_BYTES_PER_CONV, &ret_num, ADC_READ_TIMEOUT_MS);
|
||||
|
||||
if (ret == ESP_OK) {
|
||||
for (uint32_t i = 0; i < ret_num; i += ADC_RESULT_BYTE) {
|
||||
|
@ -32,11 +32,15 @@
|
||||
#include "common-hal/microcontroller/Pin.h"
|
||||
#include "py/obj.h"
|
||||
|
||||
#include "components/esp_adc/include/esp_adc/adc_continuous.h"
|
||||
|
||||
// This is the analogbufio object
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
const mcu_pin_obj_t *pin;
|
||||
uint32_t sample_rate;
|
||||
adc_continuous_handle_t handle;
|
||||
bool started;
|
||||
} analogbufio_bufferedin_obj_t;
|
||||
|
||||
#endif // MICROPY_INCLUDED_ESP32_COMMON_HAL_ANALOGBUFIO_BUFFEREDIN_H
|
||||
|
@ -96,7 +96,9 @@ void common_hal_analogio_analogout_set_value(analogio_analogout_obj_t *self,
|
||||
void analogout_reset(void) {
|
||||
#ifdef SOC_DAC_SUPPORTED
|
||||
for (uint8_t c = 0; c < SOC_DAC_CHAN_NUM; c++) {
|
||||
if (_active_handles[c] != NULL) {
|
||||
dac_oneshot_del_channel(_active_handles[c]);
|
||||
}
|
||||
_active_handles[c] = NULL;
|
||||
}
|
||||
#endif
|
||||
|
@ -44,7 +44,7 @@
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
#include "supervisor/shared/translate/translate.h"
|
||||
|
||||
#include "driver/i2s.h"
|
||||
#include "driver/i2s_std.h"
|
||||
|
||||
// Caller validates that pins are free.
|
||||
void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self,
|
||||
@ -53,15 +53,20 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self,
|
||||
if (main_clock != NULL) {
|
||||
mp_raise_NotImplementedError_varg(translate("%q"), MP_QSTR_main_clock);
|
||||
}
|
||||
port_i2s_allocate_init(&self->peripheral, left_justified);
|
||||
port_i2s_allocate_init(&self->i2s, left_justified);
|
||||
|
||||
i2s_pin_config_t i2s_pin_config = {
|
||||
.bck_io_num = bit_clock->number,
|
||||
.ws_io_num = word_select->number,
|
||||
.data_out_num = data->number,
|
||||
.data_in_num = I2S_PIN_NO_CHANGE,
|
||||
i2s_std_config_t i2s_config = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(48000),
|
||||
.slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
|
||||
.gpio_cfg = {
|
||||
.mclk = I2S_GPIO_UNUSED,
|
||||
.bclk = bit_clock->number,
|
||||
.ws = word_select->number,
|
||||
.dout = data->number,
|
||||
.din = I2S_GPIO_UNUSED,
|
||||
}
|
||||
};
|
||||
CHECK_ESP_RESULT(i2s_set_pin(self->peripheral.instance, &i2s_pin_config));
|
||||
CHECK_ESP_RESULT(i2s_channel_init_std_mode(self->i2s.handle, &i2s_config));
|
||||
self->bit_clock = bit_clock;
|
||||
self->word_select = word_select;
|
||||
self->data = data;
|
||||
@ -71,7 +76,7 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self,
|
||||
}
|
||||
|
||||
bool common_hal_audiobusio_i2sout_deinited(audiobusio_i2sout_obj_t *self) {
|
||||
return self->peripheral.instance == -1;
|
||||
return self->data == NULL;
|
||||
}
|
||||
|
||||
void common_hal_audiobusio_i2sout_deinit(audiobusio_i2sout_obj_t *self) {
|
||||
@ -79,6 +84,10 @@ void common_hal_audiobusio_i2sout_deinit(audiobusio_i2sout_obj_t *self) {
|
||||
return;
|
||||
}
|
||||
|
||||
common_hal_audiobusio_i2sout_stop(self);
|
||||
|
||||
port_i2s_deinit(&self->i2s);
|
||||
|
||||
if (self->bit_clock) {
|
||||
reset_pin_number(self->bit_clock->number);
|
||||
}
|
||||
@ -94,10 +103,6 @@ void common_hal_audiobusio_i2sout_deinit(audiobusio_i2sout_obj_t *self) {
|
||||
}
|
||||
self->data = NULL;
|
||||
|
||||
if (self->peripheral.instance >= 0) {
|
||||
port_i2s_reset_instance(self->peripheral.instance);
|
||||
}
|
||||
self->peripheral.instance = -1;
|
||||
}
|
||||
|
||||
void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self,
|
||||
@ -105,27 +110,27 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self,
|
||||
if (common_hal_audiobusio_i2sout_get_playing(self)) {
|
||||
common_hal_audiobusio_i2sout_stop(self);
|
||||
}
|
||||
port_i2s_play(&self->peripheral, sample, loop);
|
||||
port_i2s_play(&self->i2s, sample, loop);
|
||||
}
|
||||
|
||||
void common_hal_audiobusio_i2sout_pause(audiobusio_i2sout_obj_t *self) {
|
||||
port_i2s_pause(&self->peripheral);
|
||||
port_i2s_pause(&self->i2s);
|
||||
}
|
||||
|
||||
void common_hal_audiobusio_i2sout_resume(audiobusio_i2sout_obj_t *self) {
|
||||
port_i2s_resume(&self->peripheral);
|
||||
port_i2s_resume(&self->i2s);
|
||||
}
|
||||
|
||||
bool common_hal_audiobusio_i2sout_get_paused(audiobusio_i2sout_obj_t *self) {
|
||||
return port_i2s_paused(&self->peripheral);
|
||||
return port_i2s_paused(&self->i2s);
|
||||
}
|
||||
|
||||
void common_hal_audiobusio_i2sout_stop(audiobusio_i2sout_obj_t *self) {
|
||||
port_i2s_stop(&self->peripheral);
|
||||
port_i2s_stop(&self->i2s);
|
||||
}
|
||||
|
||||
bool common_hal_audiobusio_i2sout_get_playing(audiobusio_i2sout_obj_t *self) {
|
||||
return port_i2s_playing(&self->peripheral);
|
||||
return port_i2s_playing(&self->i2s);
|
||||
}
|
||||
|
||||
#endif // CIRCUITPY_AUDIOBUSIO_I2SOUT
|
||||
|
@ -36,7 +36,7 @@
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
i2s_t peripheral;
|
||||
i2s_t i2s;
|
||||
const mcu_pin_obj_t *bit_clock;
|
||||
const mcu_pin_obj_t *word_select;
|
||||
const mcu_pin_obj_t *data;
|
||||
|
@ -35,70 +35,26 @@
|
||||
|
||||
#include "shared-module/audiocore/__init__.h"
|
||||
|
||||
#define I2S_QUEUE_SIZE (3)
|
||||
|
||||
static i2s_t *i2s_instance[I2S_NUM_AUTO];
|
||||
static QueueHandle_t i2s_queues[I2S_NUM_AUTO];
|
||||
static TaskHandle_t i2s_tasks[I2S_NUM_AUTO];
|
||||
|
||||
void port_i2s_allocate_i2s0(void) {
|
||||
if (!i2s_instance[0]) {
|
||||
i2s_instance[0] = (void *)~(intptr_t)0;
|
||||
return;
|
||||
}
|
||||
|
||||
mp_raise_RuntimeError(translate("Peripheral in use"));
|
||||
}
|
||||
|
||||
static int8_t port_i2s_allocate(void) {
|
||||
#if defined(I2S_NUM_1)
|
||||
if (!i2s_instance[1]) {
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
if (!i2s_instance[0]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
mp_raise_RuntimeError(translate("Peripheral in use"));
|
||||
}
|
||||
|
||||
void port_i2s_reset_instance(int i) {
|
||||
assert(i >= 0 && i < I2S_NUM_AUTO);
|
||||
if (i2s_tasks[i]) {
|
||||
vTaskDelete(i2s_tasks[i]);
|
||||
}
|
||||
i2s_tasks[i] = NULL;
|
||||
|
||||
(void)i2s_driver_uninstall(i);
|
||||
i2s_instance[i] = NULL;
|
||||
}
|
||||
|
||||
void i2s_reset(void) {
|
||||
for (int i = 0; i < I2S_NUM_AUTO; i++) {
|
||||
port_i2s_reset_instance(i);
|
||||
}
|
||||
}
|
||||
|
||||
#define I2S_WRITE_DELAY pdMS_TO_TICKS(1)
|
||||
#define CIRCUITPY_BUFFER_COUNT 3
|
||||
#define CIRCUITPY_BUFFER_SIZE 1023
|
||||
#define CIRCUITPY_OUTPUT_SLOTS 2
|
||||
|
||||
static void i2s_fill_buffer(i2s_t *self) {
|
||||
if (self->instance < 0 || self->instance >= I2S_NUM_AUTO) {
|
||||
if (self->next_buffer_size == 0) {
|
||||
// Error, no new buffer queued.
|
||||
return;
|
||||
}
|
||||
#define STACK_BUFFER_SIZE (4096)
|
||||
int16_t signed_samples[STACK_BUFFER_SIZE / sizeof(int16_t)];
|
||||
|
||||
int16_t *output_buffer = (int16_t *)self->next_buffer;
|
||||
size_t output_buffer_size = self->next_buffer_size;
|
||||
const size_t bytes_per_output_frame = 4;
|
||||
size_t bytes_per_input_frame = self->channel_count * self->bytes_per_sample;
|
||||
if (!self->playing || self->paused || !self->sample || self->stopping) {
|
||||
memset(signed_samples, 0, sizeof(signed_samples));
|
||||
|
||||
size_t bytes_written = 0;
|
||||
do {
|
||||
CHECK_ESP_RESULT(i2s_write(self->instance, signed_samples, sizeof(signed_samples), &bytes_written, I2S_WRITE_DELAY));
|
||||
} while (bytes_written != 0);
|
||||
memset(output_buffer, 0, self->next_buffer_size);
|
||||
self->next_buffer = NULL;
|
||||
self->next_buffer_size = 0;
|
||||
return;
|
||||
}
|
||||
while (!self->stopping) {
|
||||
while (!self->stopping && output_buffer_size > 0) {
|
||||
if (self->sample_data == self->sample_end) {
|
||||
uint32_t sample_buffer_length;
|
||||
audioio_get_buffer_result_t get_buffer_result =
|
||||
@ -118,51 +74,45 @@ static void i2s_fill_buffer(i2s_t *self) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
size_t bytes_written = 0;
|
||||
size_t bytecount = self->sample_end - self->sample_data;
|
||||
size_t sample_bytecount = self->sample_end - self->sample_data;
|
||||
// The framecount is the minimum of space left in the output buffer or left in the incoming sample.
|
||||
size_t framecount = MIN(output_buffer_size / bytes_per_output_frame, sample_bytecount / bytes_per_input_frame);
|
||||
if (self->samples_signed && self->channel_count == 2) {
|
||||
if (self->bytes_per_sample == 2) {
|
||||
CHECK_ESP_RESULT(i2s_write(self->instance, self->sample_data, bytecount, &bytes_written, I2S_WRITE_DELAY));
|
||||
memcpy(output_buffer, self->sample_data, framecount * bytes_per_output_frame);
|
||||
} else {
|
||||
CHECK_ESP_RESULT(i2s_write_expand(self->instance, self->sample_data, bytecount, 8, 16, &bytes_written, I2S_WRITE_DELAY));
|
||||
audiosample_convert_s8s_s16s(output_buffer, ((int8_t *)self->sample_data), framecount);
|
||||
}
|
||||
} else {
|
||||
const size_t bytes_per_output_frame = 4;
|
||||
size_t bytes_per_input_frame = self->channel_count * self->bytes_per_sample;
|
||||
size_t framecount = MIN(STACK_BUFFER_SIZE / bytes_per_output_frame, bytecount / bytes_per_input_frame);
|
||||
if (self->samples_signed) {
|
||||
assert(self->channel_count == 1);
|
||||
if (self->bytes_per_sample == 1) {
|
||||
audiosample_convert_s8m_s16s(signed_samples, (int8_t *)(void *)self->sample_data, framecount);
|
||||
audiosample_convert_s8m_s16s(output_buffer, (int8_t *)(void *)self->sample_data, framecount);
|
||||
} else {
|
||||
audiosample_convert_s16m_s16s(signed_samples, (int16_t *)(void *)self->sample_data, framecount);
|
||||
audiosample_convert_s16m_s16s(output_buffer, (int16_t *)(void *)self->sample_data, framecount);
|
||||
}
|
||||
} else {
|
||||
if (self->channel_count == 1) {
|
||||
if (self->bytes_per_sample == 1) {
|
||||
audiosample_convert_u8m_s16s(signed_samples, (uint8_t *)(void *)self->sample_data, framecount);
|
||||
audiosample_convert_u8m_s16s(output_buffer, (uint8_t *)(void *)self->sample_data, framecount);
|
||||
} else {
|
||||
audiosample_convert_u16m_s16s(signed_samples, (uint16_t *)(void *)self->sample_data, framecount);
|
||||
audiosample_convert_u16m_s16s(output_buffer, (uint16_t *)(void *)self->sample_data, framecount);
|
||||
}
|
||||
} else {
|
||||
if (self->bytes_per_sample == 1) {
|
||||
audiosample_convert_u8s_s16s(signed_samples, (uint8_t *)(void *)self->sample_data, framecount);
|
||||
audiosample_convert_u8s_s16s(output_buffer, (uint8_t *)(void *)self->sample_data, framecount);
|
||||
} else {
|
||||
audiosample_convert_u16s_s16s(signed_samples, (uint16_t *)(void *)self->sample_data, framecount);
|
||||
audiosample_convert_u16s_s16s(output_buffer, (uint16_t *)(void *)self->sample_data, framecount);
|
||||
}
|
||||
}
|
||||
}
|
||||
size_t expanded_bytes_written = 0;
|
||||
CHECK_ESP_RESULT(i2s_write(self->instance, signed_samples, bytes_per_output_frame * framecount, &expanded_bytes_written, I2S_WRITE_DELAY));
|
||||
assert(expanded_bytes_written % 4 == 0);
|
||||
bytes_written = expanded_bytes_written / bytes_per_output_frame * bytes_per_input_frame;
|
||||
}
|
||||
self->sample_data += bytes_written;
|
||||
// We have filled the DMA buffer
|
||||
if (!bytes_written) {
|
||||
break;
|
||||
}
|
||||
self->sample_data += framecount * bytes_per_input_frame;
|
||||
output_buffer += framecount * CIRCUITPY_OUTPUT_SLOTS;
|
||||
output_buffer_size -= framecount * bytes_per_output_frame;
|
||||
}
|
||||
self->next_buffer = NULL;
|
||||
self->next_buffer_size = 0;
|
||||
}
|
||||
|
||||
static void i2s_callback_fun(void *self_in) {
|
||||
@ -170,39 +120,41 @@ static void i2s_callback_fun(void *self_in) {
|
||||
i2s_fill_buffer(self);
|
||||
}
|
||||
|
||||
static void i2s_event_task(void *self_in) {
|
||||
static bool i2s_event_interrupt(i2s_chan_handle_t handle, i2s_event_data_t *event, void *self_in) {
|
||||
i2s_t *self = self_in;
|
||||
while (true) {
|
||||
i2s_event_type_t event;
|
||||
BaseType_t result = xQueueReceive(i2s_queues[self->instance], &event, portMAX_DELAY);
|
||||
if (result && event == I2S_EVENT_TX_DONE) {
|
||||
self->underrun = self->underrun || self->next_buffer != NULL;
|
||||
self->next_buffer = *(int16_t **)event->data;
|
||||
self->next_buffer_size = event->size;
|
||||
background_callback_add(&self->callback, i2s_callback_fun, self_in);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void port_i2s_allocate_init(i2s_t *self, bool left_justified) {
|
||||
self->instance = port_i2s_allocate();
|
||||
|
||||
i2s_config_t i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
|
||||
.sample_rate = 44100,
|
||||
.bits_per_sample = 16,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.communication_format = left_justified ? I2S_COMM_FORMAT_STAND_I2S : I2S_COMM_FORMAT_STAND_I2S,
|
||||
.dma_buf_count = 3,
|
||||
.dma_buf_len = 1024, // in _frames_, so 1024 is 4096 bytes per dma buf
|
||||
.use_apll = false,
|
||||
i2s_chan_config_t chan_config = {
|
||||
.id = I2S_NUM_AUTO,
|
||||
.role = I2S_ROLE_MASTER,
|
||||
.dma_desc_num = CIRCUITPY_BUFFER_COUNT,
|
||||
.dma_frame_num = CIRCUITPY_BUFFER_SIZE, // in _frames_, so 1023 is 4092 bytes per dma buf which is the maximum
|
||||
};
|
||||
CHECK_ESP_RESULT(i2s_driver_install(self->instance, &i2s_config, I2S_QUEUE_SIZE, &i2s_queues[self->instance]));
|
||||
|
||||
if (!xTaskCreate(i2s_event_task, "I2S_task", 3 * configMINIMAL_STACK_SIZE, self, CONFIG_PTHREAD_TASK_PRIO_DEFAULT, &i2s_tasks[self->instance])) {
|
||||
mp_raise_OSError_msg(translate("xTaskCreate failed"));
|
||||
}
|
||||
i2s_instance[self->instance] = self;
|
||||
|
||||
esp_err_t err = i2s_new_channel(&chan_config, &self->handle, NULL);
|
||||
if (err == ESP_ERR_NOT_FOUND) {
|
||||
mp_raise_RuntimeError(translate("Peripheral in use"));
|
||||
}
|
||||
|
||||
i2s_event_callbacks_t callbacks = {
|
||||
.on_recv = NULL,
|
||||
.on_recv_q_ovf = NULL,
|
||||
.on_sent = i2s_event_interrupt,
|
||||
.on_send_q_ovf = NULL,
|
||||
};
|
||||
i2s_channel_register_event_callback(self->handle, &callbacks, self);
|
||||
}
|
||||
|
||||
void port_i2s_deinit(i2s_t *self) {
|
||||
port_i2s_stop(self);
|
||||
i2s_del_channel(self->handle);
|
||||
self->handle = NULL;
|
||||
}
|
||||
|
||||
void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop) {
|
||||
self->sample = sample;
|
||||
@ -216,9 +168,6 @@ void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop) {
|
||||
audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed,
|
||||
&max_buffer_length, &spacing);
|
||||
self->samples_signed = samples_signed;
|
||||
self->playing = true;
|
||||
self->paused = false;
|
||||
self->stopping = false;
|
||||
self->sample_data = self->sample_end = NULL;
|
||||
// We always output stereo so output twice as many bits.
|
||||
// uint16_t bits_per_sample_output = bits_per_sample * 2;
|
||||
@ -226,12 +175,32 @@ void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop) {
|
||||
audiosample_reset_buffer(self->sample, false, 0);
|
||||
|
||||
uint32_t sample_rate = audiosample_sample_rate(sample);
|
||||
if (sample_rate != self->i2s_config.sample_rate) {
|
||||
CHECK_ESP_RESULT(i2s_set_sample_rates(self->instance, audiosample_sample_rate(sample)));
|
||||
self->i2s_config.sample_rate = sample_rate;
|
||||
i2s_std_clk_config_t clk_config = I2S_STD_CLK_DEFAULT_CONFIG(sample_rate);
|
||||
CHECK_ESP_RESULT(i2s_channel_reconfig_std_clock(self->handle, &clk_config));
|
||||
|
||||
// preload the data
|
||||
self->playing = true;
|
||||
self->paused = false;
|
||||
self->stopping = false;
|
||||
// This will be slow but we can't rewind the underlying sample. So, we will
|
||||
// preload one frame at a time and drop the last sample that can't fit.
|
||||
// We cap ourselves at the max DMA set to prevent a sample drop if starting
|
||||
// fresh.
|
||||
uint32_t starting_frame;
|
||||
size_t bytes_loaded = 4;
|
||||
size_t preloaded = 0;
|
||||
while (bytes_loaded > 0 && preloaded < CIRCUITPY_BUFFER_SIZE * CIRCUITPY_BUFFER_COUNT) {
|
||||
self->next_buffer = &starting_frame;
|
||||
self->next_buffer_size = sizeof(starting_frame);
|
||||
i2s_fill_buffer(self);
|
||||
i2s_channel_preload_data(self->handle, &starting_frame, sizeof(uint32_t), &bytes_loaded);
|
||||
preloaded += 1;
|
||||
}
|
||||
|
||||
background_callback_add(&self->callback, i2s_callback_fun, self);
|
||||
// enable the channel
|
||||
i2s_channel_enable(self->handle);
|
||||
|
||||
// The IDF will call us back when there is a free DMA buffer.
|
||||
}
|
||||
|
||||
bool port_i2s_playing(i2s_t *self) {
|
||||
@ -243,8 +212,8 @@ bool port_i2s_paused(i2s_t *self) {
|
||||
}
|
||||
|
||||
void port_i2s_stop(i2s_t *self) {
|
||||
port_i2s_pause(self);
|
||||
self->sample = NULL;
|
||||
self->paused = false;
|
||||
self->playing = false;
|
||||
self->stopping = false;
|
||||
}
|
||||
@ -252,13 +221,13 @@ void port_i2s_stop(i2s_t *self) {
|
||||
void port_i2s_pause(i2s_t *self) {
|
||||
if (!self->paused) {
|
||||
self->paused = true;
|
||||
CHECK_ESP_RESULT(i2s_stop(self->instance));
|
||||
CHECK_ESP_RESULT(i2s_channel_disable(self->handle));
|
||||
}
|
||||
}
|
||||
|
||||
void port_i2s_resume(i2s_t *self) {
|
||||
if (self->paused) {
|
||||
self->paused = false;
|
||||
CHECK_ESP_RESULT(i2s_start(self->instance));
|
||||
CHECK_ESP_RESULT(i2s_channel_enable(self->handle));
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#include "supervisor/background_callback.h"
|
||||
|
||||
#include "driver/i2s.h"
|
||||
#include "driver/i2s_std.h"
|
||||
|
||||
typedef struct {
|
||||
mp_obj_t *sample;
|
||||
@ -42,23 +42,22 @@ typedef struct {
|
||||
bool samples_signed;
|
||||
int8_t bytes_per_sample;
|
||||
int8_t channel_count;
|
||||
int8_t instance;
|
||||
uint16_t buffer_length;
|
||||
uint8_t *sample_data, *sample_end;
|
||||
i2s_config_t i2s_config;
|
||||
void *next_buffer;
|
||||
size_t next_buffer_size;
|
||||
i2s_chan_handle_t handle;
|
||||
background_callback_t callback;
|
||||
bool underrun;
|
||||
} i2s_t;
|
||||
|
||||
|
||||
void port_i2s_allocate_init(i2s_t *self, bool left_justified);
|
||||
void port_i2s_reset_instance(int i);
|
||||
void i2s_reset(void);
|
||||
void port_i2s_deinit(i2s_t *self);
|
||||
|
||||
void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop);
|
||||
void port_i2s_stop(i2s_t *self);
|
||||
bool port_i2s_playing(i2s_t *self);
|
||||
bool port_i2s_paused(i2s_t *self);
|
||||
void port_i2s_pause(i2s_t *self);
|
||||
void port_i2s_resume(i2s_t *self);
|
||||
|
||||
// some uses (imagecapture) can only operate on i2s0 and need their own init code
|
||||
void port_i2s_allocate_i2s0(void);
|
||||
|
@ -28,12 +28,6 @@ CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN=y
|
||||
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
|
||||
# end of RMT Configuration
|
||||
|
||||
#
|
||||
# I2S Configuration
|
||||
#
|
||||
CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y
|
||||
# end of I2S Configuration
|
||||
|
||||
# end of Driver Configurations
|
||||
|
||||
#
|
||||
|
@ -41,12 +41,6 @@ CONFIG_BT_NIMBLE_EXT_ADV=y
|
||||
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
|
||||
# end of RMT Configuration
|
||||
|
||||
#
|
||||
# I2S Configuration
|
||||
#
|
||||
CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y
|
||||
# end of I2S Configuration
|
||||
|
||||
# end of Driver Configurations
|
||||
|
||||
#
|
||||
|
@ -41,12 +41,6 @@ CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN=y
|
||||
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
|
||||
# end of RMT Configuration
|
||||
|
||||
#
|
||||
# I2S Configuration
|
||||
#
|
||||
CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y
|
||||
# end of I2S Configuration
|
||||
|
||||
# end of Driver Configurations
|
||||
|
||||
#
|
||||
|
@ -41,12 +41,6 @@ CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN=y
|
||||
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
|
||||
# end of RMT Configuration
|
||||
|
||||
#
|
||||
# I2S Configuration
|
||||
#
|
||||
CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y
|
||||
# end of I2S Configuration
|
||||
|
||||
# end of Driver Configurations
|
||||
|
||||
#
|
||||
|
@ -19,12 +19,6 @@ CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN=y
|
||||
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
|
||||
# end of RMT Configuration
|
||||
|
||||
#
|
||||
# I2S Configuration
|
||||
#
|
||||
CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y
|
||||
# end of I2S Configuration
|
||||
|
||||
# end of Driver Configurations
|
||||
|
||||
#
|
||||
|
@ -49,12 +49,6 @@ CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN=y
|
||||
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
|
||||
# end of RMT Configuration
|
||||
|
||||
#
|
||||
# I2S Configuration
|
||||
#
|
||||
CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y
|
||||
# end of I2S Configuration
|
||||
|
||||
# end of Driver Configurations
|
||||
|
||||
#
|
||||
|
@ -13,12 +13,6 @@ CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
#
|
||||
# Driver Configurations
|
||||
#
|
||||
#
|
||||
# Legacy ADC Configuration
|
||||
#
|
||||
CONFIG_ADC_SUPPRESS_DEPRECATE_WARN=y
|
||||
# end of Legacy ADC Configuration
|
||||
|
||||
#
|
||||
# GPTimer Configuration
|
||||
#
|
||||
|
@ -1 +0,0 @@
|
||||
Subproject commit d07eb2733ca5d3379578f3952de04b4a4d188f36
|
@ -36,6 +36,7 @@ CIRCUITPY_I2CTARGET ?= 1
|
||||
CIRCUITPY_IMAGECAPTURE = 0
|
||||
CIRCUITPY_MEMORYMAP ?= 1
|
||||
CIRCUITPY_NVM ?= 1
|
||||
CIRCUITPY_PARALLELDISPLAY ?= 0 # Turn off because it uses the old I2S driver which conflicts with the new ADC driver.
|
||||
CIRCUITPY_PS2IO ?= 1
|
||||
# Disabled temporarily
|
||||
CIRCUITPY_RGBMATRIX ?= 0
|
||||
|
@ -49,7 +49,7 @@ extern const mp_obj_type_t mcu_pin_type;
|
||||
|
||||
#define NO_PIN (GPIO_NUM_NC)
|
||||
|
||||
#define NO_ADC 0
|
||||
#define NO_ADC SOC_ADC_PERIPH_NUM
|
||||
#define NO_ADC_CHANNEL SOC_ADC_MAX_CHANNEL_NUM
|
||||
|
||||
#define NO_TOUCH_CHANNEL TOUCH_PAD_MAX
|
||||
|
@ -74,10 +74,6 @@
|
||||
#include "peripherals/touch.h"
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_AUDIOBUSIO
|
||||
#include "common-hal/audiobusio/__init__.h"
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_BLEIO
|
||||
#include "shared-bindings/_bleio/__init__.h"
|
||||
#endif
|
||||
@ -388,10 +384,6 @@ void reset_port(void) {
|
||||
analogout_reset();
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_AUDIOBUSIO
|
||||
i2s_reset();
|
||||
#endif
|
||||
|
||||
#if CIRCUITPY_BUSIO
|
||||
i2c_reset();
|
||||
spi_reset();
|
||||
|
Loading…
Reference in New Issue
Block a user