从0学起的esp-idf之旅——i2s总线理解与运用
i2s总线理解与运用
- I2S总线基础概念
- I2S概念
- PCM音频数据
- 转换成PCM格式的三个参数
- 采样频率(声音周期量化)
- 采样位数(声音的幅度量化)
- 声道数(单声道,立体声)
- I2S总线通讯方式
- I2S总线引脚
- esp32从ES8311分析i2s驱动如何去写
- 原理图
- 例程代码分析
- 主函数
- i2s初始化
- es8311初始化
- 播放音频
I2S总线基础概念
I2S概念
I2S(Inter-IC Sound)总线, 又称集成电路内置音频总线,最早是由现在的恩智浦半导体公司针对数字音频设备之间的音频数据传输而制定的总线标准。该总线专门用于音频设备间的传输,广泛用于各种多媒体系统。它传输的是PCM格式数据。
PCM音频数据
PCM (脉冲编码调制),由A.里弗斯于1937年提出的记录音频的格式。PCM是模拟信号经过采样、量化、编码转换成标准数字音频的原始数据格式。
转换成PCM格式的三个参数
音频数据量=采样频率×量化位数×声道数/8(字节/秒)
采样频率(声音周期量化)
1秒同时对多个声道完成adc采样的次数。采样频率越高,声音质量越好,还原越真实,但同时它占的资源比较多。
采样位数(声音的幅度量化)
每个采样点用多少二进制位表示数据范围。量化位数越多,音质越好,数据量也越大
声道数(单声道,立体声)
使用声音通道的个数,有单声道和立体声之分,立体声比单声道数据量翻倍。
I2S总线通讯方式
- 支持全双工和半双工通信
- 支持主/从模式
I2S总线引脚
- SCK:(continuous serial clock) 串行时钟,I2S的心跳。
串行时钟SCK,也叫位时钟BCLK,也有的称为BCK、SCLK等。对应数字音频的每一位数据,SCK都有1个脉冲。
SCK的频率 = 声道数 * 采样频率 * 采样位数。 - WS: (word select) 字段(声道)选择
字段选择信号WS,也叫LRCLK(LRCK),用于切换左右声道的数据。
WS的频率 = 采样频率
WS为0,表示正在传输的是左声道的数据;
WS为1,表示正在传输的是右声道的数据。 - SDATA:串行数据,在全双工的模式下分为DATAin和DATAout,主从之间的in/out要交叉接线
- MCLK:主时钟频率。一般为采样频率的256倍
esp32从ES8311分析i2s驱动如何去写
原理图
┌─────────────────┐ ┌──────────────────────────┐
│ ESP │ │ ES8311 │
│ │ │ │
│ MCLK-GPIO 0 ├──────────►│PIN2-MCLK │
│ │ │ │ ┌─────────┐
│ BCLK-GPIO 4 ├──────────►│PIN6-BCLK PIN12-OUTP├───────────┤ │
│ │ │ │ │ EARPHONE│
│ WS-GPIO 5 ├──────────►│PIN8-LRCK PIN13-OUTN├───────────┤ │
│ │ │ │ └─────────┘
│ SDOUT-GPIO 18├──────────►│PIN9-SDIN │
│ │ │ │
│ SDIN-GPIO 19│◄──────────┤PIN7-SDOUT │
│ │ │ │ ┌─────────┐
│ │ │ PIN18-MIC1P├───────────┤ │
│ SCL-GPIO 16├──────────►│PIN1 -CCLK │ │ MIC │
│ (GPIO 7)│ │ PIN17-MIC1N├───────────┤ │
│ SDA-GPIO 17│◄─────────►│PIN19-CDATA │ └─────────┘
│ (GPIO 8)│ │ │
│ VCC 3.3├───────────┤VCC │
│ │ │ │
│ GND├───────────┤GND │
└─────────────────┘ └──────────────────────────┘
注意:这里的SDOUT和SDIN要交叉接线。而且除了i2s给数据流之外,我们还需要一个i2c用来初始化codec芯片
例程代码分析
主函数
void app_main(void)
{/* 初始化i2s驱动 */if (i2s_driver_init() != ESP_OK) {ESP_LOGE(TAG, "i2s driver init failed");abort();}/* 初始化 i2c 外围设备并通过 i2c 配置 es8311 编解码器 */if (es8311_codec_init() != ESP_OK) {ESP_LOGE(TAG, "es8311 codec init failed");abort();}
#if CONFIG_EXAMPLE_MODE_MUSIC/* 在音乐模式下播放一段音乐 */xTaskCreate(i2s_music, "i2s_music", 4096, NULL, 5, NULL);
#else/* 以回声模式回声来自 MIC 的声音 */xTaskCreate(i2s_echo, "i2s_echo", 8192, NULL, 5, NULL);
#endif
}
主函数整体比较简单初始化i2s后初始化i2c并且给i2c初始化,然后就是通过i2s输入音频数据。
i2s初始化
static esp_err_t i2s_driver_init(void)
{i2s_config_t i2s_cfg = {.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_RX, //设置i2s工作模式,根据需求设置.sample_rate = EXAMPLE_SAMPLE_RATE,//设置I2S 采样率,根据音频确定采样率.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,//设置采样位数.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,//设置I2S 通道格式(分离左右声道).communication_format = I2S_COMM_FORMAT_STAND_I2S,//设置I2S 通讯格式.tx_desc_auto_clear = true,//I2S 自动清除tx描述符
#if SOC_I2S_SUPPORTS_TDM.total_chan = 2,.chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1,.left_align = false,.big_edin = false,.bit_order_msb = false,.skip_msk = false,
#endif.dma_desc_num = 8, // I2S DMA 用于接收/发送数据的描述符总数.dma_frame_num = 64, // 一次性采样的帧数。这里的 frame 表示一个 WS 周期内所有通道的总数据.use_apll = false, // I2S 使用 APLL 作为主要 I2S 时钟,使其能够获得准确的时钟.mclk_multiple = EXAMPLE_MCLK_MULTIPLE, // I2S 主时钟(MCLK)与采样率的倍数,有256(默认) 128 384倍.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // 用于分配中断的标志};ESP_RETURN_ON_ERROR(i2s_driver_install(I2S_NUM, &i2s_cfg, 0, NULL), TAG, "install i2s failed");i2s_pin_config_t i2s_pin_cfg = {.mck_io_num = I2S_MCK_IO,.bck_io_num = I2S_BCK_IO,.ws_io_num = I2S_WS_IO,.data_out_num = I2S_DO_IO,.data_in_num = I2S_DI_IO};ESP_RETURN_ON_ERROR(i2s_set_pin(I2S_NUM, &i2s_pin_cfg), TAG, "set i2s pins failed");return ESP_OK;
}
关于TDM相关的这里有比较详细的说明,大致就是多声道输出。本人理解有限 ,这里不做过多解释。
es8311初始化
static esp_err_t es8311_codec_init(void)
{/* i2c初始化 */i2c_config_t es_i2c_cfg = {.sda_io_num = I2C_SDA_IO,.scl_io_num = I2C_SCL_IO,.mode = I2C_MODE_MASTER,.sda_pullup_en = GPIO_PULLUP_ENABLE,.scl_pullup_en = GPIO_PULLUP_ENABLE,.master.clk_speed = 100000,};ESP_RETURN_ON_ERROR(i2c_param_config(I2C_NUM, &es_i2c_cfg), TAG, "config i2c failed");ESP_RETURN_ON_ERROR(i2c_driver_install(I2C_NUM, I2C_MODE_MASTER, 0, 0, 0), TAG, "install i2c driver failed");/* 初始化es8311芯片 */es8311_handle_t es_handle = es8311_create(I2C_NUM, ES8311_ADDRRES_0);ESP_RETURN_ON_FALSE(es_handle, ESP_FAIL, TAG, "es8311 create failed");es8311_clock_config_t es_clk = {.mclk_from_mclk_pin = true,.sample_frequency = EXAMPLE_SAMPLE_RATE};es8311_init(es_handle, &es_clk, ES8311_RESOLUTION_16, ES8311_RESOLUTION_16);ESP_RETURN_ON_ERROR(es8311_sample_frequency_config(es_handle, EXAMPLE_SAMPLE_RATE * EXAMPLE_MCLK_MULTIPLE, EXAMPLE_SAMPLE_RATE), TAG, "set es8311 sample frequency failed");ESP_RETURN_ON_ERROR(es8311_voice_volume_set(es_handle, EXAMPLE_VOICE_VOLUME, NULL), TAG, "set es8311 volume failed");ESP_RETURN_ON_ERROR(es8311_microphone_config(es_handle, false), TAG, "set es8311 microphone failed");
#if CONFIG_EXAMPLE_MODE_ECHOESP_RETURN_ON_ERROR(es8311_microphone_gain_set(es_handle, EXAMPLE_MIC_GAIN), TAG, "set es8311 microphone gain faield");
#endifreturn ESP_OK;
}
前面部分是在初始化i2c,后面部分主要是在调用es8311库里的东西,主要是调用i2c去配置一些es8311的寄存器。
播放音频
static void i2s_music(void *args)
{esp_err_t ret = ESP_OK;size_t bytes_write = 0;while (1) {/* 将音频数据通过i2s写入es8311 */ret = i2s_write(I2S_NUM, music_pcm_start, music_pcm_end - music_pcm_start, &bytes_write, portMAX_DELAY);if (ret != ESP_OK) {/* 由于我们在 'i2s_write' 中将超时设置为 'portMAX_DELAY',所以除非设置其他超时值,否则您将无法到达此处,如果检测到超时,则表示写入操作失败。*/ESP_LOGE(TAG, "[music] i2s read failed, %s", err_reason[ret == ESP_ERR_TIMEOUT]);abort();}/* 清除 DMA 缓冲区以避免缓冲区中的旧数据产生噪声 */i2s_zero_dma_buffer(I2S_NUM);if (bytes_write > 0) {ESP_LOGI(TAG, "[music] i2s music played, %d bytes are written.", bytes_write);} else {ESP_LOGE(TAG, "[music] i2s music play falied.");abort();}vTaskDelay(1000 / portTICK_PERIOD_MS);}vTaskDelete(NULL);
}
从0学起的esp-idf之旅——i2s总线理解与运用相关推荐
- Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.
调用IIS管理组件时编写了下面一段代码,调用函数时提示错误:Run-Time Check Failure #0 - The value of ESP was not properly saved ac ...
- Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.... 此错误的解
调用DLL里的函数 或 类成员函数 碰到此错误: Run-Time Check Failure #0 - The value of ESP was not properly saved across ...
- java学习_Python基础学习教程:从0学爬虫?让爬虫满足你的好奇心
Python基础学习教程:从0学爬虫?让爬虫满足你的好奇心 有必要学爬虫吗? 我想,这已经是一个不需要讨论的问题了. 爬虫,"有用"也"有趣"! 这个数据为王的 ...
- esp分区创建 linux_Ubuntu 16.0.4下搭建ESP开发环境并实现Hello World
始言:到了年尾的12月想做点什么.于是这个计划就出来了--wifi/蓝牙的等离子音箱.接着选中了这个模块.原因很简单,便宜.顺带接触一下Ubuntu系统入门. 概述: Ubuntu 16.0.4下的E ...
- 7. 从0学ARM-GNU伪指令、代码编译,lds使用
<嵌入式工程师到底要不要学习ARM汇编指令?arm学习文章汇总> <到底什么是Cortex.ARMv8.arm架构.ARM指令集.soc?一文帮你梳理基础概念[科普]> 关于A ...
- 7-2 I Love GPLT (5 分)初用数组————从0学C/浙大pta入门c语言题目
这道超级简单的题目没有任何输入. 你只需要把这句很重要的话 -- I Love GPLT --竖着输出就可以了. 所谓"竖着输出",是指每个字符占一行(包括空格),即每行只能有1个 ...
- 0. 学城项目 后端环境配置
1. 企业的web项目类型 1. 商城 (某某团购)1.1 B2C直销商城 商家与会员直接交易(Busioness To Customer)1.2 B2B批发商城 商家与商家直接交易1.3 B2B2C ...
- 7-20 简单计算器 (20 分)————从0学C/浙大pta入门c语言题目
模拟简单运算器的工作.假设计算器只能进行加减乘除运算,运算数和结果都是整数,四种运算符的优先级相同,按从左到右的顺序计算. 输入格式: 输入在一行中给出一个四则运算算式,没有空格,且至少有一个操作数. ...
- 从0学人脸识别,我花3小时复现了Eigenfaces For Recognition
人脸识别是当下最热的领域之一.这两年尤其在安保系统.天眼系统.犯罪分子抓捕系统.人脸锁.人脸考勤机.人脸支付等等领域迅速发展. 学习人脸识别,论文是必不可少的部分. 深度之眼专门推出人脸识别论文精讲直 ...
最新文章
- redis发布与订阅消息
- Cannot load onnxruntime.capi. Error: DLL load failed: 找不到指定的模块
- 汉高澳大利亚sinox接口捆绑经典winxp,全面支持unicode跨语言处理
- QTableWidgetble自定义表头排序设置
- [云炬创业管理笔记]第6章制定创业行动测试5
- Spring框架中的SpringFactoriesLoader
- Lazy延迟实例对象
- Kafka学习(一)-------- Quickstart
- 元素(洛谷-P4570)
- php载入内存的是本地代码吗,常量和静态变量会先载入内存后在进行执行php代码...
- 【性能测试】:操作NMON的shell脚本
- 专题四:MATLAB绘图
- JTA分布式事务处理
- IE8_XP安装包.zip
- 职场 | 如何说服上级?这里有三个故事
- 微信红包在微信公账号平台如何进行配置
- linux aria2 离线,使用aria2做离线下载
- 任何情况下请通过正规渠道变更信用卡额度
- 网站建设:颜色与线条的选择
- 需求:解压获取ipa里面的图片在windows系统上打不开
热门文章
- java手机怎样越狱_ipad怎么自己越狱 两种方法介绍【图文】
- iptables拦截域名_使用iptables封锁对某个域名的DNS查询
- MATLAB的常用的三角函数 计算函数
- 【微信小程序|组件库】首页功能模块界面
- linux中top命令cpu,ps命令中的%CPU字段和top命令中的%CPU字段
- MSSQL数据库一对多和多对一查询的转换
- iPhone5s ios 12.5.4越狱后可以ssh登录但是不能打开界面
- mysql类型转换及小数点保留问题(cast函数)
- 未来计算机作文英语作文,2019英语作文预测:人工智能
- SAS、scsi、sata、ide硬盘有什么区别