跳转至

I2S 核心库

作者:梁健

一、概述

I2S(Inter-IC Sound,集成电路间音频总线)是由飞利浦(Philips) 于 1986 年制定的串行音频传输标准,专门用于解决数字音频设备(如 MCU、DSP、DAC、ADC、Codec 等)之间的高效、低干扰音频数据传输问题。它通过分离 “数据信号” 与 “时钟信号”,避免了通用总线(如 I2C、SPI)在音频传输中易出现的时序抖动(Jitter) 问题,是嵌入式音频系统中最常用的接口之一。

合宙的模块的音频接口中,有 I2S_BCLK、I2S_LRCK、I2S_DIN、I2S_DOUT、I2S_MCLK 是常见的信号管脚,它们的含义和作用如下:

  1. I2S_BCLK(Bit Clock,位时钟)

  2. 含义:也称为串行时钟(Serial Clock,SCK),是数字音频传输中的基础时钟信号。

  3. 作用:用于同步每一位音频数据的传输节奏。每传输 1 位二进制数据(0 或 1),BCLK 就会产生 1 个时钟脉冲。例如,传输 16 位音频数据时,需要 16 个 BCLK 脉冲;传输 24 位数据时,需要 24 个 BCLK 脉冲。
  4. 关键:BCLK 的频率 = 音频采样率 × 位深 × 声道数(如 44.1kHz 采样率、16 位深、立体声时,BCLK = 44100 × 16 × 2 = 1.4112MHz)。

  5. I2S_LRCK(Left/Right Clock,左右声道时钟)

  6. 含义:也称为字选择线(Word Select,WS),用于区分左声道和右声道的音频数据。

  7. 作用:通过电平高低标识当前传输的是左声道还是右声道数据:

  8. 通常高电平表示左声道,低电平表示右声道(可通过芯片配置调整);

  9. 每个声道的一组完整数据(如 16 位 / 24 位)对应 LRCK 的一个电平周期,其频率等于音频采样率(如 44.1kHz 采样率时,LRCK 频率为 44.1kHz)。

  10. I2S_DIN(Data In,数据输入)

  11. 含义:串行数据输入线。

  12. 作用:用于接收外部设备传输过来的数字音频数据(如 PCM 格式),数据在 BCLK 和 LRCK 的同步下,按位依次传入芯片(如 DAC 解码器从 DIN 接收数据,再转换为模拟音频)。

  13. I2S_DOUT(Data Out,数据输出)

  14. 含义:串行数据输出线。

  15. 作用:用于向外部设备发送数字音频数据。例如,ADC 编码器将模拟音频转换为数字信号后,通过 DOUT 输出给 MCU 或其他处理设备,数据同样在 BCLK 和 LRCK 的同步下传输。

  16. I2S_MCLK(Master Clock,主时钟)

  17. 含义:也称为系统时钟(System Clock),是音频系统的基准时钟。

  18. 作用:为整个音频传输链路提供时钟参考,确保各设备(如 Codec、DAC、ADC)的工作节奏一致,减少因时钟偏差导致的音质失真(如噪声、失真)。
  19. 特点:频率通常是采样率的整数倍(例如 44.1kHz 采样率时,256×MCLK = 44100 × 256 = 11.2896MHz)。

二、核心示例

1、核心示例是指:使用本库文件提供的核心 API,开发的基础业务逻辑的演示代码;

2、核心示例的作用是:帮助开发者快速理解如何使用本库,所以核心示例的逻辑都比较简单;

-- 录音
-- i2s数据接收buffer
local rx_buff = zbuff.create(320000)
-- i2s数据接收回调
local function record_cb(id, buff)
    if buff then
        log.info("I2S", id, "接收了", rx_buff:used())
        i2s.stop(i2s_id)    
     end
end
i2s.setup(0, 0, 8000, 16, 1, i2s.MODE_I2S)            -- 开启i2s
i2s.on(0, record_cb)                               -- 注册i2s接收回调
i2s.recv(0, rx_buff, 3200)
i2c.send(i2c_id, es8311_address, {0x00, 0xc0}, 1)
sys.wait(6000)
i2c.send(i2c_id, es8311_address, {0x00, 0x80}, 1)           -- ES8311停止录音
sys.wait(6000)
i2c.send(i2c_id, es8311_address, {0x00, 0x80}, 1)           -- ES8311停止录音
log.info("录音5秒结束")
io.writeFile(recordPath, "#!AMR\n")                 -- 向文件写入amr文件标识数据

if rx_buff:len()  then
    io.writeFile(recordPath, amr_buff:query(), "a+b")   -- 向文件写入编码后的amr数据
else
    log.info("--------------> buff nil")
end

三、常量详解

核心库常量,顾名思义是由合宙 LuatOS 内核固件中定义的、不可重新赋值或修改的固定值,在脚本代码中不需要声明,可直接调用;

常量 类型 解释 参数示例
i2s.MODE_I2S number I2S 标准格式 i2s.setup(0, 0, 8000, 16, 1, i2s.MODE_I2S) -- 开启i2s。传输数据从最高位开始传输
i2s.MODE_LSB number LSB 优先格式,数字音频数据的传输顺序从 “最低位” 开始 i2s.setup(0, 0, 8000, 16, 1, i2s.MODE_LSB) -- 开启i2s,传输数据从最低位开始传输
i2s.MODE_MSB number MSB 优先格式,数字音频数据的传输顺序从 “最高位” 开始 i2s.setup(0, 0, 8000, 16, 1, i2s.MODE_MSB) -- 开启i2s,,传输数据从最高位开始传输

四、函数详解

4.1 i2s.setup(id, mode, sample, bitw, channel, format, framebit)

功能

初始化 I2S

参数

id

参数含义:I2S的通道号
数据类型:number
取值范围:0
是否必选:必须传入此参数;
注意事项:仅支持0
参数示例:0,通道0 

mode

参数含义:主从模式;
数据类型:number
取值范围:01
是否必选:非必须传入此参数;
注意事项:0为主机模式,1为从机模式,默认为主模式;
参数示例:0,开启主机模式;

sample

参数含义:采样率;
数据类型:number
取值范围:8000,16000,24000,32000,48000,20050,44100
是否必选:非必须传入此参数;
注意事项:默认44100
参数示例:16000,使用每秒16000的采样率进行音频采样;

bitw

参数含义:采样位深;
数据类型:number
取值范围:81624
是否必选:非必须传入此参数;
注意事项:默认使用16
参数示例:16,每次采样使用16位存放模拟量;

channel

参数含义:声道;
数据类型:number
取值范围:1
是否必选:必须传入此参数;
注意事项:仅支持单声道
参数示例:1,使用单声道录音;

format

参数含义:通讯格式;
数据类型:number
取值范围:i2s.MODE_I2Si2s.MODE_LSBi2s.MODE_MSB
是否必选:非必须传入此参数;
注意事项:需要根据实际的芯片支持的格式设置,比如ES8311 支持的是i2s.MODE_I2S
参数示例:i2s.MODE_I2S,使用标准I2S 协议通信;

framebit

参数含义:i2s通道数据位数
数据类型:number
取值范围:1632
是否必选:非必须传入此参数;
注意事项:默认为16,根据具体的音频编解码芯片要求设置
参数示例:16,数据通道位数为16位;

返回值

成功 true, 失败 false

示例

i2s.setup(0, 0, 8000, 16, 1, i2s.MODE_I2S16)           -- 开启i2s

4.2 i2s.send(id, data, len)

功能

发送 I2S 数据

参数

id

参数含义:I2S的通道号
数据类型:number
取值范围:0
是否必选:必须传入此参数;
注意事项:仅支持0
参数示例:0,通道0 

data

参数含义:需要发送的数据;
数据类型:string或者zbuff
取值范围:无;
是否必选:必须传入此参数;
注意事项:数据, 可以是字符串或zbuff
参数示例:"xxx",发送xxx 的数据 

len

参数含义:数据长度,单位字节;
数据类型:number
取值范围:大于等于0
是否必选:非必须传入此参数;
注意事项:
        1. data 为字符串,可以不传入此参数
            1.1 如果没有传入此值,或者此值为nil,则表示data字符串长度
            1.2 如果传入此值,则表示发送data 的长度,单位为字节
        2. data zbuff,必须传入此参数
            2.1 如果值小于zbuff 实际长度,则表示发送的实际数据长度(发送位置从zbuff起始位置开始)
            2.2 如果值大于或者等于zbuff 实际长度,将zbuff 所有的数据全部发送
参数示例:3,需要传输的长度为3 

返回值

成功 true, 失败 false

示例

local f = io.open("/luadb/abc.wav")
while 1 do
    local data = f:read(4096)
    if not data or #data == 0 then
        break
    end
    i2s.send(0, data)
    sys.wait(100)
end

4.3 i2s.recv(id, buffer, len)

功能

接收 i2s 数据

参数

id

参数含义:I2S的通道号
数据类型:number
取值范围:0
是否必选:必须传入此参数;
注意事项:仅支持0
参数示例:0,通道0 

buffer

参数含义:数据缓存区;
数据类型:zbuff
取值范围:0
是否必选:必须传入此参数;
注意事项:接受的I2S数据,会存在此处;
参数示例:无;

len

参数含义:单次返回的数据长度;
数据类型:number
取值范围:0
是否必选:必须传入此参数;
注意事项:需要和buffer zbuff 的大小保持一致;
参数示例:5,单次返回的数据长度为5

返回值

成功 true, 失败 false

示例

local buffer = zbuff.create(3200)
local succ = i2s.recv(0, buffer, 3200);

4.4 i2s.close(id)

功能

关闭 i2s

参数

id

参数含义:I2S的通道号
数据类型:number
取值范围:0
是否必选:必须传入此参数;
注意事项:仅支持0
参数示例:0,通道0 

返回值

示例

i2s.close(0)

4.5 i2s.on(id, func)

功能

注册 I2S 事件回调

参数

id

参数含义:I2S的通道号
数据类型:number
取值范围:0
是否必选:必须传入此参数;
注意事项:仅支持0
参数示例:0,通道0 

function

参数含义:回调函数,回调函数参数详细说明如下:
{
         --id
        -- 参数含义:I2S的通道号;
        -- 数据类型:number;
        -- 取值范围:0;
        -- 是否必选:必须传入此参数;
        -- 注意事项:仅支持0;
        -- 参数示例:0,通道0 ;

         --buff
         --参数含义:标识当前的发送或者接受数据情况;
         --数据类型:boolean;
         --取值范围:true 或者 false;
         --是否必选:是;
         --注意事项:
         -- 1. 当buff 为 true 的时候,表示收到数据,收到的数据存放在i2s.recv 的buffer 里面
         -- 2. 当buff 为 false 的时候,表示发送数据完毕
         --参数示例:true 表示收到数据;
}

数据类型:function
是否必选:是
注意事项:无
参数示例:
        local i2s_callback(id, buff)
            if buff then
                log.info("i2s get data in zbuff")
            else
                log.info("i2s tx one block done")
            end
        end

返回值

示例

local i2s_callback(id, buff)
    if buff then
        log.info("i2s get data in zbuff")
    else
        log.info("i2s tx one block done")
    end
end

i2s.on(0, i2s_callback)

4.6 i2s.txStat(id)

功能

获取 i2s 的发送缓冲区状态

参数

id

参数含义:I2S的通道号
数据类型:number
取值范围:0
是否必选:必须传入此参数;
注意事项:仅支持0
参数示例:0,通道0 

返回值

local max, remain = i2s.txStat(0)

max

参数含义:底层发送缓冲区可用空间总大小,单位为字节;
数据类型:number
取值范围:大于等于0
是否必选:必须接收此参数;
注意事项:
        1. 如果小于2倍的remain,则需等待100ms 后再次判断,一直等到大于2倍的remain(待发送的数据长度),才可以继续进行数据发送;
参数示例:0,底层缓冲区大小为0 

remain

参数含义:待发送的数据长度,单位为字节;
数据类型:number
取值范围:大于等于0
是否必选:必须接收此参数;
注意事项:无;
参数示例:100,待发送的数据长度还剩下。100个字节;

示例

-- 读取发送缓冲区的状态, 从而判断是否需要继续传入音频数据
local max, remain = i2s.txStat(0)
log.info("i2s发送缓冲区状态", max, remain)

4.7 i2s.getPara(id)

功能

获取 I2S 参数,参数具体参考 setup

参数

id

参数含义:I2S的通道号
数据类型:number
取值范围:0
是否必选:必须传入此参数;
注意事项:仅支持0
参数示例:0,通道0 

返回值

work_state,mode,sample,bitw,channel,format,formatbit =i2s.getPara(0)

work_state

参数含义:是否在工作状态;
数据类型:boolean
取值范围:true 或者 false
是否必选:必须接收此参数;
注意事项:true 表示当前已经初始化了I2S(i2s.setup)false 表示还未初始化;
参数示例:true,未初始化I2S 

mode

参数含义:主从模式;
数据类型:number
取值范围:01
是否必选:必须接收此参数;
注意事项:0为主机模式,1为表示从机模式;
参数示例:0,当前是主机模式;

sample

参数含义:采样率;
数据类型:number
取值范围:8000,16000,24000,32000,48000,20050,44100
是否必选:必须接收此参数;
注意事项:默认44100
参数示例:16000,当前使用每秒16000的采样率进行采样音频;

bitw

参数含义:采样位深;
数据类型:number
取值范围:81624
是否必选:必须接收此参数;
注意事项:默认使用16
参数示例:16,当前每次采样使用16位存放模拟量;

channel

参数含义:声道;
数据类型:number
取值范围:1
是否必选:必须接收此参数;
注意事项:仅支持单声道
参数示例:1,当前使用单声道录音;

format

参数含义:通讯格式;
数据类型:number
取值范围:i2s.MODE_I2Si2s.MODE_LSBi2s.MODE_MSB
是否必选:必须接收此参数;
注意事项:需要根据实际的芯片支持的格式设置,比如ES8311 支持的是i2s.MODE_I2S
参数示例:i2s.MODE_I2S,使用标准I2S 协议通信;

framebit

参数含义:i2s通道数量位数
数据类型:number
取值范围:1632
是否必选:必须接收此参数;
注意事项:默认为16
参数示例:16,当前数据通道位数为16位;

示例

work_state,mode,sample,bitw,channel,format,formatbit =i2s.getPara(0)

五、产品支持说明

I2S 接口支持如下模块,Air780EPM,Air780EHM,Air780EHV,Air780EPM,Air780EPM