Saltar al contenido principal

Manejo de los periféricos de audio de la reTerminal D1001


Introducción

Esta guía presenta cómo manejar el periférico de audio I2S en la placa de desarrollo reTerminal D1001. La arquitectura del sistema incluye tres componentes principales:

  • ESP32-P4: El procesador principal que gestiona el flujo de datos de audio y controla la configuración de los periféricos.
  • ES8311: Un códec de audio mono de bajo consumo responsable de convertir los datos digitales I2S en señales de audio analógicas.
  • PCA9535: Un expansor de E/S I2C usado para controlar el estado de habilitación del amplificador de potencia, proporcionando una expansión flexible de GPIO para el control de periféricos.

Diagrama de bloques de la arquitectura de audio

El sistema de audio utiliza una arquitectura de doble bus: el bus I2S está dedicado a la transmisión de datos de audio digital de alta velocidad, mientras que el bus I2C maneja los comandos de control de baja velocidad tanto para el códec como para el expansor de E/S.

Asignación de pines y principios

ESP32-P4 y ES8311 (datos y control de audio)

Nombre de señalPin ESP32-P4Descripción de la función
I2C_SDAGPIO20Datos en serie: Transporta comandos de configuración (volumen, frecuencia de muestreo) al ES8311.
I2C_SCLGPIO21Reloj en serie: Sincroniza las transferencias de datos I2C.
I2S_MCKGPIO33Reloj maestro: Reloj de referencia de alta frecuencia para los moduladores delta-sigma internos del códec.
I2S_BCKGPIO32Reloj de bit: Sincroniza cada bit individual del flujo de datos de audio.
I2S_WSGPIO31Selección de palabra: También conocido como LRCK, define el inicio de una nueva trama de audio y selecciona los canales Izquierdo/Derecho.
I2S_DOGPIO30Salida de datos: Transmite los datos de audio PCM digitales desde el ESP32-P4 hacia el códec.
I2S_DIGPIO11Entrada de datos: Reservado para una posible grabación de audio o loopback desde el códec.

ESP32-P4 y PCA9535RGER (expansión de GPIO)

Nombre de señalPin ESP32-P4Descripción de la función
I2C_SDAGPIO20Bus de datos I2C compartido para controlar el expansor de E/S PCA9535.
I2C_SCLGPIO21Bus de reloj I2C compartido.
EN_PAEXP_GPO11Habilitación del PA: Se asigna al pin P13 en el PCA9535. Ajustar este pin a nivel ALTO habilita el amplificador de potencia externo.

Flujo de software

Repositorio de ejemplo en GitHub

Descarga el repositorio oficial de reTerminal D1001 desde GitHub para obtener el código fuente y los controladores.


tip

Por favor navega al directorio driver_examples/01_I2SCodec dentro del repositorio para encontrar el código fuente específico y los archivos de proyecto para este ejemplo de audio.

Secuencia de ejecución de desarrollo

Paso 1. Inicializar el expansor de E/S I2C (PCA9535RGER)

El amplificador de potencia externo (PA) se controla a través del expansor PCA9535. Habilitar el PA es crucial porque, sin él, ningún sonido audible llegará a los altavoces incluso si el códec está funcionando correctamente.

static esp_err_t pca9535_write_reg(uint8_t reg, uint8_t data)
{
uint8_t write_buf[2] = {reg, data};
return i2c_master_write_to_device(1, PCA9535_I2C_ADDR, write_buf, sizeof(write_buf), 1000 / portTICK_PERIOD_MS);
}

static void pca9535_init(void)
{
int i2c_master_port = 1; // Use I2C_NUM_1
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = MISC_I2C_SDA,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = MISC_I2C_SCL,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000,
};
i2c_param_config(i2c_master_port, &conf);
i2c_driver_install(i2c_master_port, conf.mode, 0, 0, 0);

// Configure Port 0 and Port 1 as output mode (0 = output, 1 = input)
pca9535_write_reg(0x06, 0x00);
pca9535_write_reg(0x07, 0x00);

// Set P13 to HIGH to enable the Power Amplifier
pca9535_write_reg(0x02, 0x00);
pca9535_write_reg(0x03, 0x08);

ESP_LOGI(TAG, "PCA9535 initialized, P13 set to HIGH");
}

Paso 2. Configurar el controlador I2S

I2S es un protocolo de comunicación serie síncrono utilizado específicamente para transmitir audio digital. Configuramos el ESP32-P4 como Maestro I2S, lo que significa que proporciona los relojes BCLK y WS al códec.

static esp_err_t i2s_driver_init(void)
{
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM, I2S_ROLE_MASTER);
chan_cfg.auto_clear = true; // Prevents playing stale data from the buffer
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle));
i2s_std_config_t std_cfg = {
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(EXAMPLE_SAMPLE_RATE),
.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
.gpio_cfg = {
.mclk = I2S_MCK_IO,
.bclk = I2S_BCK_IO,
.ws = I2S_WS_IO,
.dout = I2S_DO_IO,
.din = I2S_DI_IO,
.invert_flags = {
.mclk_inv = false,
.bclk_inv = false,
.ws_inv = false,
},
},
};
std_cfg.clk_cfg.mclk_multiple = EXAMPLE_MCLK_MULTIPLE;

ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_handle, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_handle, &std_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
ESP_ERROR_CHECK(i2s_channel_enable(rx_handle));
return ESP_OK;
}

Paso 3. Inicializar el códec ES8311

El ES8311 debe configurarse para coincidir con los ajustes de I2S (frecuencia de muestreo, anchura de datos) definidos en el ESP32-P4. Esto se realiza a través del bus I2C. Antes de compilar el proyecto, puedes personalizar el comportamiento de audio modificando las macros en main/example_config.h:

MacroDescripciónPrincipios de configuración
EXAMPLE_SAMPLE_RATEFrecuencia de muestreo de audio (Hz)Define la frecuencia de las muestras de audio. Valores comunes son 16000 (voz) o 44100/48000 (música).
EXAMPLE_MCLK_MULTIPLERelación MCLK a LRCLKEl reloj maestro (MCLK) debe ser un múltiplo de la frecuencia de muestreo. 256 es estándar para 16 bits, pero 384 se usa a menudo para mayor precisión.
EXAMPLE_VOICE_VOLUMEVolumen de reproducciónVa de 0 a 100. Establece el nivel de salida inicial del códec ES8311.
EXAMPLE_MIC_GAINGanancia del micrófono (dB)Ajusta la sensibilidad de los micrófonos duales. Valores más altos aumentan el volumen pero pueden introducir ruido.
EXAMPLE_RECV_BUF_SIZETamaño del búfer DMAControla el tamaño de los bloques de datos procesados por el DMA. Los búferes más grandes evitan cortes, pero aumentan la latencia de audio.
static esp_err_t es8311_codec_init(void)
{
const i2c_config_t es_i2c_cfg = {
.sda_io_num = I2C_SDA_IO,
.scl_io_num = I2C_SCL_IO,
.mode = I2C_MODE_MASTER,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000,
};
i2c_param_config(I2C_NUM, &es_i2c_cfg);
i2c_driver_install(I2C_NUM, I2C_MODE_MASTER, 0, 0, 0);

es8311_handle_t es_handle = es8311_create(I2C_NUM, ES8311_ADDRRES_0);
const es8311_clock_config_t es_clk = {
.mclk_inverted = false,
.sclk_inverted = false,
.mclk_from_mclk_pin = true,
.mclk_frequency = EXAMPLE_MCLK_FREQ_HZ,
.sample_frequency = EXAMPLE_SAMPLE_RATE
};

es8311_init(es_handle, &es_clk, ES8311_RESOLUTION_16, ES8311_RESOLUTION_16);
es8311_sample_frequency_config(es_handle, EXAMPLE_SAMPLE_RATE * EXAMPLE_MCLK_MULTIPLE, EXAMPLE_SAMPLE_RATE);
es8311_voice_volume_set(es_handle, EXAMPLE_VOICE_VOLUME, NULL);
es8311_microphone_config(es_handle, false);
return ESP_OK;
}

Paso 4. Punto de entrada principal y creación de tareas

La aplicación principal inicializa los periféricos y luego delega la lógica de reproducción a una tarea dedicada de FreeRTOS.

void app_main(void)
{
pca9535_init();

if (i2s_driver_init() != ESP_OK) {
ESP_LOGE(TAG, "i2s driver init failed");
abort();
}

if (es8311_codec_init() != ESP_OK) {
ESP_LOGE(TAG, "es8311 codec init failed");
abort();
}

xTaskCreate(i2s_music, "i2s_music", 4096, NULL, 5, NULL);
}

Paso 5. Precarga de DMA y reproducción de datos

El DMA (Acceso Directo a Memoria) permite que el periférico I2S obtenga datos directamente desde la memoria sin intervención de la CPU. La precarga del búfer DMA es una técnica crítica para evitar el ruido de “chasquidos” que se produce cuando el hardware I2S comienza con un búfer vacío, causando un cambio repentino del offset de CC.

static void i2s_music(void *args)
{
esp_err_t ret = ESP_OK;
size_t bytes_write = 0;
uint8_t *data_ptr = (uint8_t *)music_pcm_start;

// Preload data to avoid initial "pop" sound
ESP_ERROR_CHECK(i2s_channel_disable(tx_handle));
ESP_ERROR_CHECK(i2s_channel_preload_data(tx_handle, data_ptr, music_pcm_end - data_ptr, &bytes_write));
data_ptr += bytes_write;

ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
while (1) {
ret = i2s_channel_write(tx_handle, data_ptr, music_pcm_end - data_ptr, &bytes_write, portMAX_DELAY);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "[music] i2s write failed");
abort();
}
data_ptr = (uint8_t *)music_pcm_start; // Loop playback
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}

Solución de problemas

P1: No hay salida de sonido del altavoz

  • Comprobar: Verifica si el amplificador de potencia (PA) está habilitado. La señal EN_PA se controla mediante el expansor de E/S PCA9535 en el pin P13. Asegúrate de que se llame a pca9535_init() y configure correctamente el registro de salida (Puerto 1, Bit 3).
  • Comprobar: Confirma las conexiones I2S y asegúrate de que se llame a la función i2s_channel_enable() para el canal TX.

P2: El audio está distorsionado o contiene ruido crepitante

  • Comprobar: Asegúrate de que la configuración del reloj I2S (MCLK, BCLK, WS) coincida con la frecuencia de muestreo de tu archivo de audio. Una discordancia en EXAMPLE_SAMPLE_RATE puede causar problemas de tono y velocidad.
  • Comprobar: Verifica que la precarga de DMA esté implementada como se muestra en el Paso 5. La precarga evita el sonido de "pop" causado por iniciar un canal con un búfer vacío.

P3: Fallo de comunicación I2C con ES8311 o PCA9535

  • Comprobar: Verifica las conexiones I2C SDA (GPIO20) y SCL (GPIO21). Asegúrate de que ningún otro periférico esté en conflicto con estos pines.
  • Comprobar: Confirma que las direcciones I2C sean correctas: 0x20 para PCA9535 y 0x18 para ES8311.

Soporte técnico y debate sobre el producto

Loading Comments...