查看: 3940|回复: 10

【CurieI2S】播放一段音频

[复制链接]
  • TA的每日心情
    开心
    2017-7-3 15:02
  • 签到天数: 56 天

    [LV.5]常住居民I

    发表于 2017-3-15 00:18 | 显示全部楼层 |阅读模式
    本帖最后由 甲基红橙黄绿蓝 于 2017-5-1 22:31 编辑

    概述:

    I2S总线是一种音频传输总线。Curie的库中包含I2S库,却没有提供播放音频的例程。这里我提供一个Arduino101循环播放 Intel 的广告音乐“灯 等灯等灯”的例程。



    目的:
            提供一个使用Arduino 101播放音乐的例程。



    更新说明:
    此例程于3月22日更新为 DMA 版本。相比以前的版本更加简洁可靠,而且消除了必须用金属触碰LRCK引脚的bug。
    要运行DMA版本,必须更新Arduino101到 2.x版本。可以参考奈何大大的帖子:http://www.arduino.cn/thread-42890-1-1.html





    元件:

    1、Arduino 101
    2、I2S解码板,淘宝链接点此!这是一个给树莓派2用的高音质音频解码板,但树莓派3用不了,有树莓派2的同学可以考虑买一个,顺便尝试用Arduino101播放音频。
    3、耳机




    电路:

    CurieI2S.jpg

    接线方法如下表:
    I2S解码板 Arduino 101
    VCC 5V
    GND GND
    BICK 2号引脚
    LRCK 4号引脚
    DATA 7号引脚

    另外注意:
    • 在I2S解码板上将GND与MCLK用跳线帽短接
    • I2S解码板上有两个拨动开关,分别拨动到Normal lantency和I2S即可
    • 将耳机插在I2S解码板上





    DMA版本的代码:

    该例程循环播放Intel的广告音乐“灯 等灯等灯”,虽然音质不怎么样。

    音频数据是存储在data数组中的,我获取音频数据的方法是,用Python的wave库读取音频文件,打印结果后粘贴到Arduino IDE中。

    [C++] 纯文本查看 复制代码
    // 要运行此程序,必须升级Arduino101的2.x版本
    #include <CurieI2SDMA.h>
    
    // 注:data数组存储音频数据,因为太长,此处贴不下,完整代码请下载附件
    const uint32_t data[] = {10582250,10540250,10250450, ...... };
    
    void setup() {
      CurieI2SDMA.iniTX();
      CurieI2SDMA.beginTX(6000, 32,1, 1);
    }
    
    void loop() {
      CurieI2SDMA.transTX((void*)data,sizeof(data),sizeof(uint32_t));
      delay(1000);
    }
    
    






    非DMA版本的代码:

    该例程循环播放Windows U盘弹出提示音。

    注:遇到不发声的情况时,用金属物体(比如钥匙)持续触碰I2S解码板的LRCK信号,就能听到声音,原因不明。可能是我写的代码不好,也不排除CurieI2S库自身有问题的可能性。


    [C++] 纯文本查看 复制代码
    #include <CurieI2S.h>
    
    // 注:data数组存储音频数据,因为太长,此处贴不下,完整代码请下载附件
    const uint16_t data[] = {6103,6103,6103,6105,6104,...... };
    
    #define SIZE (sizeof(data)/sizeof(*data))
    
    void setup() {
      CurieI2S.begin(I2S_12K, I2S_32bit);
      CurieI2S.setI2SMode(PHILIPS_MODE);
      CurieI2S.initTX();
    }
    
    void loop() {
      static uint16_t i = 0;
      CurieI2S.startTX();
      for(uint8_t cnt=0;cnt<32;cnt++){
        while( !CurieI2S.pushData( data*1500 ) );
        i = (i+1)%SIZE;
      }
    }






    DMA与非DMA的区别:
    直观上看DMA版本的代码简洁易懂一些,实际上二者还有根本区别。DMA是“直接存储器存取”的简称,指的是大量数据在IO与存储器间存取时,可以不经过CPU转手的技术,这极大地解放了CPU。举个例子,你用电脑把一个电影从U盘拷到硬盘时,打开任务管理器看看,你的CPU是空闲的,这就是DMA的优点。

    对于本例程,在非DMA的版本里, I2S音频信号需要从存储器读取到CPU, 再向I2S口输出,实际上pushData()函数是将待发送的数据送到了一个数据缓存区FIFO中,同时I2S控制器不断地从FIFO读取数据发送出去,若pushData的执行速度太快,FIFO还有可能溢出,所以你会注意到我的程序里用了一个莫名其妙的32次循环,就是为了避免FIFO溢出。

    而 CurieI2SDMA 的版本里,只需在存储器里准备好数据,再告诉I2S的DMA控制器数据在哪个地址,以及数据长度多少,然后命令 DMA开始即可。




    源代码文件:
    游客,如果您要查看本帖隐藏内容请回复







    打赏作者鼓励一下!

    2人打赏

    该用户从未签到

    发表于 2017-3-15 08:31 | 显示全部楼层
    好厉害啊~ 不错
    打赏作者鼓励一下!
  • TA的每日心情
    奋斗
    2018-8-17 09:12
  • 签到天数: 47 天

    [LV.5]常住居民I

    发表于 2017-3-15 09:07 | 显示全部楼层
    学习了,我也考虑下用i2s做个啥
    如果以上内容对你有帮助,你可以通过打赏支持作者
  • TA的每日心情
    慵懒
    2018-9-21 08:59
  • 签到天数: 344 天

    [LV.8]以坛为家I

    发表于 2017-3-15 09:40 | 显示全部楼层
    这个学到了~~
    如果以上内容对你有帮助,你可以通过打赏支持作者

    该用户从未签到

    发表于 2017-3-22 20:16 | 显示全部楼层
    下下来学习一个
  • TA的每日心情

    2017-12-1 18:12
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2017-5-28 21:11 | 显示全部楼层
    支持楼主,希望可以越做越好。

    该用户从未签到

    发表于 2017-10-9 14:37 | 显示全部楼层
    sdfdsfdsfds

    该用户从未签到

    发表于 2017-10-9 18:58 | 显示全部楼层
    正好手上有一块DUE,试试看

    该用户从未签到

    发表于 2017-11-28 17:04 | 显示全部楼层
    来学习一个

    该用户从未签到

    发表于 2018-1-25 16:11 | 显示全部楼层
    刘明,楼主很棒,多谢了
    您需要登录后才可以回帖 登录 | 立即注册  

    本版积分规则

    热门推荐

    IDE 用arbuBlok下载不了程序。
    IDE 用arbuBlok下载不了程
    点击下载到板子就出现红字体 版本是1.8.7
    初学arduino求助
    初学arduino求助
    大佬们,我想问一下,我现在想做一个程序:按下开关持续时间t,延迟7.77t后点亮led0.
    吸顶灯接入物联网(基于Blinker与wifi开发板)
    吸顶灯接入物联网(基于Bli
    暑假开始接触Blinker和esp8266开发板,一直在捣鼓。。开学是肯定没空碰了,于是趁现在
    原创 drawbot平面关节机械臂 教程直播贴
    原创 drawbot平面关节机械
    这个项目上个月就在做了,结构和代码反反复复改了多次,加上自己又太懒,一直没来得及
    创客集结号之光控LED实验
    创客集结号之光控LED实验
    本次实验是在创客集结号上分享出来的,是做一个光控LED实验。 1.实验器件: Arduino
    Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   ( 蜀ICP备14017632号-3 )
    快速回复 返回顶部 返回列表