HC32F460驱动音频编解码器TLV320AIC3254
一.写在前面:
1.首先是第一次发布博客,内容写的不好,不喜勿喷;
2.我的代码含注释可直接用!!!
3.共享才能促进技术进步:因为工作需要国产MCU(HC32F460)驱动TI的音频编解码器TLV320AIC3254产生波形输出,同时也需要采集波形输入。在网上找了好久资料都没有相应的驱动例程,TI官网上有例程还都是Linux下的。更要命的是TI官网给的例程有部分寄存器配置和手册里面还不一样,真是无语死。
没办法,只能自己慢慢琢磨TLV320AIC3254的寄存器(没有上百也有大几十了),一点点调试,最终调试成功了,现把驱动共享给大家,共同学习进步。(HC32F460使用I2C的方式配置TLV320AIC3254,并通过I2S发送数据和读取数据),还可以用SPI配置TLV320AIC3254,但是我没有需要所以没用,但是应该跟I2C配置没啥大的区别。
首先HC32F460真的很难用好吗?I2C写地址非要左移一位用8地址(真的很不习惯,I2C大家都是用7为地址),还有ACK应答信号那里也是坑,正常人都会以为SET是ACK信号,它搞了个RESET是ACK信号![]()
HC32F460的I2C代码
部分HC32F460的I2C配置代码如下:
*I2C写数据*/
int32_t writeRegister(uint8_t addr, uint8_t value)//写寄存器
{
int32_t Ret = 0;
uint8_t addrres=0;
uint8_t data[1] = {0};
addrres = addr;
data[0] = value;
I2C_Cmd(CM_I2C1,ENABLE);//使能打开
I2C_SWResetCmd(CM_I2C1,ENABLE);
DDL_DelayUS(10);
I2C_SWResetCmd(CM_I2C1,DISABLE);
DDL_DelayUS(10);
if(LL_OK!=I2C_Start(CM_I2C1,10))//开始
Ret |= 1;
if(LL_OK!=I2C_TransAddr(CM_I2C1,TLV320_REG_WRITE,0,10000))//写设备地址
Ret |= 2;
if(LL_OK!=I2C_WaitStatus(CM_I2C1,I2C_FLAG_ACKR,RESET,100))//获取应答信号
Ret |= 4;
if(LL_OK!=I2C_TransAddr(CM_I2C1,addrres,0,10000))//写寄存器地址
Ret |= 8;
if(LL_OK!=I2C_WaitStatus(CM_I2C1,I2C_FLAG_ACKR,RESET,100))//获取应答信号
Ret |= 16;
if(LL_OK!=I2C_TransData(CM_I2C1,data,1,10000))//写寄存器数据
Ret |= 32;
if(LL_OK!=I2C_WaitStatus(CM_I2C1,I2C_FLAG_ACKR,RESET,100))//获取应答信号
Ret |= 64;
if(LL_OK!=I2C_Stop(CM_I2C1,1000))//停止
Ret |= 128;
I2C_Cmd(CM_I2C1,DISABLE);
DDL_DelayUS(100);
return Ret;
}
/*I2C读数据*/
static uint8_t readRegister(uint8_t addr)
{
int32_t Ret = 0;
uint8_t addrres=0;
uint8_t data[1] = {0};
addrres = addr;
I2C_Cmd(CM_I2C1,ENABLE);//使能打开
I2C_SWResetCmd(CM_I2C1,ENABLE);
DDL_DelayUS(10);
I2C_SWResetCmd(CM_I2C1,DISABLE);
DDL_DelayUS(10);
if(LL_OK!=I2C_Start(CM_I2C1,10))//开始
Ret |= 1;
if(LL_OK!=I2C_TransAddr(CM_I2C1,TLV320_REG_WRITE,0,10000))//写设备地址
Ret |= 2;
if(LL_OK!=I2C_WaitStatus(CM_I2C1,I2C_FLAG_ACKR,RESET,100))//获取应答信号
Ret |= 4;
if(LL_OK!=I2C_TransAddr(CM_I2C1,addrres,0,10000))//写寄存器地址
Ret |= 8;
if(LL_OK!=I2C_WaitStatus(CM_I2C1,I2C_FLAG_ACKR,RESET,100))//获取应答信号
Ret |= 16;
if(LL_OK!=I2C_Restart(CM_I2C1,1000))//重新开始
Ret |= 32;
if(LL_OK!=I2C_TransAddr(CM_I2C1,TLV320_REG_WRITE,1,10000))//读设备地址
Ret |= 64;
if(LL_OK!=I2C_WaitStatus(CM_I2C1,I2C_FLAG_ACKR,RESET,100))//获取应答信号
Ret |= 128;
if(LL_OK!=I2C_ReceiveData(CM_I2C1,data,1,10000))//读寄存器数据
Ret |= 256;
//I2C_AckConfig(CM_I2C1, I2C_NACK);
I2C_GenerateNACK(CM_I2C1);
if(LL_OK!=I2C_Stop(CM_I2C1,1000))//停止
Ret |= 512;
I2C_Cmd(CM_I2C1,DISABLE);
printf("I2C READ ERROR=%d\r\n",Ret);
return data[0];
}
TLV320AIC3254的配置代码:
static void TLV320AIC3254_CodecInit(void)
{
int32_t Ret = 0;
/* codec DAC init*/
//select Page 0
if(LL_OK!=writeRegister(PAGE_SELECT_REGISTER, 0))
printf("ERROR=1\r\n");
// 自动清除复位
if(LL_OK!=writeRegister(0x01, 0x01))
printf("ERROR=2\r\n");
//MCLK IS CODEC_CLKIN=12
if(LL_OK!=writeRegister(0x04, 0x00))
printf("ERROR=18\r\n");
// Power up the NDAC divider with value 1
if(LL_OK!=writeRegister(0x0B, 0x81))
printf("ERROR=3\r\n");
// Power up the MDAC divider with value 2
if(LL_OK!=writeRegister(0x0C, 0x82))
printf("ERROR=4\r\n");
// Program the OSR of DAC to 128/LSB Value
if(LL_OK!=writeRegister(0x0D, 0x00))
printf("ERROR=5\r\n");
if(LL_OK!=writeRegister(0x0E, 0x80))
printf("ERROR=6\r\n");
// Set the Audio Interface mode to I2S,word length=32,BCLK/WCLK input
if(LL_OK!=writeRegister(0x1B, 0x30))
printf("ERROR=7\r\n");
// Set the DAC Mode to Processing Block PRB_P1
if(LL_OK!=writeRegister(0x3C, 0x01))
printf("ERROR=8\r\n");
// Select Page 1
if(LL_OK!=writeRegister(PAGE_SELECT_REGISTER, 0x01))
printf("ERROR=9\r\n");
// Disable weak connection of AVDD with DVDD
if(LL_OK!=writeRegister(0x01, 0x08))
printf("ERROR=10\r\n");
// Enable Master Analog Power Control
//内部AVDD输出使能,1.72V
if(LL_OK!=writeRegister(0x02, 0x01))
printf("ERROR=11\r\n");
// Set the REF charging time to 40ms
if(LL_OK!=writeRegister(0x7B, 0x01))
printf("ERROR=12\r\n");
// HP soft stepping settings for optimal pop performance at power up
// Rpop used is 6k with N = 6 and soft step = 20usec. This should work with 47uF coupling
// capacitor. Can try N=5,6 or 7 time constants as well. Trade-off delay vs “pop” sound.
// if(LL_OK!=writeRegister(0x14, 0x25))//耳机输出,可不需要
// printf("ERROR=13\r\n");
// Set the Input Common Mode to 0.9V and Output Common Mode for Headphone to Input Common Mode
//耳机和扬声器输出都是FULL-CHIP COMMON MODE
//扬声器输出电压为LDOIN提供,范围1.8-3.6V
//LOR和LOL输出模式可更改,以及供电也可以更改
if(LL_OK!=writeRegister(0x0A, 0x03))
printf("ERROR=14\r\n");
// Route Left DAC to LOL
if(LL_OK!=writeRegister(0x0E, 0x08))
printf("ERROR=15\r\n");
// Route Right DAC to LOR
if(LL_OK!=writeRegister(0x0F, 0x08))
printf("ERROR=16\r\n");
// Set the DAC PTM mode to PTM_P3/4
if(LL_OK!=writeRegister(0x03, 0x00))
printf("ERROR=17\r\n");
if(LL_OK!=writeRegister(0x04, 0x00))
printf("ERROR=18\r\n");
// Set the HPL gain to 0dB
if(LL_OK!=writeRegister(0x10, 0x00))
printf("ERROR=19\r\n");
// Set the HPR gain to 0dB
if(LL_OK!=writeRegister(0x11, 0x00))
printf("ERROR=20\r\n");
// Set the LOL gain to 0dB
if(LL_OK!=writeRegister(0x12, 0x00))
printf("ERROR=21\r\n");
// Set the LOR gain to 0dB
if(LL_OK!=writeRegister(0x13, 0x00))
printf("ERROR=22\r\n");
// Power up LOL and LOR drivers
if(LL_OK!=writeRegister(0x09, 0x0c))//0X0C
printf("ERROR=23\r\n");
// Wait for 2.5 sec for soft stepping to take effect
// Else read Page 1, Register 63d, D(7:6). When = “11” soft-stepping is complete
DDL_DelayMS(2500);
// Select Page 0
if(LL_OK!=writeRegister(PAGE_SELECT_REGISTER, 0))
printf("ERROR=24\r\n");
// Power up the Left and Right DAC Channels with route the Left Audio digital data to
// Left Channel DAC and Right Audio digital data to Right Channel DAC, soft-step volume change enable
if(LL_OK!=writeRegister(0x3F, 0xD6))//0XD5
printf("ERROR=25\r\n");
// Unmute the DAC digital volume control
if(LL_OK!=writeRegister(0x40, 0x00))
printf("ERROR=26\r\n");
//codec ADC init
// Initialize to Page 0
if(LL_OK!=writeRegister(PAGE_SELECT_REGISTER, 0))
printf("ERROR=27\r\n");
// Power up NADC divider with value 1
if(LL_OK!=writeRegister(0x12, 0x81))
printf("ERROR=28\r\n");
// Power up MADC divider with value 2
if(LL_OK!=writeRegister(0x13, 0x82))
printf("ERROR=29\r\n");
// Program OSR for ADC to 128
if(LL_OK!=writeRegister(0x14, 0x80))
printf("ERROR=30\r\n");
// Select ADC PRB_R1
if(LL_OK!=writeRegister(0x3D, 0x01))//OX3D
printf("ERROR=31\r\n");
// Select Page 1
if(LL_OK!=writeRegister(PAGE_SELECT_REGISTER, 1))
printf("ERROR=32\r\n");
// Select ADC PTM_R4
if(LL_OK!=writeRegister(0x3D, 0x00))
printf("ERROR=33\r\n");
// Set MicPGA startup delay to 3.1ms
if(LL_OK!=writeRegister(0x47, 0x32))
printf("ERROR=34\r\n");
//通道1在RADC差分采集,通道2在LADC差分采集
// Route IN1R to RIGHT_P with 20K input impedance
if(LL_OK!=writeRegister(0x37, 0x80))
printf("ERROR=35\r\n");
// Route IN1L to RIGHT_N with 20K input impedance
if(LL_OK!=writeRegister(0x39, 0x20))
printf("ERROR=36\r\n");
// Route IN2L to LEFT_P with 20K input impedance
if(LL_OK!=writeRegister(0x34, 0x20))
printf("ERROR=37\r\n");
// Route IN2R to LEFT_N with 20K input impedance
if(LL_OK!=writeRegister(0x36, 0x20))
printf("ERROR=38\r\n");
// Unmute Left MICPGA, Gain selection of 6dB to make channel gain 0dB
// Register of 6dB with input impedance of 20K => Channel Gain of 0dB
if(LL_OK!=writeRegister(0x3B, 0x0C))
printf("ERROR=39\r\n");
// Unmute Right MICPGA, Gain selection of 6dB to make channel gain 0dB
// Register of 6dB with input impedance of 20K => Channel Gain of 0dB
if(LL_OK!=writeRegister(0x3C, 0x0C))
printf("ERROR=40\r\n");
// Set MICBIAS voltage 1.25 V 差分信号已经有外部电压偏置
if(LL_OK!=writeRegister(0x33, 0x40))
printf("ERROR=41\r\n");
// Select Page 0
if(LL_OK!=writeRegister(PAGE_SELECT_REGISTER, 0))
printf("ERROR=42\r\n");
// Power up Left and Right ADC Channels
if(LL_OK!=writeRegister(0x51, 0xC0))
printf("ERROR=43\r\n");
// // DOUT为I2S数据输出
if(LL_OK!=writeRegister(0x35, 0x02))
printf("ERROR=7.2\r\n");
// Unmute Left and Right ADC Digital Volume Control.
if(LL_OK!=writeRegister(0x52, 0x00))
printf("ERROR=44\r\n");
//// DIN为主数据输入
// if(LL_OK!=writeRegister(0x36, 0x02))
// printf("ERROR=7.1\r\n");
// // DOUT为I2S数据输出
// if(LL_OK!=writeRegister(0x35, 0x02))
// printf("ERROR=7.2\r\n");
}
我这边用I2S收发输出,让TLV320AIC3254输出正弦波,同时音频采集为也采集正弦波输出到串口屏上显示。
I2S收发数据代码:
void SINE_I2S(uint32_t VPPL,uint32_t VPPR)
{
uint32_t Vfz1=VPPL>>4;//左通道峰值
uint32_t Vfz2=VPPR>>4;//右通道峰值
uint8_t i=0,j=0,point=128;
uint8_t oled2=0;
uint32_t temp=0;
uint32_t t0=0;
uint32_t sindataL[128]={0};
uint32_t sindataR[128]={0};
uint32_t RXDATAL[128]={0};
uint32_t RXDATAR[128]={0};
uint32_t TEMPRXDATAR[128]={0};
float hd=0.0;//弧度
float fz1=0.0;//左通道幅值
float fz2=0.0;//右通道幅值
float f=50.0;//频率50Hz
float t1=0.0;
float oled1=0.0;
/*频率固定50Hz,一个周期内128个点*/
t1=((1/f)*1000000-6000)/point;//频率需要实测调整
t0=(int)t1/2;
// printf("t=%d\r\n",t0);
for(i=0;i<point;i++)
{
hd=2.0f*PI/((float)point);
fz1=Vfz1*sin(hd*i)+Vfz1;//向上平移VPP/2
sindataL[i]=round(fz1);
fz2=Vfz2*sin(hd*i)+Vfz2;//向上平移VPP/2
sindataR[i]=round(fz2);
I2S_WriteData(CM_I2S1,(uint32_t) sindataL[i]);//左声道电压U
RXDATAL[i]=I2S_ReadData(CM_I2S1);
I2S_WriteData(CM_I2S1, (uint32_t)sindataR[i]);//右声道电流I
RXDATAR[i]=I2S_ReadData(CM_I2S1);
oled1=(((float)RXDATAR[i])/((float)0X781a9f77))*0.835;//1.67Vpp
//printf("RXDATA=%x\r\n",RXDATAR[i]);
oled2=(uint8_t)((oled1*64)/0.835);
//printf("oled1=%.2f\r\n",oled1);
//oled2=30*sin(hd*i)+32;
OLED_DrawPoint(i,oled2,1);
//DDL_DelayMS(500);
DDL_DelayUS(t0);
}
// printf("sin sceuss\r\n");
}
写在最后
第一次写博客,给出的代码可以直接copy使用的,希望大家看完三连一下,谢谢!!!
(更详细的知识解答请私聊)
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)