I2S的应用

注意:MAX98357是否能播放PCM数据,要确保PCM的(采样率、位深度、声道数)和MAX98357一样
如果不一样者可以通过ffmpeg转换
开发流程

头文件
#include "driver/i2s.h"
i2s_pin_config_t结构体
配置 I²S 外设的引脚的结构体
typedef struct {int mck_io_num; int bck_io_num; int ws_io_num; int data_out_num; int data_in_num;
} i2s_pin_config_t;
结构体字段说明:
mck_io_num: MCLK 输出引脚(主时钟)
ESP32 只支持 GPIO0/GPIO1/GPIO3,如果不使用 MCLK 输出,可以设置为 I2S_PIN_NO_CHANGE
bck_io_num: BCK 或 SCK(Bit Clock,比特时钟)引脚号,
I2S 每传输一位数据都会在 BCK 上产生一次时钟脉冲,必填,若不连接通常设为 -1(但多数场景必需)
ws_io_num: WS、LRCK 或 LRCLK(Word Select/Left-Right Clock,左右声道选择时钟)引脚号,
用于指示当前传输的是左声道还是右声道数据,必填,典型音频 CODEC 必需。
data_out_num: 数据输出引脚号(I2S TX,MCU 向外设发送音频数据)
作为主机播放音频时需要。
不用可设为 -1。
data_in_num: 数据输入引脚号(I2S RX,MCU 从外设接收音频数据)
作为主机采集/录音时需要。
不用可设为 -1。
设置外设GPIO的引脚
esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin);
参数说明:
i2s_num:I2S 外设端口号
I2S_NUM_0
I2S_NUM_1
pin:指向 i2s_pin_config_t 的指针
返回值
- ESP_OK:设置成功。
- ESP_ERR_INVALID_ARG:参数非法(如 GPIO 不支持、端口号错误、与硬件限制不符)。
- ESP_FAIL 或其他错误码:路由失败或驱动未初始化等
i2s_driver_config_t结构体
用于配置 I2S 驱动的工作模式、采样率、数据位宽、DMA 缓冲等
typedef struct {i2s_mode_t mode; uint32_t sample_rate; i2s_bits_per_sample_t bits_per_sample; i2s_channel_fmt_t channel_format; i2s_comm_format_t communication_format; int intr_alloc_flags; int dma_buf_count; int dma_buf_len; bool use_apll; bool tx_desc_auto_clear; int fixed_mclk; i2s_mclk_multiple_t mclk_multiple; i2s_bits_per_chan_t bits_per_chan; #if SOC_I2S_SUPPORTS_TDMi2s_channel_t chan_mask; uint32_t total_chan; bool left_align; bool big_edin; bool bit_order_msb; bool skip_msk;
#endif // SOC_I2S_SUPPORTS_TDM} i2s_driver_config_t;
结构体说明:
mode:I2S 工作模式与方向、主从设置
I2S_MODE_MASTER | I2S_MODE_TX(主机发送/播放)
I2S_MODE_MASTER | I2S_MODE_RX(主机接收/录音)
sample_rate:采样率(Hz)
8000
16000
44100
48000
96000
bits_per_sample:每个通道的有效采样位数
16
24
32
channel_format:声道格式与排列方式
I2S_CHANNEL_FMT_RIGHT_LEFT(标准立体声左右通道),也可能有仅左/仅右、或多声道(TDM)场景的设置
communication_format:通信协议格式/时序兼容性
I2S 标准、左对齐、右对齐、MSB/LSB 对齐等模式标志
intr_alloc_flags:中断分配标志
ESP_INTR_FLAG_LEVELx
ESP_INTR_FLAG_IRAM
dma_buf_count:DMA 缓冲区块的数量(描述符个数
越大越平滑(降低中断频率、减小欠载/溢出风险),但占用内存更多。典型 4~16
dma_buf_len:每个 DMA 缓冲中“帧”的数量
一帧是一次 WS 周期内所有声道样本的集合
use_apll:是否使用 APLL 作为 I2S 主时钟源
tx_desc_auto_clear:在 TX 欠载(无数据可发)时是否自动清空 TX 描述符
有助于避免噪声/爆音;开启后遇到数据断流时输出静音而不是随机数据
fixed_mclk:固定 MCLK 输出频率(Hz)
若 use_apll=true 且 fixed_mclk>0,则 MCLK 固定为该值;此时 mclk_multiple 设置不再生效。
常用于对某些 CODEC 需要特定 MCLK(如 12.288 MHz、24.576 MHz)
mclk_multiple:MCLK 与采样率的倍数关系
bits_per_chan:每通道“总线传输位宽”(对齐位宽)
字段仅在芯片支持 TDM
chan_mask:使能的通道位掩码
total_chan:总通道(时隙)数
left_align:使能左对齐(Left-Justified)时序
big_edin:使能“big endian”输入模式
bit_order_msb:使能 MSB-first 位序
skip_msk:启用“跳过掩码”模式:若开启,只发送/接收已启用通道的数据;否则 DMA 缓冲中所有通道的数据都会按总通道数发送/接收
安装/初始化 I2S 驱动的函数
esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void *i2s_queue);
参数说明:
i2s_num:I2S 端口号i2s_config:指向 I2S 配置结构体的指针queue_size:若需要事件队列,设置队列容量(队列元素个数)。设置为 0 表示不创建队列i2s_queue:若需要队列,传入 QueueHandle_t* 的指针地址,用于返回创建好的队列句柄;若不需要队列,可传 NULL,或 queue_size 设为 0
返回值
- SP_OK:成功
- ESP_ERR_INVALID_ARG:参数非法(如配置超限、不支持的模式/位宽)
- ESP_ERR_NO_MEM:内存不足(DMA/队列/驱动资源申请失败)
- ESP_FAIL 或其他:初始化底层硬件失败
卸载/释放 I2S 驱动
esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num);
参数说明
i2s_num:I2S 端口号(如 I2S_NUM_0、I2S_NUM_1)
返回值
- ESP_OK:卸载成功
- ESP_ERR_INVALID_ARG:端口号非法或对应驱动未安装
- 其他错误码:底层释放失败(少见)
将音频数据写入外设设置
esp_err_t i2s_write(i2s_port_t i2s_num, const void *src, size_t size, size_t *bytes_written, TickType_t ticks_to_wait);
参数说明:
i2s_num: I2S 端口号src: 待发送的数据缓冲区指针size: 要写入的字节数src_bits: 实际写入的字节数输出指针;可为 NULL(不关心返回的写入量)bytes_written: 实际写入的字节数输出指针;可为 NULL(不关心返回的写入量)ticks_to_wait: 写入阻塞的最长 Tick 数
portMAX_DELAY:一直等到有空间
0:不阻塞,若无空间立即返回超时
pdMS_TO_TICKS(ms):按毫秒转换
返回值
- ESP_OK:调用成功。注意不代表 size 全部写入,实际写入量看 bytes_written。
- ESP_ERR_INVALID_ARG:参数非法(如 src 为 NULL、size 为 0、端口未启用 TX)
- ESP_FAIL:驱动未安装或处于错误状态
- ESP_ERR_TIMEOUT:在 ticks_to_wait 内 DMA 无可用空间(常见于非阻塞或等待时间太短)
读取音频数据
esp_err_t i2s_read(i2s_port_t i2s_num, void *dest, size_t size, size_t *bytes_read, TickType_t ticks_to_wait);
参数说明:
i2s_num: I2S 端口号(如 I2S_NUM_0、I2S_NUM_1)dest: 目标缓冲区指针,函数会将读取到的字节写入此处size: 期望读取的字节数bytes_read:实际读取到的字节数输出指针;可为 NULL(不关心实际读取量)ticks_to_wait: 阻塞等待可读数据的最长 Tick 数
portMAX_DELAY:一直等到有数据
0:非阻塞,若无数据立即返回超时
pdMS_TO_TICKS(ms):按毫秒转换
返回值
- ESP_OK:调用成功(不保证读取满 size,需查看 bytes_read)
- ESP_ERR_INVALID_ARG:参数非法(dest 为 NULL、size 为 0、端口未启用 RX 等)
- ESP_FAIL:驱动未安装或硬件状态异常
- ESP_ERR_TIMEOUT:在指定等待时间内没有足够数据可读(常见于非阻塞或等待时间过短)
