Part Number:TLV320AIC26
#include "tlv.h"
int fd;// SPI设备文件描述符
int mode = SPI_MODE_0; // SPI模式
int bits = 16;// 每字比特数
int speed = 10000000;// 最大SPI总线速度(Hz)
int delay;// 延迟时间(微秒)
/*
* 初始化SPI通信.
* 返回0表示成功,-1表示失败.
*/
int spi_init(void){int ret;// 打开SPI设备文件fd = open("/dev/spidev7.0", O_RDWR);if(fd < 0){printf("打开 /dev/spidev7.0 错误\n");return -1;}/** 设置SPI模式*/ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);if (ret == -1)printf("无法设置SPI模式\n");ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);if (ret == -1)printf("无法获取SPI模式\n");/** 设置每字比特数*/ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);if (ret == -1)printf("无法设置每字比特数\n");ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);if (ret == -1)printf("无法获取每字比特数\n");/** 设置最大传输速度*/ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);if (ret == -1)printf("无法设置最大传输速度\n");ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);if (ret == -1)printf("无法获取最大传输速度\n");printf("SPI模式: 0x%x\n", mode);printf("每字比特数: %d\n", bits);printf("最大速度: %d Hz (%d KHz)\n", speed, speed / 1000);return 0;
}
/*
* 执行SPI数据传输.
* 参数:
*fd - SPI设备文件描述符
*tx - 发送缓冲区
*rx - 接收缓冲区
*len - 数据长度
* 返回0表示成功,-1表示失败.
*/
int transfer(int fd, u_int16_t *tx, u_int16_t *rx, int len)
{int ret;struct spi_ioc_transfer tr = {.tx_buf = (unsigned long)tx,.rx_buf = (unsigned long)rx,.len = len,.delay_usecs = delay,.speed_hz = speed,.bits_per_word = bits,};ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);if (ret < 1){printf("无法发送SPI消息\n");return -1;}return 0;
}
u_int16_t tvWriteRegister(u_int16_t reg, u_int16_t value)
{
u_int16_t txdata[2];
txdata[0]=reg;
txdata[1]=value;transfer(fd, txdata, NULL, sizeof(txdata));
return 0;
}
u_int16_t tvReadRegister(u_int16_t reg)
{
u_int16_t txdata[2]={0},rxdata[2]={0};
txdata[0]=reg;
txdata[1]=0;transfer(fd, txdata, rxdata, sizeof(rxdata));
return(rxdata[1]);
}
void tvInit(void)
{u_int16_treg = 0;u_int16_tdata = 0;tvWriteRegister(AIC26_REG_RESET, 0xbb00);//Writing the code OxBBOO, Reset all registertvWriteRegister(AIC26_REG_AUX_ADC, 0x3e0);tvWriteRegister(AIC26_REG_REFERENCE, 0x17);data = tvReadRegister(AIC26_REG_REFERENCE);if(data != 0x17)printf("init audio codec failed\n\n");elseprintf("init codec success\n\n");tvWriteRegister(AIC26_REG_AUDIO_CTRL1, 0x013f); //DSP mode//tvWriteRegister(AIC26_REG_AUDIO_CTRL1,0x003f);//I2S modetvWriteRegister(AIC26_REG_ADC_GAIN, 0x3400);//tvWriteRegister(AIC26_REG_ADC_GAIN,0x2800);//tvWriteRegister(AIC26_REG_ADC_GAIN,0x0);//tvWriteRegister(AIC26_REG_DAC_GAIN,0x8080);tvWriteRegister(AIC26_REG_DAC_GAIN, 0x0202);tvWriteRegister(AIC26_REG_SIDETONE, 0x8080);tvWriteRegister(AIC26_REG_POWER_CTRL, 0xa700);tvWriteRegister(AIC26_REG_AUDIO_CTRL2, 0x0);#if 0tvWriteRegister(AIC26 REG AUDIO CTRL3,0x09fb);//Master bit11-1printf(“init codec Master mode\n”);#elsetvWriteRegister(AIC26_REG_AUDIO_CTRL3,0x01fb); //Slave bit11-0printf("init codec Slave mode\n");#endiftvWriteRegister(AIC26_REG_FILTER_COEFF_L_N0, 0x7fff);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_N0, 0x7fff);tvWriteRegister(AIC26_REG_FILTER_COEFF_L_N1, 0x81a6);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_N1, 0x81a6);tvWriteRegister(AIC26_REG_FILTER_COEFF_L_N2, 0x7cb5);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_N2, 0x7cb5);tvWriteRegister(AIC26_REG_FILTER_COEFF_L_N3, 0x7fff);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_N3, 0x7fff);tvWriteRegister(AIC26_REG_FILTER_COEFF_L_N4, 0x0);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_N4, 0x0);tvWriteRegister(AIC26_REG_FILTER_COEFF_L_N5, 0x0);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_N5, 0x0);tvWriteRegister(AIC26_REG_FILTER_COEFF_L_D1, 0x7fe2);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_D1, 0x7fe2);tvWriteRegister(AIC26_REG_FILTER_COEFF_L_D2, 0x803c);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_D2, 0x803c);tvWriteRegister(AIC26_REG_FILTER_COEFF_L_D4, 0x0);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_D4, 0x0);tvWriteRegister(AIC26_REG_FILTER_COEFF_L_D5, 0x0);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_D5, 0x0);tvWriteRegister(AIC26_REG_AUDIO_CTRL4, 0x1000);tvWriteRegister(AIC26_REG_AUDIO_CTRL5, 0xedb0);tvWriteRegister(AIC26_REG_PLL_PROG1, 0x8120);tvWriteRegister(AIC26_REG_PLL_PROG2, 0x1e00);//tvWriteRegister(AIC26_REG_POWER_CTRL_0x3191);tvWriteRegister(AIC26_REG_POWER_CTRL, 0x3091);reg = tvReadRegister(AIC26_REG_ADC_GAIN);reg = reg & (~(0x1f << 15));tvWriteRegister(AIC26_REG_ADC_GAIN, reg);
}
int main(int argc, char *argv[])
{spi_init();tvInit();return 0;
}

执行这个代码报错了,能不能帮忙看一下是我transfer,tvReadRegister,tvWriteRegister这些函数哪里错误了,导致初始化音频驱动报错了。
Alice:
您好,
这个FAQ中有驱动代码,请参考。
[FAQ] Linux Drivers: Device drivers for AIC31xx/DAC31xx/AIC325x/AIC320x/AIC326x/AIC321x – Audio forum – Audio – TI E2E support forums
,
jorks:
我用的是linux5.10代码,需要配置dts文件。使用了spi接口,请问这样配置可以吗 &spi7 { status = "okay"; mcpdevy:mcpdevy@0 { compatible = "tlv320aic26-codec"; reg = <0>; spi-max-frequency = <10000000>; status = "okay"; }; };
,
Alice:
您好,
FAQ中有DTS的配置示例。
,
jorks:
faq中是使用i2c接口的芯片,aic26是使用spi接口的,可以按照那样配置吗?
,
jorks:
另外能不能找技术人员帮忙看看我贴的代码里spi通讯问题。是不是哪里不对?因为我们使用aic26芯片是直接连接的卫星通讯模块,不是连的soc。直接配置寄存器使用更好。如果使用linux驱动也是不知道怎么设置了。
,
Alice:
您好,
请确认卫星通讯模块的可作为SPI master,因为TLV320AIC26的只能是SPI slave,TLV320AIC26寄存器配置请参考datasheet P36的register map。 SPI 与I2C只是通讯接口的区别,接口的驱动取决于您使用的平台,很遗憾,我们无法提供更多支持。
,
jorks:
就是把TLV320AIC26当作SPI slave配置的,参考datasheet配置的寄存器,只是读取的数据报错,不确定哪里问题,就想找你们支持定位一下。
,
Alice:
您好,
不是读失败,是没有写入成功。
请通过读取寄存器的“RESET VALUE”来验证SPI读时序。
然后再通过写入再回读的方法验证SPI写时序。
请参考数据手册Figure 29确认数据帧格式及R/W位,寄存器寻址采用page+addr形式(Table 6. Memory Map)。
,
jorks:
我试了把读到的值打印出来,全是0xffff。这个说明读取了,只是值不对? 数据帧格式我确认对比过。 使用了几个宏
#define AIC26_READ_COMMAND_WORD(addr) ((1 << 15) | (addr << 5))
#define AIC26_WRITE_COMMAND_WORD(addr) ((0 << 15) | (addr << 5))
#define AIC26_PAGE_ADDR(page, offset) ((page << 6) | offset) 。#ifndef APPLICATIONS_TLV320AIC26_H_ #define APPLICATIONS_TLV320AIC26_H_/* AIC26 Registers */#define AIC26_READ_COMMAND_WORD(addr)((1 << 15) | (addr << 5)) #define AIC26_WRITE_COMMAND_WORD(addr)((0 << 15) | (addr << 5)) #define AIC26_PAGE_ADDR(page, offset)((page << 6) | offset) #define AIC26_NUM_REGSAIC26_PAGE_ADDR(3, 0)/* Page 0: Auxiliary data registers */#define AIC26_REG_BAT1AIC26_PAGE_ADDR(0, 0x05) #define AIC26_REG_BAT2AIC26_PAGE_ADDR(0, 0x06) #define AIC26_REG_AUXAIC26_PAGE_ADDR(0, 0x07) #define AIC26_REG_TEMP1AIC26_PAGE_ADDR(0, 0x09) #define AIC26_REG_TEMP2AIC26_PAGE_ADDR(0, 0x0A)/* Page 1: Auxiliary control registers */#define AIC26_REG_AUX_ADCAIC26_PAGE_ADDR(1, 0x00) #define AIC26_REG_STATUSAIC26_PAGE_ADDR(1, 0x01) #define AIC26_REG_REFERENCEAIC26_PAGE_ADDR(1, 0x03) #define AIC26_REG_RESETAIC26_PAGE_ADDR(1, 0x04)/* Page 2: Audio control registers */#define AIC26_REG_AUDIO_CTRL1AIC26_PAGE_ADDR(2, 0x00) #define AIC26_REG_ADC_GAINAIC26_PAGE_ADDR(2, 0x01) #define AIC26_REG_DAC_GAINAIC26_PAGE_ADDR(2, 0x02) #define AIC26_REG_SIDETONEAIC26_PAGE_ADDR(2, 0x03) #define AIC26_REG_AUDIO_CTRL2AIC26_PAGE_ADDR(2, 0x04) #define AIC26_REG_POWER_CTRLAIC26_PAGE_ADDR(2, 0x05) #define AIC26_REG_AUDIO_CTRL3AIC26_PAGE_ADDR(2, 0x06)#define AIC26_REG_FILTER_COEFF_L_N0 AIC26_PAGE_ADDR(2, 0x07) #define AIC26_REG_FILTER_COEFF_L_N1 AIC26_PAGE_ADDR(2, 0x08) #define AIC26_REG_FILTER_COEFF_L_N2 AIC26_PAGE_ADDR(2, 0x09) #define AIC26_REG_FILTER_COEFF_L_N3 AIC26_PAGE_ADDR(2, 0x0A) #define AIC26_REG_FILTER_COEFF_L_N4 AIC26_PAGE_ADDR(2, 0x0B) #define AIC26_REG_FILTER_COEFF_L_N5 AIC26_PAGE_ADDR(2, 0x0C) #define AIC26_REG_FILTER_COEFF_L_D1 AIC26_PAGE_ADDR(2, 0x0D) #define AIC26_REG_FILTER_COEFF_L_D2 AIC26_PAGE_ADDR(2, 0x0E) #define AIC26_REG_FILTER_COEFF_L_D4 AIC26_PAGE_ADDR(2, 0x0F) #define AIC26_REG_FILTER_COEFF_L_D5 AIC26_PAGE_ADDR(2, 0x10) #define AIC26_REG_FILTER_COEFF_R_N0 AIC26_PAGE_ADDR(2, 0x11)#define AIC26_REG_FILTER_COEFF_R_N1 AIC26_PAGE_ADDR(2, 0x12) #define AIC26_REG_FILTER_COEFF_R_N2 AIC26_PAGE_ADDR(2, 0x13) #define AIC26_REG_FILTER_COEFF_R_N3 AIC26_PAGE_ADDR(2, 0x14) #define AIC26_REG_FILTER_COEFF_R_N4 AIC26_PAGE_ADDR(2, 0x15) #define AIC26_REG_FILTER_COEFF_R_N5 AIC26_PAGE_ADDR(2, 0x16) #define AIC26_REG_FILTER_COEFF_R_D1 AIC26_PAGE_ADDR(2, 0x17) #define AIC26_REG_FILTER_COEFF_R_D2 AIC26_PAGE_ADDR(2, 0x18) #define AIC26_REG_FILTER_COEFF_R_D4 AIC26_PAGE_ADDR(2, 0x19) #define AIC26_REG_FILTER_COEFF_R_D5 AIC26_PAGE_ADDR(2, 0x1A)#define AIC26_REG_PLL_PROG1AIC26_PAGE_ADDR(2, 0x1B) #define AIC26_REG_PLL_PROG2AIC26_PAGE_ADDR(2, 0x1C) #define AIC26_REG_AUDIO_CTRL4AIC26_PAGE_ADDR(2, 0x1D) #define AIC26_REG_AUDIO_CTRL5AIC26_PAGE_ADDR(2, 0x1E)#endif /* APPLICATIONS_TLV320AIC26_H_ */#include <stdio.h> #include <sys/ioctl.h> #include <linux/spi/spidev.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h>#include "tlv.h"int fd;// SPI设备文件描述符 int mode = SPI_MODE_0;// SPI模式 int bits = 16;// 每字比特数 int speed = 1000000;// 最大SPI总线速度(Hz) int delay = 10;// 延迟时间(微秒)/** 初始化SPI通信.* 返回0表示成功,-1表示失败.*/ int spi_init(void){int ret;// 打开SPI设备文件fd = open("/dev/spidev7.0", O_RDWR);if(fd < 0){printf("打开 /dev/spidev7.0 错误\n");return -1;}/** 设置SPI模式*/ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);if (ret == -1)printf("无法设置SPI模式\n");ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);if (ret == -1)printf("无法获取SPI模式\n");/** 设置每字比特数*/ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);if (ret == -1)printf("无法设置每字比特数\n");ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);if (ret == -1)printf("无法获取每字比特数\n");/** 设置最大传输速度*/ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);if (ret == -1)printf("无法设置最大传输速度\n");ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);if (ret == -1)printf("无法获取最大传输速度\n");printf("SPI模式: 0x%x\n", mode);printf("每字比特数: %d\n", bits);printf("最大速度: %d Hz (%d KHz)\n", speed, speed / 1000);return 0; }/** 执行SPI数据传输.* 参数:*fd - SPI设备文件描述符*tx - 发送缓冲区*rx - 接收缓冲区*len - 数据长度* 返回0表示成功,-1表示失败.*/ int transfer(int fd, u_int16_t *tx, u_int16_t *rx, int len) {int ret;struct spi_ioc_transfer tr = {.tx_buf = (unsigned long)tx,.rx_buf = (unsigned long)rx,.len = len,.delay_usecs = delay,.speed_hz = speed,.bits_per_word = bits,};ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);if (ret < 1){printf("无法发送SPI消息\n");return -1;}return 0; }u_int16_t tvWriteRegister(u_int16_t reg, u_int16_t value) {u_int16_t txdata[2]={0};txdata[0]=AIC26_WRITE_COMMAND_WORD(reg);txdata[1]=value;txdata[0] = __bswap_16(txdata[0]);// 使用字节序转换函数txdata[1] = __bswap_16(txdata[1]);// 使用字节序转换函数transfer(fd, txdata, NULL, 4);return0;}u_int16_t tvReadRegister(u_int16_t reg) {u_int16_t txdata[2]={0},rxdata[2]={0};printf("len%d\n",sizeof(rxdata));txdata[0]=AIC26_READ_COMMAND_WORD(reg);txdata[1]=0;txdata[0] = __bswap_16(txdata[0]);// 使用字节序转换函数transfer(fd, txdata, rxdata, sizeof(rxdata));printf("recvdat0x%x0x%x\n",rxdata[0],rxdata[1]);return(rxdata[1]);}void tvInit(void) {u_int16_treg = 0;u_int16_tdata = 0;tvWriteRegister(AIC26_REG_RESET, 0xbb00);//Writing the code OxBBOO, Reset all registerusleep(5000);// 延时1ms等待复位完成tvWriteRegister(AIC26_REG_AUX_ADC, 0x3e0);tvWriteRegister(AIC26_REG_REFERENCE, 0x17);data = tvReadRegister(AIC26_REG_REFERENCE);if(data != 0x17)printf("init audio codec failed\n\n");elseprintf("init codec success\n\n");tvWriteRegister(AIC26_REG_AUDIO_CTRL1, 0x013f); //DSP mode//tvWriteRegister(AIC26_REG_AUDIO_CTRL1,0x003f);//I2S modetvWriteRegister(AIC26_REG_ADC_GAIN, 0x3400);//tvWriteRegister(AIC26_REG_ADC_GAIN,0x2800);//tvWriteRegister(AIC26_REG_ADC_GAIN,0x0);//tvWriteRegister(AIC26_REG_DAC_GAIN,0x8080);tvWriteRegister(AIC26_REG_DAC_GAIN, 0x0202);tvWriteRegister(AIC26_REG_SIDETONE, 0x8080);tvWriteRegister(AIC26_REG_POWER_CTRL, 0xa700);tvWriteRegister(AIC26_REG_AUDIO_CTRL2, 0x0);#if 0tvWriteRegister(AIC26 REG AUDIO CTRL3,0x09fb);//Master bit11-1printf(“init codec Master mode\n”);#elsetvWriteRegister(AIC26_REG_AUDIO_CTRL3,0x01fb); //Slave bit11-0printf("init codec Slave mode\n");#endiftvWriteRegister(AIC26_REG_FILTER_COEFF_L_N0, 0x7fff);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_N0, 0x7fff);tvWriteRegister(AIC26_REG_FILTER_COEFF_L_N1, 0x81a6);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_N1, 0x81a6);tvWriteRegister(AIC26_REG_FILTER_COEFF_L_N2, 0x7cb5);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_N2, 0x7cb5);tvWriteRegister(AIC26_REG_FILTER_COEFF_L_N3, 0x7fff);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_N3, 0x7fff);tvWriteRegister(AIC26_REG_FILTER_COEFF_L_N4, 0x0);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_N4, 0x0);tvWriteRegister(AIC26_REG_FILTER_COEFF_L_N5, 0x0);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_N5, 0x0);tvWriteRegister(AIC26_REG_FILTER_COEFF_L_D1, 0x7fe2);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_D1, 0x7fe2);tvWriteRegister(AIC26_REG_FILTER_COEFF_L_D2, 0x803c);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_D2, 0x803c);tvWriteRegister(AIC26_REG_FILTER_COEFF_L_D4, 0x0);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_D4, 0x0);tvWriteRegister(AIC26_REG_FILTER_COEFF_L_D5, 0x0);tvWriteRegister(AIC26_REG_FILTER_COEFF_R_D5, 0x0);tvWriteRegister(AIC26_REG_AUDIO_CTRL4, 0x1000);tvWriteRegister(AIC26_REG_AUDIO_CTRL5, 0xedb0);tvWriteRegister(AIC26_REG_PLL_PROG1, 0x8120);tvWriteRegister(AIC26_REG_PLL_PROG2, 0x1e00);//tvWriteRegister(AIC26_REG_POWER_CTRL_0x3191);tvWriteRegister(AIC26_REG_POWER_CTRL, 0x3091);reg = tvReadRegister(AIC26_REG_ADC_GAIN);reg = reg & (~(0x1f << 15));tvWriteRegister(AIC26_REG_ADC_GAIN, reg);}int main(int argc, char *argv[]) {spi_init();tvInit();return 0; }
,
jorks:
启动后读取
AIC26_PAGE_ADDR(1, 0x00) 的值还是0xffff。是不是说明读取异常?
,
Alice:
您好,
jorks 说:
启动后读取
AIC26_PAGE_ADDR(1, 0x00) 的值还是0xffff。是不是说明读取异常?
是的, 建议用示波器参考Figure 31监测一下SPI信号。
,
jorks:
好的,稍后直接用示波器试试。
TI中文支持网





