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