音频编码芯片ES7210 在TDM模式工作的调试笔记
- ES7210初始化程序的解读
- 软件复位 /* Perform software reset */
- 配置时隙/* Set the initialization time when device powers up */
- 配置滤波/* Configure HPF for ADC1-4 */
- 设置采样位数,信号标准,时分多址/* Set bits per sample to 16, data protocal to I2S, enable 1xFS TDM */
- 配置模拟电源以及增益/* Configure analog power and VMID voltage */
- 分别对MIC1-4通道配置电压,和选配的MIC有关/* Set MIC1-4 bias to 2.87V */
- 分别对MIC1-4通道配置麦克风增益/* Set MIC1-4 gain to 30dB */
- 打开MIC1-4前置放大器电源/* Power on MIC1-4 */
- 设置采样频率/* Set ADC sample rate to 48kHz */
- /* Power down DLL */
- 打开麦克风供电/* Power on MIC1-4 bias & ADC1-4 & PGA1-4 Power */
- /* Enable device */
- 调整麦克风音量
ES7210初始化程序的解读
最近买了立创的实战派S3成品开发板,学习过程中,对音频编码器ES7210的初始化有些不理解,但找不到什么资料,对寄存器知道的太少,所以只好从源码下手,一点点解读,现记录如下,便于移植时备查。以下顺序均按官方初始化流程进行,使用I2C进行通信完成初始化设置。
软件复位 /* Perform software reset */
先给0X00寄存器写入0XFF,再写入0X32,恢复默认值
配置时隙/* Set the initialization time when device powers up */
向0X09和0X0A寄存器都写入0X30,应该是起配合设置时隙形成不同时分复用的通道作用
配置滤波/* Configure HPF for ADC1-4 */
向0X20至0X23寄存器写入数值,顺序是倒的23(0X2A)-22(0X0A)-21(0X2A)-20(0X0A),这块是关是各个模数转换时高通滤波器的功能配置
设置采样位数,信号标准,时分多址/* Set bits per sample to 16, data protocal to I2S, enable 1xFS TDM */
官方的变量i2s_format为0X00是I2S标准模式,也即飞利浦模式,0X01是左对齐模式,还有两种是DSP-A(0X03)DSP-B(0X13),占用了0X11寄存器低5位
官方的bit_width变量为0X60是位宽,我理解为就是单次采样的位深,常用的是16位,对应的值(0X60),可选的值有0X20,0X40,0X60,0X80,占用了0X11寄存器高3位
官方的变量flags.tdm_enable(0X01)为 TDM模式
这里需要注意的是,TDM模式下,寄存器0X12需要根据I2S信号模式来赋值,即与i2s_format有关
标准模式和左对齐模式下,0X12寄存器值应写入0X02,DSP-A,DSP-B模式下,0X12寄存器值0X01,非TDM模式,0X12寄存器值应写入0X00
这段初始化的内容就是
向0X11寄存器写入0X60 (i2s_format(0x00) | bit_width(0X60))
向0X12寄存器写入0X02
配置模拟电源以及增益/* Configure analog power and VMID voltage */
向0X40寄存器写入0X3C
分别对MIC1-4通道配置电压,和选配的MIC有关/* Set MIC1-4 bias to 2.87V */
向0X41寄存器写入0X70,可选值用了BIT.4,BIT.5,BIT.6,正好3位,值取1到7,控制MIC1-2的偏置电压
向0X42寄存器写入0X70,可选值用了BIT.4,BIT.5,BIT.6,正好3位,值取1到7,控制MIC3-4的偏置电压
分别对MIC1-4通道配置麦克风增益/* Set MIC1-4 gain to 30dB */
向0X43寄存器写入10(0X0A),配置MIC1增益,数值*3dB
向0X44寄存器写入10(0X0A),配置MIC2增益,同上
向0X45寄存器写入10(0X0A),配置MIC3增益,同上
向0X46寄存器写入10(0X0A),配置MIC4增益,同上
打开MIC1-4前置放大器电源/* Power on MIC1-4 */
向0X47至0X4A都写入0X08,对应MIC1-41-4
设置采样频率/* Set ADC sample rate to 48kHz */
这段程序比较绕,我一开始没看懂,算了半天总对不上程序,后来才发现官方是查表得出数据的。
官方设置了采样率为48K,MCLK=采样率*256=12.288MHz,i2s为了对齐采样率和信息的传输时钟,可能不同频率下算法不一样,官方并未直接用这两个数据进行计算赋值,而是根据查表比对,从事先固定的表中查出对应的数据,用该数据进行设置,确保对齐.
表的内容为:
/**
* @brief ES7210 clock coefficient lookup table
*
*/
static const coeff_div_t es7210_coeff_div[] = {
// mclk lrck ss_ds adc_div dll doubler osr mclk_src lrckh lrckl
/* 8k */
{12288000, 8000, 0x00, 0x03, 0x01, 0x00, 0x20, 0x00, 0x06, 0x00},
{16384000, 8000, 0x00, 0x04, 0x01, 0x00, 0x20, 0x00, 0x08, 0x00},
{19200000, 8000, 0x00, 0x1e, 0x00, 0x01, 0x28, 0x00, 0x09, 0x60},
{4096000, 8000, 0x00, 0x01, 0x01, 0x00, 0x20, 0x00, 0x02, 0x00},
/* 11.025k */
{11289600, 11025, 0x00, 0x02, 0x01, 0x00, 0x20, 0x00, 0x01, 0x00},
/* 12k */
{12288000, 12000, 0x00, 0x02, 0x01, 0x00, 0x20, 0x00, 0x04, 0x00},
{19200000, 12000, 0x00, 0x14, 0x00, 0x01, 0x28, 0x00, 0x06, 0x40},
/* 16k */
{4096000, 16000, 0x00, 0x01, 0x01, 0x01, 0x20, 0x00, 0x01, 0x00},
{19200000, 16000, 0x00, 0x0a, 0x00, 0x00, 0x1e, 0x00, 0x04, 0x80},
{16384000, 16000, 0x00, 0x02, 0x01, 0x00, 0x20, 0x00, 0x04, 0x00},
{12288000, 16000, 0x00, 0x03, 0x01, 0x01, 0x20, 0x00, 0x03, 0x00},
/* 22.05k */
{11289600, 22050, 0x00, 0x01, 0x01, 0x00, 0x20, 0x00, 0x02, 0x00},
/* 24k */
{12288000, 24000, 0x00, 0x01, 0x01, 0x00, 0x20, 0x00, 0x02, 0x00},
{19200000, 24000, 0x00, 0x0a, 0x00, 0x01, 0x28, 0x00, 0x03, 0x20},
/* 32k */
{12288000, 32000, 0x00, 0x03, 0x00, 0x00, 0x20, 0x00, 0x01, 0x80},
{16384000, 32000, 0x00, 0x01, 0x01, 0x00, 0x20, 0x00, 0x02, 0x00},
{19200000, 32000, 0x00, 0x05, 0x00, 0x00, 0x1e, 0x00, 0x02, 0x58},
/* 44.1k */
{11289600, 44100, 0x00, 0x01, 0x01, 0x01, 0x20, 0x00, 0x01, 0x00},
/* 48k */
{12288000, 48000, 0x00, 0x01, 0x01, 0x01, 0x20, 0x00, 0x01, 0x00},
{19200000, 48000, 0x00, 0x05, 0x00, 0x01, 0x28, 0x00, 0x01, 0x90},
/* 64k */
{16384000, 64000, 0x01, 0x01, 0x01, 0x00, 0x20, 0x00, 0x01, 0x00},
{19200000, 64000, 0x00, 0x05, 0x00, 0x01, 0x1e, 0x00, 0x01, 0x2c},
/* 88.2k */
{11289600, 88200, 0x01, 0x01, 0x01, 0x01, 0x20, 0x00, 0x00, 0x80},
/* 96k */
{12288000, 96000, 0x01, 0x01, 0x01, 0x01, 0x20, 0x00, 0x00, 0x80},
{19200000, 96000, 0x01, 0x05, 0x00, 0x01, 0x28, 0x00, 0x00, 0xc8},
};
该表对应的结构体如下:
typedef struct {
uint32_t mclk; /*!< mclk frequency */
uint32_t lrck; /*!< lrck */
uint8_t ss_ds; /*!< not used */
uint8_t adc_div; /*!< adcclk divider */
uint8_t dll; /*!< dll_bypass */
uint8_t doubler; /*!< doubler enable */
uint8_t osr; /*!< adc osr */
uint8_t mclk_src; /*!< select mclk source */
uint32_t lrck_h; /*!< The high 4 bits of lrck */
uint32_t lrck_l; /*!< The low 8 bits of lrck */
} coeff_div_t;
官方的查表程序
static const coeff_div_t *es7210_get_coeff(uint32_t mclk, uint32_t lrck)
{
for (int i = 0; i < sizeof(es7210_coeff_div) / sizeof(coeff_div_t); i++) {
if (es7210_coeff_div[i].lrck == lrck && es7210_coeff_div[i].mclk == mclk) {
return &es7210_coeff_div[i];
}
}
return NULL;
}
根据MCLK=12288000(48000*256),LRCK=48000,查表得知OSR=0X20,(adc_div|doubler<<6|dll<<7)=(0x01|0x01<<6|0x01<<7)=0xC1,LRCK高8位=0X01,LRCK低8位=0X00
于是,这段初始化的内容简化后就是
向0X07寄存器写入0X20
向0X02寄存器写入0XC1
向0X04寄存器写入0X01
向0X05寄存器写入0X00
/* Power down DLL */
不太明白,但照做就行了
向0X06寄存器写入0X04
打开麦克风供电/* Power on MIC1-4 bias & ADC1-4 & PGA1-4 Power */
向寄存器0X4B,0X4C都写入0X0F
/* Enable device */
先给0X00寄存器写入0X71,再写入0X41,相比0X32,即先BIT.6置1,BIT.1置0,BIT.0置1,再BIT.6置0
调整麦克风音量
另外还有个0X1B至0X1E寄存器可以分别给四个MIC通道调音量,值为191 + volume_db * 2,其中volume_db >= -95 && volume_db <= 32,
官方参考值volume_db=0
程序最终简化为以下这一段.
//通过I2C初始化ES7210工作在tdm模式,I2S信号为标准模式,采样率48000,位宽16
void init_es7210(void)
{
i2c_Write_es7210(0x00,0xff);
i2c_Write_es7210(0x00,0x32);
i2c_Write_es7210(0x09,0x30);
i2c_Write_es7210(0x0a,0x30);
i2c_Write_es7210(0x23,0x2a);
i2c_Write_es7210(0x22,0x0a);
i2c_Write_es7210(0x21,0x2a);
i2c_Write_es7210(0x20,0x0a);
i2c_Write_es7210(0x11,0x60);
i2c_Write_es7210(0x12,0x02);
i2c_Write_es7210(0x40,0x3c);
i2c_Write_es7210(0x41,0x70);
i2c_Write_es7210(0x42,0x70);
i2c_Write_es7210(0x43,0x1a);
i2c_Write_es7210(0x44,0x1a);
i2c_Write_es7210(0x45,0x1a);
i2c_Write_es7210(0x46,0x1a);
i2c_Write_es7210(0x47,0x08);
i2c_Write_es7210(0x48,0x08);
i2c_Write_es7210(0x49,0x08);
i2c_Write_es7210(0x4a,0x08);
i2c_Write_es7210(0x07,0x20);
i2c_Write_es7210(0x02,0xc1);
i2c_Write_es7210(0x04,0x01);
i2c_Write_es7210(0x05,0x00);
i2c_Write_es7210(0x06,0x00);
i2c_Write_es7210(0x4b,0x0f);
i2c_Write_es7210(0x4c,0x0f);
i2c_Write_es7210(0x00,0x71);
i2c_Write_es7210(0x00,0x41);
}