class I2S -- Inter-IC Sound 总线协议

I2S 类以控制器模式驱动 Inter-IC Sound (I2S) 总线——由 MCU 产生位时钟 (SCK) 和字选择时钟 (WS),并在 SD 线上交换采样数据。该驱动支持后台连续 DMA,因此 Python 端只需保证内部采样缓冲区始终有数据可用即可。不支持外设/仅接收模式。

可用于接有 I2S 外设的 STM32 OpenMV 摄像头以及 OpenMV Cam RT1062。OpenMV Cam AE3(alif 端口)上未提供。

STM32 OpenMV 摄像头上的 I2S(2)SPI(2) 共用引脚——位时钟位于 P2 (SCK),字选择位于 P3 (NSS),串行数据线遵循 SPI 数据方向约定:TX 使用 P0 (MOSI),RX 使用 P1 (MISO)。

示例——输出 (TX)。构建一个 TX 总线,以 44.1 kHz、16 位单声道采样驱动外部音频 DAC,并配备 16384 字节(16 KiB)的 DMA 后备缓冲区:

from machine import I2S, Pin

audio_out = I2S(
    2,
    sck=Pin("P2"), ws=Pin("P3"), sd=Pin("P0"),
    mode=I2S.TX,
    bits=16,
    format=I2S.MONO,
    rate=44100,
    ibuf=16384,
)

示例——输入 (RX)。构建一个 RX 总线,以 22.05 kHz、32 位立体声(左+右交错)从麦克风采集数据,并配备 16384 字节(16 KiB)的 DMA 后备缓冲区:

from machine import I2S, Pin

audio_in = I2S(
    2,
    sck=Pin("P2"), ws=Pin("P3"), sd=Pin("P1"),
    mode=I2S.RX,
    bits=32,
    format=I2S.STEREO,
    rate=22050,
    ibuf=16384,
)

传输方法可以采用三种方式使用:

阻塞式——write()readinto() 仅在操作完成后才返回:

num_written = audio_out.write(buf)   # blocks until buf is drained
num_read = audio_in.readinto(buf)    # blocks until buf is filled

非阻塞式——使用 irq() 安装回调,传输方法会立即返回。当 DMA 清空 TX 缓冲区或填满 RX 缓冲区时,回调会从 MicroPython 调度器中运行:

audio_out.irq(i2s_callback)
num_written = audio_out.write(buf)   # returns immediately

audio_in.irq(i2s_callback)
num_read = audio_in.readinto(buf)    # returns immediately

asyncio——I2S 是一个流,可以由 asyncio.StreamReader / asyncio.StreamWriter 封装:

swriter = asyncio.StreamWriter(audio_out)
swriter.write(buf)
await swriter.drain()

sreader = asyncio.StreamReader(audio_in)
num_read = await sreader.readinto(buf)

构造函数

class machine.I2S(id: int, *, sck: Pin, ws: Pin, sd: Pin, mck: Pin | None = None, mode: int, bits: int, format: int, rate: int, ibuf: int)

构造一个具有给定 id 的 I2S 对象:

  • id 标识一个特定的 I2S 总线;它与开发板和端口相关

所有端口都支持的仅关键字参数:

  • sck 是串行时钟线的引脚对象

  • ws 是字选择线的引脚对象

  • sd 是串行数据线的引脚对象

  • mck 是主时钟线的引脚对象;主时钟频率为采样率 * 256

  • mode 指定接收或发送

  • bits 指定采样大小(位),16 或 32

  • format 指定声道格式,STEREO 或 MONO

  • rate 指定音频采样率(Hz);即 ws 信号的频率

  • ibuf 指定内部缓冲区长度(字节)

对于所有端口,DMA 在后台连续运行,允许用户应用程序在内部缓冲区与 I2S 外设单元之间传输采样数据的同时执行其他操作。增大内部缓冲区可能会延长用户应用程序在发生下溢(例如 write 方法)或上溢(例如 readinto 方法)之前能够执行非 I2S 操作的时间。

方法

init(*, sck: Pin, ws: Pin, sd: Pin, mck: Pin | None = None, mode: int, bits: int, format: int, rate: int, ibuf: int) None

参数说明请参阅构造函数

deinit() None

反初始化 I2S 总线

readinto(buf: bytearray) int

将音频采样读入由 buf 指定的缓冲区。buf 必须支持缓冲区协议,例如 bytearray 或 array。"buf" 的字节序为小端。对于立体声格式,左声道采样位于右声道采样之前。对于单声道格式,使用左声道采样数据。返回读取的字节数

write(buf: bytes) int

写入 buf 中包含的音频采样。buf 必须支持缓冲区协议,例如 bytearray 或 array。"buf" 的字节序为小端。对于立体声格式,左声道采样位于右声道采样之前。对于单声道格式,采样数据会同时写入左右两个声道。返回写入的字节数

irq(handler: Callable[[I2S], None]) None

设置回调。当 buf 被清空(write 方法)或变满(readinto 方法)时会调用 handler。设置回调会将 writereadinto 方法改为非阻塞操作。handler 在 MicroPython 调度器的上下文中被调用。

static shift(*, buf: bytearray, bits: int, shift: int) None

buf 中包含的所有采样进行按位移位。bits 指定采样大小(位)。shift 指定每个采样要移位的位数。正值表示左移,负值表示右移。通常用于音量控制。每移位一位,采样音量变化 6dB。

常量

RX: int

用于将 I2S 总线的 mode 初始化为接收

TX: int

用于将 I2S 总线的 mode 初始化为发送

STEREO: int

用于将 I2S 总线的 format 初始化为立体声

MONO: int

用于将 I2S 总线的 format 初始化为单声道