请选择 进入手机版 | 继续访问电脑版
[X]关闭
0

S02-CH34 AXI-Lite总线音频驱动方案

摘要: 软件版本:VIVADO2017.4操作系统:WIN10 64bit硬件平台:适用米联客 ZYNQ系列开发板米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!!34.1 概述 本章讲解了使用开发板驱动音频子卡,实现音频 ...

软件版本:VIVADO2017.4

操作系统:WIN10 64bit

硬件平台:适用米联客 ZYNQ系列开发板

米联客(MSXBO)论坛:www.osrc.cn答疑解惑专栏开通,欢迎大家给我提问!!

34.1 概述

      本章讲解了使用开发板驱动音频子卡,实现音频信号采集的采集和输出的过程。

34.2 音频采集卡图片

34.2.1 ADAU1761介绍

     音频子卡使用的主芯片ADAU1761 是一款低功耗、集成数字音频处理功能的立体声音频编解码器,支持立体 声 48 kHz 录音和回放,采用1.8V 模拟电源供电,功耗为 14mW。立体声音频 ADC 和DAC 支持 8 kHz 至 96 kHz 范围内的采样速率,并支持数字音量控制。

     SigmaDSP®内核具有 28 位处理特性(56 位双精度)。系统设计人员可以利用这款处理器,通过均衡、多频段压缩、限幅和第三方算法来弥补麦克风、扬声器、功放和听音环境的实际限制,从而明显改善音质体验。

     可利用 SigmaStudio™图形开发工具对 ADAU1761 进行编程。该软件含有滤波器、动态处理器、混频器和低层次 DSP 功能等音频处理模块,可快速开发自定义信号流程。

     录音路径包括一个集成麦克风偏置电路和六路输入。可以在 ADC 之前将这些输入混 频和多路复用,或者可将其配置为旁路 ADC。ADAU1761 含有一路立体声数字麦克风输入。

     ADAU1761 内置五个高功率输出驱动器(两个差分、三个单端),支持立体声耳机、听筒或其它输出传感器。该器件还支持交流耦合或无电容配置。所有模拟输出均支持独立精密电平控制。输出混频器级允许音频灵活路由。适用于低速的 ADC/DAC 采样、输出方案。

34.2.2 音频子卡信号

音频子卡信号说明:

34.2.3 音频子卡接口

音频子卡具有两路输入和两路输出,粉色是输入接口,绿色是输出接口。

34.3 音频模块驱动设计

34.3.1 ADAU1761 收发时序

音频输入采样时序:

音频输出时序:


34.3.2 收发模块驱动设计

      音频驱动适合采用 PS+PL 的结合设计,充分发挥软件和硬件的优势。由于ADAU1761的寄存器是通过I2C总线配置的,因此适合 PS 部分C代码配置,音频的采样和发送由于是串行的,采用PL 的FPGA 硬件资源处理。本设计中将设计音频的收发模块并且将音频的硬件收发部分挂在到总线上。

       iis_deser .vhd 接收解码模块(注意代码是 VHDL 编写,不是verilog编写 

----------------------------------------------------------------------------------

-- Create Date: 2018/12/18 19:50:30

-- Module Name: iis_deser - Behavioral

-- Revision:V_1.0

-- Revision 0.01 - File Created

----------------------------------------------------------------------------------

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.std_logic_unsigned.all;


entity iis_deser is

    Port ( CLK_100MHZ : in  STD_LOGIC;

           SCLK : in  STD_LOGIC;

           LRCLK : in  STD_LOGIC;

           SDATA : in  STD_LOGIC;

           EN : in STD_LOGIC;

           LDATA : out  STD_LOGIC_VECTOR (23 downto 0);

           RDATA : out  STD_LOGIC_VECTOR (23 downto 0);

           VALID : out  STD_LOGIC);

end iis_deser;


architecture Behavioral of iis_deser is


constant bit_cntr_max : std_logic_vector(4 downto 0) := "11000";


type IIS_STATE_TYPE is (RESET, WAIT_LEFT, SKIP_LEFT, READ_LEFT, WAIT_RIGHT, SKIP_RIGHT, READ_RIGHT);


signal start_left : std_logic;

signal start_right : std_logic;

signal bit_rdy : std_logic;


signal sclk_d1 : std_logic := '0';

signal lrclk_d1 : std_logic := '0';


signal bit_cntr : std_logic_vector(4 downto 0) := (others => '0');


signal ldata_reg : std_logic_vector(23 downto 0) := (others => '0');

signal rdata_reg : std_logic_vector(23 downto 0) := (others => '0');

--signal valid_reg : std_logic := '0';


signal iis_state : IIS_STATE_TYPE := RESET;


begin


process(CLK_100MHZ)

begin

  if (rising_edge(CLK_100MHZ)) then

    sclk_d1 <= SCLK;

    lrclk_d1 <= LRCLK;

  end if;

end process;


--Detect falling edge on LRCLK

start_left <= (lrclk_d1 and not(LRCLK));

--Detect rising edge on LRCLK

start_right <= (not(lrclk_d1) and LRCLK);

--Detect rising edge on SCLK

bit_rdy <= (not(sclk_d1) and SCLK);


--Next state logic

next_iis_state_process : process (CLK_100MHZ)

begin

if (rising_edge(CLK_100MHZ)) then

case iis_state is

when RESET =>

if (EN = '1') then

iis_state <= WAIT_LEFT;

end if;

when WAIT_LEFT =>

      if (EN = '0') then

iis_state <= RESET;

elsif (start_left = '1') then

        iis_state <= SKIP_LEFT;

      end if;

    when SKIP_LEFT =>

      if (EN = '0') then

iis_state <= RESET;

elsif (bit_rdy = '1') then

        iis_state <= READ_LEFT;

      end if;

when READ_LEFT =>

      if (EN = '0') then

iis_state <= RESET;

elsif (bit_cntr = bit_cntr_max) then

        iis_state <= WAIT_RIGHT;

      end if;

when WAIT_RIGHT =>

      if (EN = '0') then

iis_state <= RESET;

elsif (start_right = '1') then

        iis_state <= SKIP_RIGHT;

      end if;

    when SKIP_RIGHT =>

      if (EN = '0') then

iis_state <= RESET;

elsif (bit_rdy = '1') then

        iis_state <= READ_RIGHT;

      end if;

when READ_RIGHT =>

      if (EN = '0') then

iis_state <= RESET;

elsif (bit_cntr = bit_cntr_max) then

        iis_state <= WAIT_LEFT;

      end if;

when others=> --should never be reached

iis_state <= RESET;

end case;

end if;

end process;


process (CLK_100MHZ)

begin

if (rising_edge(CLK_100MHZ)) then

    if (iis_state = READ_RIGHT or iis_state = READ_LEFT) then

      if (bit_rdy = '1') then

        bit_cntr <= bit_cntr + 1;

      end if;

    else

      bit_cntr <= (others => '0');

    end if;

end if;

end process;


process (CLK_100MHZ)

begin

if (rising_edge(CLK_100MHZ)) then

    if (iis_state = RESET) then

      ldata_reg <= (others => '0');

      rdata_reg <= (others => '0');

    else

      if (iis_state = READ_LEFT and bit_rdy = '1') then

        ldata_reg(23 downto 1) <= ldata_reg(22 downto 0);

        ldata_reg(0) <= SDATA;

      end if;

      if (iis_state = READ_RIGHT and bit_rdy = '1') then

        rdata_reg(23 downto 1) <= rdata_reg(22 downto 0);

        rdata_reg(0) <= SDATA;

      end if;

    end if;

  end if;

end process;


--process (CLK_100MHZ)

--begin

-- if (rising_edge(CLK_100MHZ)) then

--    if (iis_state = READ_RIGHT and bit_cntr = bit_cntr_max) then

--      valid_reg <= '1';

--    else

--      valid_reg <= '0';

--    end if;

--  end if;

--end process;


--!!!TODO:

--Ensure this triggers PWM correctly, It may be causing the data to latch before the last bit is shifted on the Right Channel

VALID <= '1' when (iis_state = READ_RIGHT and bit_cntr = bit_cntr_max) else

         '0';

LDATA <= ldata_reg;

RDATA <= rdata_reg;


end Behavioral;


iis_ser .vhd 发送模块(注意代码是 VHDL 编写,不是verilog编写

----------------------------------------------------------------------------------

-- Create Date: 2018/12/18 19:50:30

-- Module Name: iis_ser - Behavioral

-- Revision:V_1.0

-- Revision 0.01 - File Created

----------------------------------------------------------------------------------

library IEEE;

use IEEE.STD_LOGIC_1164.ALL;

use IEEE.std_logic_unsigned.all;


entity iis_ser is

Port ( CLK_100MHZ : in  STD_LOGIC; --gbuf clock

           SCLK : in  STD_LOGIC; --logic (not used as clk)

           LRCLK : in  STD_LOGIC; --logic (not used as clk)

           SDATA : out  STD_LOGIC;

           EN : in STD_LOGIC;

           LDATA : in  STD_LOGIC_VECTOR (23 downto 0);

           RDATA : in  STD_LOGIC_VECTOR (23 downto 0));

end iis_ser;


architecture Behavioral of iis_ser is


--bit cntr counts to 25 (not 24) so that it can set sdata to zero after

--the 24th bit has been sent to the receiver

constant bit_cntr_max : std_logic_vector(4 downto 0) := "11001";--25


type IIS_STATE_TYPE is (RESET, WAIT_LEFT, WRITE_LEFT, WAIT_RIGHT, WRITE_RIGHT);


signal start_left : std_logic;

signal start_right : std_logic;

signal write_bit : std_logic;


signal sclk_d1 : std_logic := '0';

signal lrclk_d1 : std_logic := '0';


signal bit_cntr : std_logic_vector(4 downto 0) := (others => '0');


signal ldata_reg : std_logic_vector(23 downto 0) := (others => '0');

signal rdata_reg : std_logic_vector(23 downto 0) := (others => '0');

signal sdata_reg : std_logic := '0';


signal iis_state : IIS_STATE_TYPE := RESET;


begin


process(CLK_100MHZ)

begin

  if (rising_edge(CLK_100MHZ)) then

    sclk_d1 <= SCLK;

    lrclk_d1 <= LRCLK;

  end if;

end process;


--Detect falling edge on LRCLK

start_left <= (lrclk_d1 and not(LRCLK));

--Detect rising edge on LRCLK

start_right <= (not(lrclk_d1) and LRCLK);

--Detect falling edge on SCLK

write_bit <= (sclk_d1 and not(SCLK));


--Next state logic

next_iis_state_process : process (CLK_100MHZ)

begin

if (rising_edge(CLK_100MHZ)) then

case iis_state is

when RESET =>

if (EN = '1') then

iis_state <= WAIT_LEFT;

end if;

when WAIT_LEFT =>

      if (EN = '0') then

iis_state <= RESET;

elsif (start_left = '1') then

        iis_state <= WRITE_LEFT;

      end if;

when WRITE_LEFT =>

      if (EN = '0') then

iis_state <= RESET;

elsif (bit_cntr = bit_cntr_max) then

        iis_state <= WAIT_RIGHT;

      end if;

when WAIT_RIGHT =>

      if (EN = '0') then

iis_state <= RESET;

elsif (start_right = '1') then

        iis_state <= WRITE_RIGHT;

      end if;

when WRITE_RIGHT =>

      if (EN = '0') then

iis_state <= RESET;

elsif (bit_cntr = bit_cntr_max) then

        iis_state <= WAIT_LEFT;

      end if;

when others=> --should never be reached

iis_state <= RESET;

end case;

end if;

end process;



process (CLK_100MHZ)

begin

if (rising_edge(CLK_100MHZ)) then

    if (iis_state = WRITE_RIGHT or iis_state = WRITE_LEFT) then

      if (write_bit = '1') then

        bit_cntr <= bit_cntr + 1;

      end if;

    else

      bit_cntr <= (others => '0');

    end if;

end if;

end process;


data_shift_proc : process (CLK_100MHZ)

begin

  if (rising_edge(CLK_100MHZ)) then

    if (iis_state = RESET) then

      ldata_reg <= (others => '0');

      rdata_reg <= (others => '0');

    elsif ((iis_state = WAIT_LEFT) and (start_left = '1')) then

      ldata_reg <= LDATA;

      rdata_reg <= RDATA;

    else

      if (iis_state = WRITE_LEFT and write_bit = '1') then

        ldata_reg(23 downto 1) <= ldata_reg(22 downto 0);

        ldata_reg(0) <= '0';

      end if;

      if (iis_state = WRITE_RIGHT and write_bit = '1') then

        rdata_reg(23 downto 1) <= rdata_reg(22 downto 0);

        rdata_reg(0) <= '0';

      end if;

    end if;

  end if;

end process data_shift_proc;


sdata_update_proc : process (CLK_100MHZ)

begin

  if (rising_edge(CLK_100MHZ)) then

    if (iis_state = RESET) then

      sdata_reg <= '0';

    elsif (iis_state = WRITE_LEFT and write_bit = '1') then

      sdata_reg <= ldata_reg(23);

    elsif (iis_state = WRITE_RIGHT and write_bit = '1') then

      sdata_reg <= rdata_reg(23);

    end if;

  end if;

end process sdata_update_proc;


SDATA <= sdata_reg;


end Behavioral;

34.3.3 创建ADAU1761的AXI4用户IP

      设计好了硬件收发的驱动程序后,还需要挂到 AXI4 总线上。因此需要将驱动封装成一个带AXI4接口的用户IP,方便以后移植和调用。

      自定义IP封装不做详细讲解,下面对需要注意的地方进行说明:

      说明1:

      设置总线形式为Lite 总线,Lite 总线是简化的AXI 总线,消耗的资源少,当然性能也是比完全版的AXI总线差一点,但是由于音频的速度并不高,因此采用Lite总线就够了,设置寄存器数量为5,因为后面我们需要用到5 个寄存器。

说明2:

ADAU1761 用户 IP 的修改

IP 创建完成后,并不能立马使用,还需要做一些修改。

修改 ADAU1761_v1_0_s00_AXI.v 文件

module ADAU1761_v1_0_S00_AXI #

(

// Users to add parameters here

// User parameters ends

// Do not modify the parameters beyond this line

// Width of S_AXI data bus

parameter integer C_S_AXI_DATA_WIDTH = 32, // Width of S_AXI address bus

parameter integer C_S_AXI_ADDR_WIDTH = 5

)

(

// Users to add ports here

output wire BCLK ,

output wire LRCLK,

input wire SDATA_I,

output wire SDATA_O,


reg [10:0]clk_cntr = 11'd0;

wire sclk_int,lrclk_int;

always @( posedge S_AXI_ACLK )

begin

clk_cntr <= clk_cntr + 1;

end

//sclk = 100MHz / 32 = 3.125 MHz

assign sclk_int = clk_cntr[4];

//lrclk = 100MHz / 2048 = 48.828125 KHz

assign lrclk_int = clk_cntr[10];

wire data_rdy;

wire [23:0]ldata_in;

wire [23:0]rdata_in;

reg [31:0]DataRx_L;

reg [31:0]DataRx_R;

iis_deser iis_deser_U0

(

.CLK_100MHZ(S_AXI_ACLK),

.SCLK(sclk_int),

.LRCLK(lrclk_int),

.SDATA(SDATA_I),

.EN(1'b1),

.LDATA(ldata_in),

.RDATA(rdata_in),

.VALID(data_rdy)

);

always @( posedge S_AXI_ACLK ) begin

if (data_rdy ==1'b1) begin

DataRx_L <= {8'd0,ldata_in};

DataRx_R <= {8'd0,rdata_in};

end

end

reg [31:0] DataTx_L;

reg [31:0] DataTx_R;

iis_ser iis_se_U0

(

.CLK_100MHZ(S_AXI_ACLK),

.SCLK(sclk_int),

.LRCLK(lrclk_int),

.SDATA(SDATA_O),

.EN(1'b1),

.LDATA(DataTx_L[23:0]),

.RDATA(DataTx_R[23:0])

);

assign LRCLK = lrclk_int;

assign BCLK = sclk_int;

reg data_rdy_bit;



always @( posedge S_AXI_ACLK )

begin

if ( S_AXI_ARESETN == 1'b0 ) begin

DataTx_L<=0; DataTx_R<=0; data_rdy_bit <= 1'b0;

end

else begin

if (slv_reg_wren) begin

case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )

3'h2: for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index =byte_index+1 )

    if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 0

DataTx_L[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];

end

3'h3:  for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index =byte_index+1 )

if ( S_AXI_WSTRB[byte_index] == 1 ) begin

// Respective byte enables are asserted as per write strobes

// Slave register 1

DataTx_R[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];

end

3'h4: begin

data_rdy_bit <= 1'b0;

end

default : begin

if (data_rdy == 1'b1) data_rdy_bit <=1'b1;

end endcase

end

end

end


assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;

always @(*)

begin

// Address decoding for reading registers

case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )

3'h0 : reg_data_out <= DataRx_L;

3'h1 : reg_data_out <= DataRx_R;

3'h2 : reg_data_out <= DataTx_L;

3'h3 : reg_data_out <= DataTx_R;

3'h4 : reg_data_out <= {31'd0,data_rdy_bit};

default: reg_data_out <= 32'd0;

endcase

end


修改ADAU1761_v1_0.v 文件修改

module ADAU1761_v1_0 #

(

// Users to add parameters here

// User parameters ends

// Do not modify the parameters beyond this line

// Parameters of Axi Slave Bus Interface S00_AXI

parameter integer C_S00_AXI_DATA_WIDTH = 32,

  parameter integer C_S00_AXI_ADDR_WIDTH = 5

)

(

// Users to add ports here

output wire BCLK ,

output wire LRCLK,

input wire SDATA_I,

output wire SDATA_O,


ADAU1761_v1_0_S00_AXI # (

.C_S_AXI_DATA_WIDTH(C_S00_AXI_DATA_WIDTH),

.C_S_AXI_ADDR_WIDTH(C_S00_AXI_ADDR_WIDTH)

) ADAU1761_v1_0_S00_AXI_inst (

.BCLK(BCLK) ,

.LRCLK(LRCLK),

.SDATA_I(SDATA_I),

.SDATA_O(SDATA_O),

.S_AXI_ACLK(s00_axi_aclk),

.S_AXI_ARESETN(s00_axi_aresetn),

.S_AXI_AWADDR(s00_axi_awaddr),

.S_AXI_AWPROT(s00_axi_awprot),

.S_AXI_AWVALID(s00_axi_awvalid),

.S_AXI_AWREADY(s00_axi_awready),

.S_AXI_WDATA(s00_axi_wdata),

.S_AXI_WSTRB(s00_axi_wstrb),

.S_AXI_WVALID(s00_axi_wvalid),

.S_AXI_WREADY(s00_axi_wready),

.S_AXI_BRESP(s00_axi_bresp),

.S_AXI_BVALID(s00_axi_bvalid),

.S_AXI_BREADY(s00_axi_bready),

.S_AXI_ARADDR(s00_axi_araddr),

.S_AXI_ARPROT(s00_axi_arprot),

.S_AXI_ARVALID(s00_axi_arvalid),

.S_AXI_ARREADY(s00_axi_arready),

.S_AXI_RDATA(s00_axi_rdata),

.S_AXI_RRESP(s00_axi_rresp),

.S_AXI_RVALID(s00_axi_rvalid),

.S_AXI_RREADY(s00_axi_rready)

)

修改完成后,重新打包生成。

34.4 创建工程中的关键设置

新建工程,并将ADAU1761的IP路径添加到IP Repository。

添加ZYNQ IP , ZYNQ IP设置如下

双击 ZYNQ 图标,在 Peripheral I/O Pins 增加I2C1用于配置 ADAU1761寄存器。

在 Clock Configuration 下,使能 FLCK_CLK1,并且把时钟配置成10Mhz,如图所示

选中 IIC_1 和 FCLK_CLK1,右击,点击 Make external,并对管脚名称进行修改。


添加 ADAU1761 IP,添加好之后点击 Run Connection Automation。

选中 ADAU1761 上其余的接口,右击,Make external,将引脚引出。

添加Constant IP,配置如下

连接好后的原理图:

34.5 PS部分设计

PS部分同时开启两路输入和两路输出。

#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

//同时开启两个输入(绿色)和输出(红色)

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);


}

}


/* ---------------------------------------------------------------------------- *

 * 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);//————6db  LINNG

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  ——————RINNG



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

}

34.6 测试

34.6.1 测试1

连接:

1、子卡与开发板连接;

2、子卡的J4接口连接音频线,音频线连接电脑的音频输出接口;

3、子卡的J2接口连接耳机线,耳机用于听从电脑上传输的音频。

测试结果:

电脑上任意播放一首歌,作为音频的输入信号;使用耳机可以听到电脑播放的音乐。

34.6.2 测试2

连接:

1、子卡与开发板连接;

2、头戴耳机,麦克风连接子卡的J3接口,耳机连接J1接口;

测试结果:

对着麦克风讲话,麦克风作为输入源,可以从耳机接口听到麦克风讲话声音。


路过

雷人

握手

鲜花

鸡蛋

最新评论

本文作者
2019-9-6 19:42
  • 7
    粉丝
  • 2800
    阅读
  • 0
    回复

关注米联客

扫描关注,了解最新资讯

联系人:汤经理
电话:0519-80699907
EMAIL:270682667@qq.com
地址:常州溧阳市天目云谷3号楼北楼201B
热门评论
排行榜