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
|
@ -147,9 +147,6 @@
|
||||||
[submodule "ports/espressif/esp-protocols"]
|
[submodule "ports/espressif/esp-protocols"]
|
||||||
path = ports/espressif/esp-protocols
|
path = ports/espressif/esp-protocols
|
||||||
url = https://github.com/espressif/esp-protocols.git
|
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"]
|
[submodule "ports/espressif/esp-camera"]
|
||||||
path = ports/espressif/esp-camera
|
path = ports/espressif/esp-camera
|
||||||
url = https://github.com/adafruit/esp32-camera.git
|
url = https://github.com/adafruit/esp32-camera.git
|
||||||
|
|
|
@ -447,10 +447,6 @@ msgstr ""
|
||||||
msgid "A hardware interrupt channel is already in use"
|
msgid "A hardware interrupt channel is already in use"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ports/espressif/common-hal/analogio/AnalogIn.c
|
|
||||||
msgid "ADC2 is being used by WiFi"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: ports/raspberrypi/common-hal/wifi/Radio.c
|
#: ports/raspberrypi/common-hal/wifi/Radio.c
|
||||||
msgid "AP could not be started"
|
msgid "AP could not be started"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -2156,11 +2152,6 @@ msgstr ""
|
||||||
msgid "Unable to allocate the heap."
|
msgid "Unable to allocate the heap."
|
||||||
msgstr ""
|
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
|
#: ports/espressif/common-hal/busio/I2C.c
|
||||||
msgid "Unable to create lock"
|
msgid "Unable to create lock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -2179,20 +2170,10 @@ msgstr ""
|
||||||
msgid "Unable to init parser"
|
msgid "Unable to init parser"
|
||||||
msgstr ""
|
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
|
#: shared-module/displayio/OnDiskBitmap.c
|
||||||
msgid "Unable to read color palette data"
|
msgid "Unable to read color palette data"
|
||||||
msgstr ""
|
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/espressif/common-hal/mdns/Server.c
|
||||||
#: ports/raspberrypi/common-hal/mdns/Server.c
|
#: ports/raspberrypi/common-hal/mdns/Server.c
|
||||||
msgid "Unable to start mDNS query"
|
msgid "Unable to start mDNS query"
|
||||||
|
@ -4207,7 +4188,8 @@ msgstr ""
|
||||||
msgid "unexpected keyword argument"
|
msgid "unexpected keyword argument"
|
||||||
msgstr ""
|
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'"
|
msgid "unexpected keyword argument '%q'"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -4364,10 +4346,6 @@ msgstr ""
|
||||||
msgid "wrong output type"
|
msgid "wrong output type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: ports/espressif/common-hal/audiobusio/__init__.c
|
|
||||||
msgid "xTaskCreate failed"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: extmod/ulab/code/scipy/signal/signal.c
|
#: extmod/ulab/code/scipy/signal/signal.c
|
||||||
msgid "zi must be an ndarray"
|
msgid "zi must be an ndarray"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
2
main.c
2
main.c
|
@ -1190,7 +1190,9 @@ void NORETURN nlr_jump_fail(void *val) {
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
static void NORETURN __fatal_error(const char *msg) {
|
static void NORETURN __fatal_error(const char *msg) {
|
||||||
|
#if CIRCUITPY_DEBUG == 0
|
||||||
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
|
reset_into_safe_mode(SAFE_MODE_HARD_FAULT);
|
||||||
|
#endif
|
||||||
while (true) {
|
while (true) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -304,17 +304,6 @@ ifneq ($(CIRCUITPY_BLEIO),0)
|
||||||
SRC_C += common-hal/_bleio/ble_events.c
|
SRC_C += common-hal/_bleio/ble_events.c
|
||||||
endif
|
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)
|
ifneq ($(CIRCUITPY_DOTCLOCKFRAMEBUFFER),0)
|
||||||
CFLAGS += -isystem esp-idf/components/esp_lcd/include
|
CFLAGS += -isystem esp-idf/components/esp_lcd/include
|
||||||
CFLAGS += -isystem esp-idf/components/esp_lcd/interface
|
CFLAGS += -isystem esp-idf/components/esp_lcd/interface
|
||||||
|
|
|
@ -4,9 +4,9 @@ CIRCUITPY_CREATION_ID = 0x00320003
|
||||||
IDF_TARGET = esp32
|
IDF_TARGET = esp32
|
||||||
|
|
||||||
CIRCUITPY_ESP_FLASH_SIZE = 8MB
|
CIRCUITPY_ESP_FLASH_SIZE = 8MB
|
||||||
CIRCUITPY_ESP_FLASH_MODE = dio
|
CIRCUITPY_ESP_FLASH_MODE = qio
|
||||||
CIRCUITPY_ESP_FLASH_FREQ = 40m
|
CIRCUITPY_ESP_FLASH_FREQ = 80m
|
||||||
|
|
||||||
CIRCUITPY_ESP_PSRAM_SIZE = 2MB
|
CIRCUITPY_ESP_PSRAM_SIZE = 2MB
|
||||||
CIRCUITPY_ESP_PSRAM_MODE = qio
|
CIRCUITPY_ESP_PSRAM_MODE = qio
|
||||||
CIRCUITPY_ESP_PSRAM_FREQ = 40m
|
CIRCUITPY_ESP_PSRAM_FREQ = 80m
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include "bindings/espidf/__init__.h"
|
||||||
#include "common-hal/analogbufio/BufferedIn.h"
|
#include "common-hal/analogbufio/BufferedIn.h"
|
||||||
#include "shared-bindings/analogbufio/BufferedIn.h"
|
#include "shared-bindings/analogbufio/BufferedIn.h"
|
||||||
#include "shared-bindings/microcontroller/Pin.h"
|
#include "shared-bindings/microcontroller/Pin.h"
|
||||||
|
@ -39,7 +40,6 @@
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "freertos/semphr.h"
|
#include "freertos/semphr.h"
|
||||||
#include "driver/adc.h"
|
|
||||||
|
|
||||||
// #define DEBUG_ANALOGBUFIO
|
// #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) {
|
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->pin = pin;
|
||||||
self->sample_rate = sample_rate;
|
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) {
|
if (pin->adc_index == NO_ADC || pin->adc_channel == NO_ADC_CHANNEL) {
|
||||||
raise_ValueError_invalid_pin();
|
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 defined(CONFIG_IDF_TARGET_ESP32)
|
||||||
if (pin->adc_index != ADC_UNIT_1) {
|
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
|
#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)
|
#if defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
/* ESP32C3 only supports alter mode */
|
/* ESP32C3 only supports alter mode */
|
||||||
*convert_mode = ADC_CONV_ALTER_UNIT;
|
*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;
|
*output_format = ADC_DIGI_OUTPUT_FORMAT_TYPE2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
common_hal_mcu_pin_claim(pin);
|
adc_continuous_handle_cfg_t adc_dma_config = {
|
||||||
|
|
||||||
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,
|
.max_store_buf_size = DMA_BUFFER_SIZE,
|
||||||
.conv_num_each_intr = NUM_SAMPLES_PER_INTERRUPT,
|
.conv_frame_size = NUM_SAMPLES_PER_INTERRUPT * SOC_ADC_DIGI_DATA_BYTES_PER_CONV
|
||||||
.adc1_chan_mask = adc1_chan_mask,
|
|
||||||
.adc2_chan_mask = adc2_chan_mask,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(DEBUG_ANALOGBUFIO)
|
#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);
|
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
|
#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) {
|
if (ESP_OK != err) {
|
||||||
stop_dma(self);
|
stop_dma(self);
|
||||||
common_hal_analogbufio_bufferedin_deinit(self);
|
CHECK_ESP_RESULT(err);
|
||||||
mp_raise_ValueError_varg(translate("Unable to initialize ADC DMA controller, ErrorCode:%d"), err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
adc_digi_configuration_t dig_cfg = {
|
adc_continuous_config_t dig_cfg = {
|
||||||
.conv_limit_en = ADC_CONV_LIMIT_EN,
|
|
||||||
.conv_limit_num = 250,
|
|
||||||
.pattern_num = NUM_ADC_CHANNELS,
|
.pattern_num = NUM_ADC_CHANNELS,
|
||||||
.sample_freq_hz = sample_rate,
|
.sample_freq_hz = sample_rate,
|
||||||
.conv_mode = *convert_mode,
|
.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);
|
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
|
#endif // DEBUG_ANALOGBUFIO
|
||||||
|
|
||||||
err = adc_digi_controller_configure(&dig_cfg);
|
err = adc_continuous_config(self->handle, &dig_cfg);
|
||||||
if (ESP_OK != err) {
|
if (ESP_OK != err) {
|
||||||
stop_dma(self);
|
stop_dma(self);
|
||||||
common_hal_analogbufio_bufferedin_deinit(self);
|
CHECK_ESP_RESULT(err);
|
||||||
mp_raise_ValueError_varg(translate("Unable to configure ADC DMA controller, ErrorCode:%d"), err);
|
|
||||||
}
|
}
|
||||||
err = adc_digi_start();
|
err = adc_continuous_start(self->handle);
|
||||||
if (ESP_OK != err) {
|
if (ESP_OK != err) {
|
||||||
stop_dma(self);
|
stop_dma(self);
|
||||||
common_hal_analogbufio_bufferedin_deinit(self);
|
CHECK_ESP_RESULT(err);
|
||||||
mp_raise_ValueError_varg(translate("Unable to start ADC DMA controller, ErrorCode:%d"), err);
|
|
||||||
}
|
}
|
||||||
|
self->started = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stop_dma(analogbufio_bufferedin_obj_t *self) {
|
static void stop_dma(analogbufio_bufferedin_obj_t *self) {
|
||||||
adc_digi_stop();
|
if (self->started) {
|
||||||
adc_digi_deinitialize();
|
adc_continuous_stop(self->handle);
|
||||||
// Release ADC Pin
|
self->started = false;
|
||||||
reset_pin_number(self->pin->number);
|
}
|
||||||
|
if (self->handle != NULL) {
|
||||||
|
adc_continuous_deinit(self->handle);
|
||||||
|
self->handle = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool common_hal_analogbufio_bufferedin_deinited(analogbufio_bufferedin_obj_t *self) {
|
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)) {
|
if (common_hal_analogbufio_bufferedin_deinited(self)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Release ADC Pin
|
||||||
|
reset_pin_number(self->pin->number);
|
||||||
self->pin = NULL;
|
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) {
|
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_samples = 0;
|
||||||
uint32_t captured_bytes = 0;
|
uint32_t captured_bytes = 0;
|
||||||
esp_err_t ret;
|
esp_err_t ret;
|
||||||
|
@ -263,7 +260,7 @@ uint32_t common_hal_analogbufio_bufferedin_readinto(analogbufio_bufferedin_obj_t
|
||||||
|
|
||||||
while (captured_bytes < len) {
|
while (captured_bytes < len) {
|
||||||
ret_num = 0;
|
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) {
|
if (ret == ESP_OK) {
|
||||||
for (uint32_t i = 0; i < ret_num; i += ADC_RESULT_BYTE) {
|
for (uint32_t i = 0; i < ret_num; i += ADC_RESULT_BYTE) {
|
||||||
|
|
|
@ -32,11 +32,15 @@
|
||||||
#include "common-hal/microcontroller/Pin.h"
|
#include "common-hal/microcontroller/Pin.h"
|
||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
|
|
||||||
|
#include "components/esp_adc/include/esp_adc/adc_continuous.h"
|
||||||
|
|
||||||
// This is the analogbufio object
|
// This is the analogbufio object
|
||||||
typedef struct {
|
typedef struct {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
const mcu_pin_obj_t *pin;
|
const mcu_pin_obj_t *pin;
|
||||||
uint32_t sample_rate;
|
uint32_t sample_rate;
|
||||||
|
adc_continuous_handle_t handle;
|
||||||
|
bool started;
|
||||||
} analogbufio_bufferedin_obj_t;
|
} analogbufio_bufferedin_obj_t;
|
||||||
|
|
||||||
#endif // MICROPY_INCLUDED_ESP32_COMMON_HAL_ANALOGBUFIO_BUFFEREDIN_H
|
#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) {
|
void analogout_reset(void) {
|
||||||
#ifdef SOC_DAC_SUPPORTED
|
#ifdef SOC_DAC_SUPPORTED
|
||||||
for (uint8_t c = 0; c < SOC_DAC_CHAN_NUM; c++) {
|
for (uint8_t c = 0; c < SOC_DAC_CHAN_NUM; c++) {
|
||||||
dac_oneshot_del_channel(_active_handles[c]);
|
if (_active_handles[c] != NULL) {
|
||||||
|
dac_oneshot_del_channel(_active_handles[c]);
|
||||||
|
}
|
||||||
_active_handles[c] = NULL;
|
_active_handles[c] = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
#include "shared-bindings/microcontroller/Pin.h"
|
#include "shared-bindings/microcontroller/Pin.h"
|
||||||
#include "supervisor/shared/translate/translate.h"
|
#include "supervisor/shared/translate/translate.h"
|
||||||
|
|
||||||
#include "driver/i2s.h"
|
#include "driver/i2s_std.h"
|
||||||
|
|
||||||
// Caller validates that pins are free.
|
// Caller validates that pins are free.
|
||||||
void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self,
|
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) {
|
if (main_clock != NULL) {
|
||||||
mp_raise_NotImplementedError_varg(translate("%q"), MP_QSTR_main_clock);
|
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 = {
|
i2s_std_config_t i2s_config = {
|
||||||
.bck_io_num = bit_clock->number,
|
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(48000),
|
||||||
.ws_io_num = word_select->number,
|
.slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
|
||||||
.data_out_num = data->number,
|
.gpio_cfg = {
|
||||||
.data_in_num = I2S_PIN_NO_CHANGE,
|
.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->bit_clock = bit_clock;
|
||||||
self->word_select = word_select;
|
self->word_select = word_select;
|
||||||
self->data = data;
|
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) {
|
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) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
common_hal_audiobusio_i2sout_stop(self);
|
||||||
|
|
||||||
|
port_i2s_deinit(&self->i2s);
|
||||||
|
|
||||||
if (self->bit_clock) {
|
if (self->bit_clock) {
|
||||||
reset_pin_number(self->bit_clock->number);
|
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;
|
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,
|
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)) {
|
if (common_hal_audiobusio_i2sout_get_playing(self)) {
|
||||||
common_hal_audiobusio_i2sout_stop(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) {
|
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) {
|
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) {
|
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) {
|
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) {
|
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
|
#endif // CIRCUITPY_AUDIOBUSIO_I2SOUT
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
mp_obj_base_t base;
|
mp_obj_base_t base;
|
||||||
i2s_t peripheral;
|
i2s_t i2s;
|
||||||
const mcu_pin_obj_t *bit_clock;
|
const mcu_pin_obj_t *bit_clock;
|
||||||
const mcu_pin_obj_t *word_select;
|
const mcu_pin_obj_t *word_select;
|
||||||
const mcu_pin_obj_t *data;
|
const mcu_pin_obj_t *data;
|
||||||
|
|
|
@ -35,70 +35,26 @@
|
||||||
|
|
||||||
#include "shared-module/audiocore/__init__.h"
|
#include "shared-module/audiocore/__init__.h"
|
||||||
|
|
||||||
#define I2S_QUEUE_SIZE (3)
|
#define CIRCUITPY_BUFFER_COUNT 3
|
||||||
|
#define CIRCUITPY_BUFFER_SIZE 1023
|
||||||
static i2s_t *i2s_instance[I2S_NUM_AUTO];
|
#define CIRCUITPY_OUTPUT_SLOTS 2
|
||||||
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)
|
|
||||||
|
|
||||||
static void i2s_fill_buffer(i2s_t *self) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
#define STACK_BUFFER_SIZE (4096)
|
int16_t *output_buffer = (int16_t *)self->next_buffer;
|
||||||
int16_t signed_samples[STACK_BUFFER_SIZE / sizeof(int16_t)];
|
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) {
|
if (!self->playing || self->paused || !self->sample || self->stopping) {
|
||||||
memset(signed_samples, 0, sizeof(signed_samples));
|
memset(output_buffer, 0, self->next_buffer_size);
|
||||||
|
self->next_buffer = NULL;
|
||||||
size_t bytes_written = 0;
|
self->next_buffer_size = 0;
|
||||||
do {
|
|
||||||
CHECK_ESP_RESULT(i2s_write(self->instance, signed_samples, sizeof(signed_samples), &bytes_written, I2S_WRITE_DELAY));
|
|
||||||
} while (bytes_written != 0);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while (!self->stopping) {
|
while (!self->stopping && output_buffer_size > 0) {
|
||||||
if (self->sample_data == self->sample_end) {
|
if (self->sample_data == self->sample_end) {
|
||||||
uint32_t sample_buffer_length;
|
uint32_t sample_buffer_length;
|
||||||
audioio_get_buffer_result_t get_buffer_result =
|
audioio_get_buffer_result_t get_buffer_result =
|
||||||
|
@ -118,51 +74,45 @@ static void i2s_fill_buffer(i2s_t *self) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size_t bytes_written = 0;
|
size_t sample_bytecount = self->sample_end - self->sample_data;
|
||||||
size_t 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->samples_signed && self->channel_count == 2) {
|
||||||
if (self->bytes_per_sample == 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 {
|
} 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 {
|
} 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) {
|
if (self->samples_signed) {
|
||||||
assert(self->channel_count == 1);
|
assert(self->channel_count == 1);
|
||||||
if (self->bytes_per_sample == 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 {
|
} 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 {
|
} else {
|
||||||
if (self->channel_count == 1) {
|
if (self->channel_count == 1) {
|
||||||
if (self->bytes_per_sample == 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 {
|
} 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 {
|
} else {
|
||||||
if (self->bytes_per_sample == 1) {
|
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 {
|
} 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) {
|
static void i2s_callback_fun(void *self_in) {
|
||||||
|
@ -170,39 +120,41 @@ static void i2s_callback_fun(void *self_in) {
|
||||||
i2s_fill_buffer(self);
|
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;
|
i2s_t *self = self_in;
|
||||||
while (true) {
|
self->underrun = self->underrun || self->next_buffer != NULL;
|
||||||
i2s_event_type_t event;
|
self->next_buffer = *(int16_t **)event->data;
|
||||||
BaseType_t result = xQueueReceive(i2s_queues[self->instance], &event, portMAX_DELAY);
|
self->next_buffer_size = event->size;
|
||||||
if (result && event == I2S_EVENT_TX_DONE) {
|
background_callback_add(&self->callback, i2s_callback_fun, self_in);
|
||||||
background_callback_add(&self->callback, i2s_callback_fun, self_in);
|
return false;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void port_i2s_allocate_init(i2s_t *self, bool left_justified) {
|
void port_i2s_allocate_init(i2s_t *self, bool left_justified) {
|
||||||
self->instance = port_i2s_allocate();
|
i2s_chan_config_t chan_config = {
|
||||||
|
.id = I2S_NUM_AUTO,
|
||||||
i2s_config_t i2s_config = {
|
.role = I2S_ROLE_MASTER,
|
||||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
|
.dma_desc_num = CIRCUITPY_BUFFER_COUNT,
|
||||||
.sample_rate = 44100,
|
.dma_frame_num = CIRCUITPY_BUFFER_SIZE, // in _frames_, so 1023 is 4092 bytes per dma buf which is the maximum
|
||||||
.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,
|
|
||||||
};
|
};
|
||||||
CHECK_ESP_RESULT(i2s_driver_install(self->instance, &i2s_config, I2S_QUEUE_SIZE, &i2s_queues[self->instance]));
|
esp_err_t err = i2s_new_channel(&chan_config, &self->handle, NULL);
|
||||||
|
if (err == ESP_ERR_NOT_FOUND) {
|
||||||
if (!xTaskCreate(i2s_event_task, "I2S_task", 3 * configMINIMAL_STACK_SIZE, self, CONFIG_PTHREAD_TASK_PRIO_DEFAULT, &i2s_tasks[self->instance])) {
|
mp_raise_RuntimeError(translate("Peripheral in use"));
|
||||||
mp_raise_OSError_msg(translate("xTaskCreate failed"));
|
|
||||||
}
|
}
|
||||||
i2s_instance[self->instance] = self;
|
|
||||||
|
|
||||||
|
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) {
|
void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop) {
|
||||||
self->sample = sample;
|
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,
|
audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed,
|
||||||
&max_buffer_length, &spacing);
|
&max_buffer_length, &spacing);
|
||||||
self->samples_signed = samples_signed;
|
self->samples_signed = samples_signed;
|
||||||
self->playing = true;
|
|
||||||
self->paused = false;
|
|
||||||
self->stopping = false;
|
|
||||||
self->sample_data = self->sample_end = NULL;
|
self->sample_data = self->sample_end = NULL;
|
||||||
// We always output stereo so output twice as many bits.
|
// We always output stereo so output twice as many bits.
|
||||||
// uint16_t bits_per_sample_output = bits_per_sample * 2;
|
// 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);
|
audiosample_reset_buffer(self->sample, false, 0);
|
||||||
|
|
||||||
uint32_t sample_rate = audiosample_sample_rate(sample);
|
uint32_t sample_rate = audiosample_sample_rate(sample);
|
||||||
if (sample_rate != self->i2s_config.sample_rate) {
|
i2s_std_clk_config_t clk_config = I2S_STD_CLK_DEFAULT_CONFIG(sample_rate);
|
||||||
CHECK_ESP_RESULT(i2s_set_sample_rates(self->instance, audiosample_sample_rate(sample)));
|
CHECK_ESP_RESULT(i2s_channel_reconfig_std_clock(self->handle, &clk_config));
|
||||||
self->i2s_config.sample_rate = sample_rate;
|
|
||||||
|
// 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) {
|
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) {
|
void port_i2s_stop(i2s_t *self) {
|
||||||
|
port_i2s_pause(self);
|
||||||
self->sample = NULL;
|
self->sample = NULL;
|
||||||
self->paused = false;
|
|
||||||
self->playing = false;
|
self->playing = false;
|
||||||
self->stopping = false;
|
self->stopping = false;
|
||||||
}
|
}
|
||||||
|
@ -252,13 +221,13 @@ void port_i2s_stop(i2s_t *self) {
|
||||||
void port_i2s_pause(i2s_t *self) {
|
void port_i2s_pause(i2s_t *self) {
|
||||||
if (!self->paused) {
|
if (!self->paused) {
|
||||||
self->paused = true;
|
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) {
|
void port_i2s_resume(i2s_t *self) {
|
||||||
if (self->paused) {
|
if (self->paused) {
|
||||||
self->paused = false;
|
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 "supervisor/background_callback.h"
|
||||||
|
|
||||||
#include "driver/i2s.h"
|
#include "driver/i2s_std.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
mp_obj_t *sample;
|
mp_obj_t *sample;
|
||||||
|
@ -42,23 +42,22 @@ typedef struct {
|
||||||
bool samples_signed;
|
bool samples_signed;
|
||||||
int8_t bytes_per_sample;
|
int8_t bytes_per_sample;
|
||||||
int8_t channel_count;
|
int8_t channel_count;
|
||||||
int8_t instance;
|
|
||||||
uint16_t buffer_length;
|
uint16_t buffer_length;
|
||||||
uint8_t *sample_data, *sample_end;
|
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;
|
background_callback_t callback;
|
||||||
|
bool underrun;
|
||||||
} i2s_t;
|
} i2s_t;
|
||||||
|
|
||||||
|
|
||||||
void port_i2s_allocate_init(i2s_t *self, bool left_justified);
|
void port_i2s_allocate_init(i2s_t *self, bool left_justified);
|
||||||
void port_i2s_reset_instance(int i);
|
void port_i2s_deinit(i2s_t *self);
|
||||||
void i2s_reset(void);
|
|
||||||
void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop);
|
void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop);
|
||||||
void port_i2s_stop(i2s_t *self);
|
void port_i2s_stop(i2s_t *self);
|
||||||
bool port_i2s_playing(i2s_t *self);
|
bool port_i2s_playing(i2s_t *self);
|
||||||
bool port_i2s_paused(i2s_t *self);
|
bool port_i2s_paused(i2s_t *self);
|
||||||
void port_i2s_pause(i2s_t *self);
|
void port_i2s_pause(i2s_t *self);
|
||||||
void port_i2s_resume(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
|
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
|
||||||
# end of RMT Configuration
|
# end of RMT Configuration
|
||||||
|
|
||||||
#
|
|
||||||
# I2S Configuration
|
|
||||||
#
|
|
||||||
CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y
|
|
||||||
# end of I2S Configuration
|
|
||||||
|
|
||||||
# end of Driver Configurations
|
# end of Driver Configurations
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -41,12 +41,6 @@ CONFIG_BT_NIMBLE_EXT_ADV=y
|
||||||
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
|
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
|
||||||
# end of RMT Configuration
|
# end of RMT Configuration
|
||||||
|
|
||||||
#
|
|
||||||
# I2S Configuration
|
|
||||||
#
|
|
||||||
CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y
|
|
||||||
# end of I2S Configuration
|
|
||||||
|
|
||||||
# end of Driver Configurations
|
# end of Driver Configurations
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -41,12 +41,6 @@ CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN=y
|
||||||
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
|
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
|
||||||
# end of RMT Configuration
|
# end of RMT Configuration
|
||||||
|
|
||||||
#
|
|
||||||
# I2S Configuration
|
|
||||||
#
|
|
||||||
CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y
|
|
||||||
# end of I2S Configuration
|
|
||||||
|
|
||||||
# end of Driver Configurations
|
# end of Driver Configurations
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -41,12 +41,6 @@ CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN=y
|
||||||
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
|
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
|
||||||
# end of RMT Configuration
|
# end of RMT Configuration
|
||||||
|
|
||||||
#
|
|
||||||
# I2S Configuration
|
|
||||||
#
|
|
||||||
CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y
|
|
||||||
# end of I2S Configuration
|
|
||||||
|
|
||||||
# end of Driver Configurations
|
# end of Driver Configurations
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -19,12 +19,6 @@ CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN=y
|
||||||
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
|
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
|
||||||
# end of RMT Configuration
|
# end of RMT Configuration
|
||||||
|
|
||||||
#
|
|
||||||
# I2S Configuration
|
|
||||||
#
|
|
||||||
CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y
|
|
||||||
# end of I2S Configuration
|
|
||||||
|
|
||||||
# end of Driver Configurations
|
# end of Driver Configurations
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -49,12 +49,6 @@ CONFIG_PCNT_SUPPRESS_DEPRECATE_WARN=y
|
||||||
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
|
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
|
||||||
# end of RMT Configuration
|
# end of RMT Configuration
|
||||||
|
|
||||||
#
|
|
||||||
# I2S Configuration
|
|
||||||
#
|
|
||||||
CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y
|
|
||||||
# end of I2S Configuration
|
|
||||||
|
|
||||||
# end of Driver Configurations
|
# end of Driver Configurations
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -13,12 +13,6 @@ CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||||
#
|
#
|
||||||
# Driver Configurations
|
# Driver Configurations
|
||||||
#
|
#
|
||||||
#
|
|
||||||
# Legacy ADC Configuration
|
|
||||||
#
|
|
||||||
CONFIG_ADC_SUPPRESS_DEPRECATE_WARN=y
|
|
||||||
# end of Legacy ADC Configuration
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# GPTimer Configuration
|
# GPTimer Configuration
|
||||||
#
|
#
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit d07eb2733ca5d3379578f3952de04b4a4d188f36
|
|
|
@ -36,6 +36,7 @@ CIRCUITPY_I2CTARGET ?= 1
|
||||||
CIRCUITPY_IMAGECAPTURE = 0
|
CIRCUITPY_IMAGECAPTURE = 0
|
||||||
CIRCUITPY_MEMORYMAP ?= 1
|
CIRCUITPY_MEMORYMAP ?= 1
|
||||||
CIRCUITPY_NVM ?= 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
|
CIRCUITPY_PS2IO ?= 1
|
||||||
# Disabled temporarily
|
# Disabled temporarily
|
||||||
CIRCUITPY_RGBMATRIX ?= 0
|
CIRCUITPY_RGBMATRIX ?= 0
|
||||||
|
|
|
@ -49,7 +49,7 @@ extern const mp_obj_type_t mcu_pin_type;
|
||||||
|
|
||||||
#define NO_PIN (GPIO_NUM_NC)
|
#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_ADC_CHANNEL SOC_ADC_MAX_CHANNEL_NUM
|
||||||
|
|
||||||
#define NO_TOUCH_CHANNEL TOUCH_PAD_MAX
|
#define NO_TOUCH_CHANNEL TOUCH_PAD_MAX
|
||||||
|
|
|
@ -74,10 +74,6 @@
|
||||||
#include "peripherals/touch.h"
|
#include "peripherals/touch.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CIRCUITPY_AUDIOBUSIO
|
|
||||||
#include "common-hal/audiobusio/__init__.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CIRCUITPY_BLEIO
|
#if CIRCUITPY_BLEIO
|
||||||
#include "shared-bindings/_bleio/__init__.h"
|
#include "shared-bindings/_bleio/__init__.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -388,10 +384,6 @@ void reset_port(void) {
|
||||||
analogout_reset();
|
analogout_reset();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CIRCUITPY_AUDIOBUSIO
|
|
||||||
i2s_reset();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CIRCUITPY_BUSIO
|
#if CIRCUITPY_BUSIO
|
||||||
i2c_reset();
|
i2c_reset();
|
||||||
spi_reset();
|
spi_reset();
|
||||||
|
|
Loading…
Reference in New Issue