Arduino ESP32 指南

Arduino ESP32 指南 > API > I2S

I2S

I2S - Inter-IC Sound,正确书写的 I²S 发音为“eye-squared-ess”,另一种表示法是 IIS。I²S 是一种电气串行总线接口标准,用于将数字音频设备连接在一起。

它用于在电子设备中的集成电路之间传输 PCM(脉冲编码调制)音频数据。I²S 总线将时钟和串行数据信号分开,与需要从数据流中恢复时钟的异步通信系统所需的接收器相比,接收器更简单。

尽管名称相似,但 I²S 与双向 I²C (IIC) 总线无关且不兼容。

I²S 总线至少由三条线路组成:

注意

所有线路都可以连接到几乎任何引脚,即使在运行过程中也会发生这种变化。

  • Bit clock line
    • 正式名称为“continuous serial clock (SCK)”。通常写成 “bit clock (BCLK)”。
    • 在此库函数参数 sck.
  • Word clock line
    • 正式的 “word select (WS)”。通常称为“左右时钟 (LRCLK)”或“帧同步 (FS)”。
    • 0 = 左声道,1 = 右声道
    • 在此库函数参数 ws.
  • Data line
    • 正式名称为“串行数据 (SD)”,但可以称为 SDATA、SDIN、SDOUT、DACDAT、ADCDAT 等。
    • 与在输入和输出之间使用单个数据引脚切换的 Arduino I2S 不同,ESP 核心驱动程序使用单独的数据线进行输入和输出。
    • 输出数据行称为函数参数的 dout。
    • 输入数据行称为函数参数的 din。

它还可能包括 Master clock 线:

  • Master clock  主时钟
    • 正式名称为 “master clock (MCLK)”。
    • 这不是 I2S 总线的一部分,但用于同步多个 I2S 设备。
    • 在此库函数参数 mclk 中。

注意

有关每个 ESP32 芯片的 I2S 外设的更多详细信息,请查看 ESP-IDF 文档 

I2S 配置

Master / Slave Mode  主/从模式

在 Master mode (默认) 下,器件在 ws.

在 Slave 模式下 ,器件监听连接的 pins 的 clock 信号和字选择 - 即,除非外部驱动,否则 pins 将保持低电平。目前尚不支持此模式。

Operation Modes  操作模式

作模式的设置是通过函数 begin 完成的,也是由函数参数模式设置的。

  • 在 Standard 模式下,总是有两个声音通道,即左通道和右通道,它们被称为 “插槽”。这些插槽支持 8/16/24/32 位宽的采样数据。插槽的通信格式遵循 Philips 标准。
  • 在时分多路复用模式 (TDM) 中,声音通道的数量是可变的,每个通道的宽度是固定的。
  • TX 通道的 PDM(Pulse-density Modulation)模式可以将 PCM 数据转换为 PDM 格式,该格式始终具有左右插槽。PDM TX 仅在 I2S0 上受支持,并且仅支持 16 位宽度的采样数据。它至少需要一个用于 clock 信号的 CLK pin 和一个用于数据信号的 DOUT pin 。
  • RX 通道的 PDM(Pulse-density Modulation)模式可以接收 PDM 格式的数据并将数据转换为 PCM 格式。PDM RX 仅在 I2S0 上受支持,并且仅支持 16 位宽度的采样数据。PDM RX 至少需要一个用于时钟信号的 CLK 引脚和一个用于数据信号的 DIN 引脚。

Simplex / Duplex Mode  单工/双工模式

由于时钟源不同,PDM 模式始终处于 Simplex 模式,仅使用一个数据引脚。

STD 和 TDM 模式在双工模式下工作,使用两个独立的数据引脚:

  • 功能参数的输出引脚 dout
  • 功能参数的输入引脚 din

在此模式下,驱动程序能够在每条线路上同时读取和写入,适用于对讲机或电话等应用程序。

Data Bit Width  数据位宽

这是通道样本中的位数。数据位宽由函数参数 bits_cfg 设置。当前支持的值为:

  • I2S_DATA_BIT_WIDTH_8BIT
  • I2S_DATA_BIT_WIDTH_16BIT
  • I2S_DATA_BIT_WIDTH_24BIT, requires the MCLK multiplier to be manually set to 384
    I2S_DATA_BIT_WIDTH_24BIT,需要手动将 MCLK 乘法器设置为 384
  • I2S_DATA_BIT_WIDTH_32BIT

Sample Rate  采样率

采样率由函数参数 rate 设置。它是每秒的采样数,以 Hz 为单位。

Slot Mode  插槽模式

插槽模式由功能参数 ch 设置。当前支持的值为:

  • I2S 通道插槽格式单声道。在 TX 模式的所有插槽中传输相同的数据。仅在 RX 模式的第一个插槽中接收数据。
  • I2S 声道插槽格式立体声。在 TX 模式的不同插槽中传输不同的数据。在 RX 模式的所有插槽中接收数据。

Arduino-ESP32 I2S API

初始化和取消初始化

在初始化之前,设置要使用的引脚。

begin (主模式)

使用前,请选择要使用的 pin。

bool begin(i2s_mode_t mode, uint32_t rate, i2s_data_bit_width_t bits_cfg, i2s_slot_mode_t ch, int8_t slot_mask=-1)

Parameters:  参数:

  • mode:上述作模式之一,例如 I2S_MODE_STD。
  • rate:是以 Hz 为单位的采样率,例如 16000。
  • bits_cfg:是通道样本中的位数,例如 I2S_DATA_BIT_WIDTH_16BIT。
  • ch: 是插槽模式,例如 I2S_SLOT_MODE_STEREO。
  • slot_mask: 是槽掩码,例如 0b11。此参数是可选的,默认为 -1(未使用)。

此函数将在成功时返回 true,如果失败,则返回 true。

失败时,如果设置了正确的日志级别,将打印错误消息。

end  结束

执行安全的取消初始化 - free buffers、destroy task、end driver operation 等。

void end()

Pin setup  引脚设置

设置引脚的功能将取决于作模式。

setPins 

使用标准或 TDM 模式时设置 I2S 接口的引脚。

void setPins(int8_t bclk, int8_t ws, int8_t dout, int8_t din=-1, int8_t mclk=-1)

Parameters:  参数:

  • bclk 是 bit clock pin。
  • ws 是单词 select pin。
  • dout 是数据输出引脚。如果不使用,可以设置为 -1。
  • DIN 是数据输入引脚。此参数是可选的,默认为 -1(未使用)。
  • MCLK 是 MASTER clock 引脚。此参数是可选的,默认为 -1(未使用)。

setPinsPdmTx

使用 PDM TX 模式时,设置 I2S 接口的引脚。

void setPinsPdmTx(int8_t clk, int8_t dout0, int8_t dout1=-1)

Parameters:  参数:

  • clk 是 clock pin。
  • dout0 是数据输出引脚 0。
  • DOUT1 是数据输出引脚 1。此参数是可选的,默认为 -1(未使用)。

setPinsPdmRx

使用 PDM RX 模式时,设置 I2S 接口的引脚。

void setPinsPdmRx(int8_t clk, int8_t din0, int8_t din1=-1, int8_t din2=-1, int8_t din3=-1)

Parameters:  参数:

  • clk 是 clock pin。
  • din0 是数据输入引脚 0。
  • DIN1 是数据输入引脚 1。此参数是可选的,默认为 -1(未使用)。
  • DIN2 是数据输入引脚 2。此参数是可选的,默认为 -1(未使用)。
  • DIN3 是数据输入引脚 3。此参数是可选的,默认为 -1(未使用)。

setInverted

设置在使用 standard 或 TDM 模式时哪些 pins 具有 inverted logic 。数据引脚不能反转。

void setInverted(bool bclk, bool ws, bool mclk=false)

Parameters:  参数:

  • bclk: 如果 bit clock pin 反转,则为true。否则为 False。
  • ws: 如果 word Select pin 反转,则为true,否则为 False。
  • mclk: 如果 master clock pin 反转,则为true。否则为 False。此参数是可选的,默认为 false。

setInvertedPdm

设置在使用 PDM 模式时哪些引脚具有反转逻辑。数据引脚不能反转。

void setInvertedPdm(bool clk)

Parameters:  参数:

  • clk:如果 clock pin 反转,则为 true。否则为 False。

I2S Configuration  I2S 配置

I2S 配置可以在运行期间更改。

configureTX  配置 TX

配置 I2S TX 通道。

bool configureTX(uint32_t rate, i2s_data_bit_width_t bits_cfg, i2s_slot_mode_t ch, int8_t slot_mask=-1)

Parameters:  参数:

  • rate 是以 Hz 为单位的采样率,例如 16000。
  • bits_cfg 是通道样本中的位数,例如 I2S_DATA_BIT_WIDTH_16BIT。
  • ch 是插槽模式,例如 I2S_SLOT_MODE_STEREO。
  • slot_mask 是槽掩码,例如 0b11。此参数是可选的,默认为 -1(未使用)。

此函数将在成功时返回 true,如果失败,则返回 true。

失败时,如果设置了正确的日志级别,将打印错误消息。

configureRX  配置 RX

配置 I2S RX 通道。

bool configureRX(uint32_t rate, i2s_data_bit_width_t bits_cfg, i2s_slot_mode_t ch, i2s_rx_transform_t transform=I2S_RX_TRANSFORM_NONE)

Parameters:  参数:

  • rate 是以 Hz 为单位的采样率,例如 16000。
  • bits_cfg 是通道样本中的位数,例如 I2S_DATA_BIT_WIDTH_16BIT。
  • ch 是插槽模式,例如 I2S_SLOT_MODE_STEREO。
  • transform 是变换模式,例如 I2S_RX_TRANSFORM_NONE。
    这可用于对接收的数据应用转换/转换。支持的值为:I2S_RX_TRANSFORM_NONE (无转换)、 I2S_RX_TRANSFORM_32_TO_16(从 32 位数据宽度转换为 16 位)和 I2S_RX_TRANSFORM_16_STEREO_TO_MONO (使用 16 位数据宽度时,从立体声转换为单声道)。

此函数将在成功时返回 true,如果失败,则返回 true。

失败时,如果设置了正确的日志级别,将打印错误消息。

txChan

获取 TX 通道处理程序指针。

i2s_chan_handle_t txChan()

txSampleRate  txSampleRate (交易采样率)

获取 TX 采样率。

uint32_t txSampleRate()

txDataWidth

获取 TX 数据宽度(8 位、16 位或 32 位)。

i2s_data_bit_width_t txDataWidth()

txSlotMode

获取 TX 插槽模式(立体声或单声道)。

i2s_slot_mode_t txSlotMode()

rxChan

获取 RX 通道处理程序指针。

i2s_chan_handle_t rxChan()

rxSampleRate  rxSampleRate (rx 采样率)

获取 RX 采样率。

uint32_t rxSampleRate()

rxDataWidth

获取 RX 数据宽度(8 位、16 位或 32 位)。

i2s_data_bit_width_t rxDataWidth()

rxSlotMode  rxSlotMode (rx 插槽模式)

获取 RX 插槽模式(立体声或单声道)。

i2s_slot_mode_t rxSlotMode()

I/O 操作

readBytes  读取字节

从 I2S 接口读取一定数量的数据字节。

size_t readBytes(char *buffer, size_t size)

Parameters:  参数:

  • buffer 是存储读取数据的缓冲区。缓冲区的长度必须至少为 size 字节。
  • size 是要读取的字节数。

此函数将返回读取的字节数。

read  读取

从 I2S 接口读取下一个可用字节。

int read()

此函数将返回下一个可用字节,如果没有可用数据或发生错误,则返回 -1。

write  写入

write 函数有两个版本:

第一个版本向 I2S 接口写入一定数量的数据字节。

size_t write(uint8_t *buffer, size_t size)

Parameters:  参数:

  • buffer 是包含要写入的数据的缓冲区。
  • size 是从缓冲区写入的字节数。

此函数将返回写入的字节数。

第二个版本将单个字节写入 I2S 接口。

size_t write(uint8_t d)

Parameters:  参数:

  • d 是要写入的字节。

如果写入了字节,则此函数将返回 1,如果发生错误,则返回 0。

available  可用

Get 如果有可供读取的数据。

int available()

如果有可供读取的数据 , 此函数将返回 I2S_READ_CHUNK_SIZE,如果没有,则返回 -1。

peek  获取

从 I2S 接口获取下一个可用字节,而无需将其从缓冲区中删除。当前未实现。

int peek()

此函数当前将始终返回 -1。

lastError

获取 I2S 接口上 I/O 作的最后一个错误代码。

int lastError()

recordWAV  录制 WAV

使用当前的 RX 设置将短的 PCM WAV 录制到内存中。返回必须由用户释放的缓冲区。

uint8_t * recordWAV(size_t rec_seconds, size_t * out_size)

Parameters:  参数:

  • rec_seconds 是要录制的秒数。
  • out_size 是返回的缓冲区的大小(以字节为单位)。

此函数将返回一个指针,该指针指向包含录制的 WAV 数据的缓冲区,如果发生错误,则返回 NULL。

playWAV  播放 WAV

使用当前 TX 设置从内存中播放 PCM WAV。

void playWAV(uint8_t * data, size_t len)

Parameters:  参数:

  • data 是包含 WAV 数据的缓冲区。
  • len 是缓冲区的大小(以字节为单位)。

playMP3  播放 MP3

使用当前 TX 设置从内存中播放 MP3。

bool playMP3(uint8_t *src, size_t src_len)

Parameters:  参数:

  • src 是包含 MP3 数据的缓冲区。
  • src_len 是缓冲区的大小(以字节为单位)。

此函数将在成功时返回 true,如果失败,则返回 false。

失败时,如果设置了正确的日志级别,将打印错误消息。

Sample code  示例代码

#include <ESP_I2S.h>

const int buff_size = 128;
int available_bytes, read_bytes;
uint8_t buffer[buff_size];
I2SClass I2S;

void setup() {
  I2S.setPins(5, 25, 26, 35, 0); //SCK, WS, SDOUT, SDIN, MCLK
  I2S.begin(I2S_MODE_STD, 16000, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO);
  I2S.read();
  available_bytes = I2S.available();
  if(available_bytes < buff_size) {
    read_bytes = I2S.readBytes(buffer, available_bytes);
  } else {
    read_bytes = I2S.readBytes(buffer, buff_size);
  }
  I2S.write(buffer, read_bytes);
  I2S.end();
}

void loop() {}