设为首页 收藏本站
查看: 1370|回复: 0

[经验分享] Cortex-M3 (NXP LPC1788)之IIS应用--UDA1380进行音频数据播放

[复制链接]

尚未签到

发表于 2015-11-15 08:45:20 | 显示全部楼层 |阅读模式
          LPC1788发送到I2S总线上的音频数据要通过音频解码芯片才能输出模拟音频信号。开发板上使用的是UDA1380,对它的寄存器的配置可以通过L3总线或者I2C总线进行,这里使用I2C总线进行控制,对于I2C总线的操作可以参考之前I2C的介绍。UDA1380的寄存器主要分成3类,系统控制、插值滤波(interpolation filter)、抽取滤波(decimator filter)。插值滤波和DAC转换有关,用于控制控制声音的输出参数。抽取滤波和ADC有关,用于控制对音频的采样。寄存器的地址和功能如图1所示。
   DSC0000.jpg


图1:UDA1380寄存器地址和功能

        根据图1的红色标记中的内容,可以知道两个滤波器的正常使用需要一个128fs的clock,这个时钟可以通过SYSCLK引脚或者WSI的信号获得。在硬件连接上,通过将LPC1788的MCLK输出的时钟,连接到UDA1380的SYSCLK引脚。因此,我们需要配置I2S的发送模式控制寄存器I2STXMODE,使能TX_REF在MCLK输出,使UDA1380内部产生一个滤波器需要的时钟。

        程序中我们通过I2S发送一段音频数据,该数据是我从WAV格式的文件中去掉WAV头格式后得到的一个纯音频数据数组。该WAV音频为16位双通道 采样频率为44.1KHZ。LPC1788将该数组发送到I2S总线,UDA1380读取该数据进行声音的输出。程序如下



#include "i2c.h"
#include "audio.h"
#define rI2SDAO         (*(volatile unsigned *)(0x400A8000))
#define rI2STXFIFO      (*(volatile unsigned *)(0x400A8008))
#define rI2STXRATE      (*(volatile unsigned *)(0x400A8020))
#define rI2STXBITRATE   (*(volatile unsigned *)(0x400A8028))
#define rI2STXMODE      (*(volatile unsigned *)(0x400A8030))
#define rI2SDMA1        (*(volatile unsigned *)(0x400A8014))
#define rI2SDMA2        (*(volatile unsigned *)(0x400A8018))
#define rI2SSTATE       (*(volatile unsigned *)(0x400A8010))
#define rI2SIRQ         (*(volatile unsigned *)(0x400A801C))
#define rI2SDAI         (*(volatile unsigned *)(0x400A8004))
#define rI2SRXFIFO      (*(volatile unsigned *)(0x400A800C))
#define rI2SRXRATE      (*(volatile unsigned *)(0x400A8024))
#define rI2SRXBITRATE   (*(volatile unsigned *)(0x400A802C))
#define rI2SRXMODE      (*(volatile unsigned *)(0x400A8034))
#define rIOCON_P0_07(*(volatile unsigned *)(0x4002C01C))
#define rIOCON_P0_08(*(volatile unsigned *)(0x4002C020))
#define rIOCON_P0_09(*(volatile unsigned *)(0x4002C024))
#define rIOCON_P1_16(*(volatile unsigned *)(0x4002C0C0))
#define UDA1380_ADDRESS 0x1A
void Uda1380_WriteData(unsigned char reg, unsigned short int data)
{
unsigned char config[3];
config[0] = reg;
config[1] = (data >> 8) & 0xFF;    //MS
config[2] = data&0xFF;             //LS

I2C0_MasterTransfer(UDA1380_ADDRESS, config, sizeof(config), 0, 0);
I2C0_MasterTransfer(UDA1380_ADDRESS, config, 1, &config[1], 2);     //校验写入的数据是否正确
if((config[1]<<8|config[2]) != data)
{
while(1);   //写入和读出的数据不一致
}
}
void Uda1380_config()
{
I2C0_Init();
Uda1380_WriteData(0x7F, 0x0);         //restore L3-default values
Uda1380_WriteData(0x01, 0x0);         //数据格式为标准的I2S格式
Uda1380_WriteData(0x13, 0x0);         //配置音频的输出
Uda1380_WriteData(0x14, 0x0);           
Uda1380_WriteData(0x00, 0x2|0x1<<8|0x1<<9);     //使能DAC的时钟,选择使用SYSCLK产生128fs的时钟
Uda1380_WriteData(0x02,0x1<<15|0x1<<13|0x1<<10|0x1<<8); //使能DAC 电源
}
int main(void)
{   
unsigned int count=0, i;
unsigned char flag=1;
rIOCON_P0_07 = (rIOCON_P0_07&(~0x3))|0x1;   //I2S_TX_SCK
rIOCON_P0_08 = (rIOCON_P0_08&(~0x3))|0x1;   //I2S_TX_WS
rIOCON_P0_09 = (rIOCON_P0_09&(~0x3))|0x1;   //I2S_TX_SDA
rIOCON_P1_16 = (rIOCON_P1_16&(~0x3))|0x2;   //I2SMCLK
rPCONP |= 0x1<<27;
rI2SDAO = (16 - 1)<<6 | 0x1<<4 | 0x1<<3  |0x1;  //16位, 立体音, 禁止发送
rI2STXMODE |= 0x1<<3;       //使能MCLK输出,使TX_REF输出到UDA1380的SYSCLK引脚
rI2STXRATE = 0x1<<8|0x1;    //配置分数速率寄存器 得到TX_REF=CCLK/(1/1)/2
rI2STXBITRATE = CCLK/2/(44100*2*16) - 1;  //44.1KHZ采样16位
for(i = 0; i <0x1000000; i++);  //延时 等待UDA1380内部通过SYSCLK产生稳定的128fs提供插值滤波和抽取滤波使用
Uda1380_config();
rI2SDAO &= ~ (1<<4);
rI2SDAO &= ~ (1<<3);
rI2SDAO &= ~ (1<<15);   //启动I2S数据传输
while(flag)
{
if(((rI2SSTATE>>16)&0xFF)<=4)       //如果发送FIFO中的数据小于或等于4个字
{
for(i=0; i<8-(((rI2SSTATE>>16)&0xFF)); i++)     //将FIFO填充到8个字
{
rI2STXFIFO = *(unsigned int *)(audio + count);  //转换成int类型的指针,从指针指向的位置读取32位数据
count+=4;               //读取一个字,相当于读取char类型数组中的4个元素
if(count>=sizeof(audio)) //数组中的数据发送完
{
flag = 0;
break;
}
}
}
}
rI2SDAO |= 0x1<<3|0x1<<4;   //停止I2S传输
return 0;
}
下面对程序需要注意的做下说明:  
1,i2c.h中是上一篇介绍I2C总线中所用的函数,aduio.h中存放的是音频数据的数组,const unsigned char audio[]={0,0,0,0,0,......................

2,I2C总线每次发送的数据为1个字节,而UDA1380的寄存器为16为,因此我们先发送高字节然后再发送低字节,具体的时序可以参考UDA1380的数据手册。

3,程序中配置发送控制寄存器I2STXMODE使能了MCLK输出TX_REF的时钟到UDA1380的SYSCLK引脚,而UDA1380中配置成使用该时钟产生内部滤波器需要的128fs的时钟。在图1中标志中说明run at ....因此在程序中配置UDA1380之前,使用了一个for延时,用于等待UDA1380内部产生稳定的128fs时钟。只有这样才能正确的配置0x10之后的滤波器相关寄存器。否则对0x10之后的滤波器相关寄存器操作会失败。这点没有验证,但是在debug调试的时候可以正常的有声音输出,但是下载到板子上运行,则没有效果。如果去掉for循环延时效果也不正常发音。如果不使能MCLK输出,则写0x13寄存器的&#20540;不会成功,读取该寄存器的&#20540;永远都是其默认&#20540;。因此推测和UDA1380的SYSCLK产生内部滤波器使用的128fs时钟有关。

      参考了linux内核里面的uda1380的驱动,其中也提到了配置0x10以后的滤波器相关寄存器要满足条件

107         /* the interpolator & decimator regs must only be written when the
108          * codec DAI is active.
109          */

  
  谁有这方面的经验,希望多指教!
DSC0001.jpg

版权声明:本文为博主原创文章,未经博主允许不得转载。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-139379-1-1.html 上篇帖子: AppPoolService-IIS应用程序池辅助类(C#控制应用程序池操作) 下篇帖子: 浏览器访问IIS服务器上面的plist文件报错:HTTP Error 404.3
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表