OpenCores
URL https://opencores.org/ocsvn/i2s_to_parallel/i2s_to_parallel/trunk

Subversion Repositories i2s_to_parallel

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 2 to Rev 3
    Reverse comparison

Rev 2 → Rev 3

/tags/V10/i2s_to_parallel.vhd
0,0 → 1,135
---------------------------------------------------------------------------------
-- Engineer: Fabio Gravina <fabio.gravina@gmail.com>
-- http://www.fgravina.net
-- Primiano Tucci <p.tucci@gmail.com>
-- http://www.primianotucci.com
--
-- Create Date: 17:26:41 12/19/2008
-- Design Name: i2s_to_parallel
--
-- Description:
--
-- This module provides a bridge between an I2S serial device (audio ADC, S/PDIF
-- Decoded data) and a parallel device (microcontroller, IP block).
--
-- It's coded as a generic VHDL entity, so developer can choose the proper signal
-- width (8/16/24 bit)
--
-- Input takes:
-- -I2S Bit Clock
-- -I2S LR Clock (Left/Right channel indication)
-- -I2S Data
--
-- Output provides:
-- -DATA_L / DATA_R parallel outputs
-- -STROBE and STROBE_LR output ready signals.
--
-- As soon as data is read from the serial I2S line, it's written on the proper
-- parallel output and a rising edge of the STROBE signal indicates that new
-- data is ready.
-- STROBE_LR signal tells if the strobe signal was relative to the
-- Left or Right channel.
--
--------------------------------------------------------------------------------
-- I2S Waveform summary
--
-- BIT_CK __ __ __ __ __ __ __ __ __
-- | 1|__| 2|_| 3|__| 4|__| 5|__... ... |32|__| 1|__| 2|__| 3| ...
--
-- LR_CK ... ... _________________
-- ____________R_Channel_Data______________| L Channel Data ...
--
-- DATA x< 00 ><D24><D22><D21><D20> ... ... < 00 ><D24><D23> ...
--
--
-- Each time enough ('width' bits of) data is collected from the serial input
-- it is outputed on the corresponding DATA_R/L port and the proper
-- STROBE signals are emitted
-- A rising edge of the STROBE signal tells that parallel data is ready
-- STROBE_LR signal tells which of the DATA_L / DATA_R has been generated
-- DATA_L/R remain valid for the whole cycle (until next data is processed)
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
 
entity i2s_to_parallel is
-- width: How many bits (from MSB) are gathered from the serial I2S input
generic(width : integer := 16);
port(
-- I2S Input ports
LR_CK : in std_logic; --Left/Right indicator clock
BIT_CK : in std_logic; --Bit clock
DIN : in std_logic; --Data Input
-- Control ports
RESET : in std_logic; --Asynchronous Reset (Active Low)
-- Parallel Output ports
DATA_L : out std_logic_vector(width-1 downto 0);
DATA_R : out std_logic_vector(width-1 downto 0);
-- Output status ports
STROBE : out std_logic; --Rising edge means data is ready
STROBE_LR : out std_logic
);
end i2s_to_parallel;
 
architecture Behavioral of i2s_to_parallel is
signal current_lr : std_logic;
signal counter : integer range 0 to width;
signal shift_reg : std_logic_vector(width-1 downto 0);
signal output_strobed : std_logic;
begin
process(RESET, BIT_CK, LR_CK, DIN)
begin
if(RESET = '0') then
DATA_L <= (others => '0');
DATA_R <= (others => '0');
shift_reg <= (others => '0');
current_lr <= '0';
STROBE_LR <= '0';
STROBE <= '0';
counter <= width;
output_strobed <= '0';
elsif rising_edge(BIT_CK) then
-- Note: LRCK changes on the falling edge of BCK
-- We notice of the first LRCK transition only on the
-- next rising edge of BCK
-- In this way we discard the first data bit as we start pushing
-- data into the shift register only on the next BCK rising edge
-- This is right for I2S standard (data starts on the 2nd clock)
if(LR_CK /= current_lr) then
current_lr <= LR_CK;
counter <= width;
--clear the shift register
shift_reg <= (others => '0');
STROBE <= '0';
output_strobed <= '0';
elsif(counter > 0) then
-- Push data into the shift register
shift_reg <= shift_reg(width-2 downto 0) & DIN;
-- Decrement counter
counter <= counter - 1;
elsif(counter = 0) then
--TODO Optimization
-- Data could be written one clock behind
-- when counter = 1 (step down counter)
-- We're wasting a cycle here
if(output_strobed = '0') then
if(current_lr = '1') then
--Output Right Channel
DATA_R <= shift_reg;
else
--Output Left Channel
DATA_L <= shift_reg;
end if;
STROBE_LR <= current_lr;
output_strobed <= '1';
else
STROBE <= '1';
end if; --(output_strobed = '0')
end if; -- (counter = 0)
end if; -- reset / rising_edge
end process;
 
end Behavioral;
/tags/V10/i2s_to_parallelTEST.vhd
0,0 → 1,152
 
--------------------------------------------------------------------------------
-- Engineer: Primiano Tucci
--
-- Create Date: 17:26:41 12/19/2008
-- Design Name: i2s_to_parallel
-- Description:
--
-- VHDL Test Bench for module: i2s_to_parallel
--
--
--------------------------------------------------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.std_logic_unsigned.all;
USE ieee.numeric_std.ALL;
 
ENTITY i2s_to_parallel_tb_vhd IS
END i2s_to_parallel_tb_vhd;
 
ARCHITECTURE behavior OF i2s_to_parallel_tb_vhd IS
constant width : integer := 24;
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT i2s_to_parallel
generic(width : integer := width);
PORT(
LR_CK : IN std_logic;
BIT_CK : IN std_logic;
DIN : IN std_logic;
RESET : IN std_logic;
DATA_L : OUT std_logic_vector(width-1 downto 0);
DATA_R : OUT std_logic_vector(width-1 downto 0);
STROBE : OUT std_logic;
STROBE_LR : OUT std_logic
);
END COMPONENT;
 
--Inputs
SIGNAL LR_CK : std_logic := '0';
SIGNAL BIT_CK : std_logic := '0';
SIGNAL DIN : std_logic := '0';
SIGNAL RESET : std_logic := '0';
 
--Outputs
SIGNAL DATA_L : std_logic_vector(width-1 downto 0);
SIGNAL DATA_R : std_logic_vector(width-1 downto 0);
SIGNAL STROBE_LR : std_logic;
SIGNAL STROBE : std_logic;
 
BEGIN
 
-- Instantiate the Unit Under Test (UUT)
uut: i2s_to_parallel PORT MAP(
LR_CK => LR_CK,
BIT_CK => BIT_CK,
DIN => DIN,
RESET => RESET,
DATA_L => DATA_L,
DATA_R => DATA_R,
STROBE_LR => STROBE_LR,
STROBE => STROBE
);
 
tb : PROCESS
subtype test_record is std_logic_vector(23 downto 0);
type test_array is array(positive range<>) of test_record;
constant test_vectors : test_array:= (
"000000000000000000000000",
"111100000000000000000000",
"101010101010101010101010",
"010101010101010101010101",
"111100001111000011110000",
"000011110000111100001111",
"111111110000000011111111",
"111111111111111111111111",
"000000000000000000000000"
) ;
constant frequency : integer := 48000;
 
constant bit_clock : integer := 64 * 48000;
constant bit_count: integer := 32;
constant Tbcdo : time := 1 ns;
constant Tcklr : time := 500 ps;
variable cur_lrck : boolean := true;
variable cur_bit : std_logic;
variable vector : test_record;
BEGIN
RESET <= '0';
LR_CK <= '1';
wait for 100 ns;
RESET <= '1';
-- Reset finished
wait for 100 ns;
BIT_CK <= '1';
wait for 10 ns;
LR_CK <= '0';
for vector_index in test_vectors'range loop
vector := test_vectors(vector_index);
--for bit_index in -1 to bit_count-2 loop
--for bit_index in 24 downto -7 loop
for bit_index in vector'length downto (0-bit_count+(vector'length)+1) loop
-- Determine bit to send
if(bit_index >=0 and bit_index < vector'length) then
cur_bit := vector(bit_index);
else
cur_bit := '0';
end if;
--Bit Clock falling edge
BIT_CK <= '0';
--Simulate Delay time of BCKO falling edge to DOUT valid
wait for Tbcdo;
--Output current data bit
DIN <= cur_bit;
--Wait for remaining clock time
wait for (1000000000 ns / bit_clock / 2) - Tbcdo;
--Bit CLock rising edge
BIT_CK <= '1';
wait for 1000000000 ns / bit_clock / 2;
end loop;
--Delay time of BCKO falling edge to LRCKO valid
wait for Tcklr;
-- Update RL_CK
if cur_lrck = true then
LR_CK <= '1';
assert STROBE_LR = '0' report "Bad STROBE_LR signal" severity FAILURE;
assert DATA_L(width-1 downto 0) = vector((vector'length-1) downto (vector'length-width)) report "DATA_L is incorrect" severity FAILURE;
--assert DATA_L(width-1 downto 0) = vector(width-1 downto 0) report "DATA_L is incorrect" severity FAILURE;
else
LR_CK <= '0';
assert STROBE_LR = '1' report "Bad STROBE_LR signal" severity FAILURE;
--assert DATA_R(width-1 downto 0) = vector(width-1 downto 0) report "DATA_R is incorrect" severity FAILURE;
assert DATA_R(width-1 downto 0) = vector((vector'length-1) downto (vector'length-width)) report "DATA_R is incorrect" severity FAILURE;
end if;
cur_lrck := not cur_lrck;
end loop;
 
report "Testbench of I2S to Parallel completed successfully!" ;
 
wait;
END PROCESS;
 
END;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.