图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寄存器的值不会成功,读取该寄存器的值永远都是其默认值。因此推测和UDA1380的SYSCLK产生内部滤波器使用的128fs时钟有关。
参考了linux内核里面的uda1380的驱动,其中也提到了配置0x10以后的滤波器相关寄存器要满足条件
- 107 /* the interpolator & decimator regs must only be written when the
- 108 * codec DAI is active.
- 109 */
谁有这方面的经验,希望多指教!
上一篇:STM32 IAP 设计实例 (二)
下一篇:Cortex-M3 (NXP LPC1788)之IIS控制器
推荐阅读最新更新时间:2024-03-16 14:55
设计资源 培训 开发板 精华推荐
- 消息称 AMD 将入局手机芯片领域,采用台积电 3nm 工艺
- 英飞凌推出OptiMOS™ Linear FET 2 MOSFET, 赋能先进的热插拔技术和电池保护功能
- SGMII及其应用
- 贸泽开售用于机器人和机器视觉的 STMicroelectronics B-CAMS-IMX模块
- 三星 Exynos 2600 芯片前景堪忧:良率挑战严峻,有被取消量产风险
- 苹果搁置反垄断报告的请求遭印度监管机构拒绝,案件将继续推进
- 2024年Automechanika Shanghai海量同期活动刷新历届记录,汇聚行业智慧,共谋未来发展
- 企业文化分享 如何培养稀缺的硅IP专业人员?SmartDV开启的个人成长与团队协作之旅
- 恩智浦发布首个超宽带无线电池管理系统解决方案
- 北交大本科生探秘泰克先进半导体开放实验室,亲历前沿高科技魅力
- 树莓派4B成功刷入OpenHarmony 3.0:仅显示、触摸
- 华为9款手机升级鸿蒙!6款同步开启公测
- 谷歌公布Android最新版本分布:安卓11一路狂飙 居第二
- 天玑9000机型发布时间曝光
- 骁龙8 Gen 1!小米12重要参数曝光:大升级
- 【STM32H7教程】第17章 STM32H7之GPIO的HAL库API
- 【STM32H7教程】第18章 STM32H7的GPIO应用之跑马灯
- 【STM32H7教程】第19章 STM32H7的GPIO应用之按键FIFO
- 【STM32H7教程】第20章 STM32H7的GPIO应用之无源蜂鸣器
- 【STM32H7教程】第21章 STM32H7的NVIC中断分组和配置(重要)