STGL5000

From Hamsterworks Wiki!

Jump to: navigation, search

This FPGA Project was completed in August 2017

The STGL5000 is a low power audio codec chip, and is used on the FE-Pi audio 'plate' for the Raspberry Pi. The full details are on http://www.nxp.com/products/media-and-audio-processing/audio-converters/audio-codec/ultra-low-power-audio-codec:SGTL5000

This small design configures the chip over I2C and passes the audio samples through a Digilent CMOD-A7 FPGA.

Sgtl5000.jpg

The setup in the picture is Chromecast Audio -> Codec line in -> FPGA -> Codec line out -> Speakers

  • Note - both 3.3V and 5.0V power connections are needed for the Fe-Pi board.

Source files

sgtl5000_interface.vhd

This is by no means the best set of register values, it was just what was sniffed from when the codec is used with the Raspberry Pi.

You will find the audio samples in 'rx_sample_left' and 'rx_sample_right'.

A better design would separate out the I2C control, the I2S RX and the i@S TX functions.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

Library UNISIM;
use UNISIM.vcomponents.all;

entity sgtl5000_interface is
    Port ( clk         : in    STD_LOGIC;
           pin03_sda   : inout STD_LOGIC ;
           pin05_scl   : out   STD_LOGIC := '1';
           pin12_bclk  : in    STD_LOGIC := '1';
           pin35_lrclk : in    STD_LOGIC := '1';
           pin38_din   : out   STD_LOGIC := '1';
           pin40_dout  : in    STD_LOGIC);
end sgtl5000_interface;

architecture Behavioral of sgtl5000_interface is
    constant SGTL5000_DEV_ADDR_R            : std_logic_vector( 7 downto 0) := "00010101";
    constant SGTL5000_DEV_ADDR_W            : std_logic_vector( 7 downto 0) := "00010100";

    constant SGTL5000_CHIP_ID               : std_logic_vector(15 downto 0) := x"0000";
    constant SGTL5000_CHIP_DIG_POWER        : std_logic_vector(15 downto 0) := x"0002";
    constant SGTL5000_CHIP_CLK_CTRL         : std_logic_vector(15 downto 0) := x"0004";
    constant SGTL5000_CHIP_I2S_CTRL         : std_logic_vector(15 downto 0) := x"0006";
    constant SGTL5000_CHIP_SSS_CTRL         : std_logic_vector(15 downto 0) := x"000a";
    constant SGTL5000_CHIP_ADCDAC_CTRL      : std_logic_vector(15 downto 0) := x"000e";
    constant SGTL5000_CHIP_DAC_VOL          : std_logic_vector(15 downto 0) := x"0010";
    --- 0x0012 ?
    constant SGTL5000_CHIP_PAD_STRENGTH     : std_logic_vector(15 downto 0) := x"0014";
    --- 0x0016 ?
    constant SGTL5000_CHIP_ANA_ADC_CTRL     : std_logic_vector(15 downto 0) := x"0020";
    constant SGTL5000_CHIP_ANA_HP_CTRL      : std_logic_vector(15 downto 0) := x"0022";
    constant SGTL5000_CHIP_ANA_CTRL         : std_logic_vector(15 downto 0) := x"0024";
    constant SGTL5000_CHIP_LINREG_CTRL      : std_logic_vector(15 downto 0) := x"0026";
    constant SGTL5000_CHIP_REF_CTRL         : std_logic_vector(15 downto 0) := x"0028";
    constant SGTL5000_CHIP_MIC_CTRL         : std_logic_vector(15 downto 0) := x"002a";
    constant SGTL5000_CHIP_LINE_OUT_CTRL    : std_logic_vector(15 downto 0) := x"002c";
    constant SGTL5000_CHIP_LINE_OUT_VOL     : std_logic_vector(15 downto 0) := x"002e";
    constant SGTL5000_CHIP_ANA_POWER        : std_logic_vector(15 downto 0) := x"0030";
    constant SGTL5000_CHIP_PLL_CTRL         : std_logic_vector(15 downto 0) := x"0032";
    constant SGTL5000_CHIP_CLK_TOP_CTRL     : std_logic_vector(15 downto 0) := x"0034";
    constant SGTL5000_CHIP_ANA_STATUS       : std_logic_vector(15 downto 0) := x"0036";
    constant SGTL5000_CHIP_ANA_TEST1        : std_logic_vector(15 downto 0) := x"0038";
    constant SGTL5000_CHIP_ANA_TEST2        : std_logic_vector(15 downto 0) := x"003a";
    constant SGTL5000_CHIP_SHORT_CTRL       : std_logic_vector(15 downto 0) := x"003c";

    -- DAP (Digital Audio Processor) Registers
    constant SGTL5000_DAP_CTRL              : std_logic_vector(15 downto 0) := x"0100";
    constant SGTL5000_DAP_PEQ               : std_logic_vector(15 downto 0) := x"0102";
    constant SGTL5000_DAP_BASS_ENHANCE      : std_logic_vector(15 downto 0) := x"0104";
    constant SGTL5000_DAP_BASS_ENHANCE_CTRL : std_logic_vector(15 downto 0) := x"0106";
    constant SGTL5000_DAP_AUDIO_EQ          : std_logic_vector(15 downto 0) := x"0108";
    constant SGTL5000_DAP_SURROUND          : std_logic_vector(15 downto 0) := x"010a";
    constant SGTL5000_DAP_FLT_COEF_ACCESS   : std_logic_vector(15 downto 0) := x"010c";
    constant SGTL5000_DAP_COEF_WR_B0_MSB    : std_logic_vector(15 downto 0) := x"010e";
    constant SGTL5000_DAP_COEF_WR_B0_LSB    : std_logic_vector(15 downto 0) := x"0110";
    constant SGTL5000_DAP_EQ_BASS_BAND0     : std_logic_vector(15 downto 0) := x"0116";
    constant SGTL5000_DAP_EQ_BASS_BAND1     : std_logic_vector(15 downto 0) := x"0118";
    constant SGTL5000_DAP_EQ_BASS_BAND2     : std_logic_vector(15 downto 0) := x"011a";
    constant SGTL5000_DAP_EQ_BASS_BAND3     : std_logic_vector(15 downto 0) := x"011c";
    constant SGTL5000_DAP_EQ_BASS_BAND4     : std_logic_vector(15 downto 0) := x"011e";
    constant SGTL5000_DAP_MAIN_CHAN         : std_logic_vector(15 downto 0) := x"0120";
    constant SGTL5000_DAP_MIX_CHAN          : std_logic_vector(15 downto 0) := x"0122";
    constant SGTL5000_DAP_AVC_CTRL          : std_logic_vector(15 downto 0) := x"0124";
    constant SGTL5000_DAP_AVC_THRESHOLD     : std_logic_vector(15 downto 0) := x"0126";
    constant SGTL5000_DAP_AVC_ATTACK        : std_logic_vector(15 downto 0) := x"0128";
    constant SGTL5000_DAP_AVC_DECAY         : std_logic_vector(15 downto 0) := x"012a";
    constant SGTL5000_DAP_COEF_WR_B1_MSB    : std_logic_vector(15 downto 0) := x"012c";
    constant SGTL5000_DAP_COEF_WR_B1_LSB    : std_logic_vector(15 downto 0) := x"012e";
    constant SGTL5000_DAP_COEF_WR_B2_MSB    : std_logic_vector(15 downto 0) := x"0130";
    constant SGTL5000_DAP_COEF_WR_B2_LSB    : std_logic_vector(15 downto 0) := x"0132";
    constant SGTL5000_DAP_COEF_WR_A1_MSB    : std_logic_vector(15 downto 0) := x"0134";
    constant SGTL5000_DAP_COEF_WR_A1_LSB    : std_logic_vector(15 downto 0) := x"0136";
    constant SGTL5000_DAP_COEF_WR_A2_MSB    : std_logic_vector(15 downto 0) := x"0138";
    constant SGTL5000_DAP_COEF_WR_A2_LSB    : std_logic_vector(15 downto 0) := x"013a";

    type t_array is array(0 to 61) of std_logic_vector(31 downto 0);
    
    signal settings : t_array := ( SGTL5000_CHIP_CLK_CTRL         & x"0008",
                                   SGTL5000_CHIP_ANA_POWER        & x"4060",
                                   SGTL5000_CHIP_DIG_POWER        & x"0000",
                                   SGTL5000_CHIP_I2S_CTRL         & x"0010",
                                   SGTL5000_CHIP_SSS_CTRL         & x"0010",

                                   SGTL5000_CHIP_ADCDAC_CTRL      & x"020c",
                                   SGTL5000_CHIP_DAC_VOL          & x"3c3c",
                                   SGTL5000_CHIP_PAD_STRENGTH     & x"015f",
                                   SGTL5000_CHIP_ANA_ADC_CTRL     & x"0000",
                                   SGTL5000_CHIP_ANA_HP_CTRL      & x"1818",
                                   
                                   SGTL5000_CHIP_ANA_CTRL         & x"0111",
                                   SGTL5000_CHIP_REF_CTRL         & x"0000",
                                   SGTL5000_CHIP_MIC_CTRL         & x"0000",
                                   SGTL5000_CHIP_LINE_OUT_CTRL    & x"0000",
                                   SGTL5000_CHIP_LINE_OUT_VOL     & x"0404",

                                   SGTL5000_CHIP_PLL_CTRL         & x"5000",
                                   SGTL5000_CHIP_CLK_TOP_CTRL     & x"0000",
                                   SGTL5000_CHIP_SHORT_CTRL       & x"0000",
                                   SGTL5000_CHIP_ANA_TEST1        & x"0000",
                                   SGTL5000_CHIP_ANA_TEST2        & x"0000",

                                   SGTL5000_DAP_CTRL              & x"0000",
                                   SGTL5000_DAP_PEQ               & x"0000",
                                   SGTL5000_DAP_BASS_ENHANCE      & x"0040",
                                   SGTL5000_DAP_BASS_ENHANCE_CTRL & x"051f",
                                   SGTL5000_DAP_AUDIO_EQ          & x"0000",

                                   SGTL5000_DAP_SURROUND          & x"0040",
                                   SGTL5000_DAP_EQ_BASS_BAND0     & x"002f",
                                   SGTL5000_DAP_EQ_BASS_BAND1     & x"002f",
                                   SGTL5000_DAP_EQ_BASS_BAND2     & x"002f",
                                   SGTL5000_DAP_EQ_BASS_BAND3     & x"002f",

                                   SGTL5000_DAP_EQ_BASS_BAND4     & x"002f",
                                   SGTL5000_DAP_MAIN_CHAN         & x"8000",
                                   SGTL5000_DAP_MIX_CHAN          & x"0000",
                                   SGTL5000_DAP_AVC_CTRL          & x"0510",
                                   SGTL5000_DAP_AVC_THRESHOLD     & x"1473",

                                   SGTL5000_DAP_AVC_ATTACK        & x"0028",
                                   SGTL5000_DAP_AVC_DECAY         & x"0050",
                                   SGTL5000_CHIP_LINREG_CTRL      & x"0060",
                                   SGTL5000_CHIP_ANA_POWER        & x"4060",
                                   SGTL5000_CHIP_REF_CTRL         & x"01F0",

                                   SGTL5000_CHIP_ADCDAC_CTRL      & x"020c",
                                   SGTL5000_CHIP_LINE_OUT_CTRL    & x"0322",
                                   SGTL5000_CHIP_LINE_OUT_VOL     & x"0D0D",
                                   SGTL5000_CHIP_REF_CTRL         & x"01F1",
                                   SGTL5000_CHIP_SHORT_CTRL       & x"0000",

                                   SGTL5000_CHIP_SSS_CTRL         & x"0010",
                                   SGTL5000_CHIP_DIG_POWER        & x"0063",
                                   SGTL5000_CHIP_ADCDAC_CTRL      & x"020c",
                                   SGTL5000_CHIP_PAD_STRENGTH     & x"015f",
                                   SGTL5000_CHIP_ANA_CTRL         & x"0026",

                                   SGTL5000_CHIP_MIC_CTRL         & x"0100",
                                   SGTL5000_CHIP_MIC_CTRL         & x"0170",
                                   SGTL5000_DAP_CTRL              & x"0000",
                                   SGTL5000_CHIP_ANA_POWER        & x"40E0",
                                   SGTL5000_CHIP_I2S_CTRL         & x"0080",

                                   SGTL5000_CHIP_ANA_POWER        & x"40E8",
                                   SGTL5000_CHIP_ANA_POWER        & x"40E9",
                                   SGTL5000_CHIP_ANA_POWER        & x"40EB",
                                   SGTL5000_CHIP_DAC_VOL          & x"6c6c",
                                   SGTL5000_CHIP_ADCDAC_CTRL      & x"0300",

                                   SGTL5000_CHIP_ANA_CTRL         & x"0002",
                                   SGTL5000_CHIP_ANA_CTRL         & x"0006"
                        );
                                           
    signal index    : unsigned(7 downto 0) := (others => '0');
    signal data     : std_logic_vector(63 downto 0);
    
    signal data_from_codec_i2c : std_logic := '0';
    signal data_to_codec_i2c   : std_logic := '0';
    signal tristate_bit        : std_logic := '1';

    signal counter             : unsigned(15 downto 0) := x"00FF";

    signal i2s_counter         : unsigned(12 downto 0) := (others => '0');

    signal clk_div             : unsigned(4 downto 0)  := (others => '0');

    signal pin35_lrclk_last       : std_logic := '0';
    signal pin35_lrclk_last_last  : std_logic := '0';

    signal rx_shift_reg      : std_logic_vector(31 downto 0) := (others => '0');

    signal rx_sample_left    : std_logic_vector(15 downto 0) := (others => '0');
    signal rx_sample_right   : std_logic_vector(15 downto 0) := (others => '0');

    signal tx_shift_reg      : std_logic_vector(61 downto 0) := (others => '0');
begin
    
PULLUP_inst : PULLUP
   port map (
      O => pin03_sda     -- Pullup output (connect directly to top-level port)
   );

output_buffer : IOBUF generic map (DRIVE => 12, IOSTANDARD => "DEFAULT", SLEW => "SLOW")
    port map (
        O  => data_from_codec_i2c,   -- Buffer output
        IO => pin03_sda,             -- Buffer inout port (connect directly to top-level port)
        I  => '0',                   -- Buffer input
        T  => tristate_bit);         -- 3-state enable input, high=input, low=output 
    
    -- Just to make things easier, take the top 8 bits of counter
    index <= counter(15 downto 8);
    
    -- Data that will be sent out
    data <= "11111111111111"
          & SGTL5000_DEV_ADDR_W                       & "1" 
          & settings(to_integer(index))(31 downto 24) & "1" 
          & settings(to_integer(index))(23 downto 16) & "1" 
          & settings(to_integer(index))(15 downto  8) & "1" 
          & settings(to_integer(index))( 7 downto  0) & "1"
          & "11111";
    
i2s_receiver: process(pin12_bclk)
    begin
        if rising_edge(pin12_bclk) then
            pin38_din <= tx_shift_reg(tx_shift_reg'high);
            
            tx_shift_reg      <= tx_shift_reg(tx_shift_reg'high-1 downto 0) & "0";

            if pin35_lrclk_last = '1' and pin35_lrclk_last_last = '0' then
                rx_sample_left  <=  rx_shift_reg(31 downto 16);
                rx_sample_right <=  rx_shift_reg(15 downto  0);

                tx_shift_reg(31 downto 0) <= rx_sample_left  & rx_sample_right;
            end if;
            
            rx_shift_reg      <= rx_shift_reg(rx_shift_reg'high-1 downto 0) & pin40_dout;
            
            pin35_lrclk_last_last <= pin35_lrclk_last;  
            pin35_lrclk_last      <= pin35_lrclk;  
        end if;
    end process;

i2c_transmitter: process(clk)
    begin
        if rising_edge(clk) then
            if clk_div = 0 then
                if counter(7 downto 0) = 200 or counter(7 downto 0) = 201 then 
                    tristate_bit <= '0'; -- force the start condition
                elsif counter(7 downto 0) = 19 or counter(7 downto 0) = 18 then
                    tristate_bit <= '0'; -- force the end condition            
                else
                    tristate_bit <= data(to_integer(counter(7 downto 2)));
                end if;
                
                if counter(7 downto 0) > 200 OR counter(7 downto 0) < 17 then
                    pin05_scl <= '1'; 
                else
                    pin05_scl <= std_logic(counter(1) xor counter(0));
                end if;
                
                -- Counting stupidly to send the bits in the correct order
                if counter /= to_unsigned(settings'high,8) & x"00" then
                    if counter(7 downto 0) = 0 then
                      counter <= counter + 511;
                    else
                      counter <= counter - 1;
                    end if; 
                end if;
                clk_div <= to_unsigned(30, clk_div'length);
            else
                clk_div <= clk_div - 1;            
            end if;
        end if;
    end process;                  
end Behavioral;

cmod-a7.xdc

## Clock signal 12 MHz
set_property -dict { PACKAGE_PIN L17   IOSTANDARD LVCMOS33 } [get_ports { clk }]; #IO_L12P_T1_MRCC_14 Sch=gclk
create_clock -add -name sys_clk_pin -period 83.33 -waveform {0 41.66} [get_ports {clk}];

# PIN 01
set_property -dict { PACKAGE_PIN M3    IOSTANDARD LVCMOS33 } [get_ports { pin05_scl  }]; #IO_L8N_T1_AD14N_35 Sch=pio[01]
# PIN 02
set_property -dict { PACKAGE_PIN L3    IOSTANDARD LVCMOS33 } [get_ports { pin03_sda   }]; #IO_L8P_T1_AD14P_35 Sch=pio[02]
# PIN 03
set_property -dict { PACKAGE_PIN A16   IOSTANDARD LVCMOS33 } [get_ports { pin12_bclk  }]; #IO_L12P_T1_MRCC_16 Sch=pio[03]
# PIN 04
set_property -dict { PACKAGE_PIN K3    IOSTANDARD LVCMOS33 } [get_ports { pin35_lrclk }]; #IO_L7N_T1_AD6N_35 Sch=pio[04]
# PIN 05
set_property -dict { PACKAGE_PIN C15   IOSTANDARD LVCMOS33 } [get_ports { pin38_din   }]; #IO_L11P_T1_SRCC_16 Sch=pio[05]
# Pin 06
set_property -dict { PACKAGE_PIN H1    IOSTANDARD LVCMOS33 } [get_ports { pin40_dout  }]; #IO_L3P_T0_DQS_AD5P_35 Sch=pio[06]

Personal tools