📄 pcm1804_i2s_data_adjust2.vhd
字号:
-- ************************************* 文件名 *************************************
--pcm1804_i2s_data_adjust2.vhd creatby:liubingyang
-- *************************************程序功能*************************************
-- 用于pcm1804调整I2S的数据,使I2S的音频同步并且在FIFO中不溢出。能够自动判断FIFO
--中的状态,通过调整从FIFO中输出的数据的个数来使FIFO既不上溢也不下溢。
-- 为了达到更高的精度要求,可以通过加大采样时钟clk的频率。
-- *************************************程序说明*************************************
--1.将左右声道标志也存入FIFO中,从FIFO中直接输出数据和lrck信息。通过改变输出无效数据
-- 的个数来达到延迟或者提前输出lrck的目的,以达到fifo不溢出而又是同步的。
--2.采用12.288MHz的时钟,在计数到128时时钟正好为48kHz,若为127则48.377KHz,为129则是
-- 47.627。若测试无效,则直接增加clk的时钟频率
--3.采用更高频率的时钟时,需保证,这个时钟的上升延是产生时钟bck变化的延,到时候直接修
-- 改compare_cnt和clk_cnt的位数,和相应的修改计数达到的比较值即可。
--4.例如:108MHz时钟,计数到1125就产生2分频的48KHz时钟,如果计数到1126,则产生时钟是
--108M/1126/2=47.9573kHz,计数到1124则产生时钟48.0427kHz。精度可以达到40Hz。
-- *************************************修改纪录*************************************
--2007年11月9日
--首次创建
-- 第一个版本的机制是直接去改变输出的lrck,第二版则是通过改变等待时间来延迟或提前。
--2007年11月10日
-- 加入了另一个采样时钟clk,以提高改变lrck频率的精度。通过clk计数,根据FIFO的状态来
--多计或者少计,达到比较值时让产生读FIFO的使能复位。
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.std_logic_arith.all ;
use ieee.std_logic_unsigned.all ;
entity pcm1804_i2s_data_adjust2 is
port(
data : in std_logic ; --输入数据
lrck : in std_logic ; --输入的左右声道
bck : in std_logic ; --输入的时钟
read_bck : in std_logic ; --3.072MHz
clk : in std_logic ; --12.288MHz
--指示
wrempty : out std_logic ; --全空标志
wrfull : out std_logic ; --全满标志
-- wren_out : out std_logic ;
-- rden_out : out std_logic ; --读使能 test
--输出
data_out : out std_logic ;
lrck_out : out std_logic ;
bck_out : out std_logic
);
end pcm1804_i2s_data_adjust2 ;
architecture behave of pcm1804_i2s_data_adjust2 is
component fifo1k
PORT
(
data : IN STD_LOGIC_VECTOR (1 DOWNTO 0);
rdclk : IN STD_LOGIC ;
rdreq : IN STD_LOGIC ;
wrclk : IN STD_LOGIC ;
wrreq : IN STD_LOGIC ;
q : OUT STD_LOGIC_VECTOR (1 DOWNTO 0);
rdusedw : OUT STD_LOGIC_VECTOR (9 DOWNTO 0);
wrempty : OUT STD_LOGIC ;
wrfull : OUT STD_LOGIC
);
END component;
signal left_count : std_logic_vector ( 4 downto 0 ) ;
signal right_count : std_logic_vector ( 4 downto 0 ) ;
signal wren : std_logic ;
signal rden : std_logic ;
signal fifo_rd_start : std_logic := '0' ;
signal rd_cnt : std_logic_vector ( 5 downto 0 ) ;
signal compare_cnt : std_logic_vector ( 7 downto 0 ) ;
signal rdusedw : std_logic_vector ( 9 downto 0 ) ;
signal data_reg : std_logic_vector ( 1 downto 0 ) ;
signal data_in : std_logic_vector ( 1 downto 0 ) ;
signal clk_cnt : std_logic_vector ( 7 downto 0 ) ;
begin
fifo:fifo1k
port map(
data => data_in,
rdclk => not (read_bck),
rdreq => rden,
wrclk => bck,
wrreq => wren,
q => data_reg,
rdusedw => rdusedw,
wrempty => wrempty,
wrfull => wrfull
);
--******************************************************************************************
data_in <= lrck & data ;
data_out <= data_reg(0) ;
lrck_out <= data_reg(1) ;
bck_out <= read_bck ;
-- rden_out <= rden ;
-- wren_out <= wren ;
--产生FIFO写使能的左右声道计数
process(lrck,bck,left_count)
begin
if lrck = '1' then
left_count <= "00000" ;
elsif bck'event and bck = '0' then
if left_count < "11111" then
left_count <= left_count + 1 ;
else
left_count <= left_count ;
end if ;
end if ;
end process ;
process(lrck,bck,right_count)
begin
if lrck = '0' then
right_count <= "00000" ;
elsif bck'event and bck = '0' then
if right_count < "11111" then
right_count <= right_count + 1 ;
else
right_count <= right_count ;
end if ;
end if ;
end process ;
--FIFO的写使能
process(lrck,left_count,right_count)
begin
case lrck is
when '0' =>
if left_count <= "11000" then --0到24产生写使能,正好25个数
wren <= '1' ;
else
wren <= '0' ;
end if ;
when '1' =>
if right_count <= "11000" then
wren <= '1' ;
else
wren <= '0' ;
end if ;
when others =>
null ;
end case ;
end process ;
--FIFO的读开始标志
process(read_bck)
begin
if read_bck'event and read_bck = '0' then
if rdusedw( 9 downto 0 ) = "0110011001" then --1kfifo的4/10
fifo_rd_start <= '1' ; --产生开始读取fifo的标志。
end if ;
end if ;
end process ;
--clk 12.488MHz时钟的计数
process(fifo_rd_start,clk)
begin
if fifo_rd_start = '0' then -- 采样计数从1到要调整的值依次循环以控制FIFO中数据输出。
clk_cnt <= "00000000" ; --当计数等于比较值时,既始FIFO的读使能计数清零,开始新一轮
elsif clk'event and clk = '0' then --的从FIFO中读取数据。改变比较值的大小就可以达到自动调整
if clk_cnt < compare_cnt then --的作用了。
clk_cnt <= clk_cnt + 1 ;
else
clk_cnt <= "00000001" ;
end if ;
end if ;
end process ;
--FIFO的读计数
process(fifo_rd_start,read_bck,clk_cnt,compare_cnt)
begin
if fifo_rd_start = '0' or clk_cnt = compare_cnt then --当采样计数达到比较的那个值时,产生读使能的计数复位归零。
rd_cnt <= "000000" ;
elsif read_bck'event and read_bck = '1' then
if rd_cnt < "111111" then
rd_cnt <= rd_cnt + 1 ;
else
rd_cnt <= rd_cnt ;
end if ;
end if ;
end process ;
--FIFO的读使能的产生 fifo读时钟not(read_bck)
process(fifo_rd_start,rd_cnt)
begin
if fifo_rd_start = '0' then
rden <= '0' ;
else
if rd_cnt >= "000001" and rd_cnt <= "011001" then --1到25产生读使能,正好25个数。
rden <= '1' ;
else
rden <= '0' ;
end if ;
end if ;
end process ;
--改变读数长度的计数比较的产生
process(read_bck,rd_cnt)
begin
if read_bck'event and read_bck = '0' then --根据FIFO的读状态来改变比较数的数值。
if rd_cnt = "011001" then
if rdusedw( 9 downto 0 ) <= "0110011001" then
compare_cnt <= "10000001" ;
elsif rdusedw( 9 downto 0 ) <= "1001100110" then
compare_cnt <= "10000000" ;
else
compare_cnt <= "01111111" ;
end if ;
end if ;
end if ;
end process ;
end behave ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -