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

Subversion Repositories i2s_interface

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 6 to Rev 7
    Reverse comparison

Rev 6 → Rev 7

/trunk/rtl/vhdl/i2s_codec.vhd
0,0 → 1,448
----------------------------------------------------------------------
---- ----
---- WISHBONE I2S Interface IP Core ----
---- ----
---- This file is part of the I2S Interface project ----
---- http://www.opencores.org/cores/i2s_interface/ ----
---- ----
---- Description ----
---- I2S encoder/decoder. ----
---- ----
---- ----
---- To Do: ----
---- - ----
---- ----
---- Author(s): ----
---- - Geir Drange, gedra@opencores.org ----
---- ----
----------------------------------------------------------------------
---- ----
---- Copyright (C) 2004 Authors and OPENCORES.ORG ----
---- ----
---- This source file may be used and distributed without ----
---- restriction provided that this copyright statement is not ----
---- removed from the file and that any derivative work contains ----
---- the original copyright notice and the associated disclaimer. ----
---- ----
---- This source file is free software; you can redistribute it ----
---- and/or modify it under the terms of the GNU General ----
---- Public License as published by the Free Software Foundation; ----
---- either version 2.0 of the License, or (at your option) any ----
---- later version. ----
---- ----
---- This source is distributed in the hope that it will be ----
---- useful, but WITHOUT ANY WARRANTY; without even the implied ----
---- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ----
---- PURPOSE. See the GNU General Public License for more details.----
---- ----
---- You should have received a copy of the GNU General ----
---- Public License along with this source; if not, download it ----
---- from http://www.gnu.org/licenses/gpl.txt ----
---- ----
----------------------------------------------------------------------
--
-- CVS Revision History
--
-- $Log: not supported by cvs2svn $
--
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
entity i2s_codec is
generic (DATA_WIDTH: integer;
ADDR_WIDTH: integer;
IS_MASTER: integer range 0 to 1;
IS_RECEIVER: integer range 0 to 1);
port (
wb_clk_i: in std_logic; -- wishbone clock
conf_res: in std_logic_vector(5 downto 0); -- sample resolution
conf_ratio: in std_logic_vector(7 downto 0); -- clock divider ratio
conf_swap: in std_logic; -- left/right sample order
conf_inten: in std_logic; -- interrupt enable
conf_en: in std_logic; -- transmitter/recevier enable
i2s_sd_i: in std_logic; -- I2S serial data input
i2s_sck_i: in std_logic; -- I2S clock input
i2s_ws_i: in std_logic; -- I2S word select input
sample_dat_i: in std_logic_vector(DATA_WIDTH - 1 downto 0); -- audio data
sample_dat_o: out std_logic_vector(DATA_WIDTH - 1 downto 0); -- audio data
mem_rdwr: out std_logic; -- sample buffer read/write
sample_addr: out std_logic_vector(ADDR_WIDTH - 2 downto 0); -- address
evt_hsbf: out std_logic; -- higher sample buf empty event
evt_lsbf: out std_logic; -- lower sample buf empty event
i2s_sd_o: out std_logic; -- I2S serial data output
i2s_sck_o: out std_logic; -- I2S clock output
i2s_ws_o: out std_logic); -- I2S word select output
end i2s_codec;
 
architecture rtl of i2s_codec is
signal i2s_clk_en, zsck, zzsck, zzzsck, imem_rd : std_logic;
signal clk_cnt : integer range 0 to 255;
signal adr_cnt : integer range 0 to 2**(ADDR_WIDTH - 1) - 1;
type srx_states is (IDLE, WAIT_CLK, TRX_DATA, RX_WRITE, SYNC);
signal sd_ctrl : srx_states;
signal bit_cnt, bits_to_trx : integer range 0 to 63;
signal toggle, master, neg_edge, ws_pos_edge, ws_neg_edge : std_logic;
signal data_in : std_logic_vector(DATA_WIDTH - 1 downto 0);
signal zws, zzws, zzzws, i2s_ws, new_word, last_bit: std_logic;
signal imem_rdwr, receiver : std_logic;
signal ws_cnt : integer range 0 to 31;
begin
 
-- Create signals that reflect generics
SGM: if IS_MASTER = 1 generate
master <= '1';
end generate SGM;
SGS: if IS_MASTER = 0 generate
master <= '0';
end generate SGS;
SGRX: if IS_RECEIVER = 1 generate
receiver <= '1';
end generate SGRX;
SGTX: if IS_RECEIVER = 0 generate
receiver <= '0';
end generate SGTX;
-- I2S clock enable generation, master mode. The clock is a fraction of the
-- Wishbone bus clock, determined by the conf_ratio value.
CGM: if IS_MASTER = 1 generate
CGEN: process (wb_clk_i)
begin
if rising_edge(wb_clk_i) then
if conf_en = '0' then -- disabled
i2s_clk_en <= '0';
clk_cnt <= 0;
neg_edge <= '0';
toggle <= '0';
else -- enabled
if clk_cnt < to_integer(unsigned(conf_ratio)) + 1 then
clk_cnt <= (clk_cnt + 1) mod 256;
i2s_clk_en <= '0';
else
clk_cnt <= 0;
i2s_clk_en <= '1';
neg_edge <= not neg_edge;
end if;
toggle <= neg_edge;
end if;
end if;
end process CGEN;
end generate CGM;
 
-- I2S clock enable generation, slave mode. The input clock signal is sampeled
-- and the negative edge is located.
CGS: if IS_MASTER = 0 generate
CGEN: process (wb_clk_i)
begin
if rising_edge(wb_clk_i) then
if conf_en = '0' then -- disabled
i2s_clk_en <= '0';
zsck <= '0';
zzsck <= '0';
zzzsck <= '0';
toggle <= '0';
neg_edge <= '0';
else -- enabled
-- synchronize input clock to Wishbone clock domaine
zsck <= i2s_sck_i;
zzsck <= zsck;
zzzsck <= zzsck;
-- look for edges
if zzzsck = '1' and zzsck = '0' then
i2s_clk_en <= '1';
neg_edge <= '1';
elsif zzzsck = '0' and zzsck = '1' then
i2s_clk_en <= '1';
neg_edge <= '0';
else
i2s_clk_en <= '0';
end if;
toggle <= neg_edge;
end if;
end if;
end process CGEN;
end generate CGS;
 
-- Process to generate word select signal, master mode
WSM: if IS_MASTER = 1 generate
i2s_ws_o <= i2s_ws;
WSG: process (wb_clk_i)
begin
if rising_edge(wb_clk_i) then
if conf_en = '0' then
i2s_ws <= '0';
ws_cnt <= 0;
ws_pos_edge <= '0';
ws_neg_edge <= '0';
else
if i2s_clk_en = '1' and toggle = '1' then
if ws_cnt < bits_to_trx then
ws_cnt <= ws_cnt + 1;
else
i2s_ws <= not i2s_ws;
ws_cnt <= 0;
if i2s_ws = '1' then
ws_neg_edge <= '1';
else
ws_pos_edge <= '1';
end if;
end if;
else
ws_pos_edge <= '0';
ws_neg_edge <= '0';
end if;
end if;
end if;
end process WSG;
end generate WSM;
 
-- Process to detect word select edges, slave mode
WSD: if IS_MASTER = 0 generate
i2s_ws <= i2s_ws_i;
WSDET: process (wb_clk_i)
begin
if rising_edge(wb_clk_i) then
if conf_en = '0' then
ws_pos_edge <= '0';
ws_neg_edge <= '0';
zws <= i2s_ws;
zzws <= i2s_ws;
zzzws <= i2s_ws;
else
-- sync i2s_ws_io to our clock domaine
zws <= i2s_ws;
zzws <= zws;
zzzws <= zzws;
-- detect negative edge
if zzzws = '1' and zzws = '0' then
ws_neg_edge <= '1';
else
ws_neg_edge <= '0';
end if;
-- detect positive edge
if zzzws = '0' and zzws = '1' then
ws_pos_edge <= '1';
else
ws_pos_edge <= '0';
end if;
end if;
end if;
end process WSDET;
end generate WSD;
 
-- Logic to generate clock signal, master mode
SCKM: if IS_MASTER = 1 generate
i2s_sck_o <= toggle;
end generate SCKM;
-- Process to receive data on i2s_sd_i, or transmit data on i2s_sd_o
sample_addr <= std_logic_vector(to_unsigned(adr_cnt, ADDR_WIDTH - 1));
mem_rdwr <= imem_rdwr;
sample_dat_o <= data_in;
SDRX: process (wb_clk_i)
begin
if rising_edge(wb_clk_i) then
if conf_en = '0' then -- codec disabled
imem_rdwr <= '0';
sd_ctrl <= IDLE;
data_in <= (others => '0');
bit_cnt <= 0;
bits_to_trx <= 0;
new_word <= '0';
last_bit <= '0';
adr_cnt <= 0;
evt_lsbf <= '0';
evt_hsbf <= '0';
i2s_sd_o <= '0';
else
case sd_ctrl is
when IDLE =>
imem_rdwr <= '0';
if to_integer(unsigned(conf_res)) > 15 and
to_integer(unsigned(conf_res)) < 33 then
bits_to_trx <= to_integer(unsigned(conf_res)) - 1;
else
bits_to_trx <= 15;
end if;
if conf_en = '1' then
if (ws_pos_edge = '1' and conf_swap = '1') or
(ws_neg_edge = '1' and conf_swap = '0') then
if receiver = '1' then -- recevier
sd_ctrl <= WAIT_CLK;
else
imem_rdwr <= '1'; -- read first data if transmitter
sd_ctrl <= TRX_DATA;
end if;
end if;
end if;
when WAIT_CLK => -- wait for first bit after WS
adr_cnt <= 0;
bit_cnt <= 0;
new_word <= '0';
last_bit <= '0';
data_in <= (others => '0');
if i2s_clk_en = '1' and neg_edge = '0' then
sd_ctrl <= TRX_DATA;
end if;
when TRX_DATA => -- transmit/receive serial data
imem_rdwr <= '0';
evt_hsbf <= '0';
evt_lsbf <= '0';
if master = '0' then
if zzzws /= zzws then
new_word <= '1';
end if;
else
if ws_pos_edge = '1' or ws_neg_edge = '1' then
new_word <= '1';
end if;
end if;
if new_word = '1' and i2s_clk_en = '1' and neg_edge = '0' then
last_bit <= '1';
end if;
-- recevier operation
if receiver = '1' then
if i2s_clk_en = '1' and neg_edge = '1' then
if master = '1' then -- master mode
if bit_cnt < bits_to_trx and new_word = '0' then
bit_cnt <= bit_cnt + 1;
data_in(bits_to_trx - bit_cnt) <= i2s_sd_i;
else
imem_rdwr <= '1';
data_in(bits_to_trx - bit_cnt) <= i2s_sd_i;
sd_ctrl <= RX_WRITE;
end if;
else -- slave mode
if bit_cnt <= bits_to_trx and new_word = '0' then
bit_cnt <= bit_cnt + 1;
data_in(bits_to_trx - bit_cnt) <= i2s_sd_i;
else
imem_rdwr <= '1';
sd_ctrl <= RX_WRITE;
end if;
end if;
end if;
end if;
-- transmitter operation
if receiver = '0' then
if master = '1' then -- master mode
if i2s_clk_en = '1' and neg_edge = '0' then
if bit_cnt < bits_to_trx and new_word = '0' then
bit_cnt <= bit_cnt + 1;
i2s_sd_o <= sample_dat_i(bits_to_trx - bit_cnt);
else
bit_cnt <= bit_cnt + 1;
if bit_cnt > bits_to_trx then
i2s_sd_o <= '0';
end if;
-- transmitter address counter
imem_rdwr <= '1';
adr_cnt <= (adr_cnt + 1) mod 2**(ADDR_WIDTH - 1);
if adr_cnt = 2**(ADDR_WIDTH - 2) - 1 then
evt_lsbf <= '1';
else
evt_lsbf <= '0';
end if;
if adr_cnt = 2**(ADDR_WIDTH - 1) - 1 then
evt_hsbf <= '1';
else
evt_hsbf <= '0';
end if;
sd_ctrl <= SYNC;
end if;
end if;
else -- slave mode
if i2s_clk_en = '1' and neg_edge = '1' then
if bit_cnt < bits_to_trx and new_word = '0' then
bit_cnt <= bit_cnt + 1;
i2s_sd_o <= sample_dat_i(bits_to_trx - bit_cnt);
else
bit_cnt <= bit_cnt + 1;
if bit_cnt > bits_to_trx then
i2s_sd_o <= '0';
else
i2s_sd_o <= sample_dat_i(bits_to_trx - bit_cnt);
end if;
if new_word = '1' then -- transmitter address counter
imem_rdwr <= '1';
adr_cnt <= (adr_cnt + 1) mod 2**(ADDR_WIDTH - 1);
if adr_cnt = 2**(ADDR_WIDTH - 2) - 1 then
evt_lsbf <= '1';
else
evt_lsbf <= '0';
end if;
if adr_cnt = 2**(ADDR_WIDTH - 1) - 1 then
evt_hsbf <= '1';
else
evt_hsbf <= '0';
end if;
sd_ctrl <= SYNC;
end if;
end if;
end if;
end if;
end if;
when RX_WRITE => -- write received word to sample buffer
imem_rdwr <= '0';
adr_cnt <= (adr_cnt + 1) mod 2**(ADDR_WIDTH - 1);
if adr_cnt = 2**(ADDR_WIDTH - 2) - 1 then
evt_lsbf <= '1';
else
evt_lsbf <= '0';
end if;
if adr_cnt = 2**(ADDR_WIDTH - 1) - 1 then
evt_hsbf <= '1';
else
evt_hsbf <= '0';
end if;
sd_ctrl <= SYNC;
when SYNC => -- synchronise with next word
imem_rdwr <= '0';
evt_hsbf <= '0';
evt_lsbf <= '0';
bit_cnt <= 0;
if ws_pos_edge = '1' or ws_neg_edge = '1' then
new_word <= '1';
end if;
if new_word = '1' and i2s_clk_en = '1' and neg_edge = '0' then
last_bit <= '1';
end if;
if receiver = '1' then -- receive mode
if master = '1' then
new_word <= '0';
last_bit <= '0';
data_in <= (others => '0');
sd_ctrl <= TRX_DATA;
else
if i2s_clk_en = '1' and neg_edge = '0' and new_word = '1' then
new_word <= '0';
last_bit <= '0';
data_in <= (others => '0');
sd_ctrl <= TRX_DATA;
end if;
end if;
else -- transmit mode
if master = '1' then
new_word <= '0';
last_bit <= '0';
data_in <= (others => '0');
sd_ctrl <= TRX_DATA;
elsif i2s_clk_en = '1' and neg_edge = '0' then
new_word <= '0';
last_bit <= '0';
data_in <= (others => '0');
sd_ctrl <= TRX_DATA;
end if;
end if;
when others => null;
end case;
end if;
end if;
end process SDRX;
end rtl;

powered by: WebSVN 2.1.0

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