本帖最后由 RZJM 于 2016-3-17 10:40 编辑
本编文章将使用Zynq开发平台Miz702上的ADAU1761音频编解码芯片,进行采样模拟音频信号(2路),转成数字信号,然后再通过ADAU1761转成模拟信号输出(2路)。在此基础上通过左右声道相减,简单的实现人声消除。本文不介绍ADAU1761驱动的编写方法,直接采用 Ali Aljaani编写的IP。
ADAU1761参数的配置参考 ADA1761 Datasheet
本文所使用的开发板是Miz702(兼容zedboard)
PC 开发环境版本:Vivado 2015.2 Xilinx SDK 2015.2
3.5mm公对公的音频连接线一根
ADA1761驱动IP core 和本编文章工程源码下载
建立vivado工程 建好工程之后,把下载好的IP添加到IP Repository里面,如图所示
点击Create Blcok Design,完成后点击Add IP,把ZYNQ PS,添加进来,然后双击ZYNQ,进行如下配置
在Clock Configuration下,使能FLCK_CLK1,并且把时钟配置成10Mhz,如图所示
选中IIC_1和FCLK_CLK1,右击,点击Make external
结果如图所示
点击Add IP,添加zed_audio_ctrl IP,添加好之后点击Run Connection Automation
选中zed_audio_ctrl上其余的接口,右击,Make external
在空白处右击,选择Create port
然后按照如图所示配置
点击Add IP,添加Constant IP,配置如下
新建一个约束文件,把以下引脚约束添加进来
配置好之后和ADDRESS连接在一起,
然后就可以Create HDL wapper,点击Generate bitstream
新建一个约束文件,把以下引脚约束添加进来
# Miz702 or zedboard Audio Codec Constraints
set_property PACKAGE_PIN AA6 [get_ports BCLK]
set_property IOSTANDARD LVCMOS33 [get_ports BCLK]
set_property PACKAGE_PIN Y6 [get_ports LRCLK]
set_property IOSTANDARD LVCMOS33 [get_ports LRCLK]
set_property PACKAGE_PIN AA7 [get_ports SDATA_I]
set_property IOSTANDARD LVCMOS33 [get_ports SDATA_I]
set_property PACKAGE_PIN Y8 [get_ports SDATA_O]
set_property IOSTANDARD LVCMOS33 [get_ports SDATA_O]
#MCLK
set_property PACKAGE_PIN AB2 [get_ports FCLK_CLK1]
set_property IOSTANDARD LVCMOS33 [get_ports FCLK_CLK1]
set_property PACKAGE_PIN AB4 [get_ports iic_1_scl_io]
set_property IOSTANDARD LVCMOS33 [get_ports iic_1_scl_io]
set_property PACKAGE_PIN AB5 [get_ports iic_1_sda_io]
set_property IOSTANDARD LVCMOS33 [get_ports iic_1_sda_io]
set_property PACKAGE_PIN AB1 [get_ports {ADDRESS[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ADDRESS[0]}]
set_property PACKAGE_PIN Y5 [get_ports {ADDRESS[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ADDRESS[1]}] 复制代码
建立软件工程 打开SDK之后,新建一个空的工程
新建头文件文件,
audio.h
#ifndef __AUDIO_H_
#define __AUDIO_H_
#include "xparameters.h"
/* Redefine audio controller base address from xparameters.h */
#define AUDIO_BASE XPAR_ZED_AUDIO_CTRL_0_BASEADDR
/* Slave address for the ADAU audio controller 8 */
#define IIC_SLAVE_ADDR 0x70
/* I2C Serial Clock frequency in Hertz */
#define IIC_SCLK_RATE 400000
/* ADAU internal registers */
enum audio_regs {
R0_CLOCK_CONTROL = 0x00,
R1_PLL_CONTROL = 0x02,
R2_DIGITAL_MIC_JACK_DETECTION_CONTROL = 0x08,
R3_RECORD_POWER_MANAGEMENT = 0x09,
R4_RECORD_MIXER_LEFT_CONTROL_0 = 0x0A,
R5_RECORD_MIXER_LEFT_CONTROL_1 = 0x0B,
R6_RECORD_MIXER_RIGHT_CONTROL_0 = 0x0C,
R7_RECORD_MIXER_RIGHT_CONTROL_1 = 0x0D,
R8_LEFT_DIFFERENTIAL_INPUT_VOLUME_CONTROL = 0x0E,
R9_RIGHT_DIFFERENTIAL_INPUT_VOLUME_CONTROL = 0x0F,
R10_RECORD_MICROPHONE_BIAS_CONTROL = 0x10,
R11_ALC_CONTROL_0 = 0x11,
R12_ALC_CONTROL_1 = 0x12,
R13_ALC_CONTROL_2 = 0x13,
R14_ALC_CONTROL_3 = 0x14,
R15_SERIAL_PORT_CONTROL_0 = 0x15,
R16_SERIAL_PORT_CONTROL_1 = 0x16,
R17_CONVERTER_CONTROL_0 = 0x17,
R18_CONVERTER_CONTROL_1 = 0x18,
R19_ADC_CONTROL = 0x19,
R20_LEFT_INPUT_DIGITAL_VOLUME = 0x1A,
R21_RIGHT_INPUT_DIGITAL_VOLUME = 0x1B,
R22_PLAYBACK_MIXER_LEFT_CONTROL_0 = 0x1C,
R23_PLAYBACK_MIXER_LEFT_CONTROL_1 = 0x1D,
R24_PLAYBACK_MIXER_RIGHT_CONTROL_0 = 0x1E,
R25_PLAYBACK_MIXER_RIGHT_CONTROL_1 = 0x1F,
R26_PLAYBACK_LR_MIXER_LEFT_LINE_OUTPUT_CONTROL = 0x20,
R27_PLAYBACK_LR_MIXER_RIGHT_LINE_OUTPUT_CONTROL = 0x21,
R28_PLAYBACK_LR_MIXER_MONO_OUTPUT_CONTROL = 0x22,
R29_PLAYBACK_HEADPHONE_LEFT_VOLUME_CONTROL = 0x23,
R30_PLAYBACK_HEADPHONE_RIGHT_VOLUME_CONTROL = 0x24,
R31_PLAYBACK_LINE_OUTPUT_LEFT_VOLUME_CONTROL = 0x25,
R32_PLAYBACK_LINE_OUTPUT_RIGHT_VOLUME_CONTROL = 0x26,
R33_PLAYBACK_MONO_OUTPUT_CONTROL = 0x27,
R34_PLAYBACK_POP_CLICK_SUPPRESSION = 0x28,
R35_PLAYBACK_POWER_MANAGEMENT = 0x29,
R36_DAC_CONTROL_0 = 0x2A,
R37_DAC_CONTROL_1 = 0x2B,
R38_DAC_CONTROL_2 = 0x2C,
R39_SERIAL_PORT_PAD_CONTROL = 0x2D,
R40_CONTROL_PORT_PAD_CONTROL_0 = 0x2F,
R41_CONTROL_PORT_PAD_CONTROL_1 = 0x30,
R42_JACK_DETECT_PIN_CONTROL = 0x31,
R67_DEJITTER_CONTROL = 0x36,
R58_SERIAL_INPUT_ROUTE_CONTROL = 0xF2,
R59_SERIAL_OUTPUT_ROUTE_CONTROL = 0xF3,
R61_DSP_ENABLE = 0xF5,
R62_DSP_RUN = 0xF6,
R63_DSP_SLEW_MODES = 0xF7,
R64_SERIAL_PORT_SAMPLING_RATE = 0xF8,
R65_CLOCK_ENABLE_0 = 0xF9,
R66_CLOCK_ENABLE_1 = 0xFA
};
/* Audio controller registers */
enum i2s_regs {
I2S_DATA_RX_L_REG = 0x00 + AUDIO_BASE,
I2S_DATA_RX_R_REG = 0x04 + AUDIO_BASE,
I2S_DATA_TX_L_REG = 0x08 + AUDIO_BASE,
I2S_DATA_TX_R_REG = 0x0c + AUDIO_BASE,
I2S_STATUS_REG = 0x10 + AUDIO_BASE,
};
#endif 复制代码
新建C文件
audio.c #include <stdio.h>
#include <xil_io.h>
#include <sleep.h>
#include "xiicps.h"
#include <xil_printf.h>
#include <xparameters.h>
#include "xuartps.h"
#include "stdlib.h"
#include "audio.h"
// Parameter definitions
#define UART_BASEADDR XPAR_PS7_UART_1_BASEADDR
#define GPIO_BASE XPAR_GPIO_0_BASEADDR
#define LED_CHANNEL 1
//----------------------------------------------------
// PROTOTYPE FUNCTIONS
//----------------------------------------------------
unsigned char IicConfig(unsigned int DeviceIdPS);
void AudioPllConfig();
void AudioWriteToReg(unsigned char u8RegAddr, unsigned char u8Data);
void AudioConfigureJacks();
void LineinLineoutConfig();
void read_superpose_play();;
//Global variables
XIicPs Iic;
int main(void)
{
xil_printf("------------------Enter Main Fun------------------------------\r\n");
//Configure the IIC data structure
IicConfig(XPAR_XIICPS_0_DEVICE_ID);
//Configure the Audio Codec's PLL
AudioPllConfig();
//Configure the Line in and Line out ports.
//Call LineInLineOutConfig() for a configuration that
//同时开启Miz702的两个输入(绿色)和输出(红色)
AudioConfigureJacks();
xil_printf("-----------------ADAU1761 configured----------------------------\n\r");
while(1)
{
//循环采集 播放
read_superpose_play();
}
return 0;
}
//
void read_superpose_play(void)
{
u32 in_left, in_right, out_left, out_right;
while (!XUartPs_IsReceiveData(UART_BASEADDR)){
// 采集到的左右声道的数据
in_left = Xil_In32(I2S_DATA_RX_L_REG);
in_right = Xil_In32(I2S_DATA_RX_R_REG);
out_left = in_left ;
out_right = in_right ;
//输出
Xil_Out32(I2S_DATA_TX_L_REG, out_left);
Xil_Out32(I2S_DATA_TX_R_REG, out_right);
//消除人声
// out_right = in_right - out_right ;
//Xil_Out32(I2S_DATA_TX_L_REG, out_right );
//Xil_Out32(I2S_DATA_TX_R_REG, out_right);
}
}
/* ---------------------------------------------------------------------------- *
* IicConfig() *
* ---------------------------------------------------------------------------- *
* Initialises the IIC driver by looking up the configuration in the config
* table and then initialising it. Also sets the IIC serial clock rate.
* ---------------------------------------------------------------------------- */
unsigned char IicConfig(unsigned int DeviceIdPS)
{
XIicPs_Config *Config;
int Status;
/* Initialise the IIC driver so that it's ready to use */
// Look up the configuration in the config table
Config = XIicPs_LookupConfig(DeviceIdPS);
if(NULL == Config) {
return XST_FAILURE;
}
// Initialise the IIC driver configuration
Status = XIicPs_CfgInitialize(&Iic, Config, Config->BaseAddress);
if(Status != XST_SUCCESS) {
return XST_FAILURE;
}
//Set the IIC serial clock rate.
XIicPs_SetSClk(&Iic, IIC_SCLK_RATE);
return XST_SUCCESS;
}
/* ---------------------------------------------------------------------------- *
* AudioPllConfig() *
* ---------------------------------------------------------------------------- *
* Configures audio codes's internal PLL. With MCLK = 10 MHz it configures the
* PLL for a VCO frequency = 49.152 MHz, and an audio sample rate of 48 KHz.
* ---------------------------------------------------------------------------- */
void AudioPllConfig() {
unsigned char u8TxData[8], u8RxData[6];
int Status;
Status = IicConfig(XPAR_XIICPS_0_DEVICE_ID);
if(Status != XST_SUCCESS) {
xil_printf("\nError initializing IIC");
}
// Disable Core Clock
AudioWriteToReg(R0_CLOCK_CONTROL, 0x0E);
// Write 6 bytes to R1 @ register address 0x4002
u8TxData[0] = 0x40; // Register write address [15:8]
u8TxData[1] = 0x02; // Register write address [7:0]
u8TxData[2] = 0x02; // byte 6 - M[15:8]
u8TxData[3] = 0x71; // byte 5 - M[7:0]
u8TxData[4] = 0x02; // byte 4 - N[15:8]
u8TxData[5] = 0x3C; // byte 3 - N[7:0]
u8TxData[6] = 0x21; // byte 2 - 7 = reserved, bits 6:3 = R[3:0], 2:1 = X[1:0], 0 = PLL operation mode
u8TxData[7] = 0x01; // byte 1 - 7:2 = reserved, 1 = PLL Lock, 0 = Core clock enable
// Write bytes to PLL Control register R1 @ 0x4002
XIicPs_MasterSendPolled(&Iic, u8TxData, 8, (IIC_SLAVE_ADDR >> 1));
while(XIicPs_BusIsBusy(&Iic));
// Register address set: 0x4002
u8TxData[0] = 0x40;
u8TxData[1] = 0x02;
// Poll PLL Lock bit
do {
XIicPs_MasterSendPolled(&Iic, u8TxData, 2, (IIC_SLAVE_ADDR >> 1));
while(XIicPs_BusIsBusy(&Iic));
XIicPs_MasterRecvPolled(&Iic, u8RxData, 6, (IIC_SLAVE_ADDR >> 1));
while(XIicPs_BusIsBusy(&Iic));
}
while((u8RxData[5] & 0x02) == 0); // while not locked
AudioWriteToReg(R0_CLOCK_CONTROL, 0x0F); // 1111
// bit 3: CLKSRC = PLL Clock input
// bits 2:1: INFREQ = 1024 x fs
// bit 0: COREN = Core Clock enabled
}
/* ---------------------------------------------------------------------------- *
* AudioWriteToReg *
* ---------------------------------------------------------------------------- *
* Function to write one byte (8-bits) to one of the registers from the audio
* controller.
* ---------------------------------------------------------------------------- */
void AudioWriteToReg(unsigned char u8RegAddr, unsigned char u8Data) {
unsigned char u8TxData[3];
u8TxData[0] = 0x40;
u8TxData[1] = u8RegAddr;
u8TxData[2] = u8Data;
XIicPs_MasterSendPolled(&Iic, u8TxData, 3, (IIC_SLAVE_ADDR >> 1));
while(XIicPs_BusIsBusy(&Iic));
}
/* ---------------------------------------------------------------------------- *
* AudioConfigureJacks() *
* ---------------------------------------------------------------------------- *
* Configures audio codes's various mixers, ADC's, DAC's, and amplifiers to
* accept stereo input from line in and push stereo output to line out.
* ---------------------------------------------------------------------------- */
void AudioConfigureJacks()
{
//AudioWriteToReg(R4_RECORD_MIXER_LEFT_CONTROL_0, 0x01); //enable mixer 1
AudioWriteToReg(R4_RECORD_MIXER_LEFT_CONTROL_0, 0x0f);
AudioWriteToReg(R5_RECORD_MIXER_LEFT_CONTROL_1, 0x07); //unmute Left channel of line in into mxr 1 and set gain to 6 db
AudioWriteToReg(R6_RECORD_MIXER_RIGHT_CONTROL_0, 0x0f); //enable mixer 2
AudioWriteToReg(R8_LEFT_DIFFERENTIAL_INPUT_VOLUME_CONTROL,0x03);
AudioWriteToReg(R9_RIGHT_DIFFERENTIAL_INPUT_VOLUME_CONTROL,0x03);
AudioWriteToReg(R10_RECORD_MICROPHONE_BIAS_CONTROL, 0x01);
AudioWriteToReg(R7_RECORD_MIXER_RIGHT_CONTROL_1, 0x07); //unmute Right channel of line in into mxr 2 and set gain to 6 db
AudioWriteToReg(R19_ADC_CONTROL, 0x13); //enable ADCs
AudioWriteToReg(R22_PLAYBACK_MIXER_LEFT_CONTROL_0, 0x21); //unmute Left DAC into Mxr 3; enable mxr 3
AudioWriteToReg(R24_PLAYBACK_MIXER_RIGHT_CONTROL_0, 0x41); //unmute Right DAC into Mxr4; enable mxr 4
AudioWriteToReg(R26_PLAYBACK_LR_MIXER_LEFT_LINE_OUTPUT_CONTROL, 0x05); //unmute Mxr3 into Mxr5 and set gain to 6db; enable mxr 5
AudioWriteToReg(R27_PLAYBACK_LR_MIXER_RIGHT_LINE_OUTPUT_CONTROL, 0x11); //unmute Mxr4 into Mxr6 and set gain to 6db; enable mxr 6
AudioWriteToReg(R29_PLAYBACK_HEADPHONE_LEFT_VOLUME_CONTROL, 0xFF);//Mute Left channel of HP port (LHP)
AudioWriteToReg(R30_PLAYBACK_HEADPHONE_RIGHT_VOLUME_CONTROL, 0xFF); //Mute Right channel of HP port (LHP)
//AudioWriteToReg(R31_PLAYBACK_LINE_OUTPUT_LEFT_VOLUME_CONTROL, 0xE6); //set LOUT volume (0db); unmute left channel of Line out port; set Line out port to line out mode
//AudioWriteToReg(R32_PLAYBACK_LINE_OUTPUT_RIGHT_VOLUME_CONTROL, 0xE6); // set ROUT volume (0db); unmute right channel of Line out port; set Line out port to line out mode
AudioWriteToReg(R31_PLAYBACK_LINE_OUTPUT_LEFT_VOLUME_CONTROL, 0xFE); //set LOUT volume (0db); unmute left channel of Line out port; set Line out port to line out mode
AudioWriteToReg(R32_PLAYBACK_LINE_OUTPUT_RIGHT_VOLUME_CONTROL, 0xFE); // set ROUT volume (0db); unmute right channel of Line out port; set Line out port to line out mode
AudioWriteToReg(R35_PLAYBACK_POWER_MANAGEMENT, 0x03); //enable left and right channel playback (not sure exactly what this does...)
AudioWriteToReg(R36_DAC_CONTROL_0, 0x03); //enable both DACs
AudioWriteToReg(R58_SERIAL_INPUT_ROUTE_CONTROL, 0x01); //Connect I2S serial port output (SDATA_O) to DACs
AudioWriteToReg(R59_SERIAL_OUTPUT_ROUTE_CONTROL, 0x01); //connect I2S serial port input (SDATA_I) to ADCs
AudioWriteToReg(R65_CLOCK_ENABLE_0, 0x7F); //Enable clocks
AudioWriteToReg(R66_CLOCK_ENABLE_1, 0x03); //Enable rest of clocks
}
/* ---------------------------------------------------------------------------- *
* LineinLineoutConfig() *
* ---------------------------------------------------------------------------- *
* Configures Line-In input, ADC's, DAC's, Line-Out and HP-Out.
* ---------------------------------------------------------------------------- */
void LineinLineoutConfig() {
AudioWriteToReg(R17_CONVERTER_CONTROL_0, 0x05);//48 KHz
AudioWriteToReg(R64_SERIAL_PORT_SAMPLING_RATE, 0x05);//48 KHz
AudioWriteToReg(R19_ADC_CONTROL, 0x13);
AudioWriteToReg(R36_DAC_CONTROL_0, 0x03);
AudioWriteToReg(R35_PLAYBACK_POWER_MANAGEMENT, 0x03);
AudioWriteToReg(R58_SERIAL_INPUT_ROUTE_CONTROL, 0x01);
AudioWriteToReg(R59_SERIAL_OUTPUT_ROUTE_CONTROL, 0x01);
AudioWriteToReg(R65_CLOCK_ENABLE_0, 0x7F);
AudioWriteToReg(R66_CLOCK_ENABLE_1, 0x03);
AudioWriteToReg(R4_RECORD_MIXER_LEFT_CONTROL_0, 0x01);
AudioWriteToReg(R5_RECORD_MIXER_LEFT_CONTROL_1, 0x05);//0 dB gain
AudioWriteToReg(R6_RECORD_MIXER_RIGHT_CONTROL_0, 0x01);
AudioWriteToReg(R7_RECORD_MIXER_RIGHT_CONTROL_1, 0x05);//0 dB gain
AudioWriteToReg(R22_PLAYBACK_MIXER_LEFT_CONTROL_0, 0x21);
AudioWriteToReg(R24_PLAYBACK_MIXER_RIGHT_CONTROL_0, 0x41);
AudioWriteToReg(R26_PLAYBACK_LR_MIXER_LEFT_LINE_OUTPUT_CONTROL, 0x03);//0 dB
AudioWriteToReg(R27_PLAYBACK_LR_MIXER_RIGHT_LINE_OUTPUT_CONTROL, 0x09);//0 dB
AudioWriteToReg(R29_PLAYBACK_HEADPHONE_LEFT_VOLUME_CONTROL, 0xE7);//0 dB
AudioWriteToReg(R30_PLAYBACK_HEADPHONE_RIGHT_VOLUME_CONTROL, 0xE7);//0 dB
AudioWriteToReg(R31_PLAYBACK_LINE_OUTPUT_LEFT_VOLUME_CONTROL, 0xE6);//0 dB
AudioWriteToReg(R32_PLAYBACK_LINE_OUTPUT_RIGHT_VOLUME_CONTROL, 0xE6);//0 dB
} 复制代码
下载完成后测试效果:采集的音频信号,再次输出
修改代码,左右声道相减可以消除部分人声
红色的线是音频输入,白色的是耳机输出