Skip to main content

High quality Raspberry Pi I2S HAT - part 3 - VHDL code

VHDL code

VHDL code is very simple. It uses only one counter and few multiplexers:

----------------------------------------------------------------------------------
-- Company: 
-- Engineer: Alexx
-- 
-- Create Date:    12:32:29 02/02/2020 
-- Design Name: 
-- Module Name:    top - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
library UNISIM;
use UNISIM.VComponents.all;

entity top is
    Port (  clock   : in  STD_LOGIC;
    data_i  : in  STD_LOGIC;
    clock44ena  : out STD_LOGIC;
    clock48ena  : out STD_LOGIC;
    led   : out STD_LOGIC;
    bck : out  STD_LOGIC;
            lrck : out  STD_LOGIC;
    bck_o : out  STD_LOGIC;
            lrck_o : out  STD_LOGIC;
    data_o : out  STD_LOGIC;
      pins : in std_logic_vector (2 downto 0)
      );
end top;

architecture Behavioral of top is


signal clk_divider  : unsigned(9 downto 0):=(others=>'0');
signal bck_tmp, lrck_tmp: std_logic;

begin


clock44ena <= '1' when pins(2) = '0' else '0';
clock48ena <= '1' when pins(2) = '1' else '0';

--clock counter
o_clk_divider: process(clock)
begin
  if(rising_edge(clock)) then
    clk_divider   <= clk_divider + 1;
  end if;
end process o_clk_divider;

--multiplexers
bck_tmp <= clk_divider(3) when pins(1 downto 0) = "00" else --2.8224M
     clk_divider(2) when pins(1 downto 0) = "01" else --5.6448M
     clk_divider(1) when pins(1 downto 0) = "10" else --11.2896M
     clk_divider(0) when pins(1 downto 0) = "11" ;    --22.5792M


lrck_tmp <= clk_divider(9) when pins(1 downto 0) = "00" else --44.1/48
    clk_divider(8) when pins(1 downto 0) = "01" else --88.2/96
    clk_divider(7) when pins(1 downto 0) = "10" else --176.4/192
    clk_divider(6) when pins(1 downto 0) = "11" ;    --352.8/384

-- led
led <= data_i;
  

-- to i2s
bck    <= bck_tmp;
lrck   <= lrck_tmp;


-- from Rpi to output
data_o <= data_i;

-- to Rpi
bck_o    <= bck_tmp;
lrck_o   <= lrck_tmp;

end Behavioral;


Here is ucf file:

NET "clock" LOC =  "P43";
NET "clock" PERIOD = 20nS high 10nS;


NET "clock44ena" LOC =  "P41";
NET "clock48ena" LOC =  "P42";

NET "PINS(2)" LOC =  "P32"; #Rpi GPIO17
NET "PINS(1)" LOC =  "P31"; #Rpi GPIO27
NET "PINS(0)" LOC =  "P30"; #Rpi GPIO22


NET "led" LOC =  "P22";

NET "bck" LOC =  "P5";
NET "lrck" LOC =  "P7";
NET "data_o" LOC =  "P8";


NET "data_i" LOC =  "P27";
NET "bck_o" LOC =  "P33";
NET "lrck_o" LOC =  "P28";

You can compile using Xilinx WebPack ISE 14.7 (free download on Xilinx website, only registration is required).

You can download ready made files for OpenOCD swd programmer:

for xc9536xl here, and for xc9572xl here.

If you create own svf file, remember to change freq in the file from 1E6 to 1E5.

Comments

Post a Comment

Popular posts from this blog

High quality Raspberry Pi I2S HAT - part 1 - overview

As it is known the Raspberry Pi can output I2S signals but there are some big disadvantages resulting in poor sound quality. First of all, Rpi cannot output exact audio frequencies (44.1/48 and multiple) due to main oscillator - this causes lot of jitter in output I2S signals. Second of all, Rpi cannot output MCLK (master clock) and although this clock is beyond  I2S bus specification , is often needed by modern DAC chips. Basic idea is to run Rpi as SLAVE , exactly as shown here: Transmitter = Rpi Receiver = I2S HAT If we take high quality oscillators, all mentioned problems will disappear. But this idea requires kernel modification (HAT has to know the value of the actual sampling frequency). This whole project is divided into four subsections - hardware, VHDL code, OpenOCD program and GNU/Linux kernel modification.

High quality Raspberry Pi I2S HAT - part 2 - hardware

Schematic diagram You can download pdf version here . Schematic is very simple: Design consists of three main parts: Q1, Q2 oscillators 45/49Mhz, U4 - Xilinx CPLD - main logic and reclocker circuit build on U5, U6 and U7. Each part has its own LDO (U1, U2, U3). You can use many IC's in SOT23 package, also there is footprint on the PCB for bypass cap. In the prototype I'm using LP5907. X1 is the input of the external power supply. In case of an external supply, JP3 should be open. There is no need for a separate jtag port, as we will program Xilinx directly through Raspberry Pi gpio.   PCB           Assembled boards Here with ordinary oscillators and xc9572xl           And here with CCHD-957 from Crystek and xc9536xl             Here is the BOM: C1 47uF/10V SMB tantal. C2, C5, C18 2.2uF/25V 1206 X7R C3, C4, C19 10uF/16V 1206 X7R C6, C7, C8, C9,

High quality Raspberry Pi I2S HAT - part 6 - conclusion

Now you have clean I2S signals, without using USB, SPDIF etc. :) This HAT was tested with different DAC's, oscillators and worked perfectly. On this picture with PCM5102 board (new post is coming):) P.S. I’ve made a small batch of this PCB and for those who wish to buy one, please do not hesitate to contact me via email.