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 是常见的信号管脚,它们的含义和作用如下:
-
I2S_BCLK(Bit Clock,位时钟)
-
含义:也称为串行时钟(Serial Clock,SCK),是数字音频传输中的基础时钟信号。
- 作用:用于同步每一位音频数据的传输节奏。每传输 1 位二进制数据(0 或 1),BCLK 就会产生 1 个时钟脉冲。例如,传输 16 位音频数据时,需要 16 个 BCLK 脉冲;传输 24 位数据时,需要 24 个 BCLK 脉冲。
-
关键:BCLK 的频率 = 音频采样率 × 位深 × 声道数(如 44.1kHz 采样率、16 位深、立体声时,BCLK = 44100 × 16 × 2 = 1.4112MHz)。
-
I2S_LRCK(Left/Right Clock,左右声道时钟)
-
含义:也称为字选择线(Word Select,WS),用于区分左声道和右声道的音频数据。
-
作用:通过电平高低标识当前传输的是左声道还是右声道数据:
-
通常高电平表示左声道,低电平表示右声道(可通过芯片配置调整);
-
每个声道的一组完整数据(如 16 位 / 24 位)对应 LRCK 的一个电平周期,其频率等于音频采样率(如 44.1kHz 采样率时,LRCK 频率为 44.1kHz)。
-
I2S_DIN(Data In,数据输入)
-
含义:串行数据输入线。
-
作用:用于接收外部设备传输过来的数字音频数据(如 PCM 格式),数据在 BCLK 和 LRCK 的同步下,按位依次传入芯片(如 DAC 解码器从 DIN 接收数据,再转换为模拟音频)。
-
I2S_DOUT(Data Out,数据输出)
-
含义:串行数据输出线。
-
作用:用于向外部设备发送数字音频数据。例如,ADC 编码器将模拟音频转换为数字信号后,通过 DOUT 输出给 MCU 或其他处理设备,数据同样在 BCLK 和 LRCK 的同步下传输。
-
I2S_MCLK(Master Clock,主时钟)
-
含义:也称为系统时钟(System Clock),是音频系统的基准时钟。
- 作用:为整个音频传输链路提供时钟参考,确保各设备(如 Codec、DAC、ADC)的工作节奏一致,减少因时钟偏差导致的音质失真(如噪声、失真)。
- 特点:频率通常是采样率的整数倍(例如 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;
取值范围:0,1;
是否必选:非必须传入此参数;
注意事项:0为主机模式,1为从机模式,默认为主模式;
参数示例:0,开启主机模式;
sample
参数含义:采样率;
数据类型:number;
取值范围:8000,16000,24000,32000,48000,20050,44100;
是否必选:非必须传入此参数;
注意事项:默认44100
参数示例:16000,使用每秒16000的采样率进行音频采样;
bitw
参数含义:采样位深;
数据类型:number;
取值范围:8,16,24;
是否必选:非必须传入此参数;
注意事项:默认使用16位
参数示例:16,每次采样使用16位存放模拟量;
channel
参数含义:声道;
数据类型:number;
取值范围:1;
是否必选:必须传入此参数;
注意事项:仅支持单声道
参数示例:1,使用单声道录音;
format
参数含义:通讯格式;
数据类型:number;
取值范围:i2s.MODE_I2S,i2s.MODE_LSB,i2s.MODE_MSB;
是否必选:非必须传入此参数;
注意事项:需要根据实际的芯片支持的格式设置,比如ES8311 支持的是i2s.MODE_I2S
参数示例:i2s.MODE_I2S,使用标准I2S 协议通信;
framebit
参数含义:i2s通道数据位数;
数据类型:number;
取值范围:16,32;
是否必选:非必须传入此参数;
注意事项:默认为16,根据具体的音频编解码芯片要求设置
参数示例:16,数据通道位数为16位;
返回值
成功 true, 失败 false
示例
i2s.setup(0, 0, 8000, 16, 1, i2s.MODE_I2S,16) -- 开启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;
取值范围:0,1;
是否必选:必须接收此参数;
注意事项:0为主机模式,1为表示从机模式;
参数示例:0,当前是主机模式;
sample
参数含义:采样率;
数据类型:number;
取值范围:8000,16000,24000,32000,48000,20050,44100;
是否必选:必须接收此参数;
注意事项:默认44100
参数示例:16000,当前使用每秒16000的采样率进行采样音频;
bitw
参数含义:采样位深;
数据类型:number;
取值范围:8,16,24;
是否必选:必须接收此参数;
注意事项:默认使用16位
参数示例:16,当前每次采样使用16位存放模拟量;
channel
参数含义:声道;
数据类型:number;
取值范围:1;
是否必选:必须接收此参数;
注意事项:仅支持单声道
参数示例:1,当前使用单声道录音;
format
参数含义:通讯格式;
数据类型:number;
取值范围:i2s.MODE_I2S,i2s.MODE_LSB,i2s.MODE_MSB;
是否必选:必须接收此参数;
注意事项:需要根据实际的芯片支持的格式设置,比如ES8311 支持的是i2s.MODE_I2S
参数示例:i2s.MODE_I2S,使用标准I2S 协议通信;
framebit
参数含义:i2s通道数量位数;
数据类型:number;
取值范围:16,32;
是否必选:必须接收此参数;
注意事项:默认为16
参数示例:16,当前数据通道位数为16位;
示例
work_state,mode,sample,bitw,channel,format,formatbit =i2s.getPara(0)
五、产品支持说明
I2S 接口支持如下模块,Air780EPM,Air780EHM,Air780EHV,Air780EPM,Air780EPM