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

Subversion Repositories sd_card_controller

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /sd_card_controller/trunk/rtl
    from Rev 14 to Rev 15
    Reverse comparison

Rev 14 → Rev 15

/VHDL/sd_card_pack.vhd File deleted
/VHDL/dds_pack.vhd
0,0 → 1,970
--------------------------------------------------------------------------
-- Package of Direct Digital Synthesizer (DDS) components
--
-- NOTE: These components are for producing digital pulse outputs at
-- desired frequencies and/or duty cycles. In other words, there
-- are no modules here which include sinewave lookup tables. For
-- that type of module, please refer to "dds_sine_pack.vhd"
--
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
package dds_pack is
 
component dds_constant_squarewave
generic (
OUTPUT_FREQ : real; -- Desired output frequency
SYS_CLK_RATE : real; -- underlying clock rate
ACC_BITS : integer -- Bit width of DDS phase accumulator
);
port (
 
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Output
pulse_o : out std_logic;
squarewave_o : out std_logic
);
end component;
 
component dds_squarewave
generic (
ACC_BITS : integer -- Bit width of DDS phase accumulator
);
port (
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Frequency setting
freq_i : in unsigned(ACC_BITS-1 downto 0);
 
-- Output
pulse_o : out std_logic;
squarewave_o : out std_logic
);
end component;
 
component dds_squarewave_phase_load
generic (
ACC_BITS : integer -- Bit width of DDS phase accumulator
);
port (
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Frequency setting
freq_i : in unsigned(ACC_BITS-1 downto 0);
 
-- Synchronous load
phase_i : in unsigned(ACC_BITS-1 downto 0);
phase_ld_i : in std_logic;
 
-- Output
pulse_o : out std_logic;
squarewave_o : out std_logic
);
end component;
 
component dds_constant_clk_en_gen
generic (
OUTPUT_FREQ : real; -- Desired output frequency
SYS_CLK_RATE : real; -- underlying clock rate
ACC_BITS : integer -- Bit width of DDS phase accumulator
);
port (
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Output
clk_en_o : out std_logic
);
end component;
 
component dds_clk_en_gen
generic (
ACC_BITS : integer -- Bit width of DDS phase accumulator
);
port (
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Frequency setting
freq_i : in unsigned(ACC_BITS-1 downto 0);
 
-- Output
clk_en_o : out std_logic
);
end component;
 
component calibrated_clk_en_gen
generic (
SYS_CLK_RATE : real -- underlying clock rate
);
port (
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Frequency setting
freq_i : in unsigned(31 downto 0); -- some MSBs may be ignored
 
-- Output
clk_en_o : out std_logic
);
end component;
 
component dds_pwm_dac
generic (
ACC_BITS : integer -- Bit width of DDS phase accumulator
);
port (
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Frequency setting
freq_i : in unsigned(ACC_BITS-1 downto 0);
 
-- Output
clk_en_o : out std_logic
);
end component;
 
component dds_pwm_dac_srv
generic (
ACC_BITS : integer -- Bit width of DDS phase accumulator
);
port (
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Frequency/Phase settings
phase_load_i : in std_logic;
phase_val_i : in unsigned(ACC_BITS-1 downto 0);
freq_i : in unsigned(ACC_BITS-1 downto 0);
 
-- Output
clk_en_o : out std_logic
);
end component;
 
end dds_pack;
 
package body dds_pack is
end dds_pack;
 
-------------------------------------------------------------------------------
-- Direct Digital Synthesizer Constant Squarewave module
-------------------------------------------------------------------------------
--
-- Author: John Clayton
-- Update: Sep. 5, 2002 copied this file from "auto_baud_pack.vhd"
-- Added tracking functions, and debugged them.
--
-- Description
-------------------------------------------------------------------------------
-- This is a simple direct digital synthesizer module. It includes a phase
-- accumulator which increments in order to produce the desired output
-- frequency in its most significant bit, which is the squarewave output.
--
-- In addition to the squarewave output there is a pulse output which is
-- high for one sys_clk period, during the sys_clk period immediately
-- preceding the rising edge of the squarewave output.
--
-- NOTES:
-- The accumulator increment word is:
-- increment = Fout*2^N/Fsys_clk
--
-- Where N is the number of bits in the phase accumulator.
--
-- There will always be jitter with this type of clock source, but the
-- long time average frequency can be made arbitrarily close to whatever
-- value is desired, simply by increasing N.
--
-- To reduce jitter, use a higher underlying system clock frequency, and
-- for goodness sakes, try to keep the desired output frequency much lower
-- than the system clock frequency. The closer it gets to Fsys_clk/2, the
-- closer it is to the Nyquist limit, and the output jitter is much more
-- significant at that point.
--
--
 
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;
 
entity dds_constant_squarewave is
generic (
OUTPUT_FREQ : real := 8000.0; -- Desired output frequency
SYS_CLK_RATE : real := 48000000.0; -- underlying clock rate
ACC_BITS : integer := 16 -- Bit width of DDS phase accumulator
);
port (
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Output
pulse_o : out std_logic;
squarewave_o : out std_logic
);
end dds_constant_squarewave;
 
architecture beh of dds_constant_squarewave is
 
-- Constants
constant DDS_INCREMENT : integer := integer(OUTPUT_FREQ*(2**real(ACC_BITS))/SYS_CLK_RATE);
 
-- Signals
signal dds_phase : unsigned(ACC_BITS-1 downto 0); -- phase accumulator register
signal dds_phase_next : unsigned(ACC_BITS-1 downto 0);
 
-----------------------------------------------------------------------------
begin
 
dds_proc: Process(sys_rst_n,sys_clk)
begin
if (sys_rst_n = '0') then
dds_phase <= (others=>'0');
elsif (sys_clk'event and sys_clk='1') then
if (sys_clk_en='1') then
dds_phase <= dds_phase_next;
end if;
end if; -- sys_clk
end process dds_proc;
dds_phase_next <= dds_phase + DDS_INCREMENT;
pulse_o <= '1' when sys_clk_en='1' and dds_phase(dds_phase'length-1)='0' and dds_phase_next(dds_phase_next'length-1)='1' else '0';
squarewave_o <= dds_phase(dds_phase'length-1);
 
end beh;
 
 
-------------------------------------------------------------------------------
-- Direct Digital Synthesizer Variable Frequency Squarewave module
-------------------------------------------------------------------------------
--
-- Author: John Clayton
-- Update: Jan. 31, 2013 copied code from dds_constant_squarewave, and
-- modified it to accept a frequency setting input.
--
-- Description
-------------------------------------------------------------------------------
-- This is a simple direct digital synthesizer module. It includes a phase
-- accumulator which increments in order to produce the desired output
-- frequency in its most significant bit, which is the squarewave output.
--
-- In addition to the squarewave output there is a pulse output which is
-- high for one sys_clk period, during the sys_clk period immediately
-- preceding the rising edge of the squarewave output.
--
-- NOTES:
-- The accumulator increment word is:
-- increment = Fout*2^N/Fsys_clk
--
-- Where N is the number of bits in the phase accumulator.
--
-- There will always be jitter with this type of clock source, but the
-- long time average frequency can be made arbitrarily close to whatever
-- value is desired, simply by increasing N.
--
-- To reduce jitter, use a higher underlying system clock frequency, and
-- for goodness sakes, try to keep the desired output frequency much lower
-- than the system clock frequency. The closer it gets to Fsys_clk/2, the
-- closer it is to the Nyquist limit, and the output jitter is much more
-- significant as compared to the output period at that point.
--
--
 
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;
 
entity dds_squarewave is
generic (
ACC_BITS : integer := 16 -- Bit width of DDS phase accumulator
);
port (
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Frequency setting
freq_i : in unsigned(ACC_BITS-1 downto 0);
 
-- Output
pulse_o : out std_logic;
squarewave_o : out std_logic
);
end dds_squarewave;
 
architecture beh of dds_squarewave is
 
-- Signals
signal dds_phase : unsigned(ACC_BITS-1 downto 0); -- phase accumulator register
signal dds_phase_next : unsigned(ACC_BITS-1 downto 0);
 
-----------------------------------------------------------------------------
begin
 
dds_proc: Process(sys_rst_n,sys_clk)
begin
if (sys_rst_n = '0') then
dds_phase <= (others=>'0');
elsif (sys_clk'event and sys_clk='1') then
if (sys_clk_en='1') then
dds_phase <= dds_phase_next;
end if;
end if; -- sys_clk
end process dds_proc;
dds_phase_next <= dds_phase + freq_i;
pulse_o <= '1' when sys_clk_en='1' and dds_phase(dds_phase'length-1)='0' and dds_phase_next(dds_phase_next'length-1)='1' else '0';
squarewave_o <= dds_phase(dds_phase'length-1);
 
end beh;
 
 
-------------------------------------------------------------------------------
-- Direct Digital Synthesizer Variable Frequency Squarewave module,
-- with synchronous phase load
-------------------------------------------------------------------------------
--
-- Author: John Clayton
-- Update: Aug. 1, 2013 copied code from dds_squarewave, and
-- modified it to accept a synchronous load input.
--
-- Description
-------------------------------------------------------------------------------
-- This is a simple direct digital synthesizer module. It includes a phase
-- accumulator which increments in order to produce the desired output
-- frequency in its most significant bit, which is the squarewave output.
--
-- In addition to the squarewave output there is a pulse output which is
-- high for one sys_clk period, during the sys_clk period immediately
-- preceding the rising edge of the squarewave output.
--
-- A synchronous load input allows the synthesizer to be adjusted to any
-- desired initial phase condition. This is useful when using it for
-- timing and synchronization.
--
-- NOTES:
-- The accumulator increment word is:
-- increment = Fout*2^N/Fsys_clk
--
-- Where N is the number of bits in the phase accumulator.
--
-- There will always be jitter with this type of clock source, but the
-- long time average frequency can be made arbitrarily close to whatever
-- value is desired, simply by increasing N.
--
-- To reduce jitter, use a higher underlying system clock frequency, and
-- for goodness sakes, try to keep the desired output frequency much lower
-- than the system clock frequency. The closer it gets to Fsys_clk/2, the
-- closer it is to the Nyquist limit, and the output jitter is much more
-- significant as compared to the output period at that point.
--
--
 
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;
 
entity dds_squarewave_phase_load is
generic (
ACC_BITS : integer := 16 -- Bit width of DDS phase accumulator
);
port (
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Frequency setting
freq_i : in unsigned(ACC_BITS-1 downto 0);
 
-- Synchronous load
phase_i : in unsigned(ACC_BITS-1 downto 0);
phase_ld_i : in std_logic;
 
-- Output
pulse_o : out std_logic;
squarewave_o : out std_logic
);
end dds_squarewave_phase_load;
 
architecture beh of dds_squarewave_phase_load is
 
-- Signals
signal dds_phase : unsigned(ACC_BITS-1 downto 0); -- phase accumulator register
signal dds_phase_next : unsigned(ACC_BITS-1 downto 0);
 
-----------------------------------------------------------------------------
begin
 
dds_proc: Process(sys_rst_n,sys_clk)
begin
if (sys_rst_n = '0') then
dds_phase <= (others=>'0');
elsif (sys_clk'event and sys_clk='1') then
if (sys_clk_en='1') then
dds_phase <= dds_phase_next;
end if;
if (phase_ld_i='1') then
dds_phase <= phase_i;
end if;
end if; -- sys_clk
end process dds_proc;
dds_phase_next <= dds_phase + freq_i;
pulse_o <= '1' when sys_clk_en='1' and dds_phase(dds_phase'length-1)='0' and dds_phase_next(dds_phase_next'length-1)='1' else '0';
squarewave_o <= dds_phase(dds_phase'length-1);
 
end beh;
 
 
-------------------------------------------------------------------------------
-- Direct Digital Synthesizer Clock Enable Generator, Constant output frequency
-------------------------------------------------------------------------------
--
-- Author: John Clayton
-- Update: Oct. 4, 2013 Copied code from dds_clk_en_gen, and modified it to
-- create a clock enable output using generics to set
-- the frequency.
--
-- Description
-------------------------------------------------------------------------------
-- This is a simple direct digital synthesizer module. It includes a phase
-- accumulator which increments in order to produce the desired output
-- frequency in its most significant bit, which is a squarewave with
-- some unavoidable jitter.
--
-- In this module, the squarewave is not provided as an output, because
-- this module's purpose is to generate a clock enable signal.
--
-- The clock enable output is a pulsed output which, for frequencies below
-- the Nyquist frequency is high for one sys_clk period, during the sys_clk
-- period immediately preceding the rising edge of the squarewave output.
--
-- A special "trick" is performed inside this module, which is to invert the
-- pulse output for frequencies above the Nyquist frequency. Since the pulse
-- train is a perfect 50% duty cycle squarewave at the Nyquist frequency, the
-- pulse train and its inverse are equivalent at that point... But for
-- higher frequencies, the squarewave reduces in frequency back down towards
-- zero Hz. However, since the pulse train is inverted for frequencies above
-- the Nyquist frequency (Fsys_clk/2), then the output pulse train is high for
-- a larger and larger fraction of time... essentially forming a nice clock
-- enable which can be varied from 0% duty cycle, all the way up to N% duty
-- cycle, where K is given by:
--
-- K = max_duty_cycle = 100 * (1-2**(-N)) percent
--
-- Where N is the number of bits in the phase accumulator (ACC_BITS)
--
--
-- NOTES:
-- The accumulator increment word is set by generics:
-- increment = OUTPUT_FREQ*2^ACC_BITS/SYS_CLK_RATE
--
-- Where N is the number of bits in the phase accumulator (ACC_BITS)
--
-- There will always be jitter with this type of clock source, but the
-- clock enable output duty cycle can be adjusted in increments as fine
-- as may be desired, simply by increasing N.
--
--
 
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;
 
entity dds_constant_clk_en_gen is
generic (
OUTPUT_FREQ : real := 32000000.0; -- Desired output frequency
SYS_CLK_RATE : real := 50000000.0; -- underlying clock rate
ACC_BITS : integer := 30 -- Bit width of DDS phase accumulator
);
port (
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Output
clk_en_o : out std_logic
);
end dds_constant_clk_en_gen;
 
architecture beh of dds_constant_clk_en_gen is
 
-- Constants
constant DDS_INCREMENT : integer := integer(OUTPUT_FREQ*(2**real(ACC_BITS))/SYS_CLK_RATE);
constant HALFWAY : integer := integer(2**real(ACC_BITS-1));
 
-- Signals
signal dds_phase : unsigned(ACC_BITS-1 downto 0); -- phase accumulator register
signal dds_phase_next : unsigned(ACC_BITS-1 downto 0);
signal pulse_l : std_logic;
 
-----------------------------------------------------------------------------
begin
 
dds_proc: Process(sys_rst_n,sys_clk)
begin
if (sys_rst_n = '0') then
dds_phase <= (others=>'0');
elsif (sys_clk'event and sys_clk='1') then
if (sys_clk_en='1') then
dds_phase <= dds_phase_next;
end if;
end if; -- sys_clk
end process dds_proc;
dds_phase_next <= dds_phase + DDS_INCREMENT;
pulse_l <= '1' when sys_clk_en='1' and dds_phase(dds_phase'length-1)='0' and dds_phase_next(dds_phase_next'length-1)='1' else '0';
clk_en_o <= pulse_l when (DDS_INCREMENT<HALFWAY) else not pulse_l;
 
end beh;
 
 
-------------------------------------------------------------------------------
-- Direct Digital Synthesizer Clock Enable Generator
-------------------------------------------------------------------------------
--
-- Author: John Clayton
-- Update: Oct. 4, 2013 Copied code from dds_squarewave, and modified it to
-- create a clock enable output which essentially has
-- a duty cycle that varies from zero up to 100%. This
-- is similar in some ways to a first order sigma-delta
-- modulator, my friend! It can be used as a DAC, if
-- the sys_clk_en is high. See dds_pwm_dac for a
-- similar unit that allows slowing down the output
-- waveform according to the period between sys_clk_en
-- pulses.
--
-- Description
-------------------------------------------------------------------------------
-- This is a simple direct digital synthesizer module. It includes a phase
-- accumulator which increments in order to produce the desired output
-- frequency in its most significant bit, which is a squarewave with
-- some unavoidable jitter.
--
-- In this module, the squarewave is not provided as an output, because
-- this module's purpose is to generate a clock enable signal.
--
-- The clock enable output is a pulsed output which, for frequencies below
-- the Nyquist frequency is high for one sys_clk period, during the sys_clk
-- period immediately preceding the rising edge of the squarewave output.
--
-- A special "trick" is performed inside this module, which is to invert the
-- pulse output for frequencies above the Nyquist frequency. Since the pulse
-- train is a perfect 50% duty cycle squarewave at the Nyquist frequency, the
-- pulse train and its inverse are equivalent at that point... But for
-- higher frequencies, the squarewave reduces in frequency back down towards
-- zero Hz. However, since the pulse train is inverted for frequencies above
-- the Nyquist frequency (Fsys_clk/2), then the output pulse train is high for
-- a larger and larger fraction of time... essentially forming a nice clock
-- enable which can be varied from 0% duty cycle, all the way up to N% duty
-- cycle, where K is given by:
--
-- K = max_duty_cycle = 100 * (1-2**(-N)) percent
--
-- Where N is the number of bits in the phase accumulator (ACC_BITS)
--
-- This can perhaps operate as a form of PWM also... although the fundamental
-- frequency is not constant, as it is in true PWM.
--
--
-- NOTES:
-- The accumulator increment word is:
-- increment = Fout*2^N/Fsys_clk
--
-- Where N is the number of bits in the phase accumulator (ACC_BITS)
--
-- There will always be jitter with this type of clock source, but the
-- clock enable output duty cycle can be adjusted in increments as fine
-- as may be desired, simply by increasing N.
--
--
 
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;
 
entity dds_clk_en_gen is
generic (
ACC_BITS : integer := 16 -- Bit width of DDS phase accumulator
);
port (
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Frequency setting
freq_i : in unsigned(ACC_BITS-1 downto 0);
 
-- Output
clk_en_o : out std_logic
);
end dds_clk_en_gen;
 
architecture beh of dds_clk_en_gen is
 
-- Signals
signal dds_phase : unsigned(ACC_BITS-1 downto 0); -- phase accumulator register
signal dds_phase_next : unsigned(ACC_BITS-1 downto 0);
signal pulse_l : std_logic;
 
-----------------------------------------------------------------------------
begin
 
dds_proc: Process(sys_rst_n,sys_clk)
begin
if (sys_rst_n = '0') then
dds_phase <= (others=>'0');
elsif (sys_clk'event and sys_clk='1') then
if (sys_clk_en='1') then
dds_phase <= dds_phase_next;
end if;
end if; -- sys_clk
end process dds_proc;
dds_phase_next <= dds_phase + freq_i;
pulse_l <= '1' when sys_clk_en='1' and dds_phase(dds_phase'length-1)='0' and dds_phase_next(dds_phase_next'length-1)='1' else '0';
clk_en_o <= pulse_l when freq_i(freq_i'length-1)='0' else not pulse_l;
 
end beh;
 
 
-------------------------------------------------------------------------------
-- Calibrated Direct Digital Synthesizer Clock Enable Generator
-------------------------------------------------------------------------------
--
-- Author: John Clayton
-- Update: Nov. 11, 2013 Copied code from dds_clk_en_gen, and modified it.
--
-- Description
-------------------------------------------------------------------------------
-- This is two DDS units tied together. The first unit produces a calibration
-- clock enable, at a frequency which is very close to a power of two Hz.
-- It uses the highest power of two which can be achieved using the given
-- system clock frequency.
--
-- The second DDS unit then uses the calibration clock enable for its
-- clock enable input. This effectively "calibrates" the second unit
-- so that its input frequency is in Hz.
--
-- The input frequency to this module was fixed at 32 bits, but the
-- most significant bits may be ignored.
--
 
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;
 
library work;
use work.dds_pack.all;
use work.convert_pack.all;
 
entity calibrated_clk_en_gen is
generic (
SYS_CLK_RATE : real := 50000000.0 -- underlying clock rate
);
port (
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Frequency setting
freq_i : in unsigned(31 downto 0);
 
-- Output
clk_en_o : out std_logic
);
end calibrated_clk_en_gen;
 
architecture beh of calibrated_clk_en_gen is
 
-- Constants
constant LOG2_CAL_BITS : natural := bit_width(SYS_CLK_RATE)-1;
 
-- Signals
signal cal_clk_en : std_logic;
 
 
 
-----------------------------------------------------------------------------
begin
 
-- Calibration clock enable
cal_clk_gen : dds_constant_clk_en_gen
generic map(
OUTPUT_FREQ => real(2**LOG2_CAL_BITS),
SYS_CLK_RATE => SYS_CLK_RATE,
ACC_BITS => 30
)
port map(
sys_rst_n => sys_rst_n,
sys_clk => sys_clk,
sys_clk_en => sys_clk_en,
 
-- Output
clk_en_o => cal_clk_en
);
 
clk_en_gen : dds_clk_en_gen
generic map(
ACC_BITS => LOG2_CAL_BITS
)
port map(
sys_rst_n => sys_rst_n,
sys_clk => sys_clk,
sys_clk_en => cal_clk_en,
 
-- Frequency setting
freq_i => freq_i(LOG2_CAL_BITS-1 downto 0),
 
-- Output
clk_en_o => clk_en_o
);
 
end beh;
 
 
-------------------------------------------------------------------------------
-- Direct Digital Synthesizer PWM DAC
-------------------------------------------------------------------------------
--
-- Author: John Clayton
-- Update:
-- Jan. 23, 2015 Copied code from clk_en_gen, and brought pulse_l
-- logic inside the sys_clk_en enabled process, so
-- that the pulses are widened according to sys_clk_en.
--
-- Description
-------------------------------------------------------------------------------
-- This is exactly the same as dds_clk_en_gen, except that it brings the pulse_l
-- logic inside the clocked process, so that output pulses are no longer 1
-- sys_clk wide, but are instead lengthened according to sys_clk_en. This makes
-- the unit useful for generating a PWM output signal, with the smallest pulse
-- being the period between sys_clk_en pulses.
--
-- This is a simple direct digital synthesizer module. It includes a phase
-- accumulator which increments in order to produce the desired output
-- frequency in its most significant bit, which is a squarewave with
-- some unavoidable jitter.
--
-- In this module, the squarewave is not provided as an output, because
-- this module's purpose is to generate a clock enable signal.
--
-- The clock enable output is a pulsed output which, for frequencies below
-- the Nyquist frequency is high for one sys_clk period, during the sys_clk
-- period immediately preceding the rising edge of the squarewave output.
--
-- A special "trick" is performed inside this module, which is to invert the
-- pulse output for frequencies above the Nyquist frequency. Since the pulse
-- train is a perfect 50% duty cycle squarewave at the Nyquist frequency, the
-- pulse train and its inverse are equivalent at that point... But for
-- higher frequencies, the squarewave reduces in frequency back down towards
-- zero Hz. However, since the pulse train is inverted for frequencies above
-- the Nyquist frequency (Fsys_clk/2), then the output pulse train is high for
-- a larger and larger fraction of time... essentially forming a nice clock
-- enable which can be varied from 0% duty cycle, all the way up to N% duty
-- cycle, where K is given by:
--
-- K = max_duty_cycle = 100 * (1-2**(-N)) percent
--
-- Where N is the number of bits in the phase accumulator (ACC_BITS)
--
-- This can perhaps operate as a form of PWM also... although the fundamental
-- frequency is not constant, as it is in true PWM.
--
--
-- NOTES:
-- The accumulator increment word is:
-- increment = Fout*2^N/Fsys_clk
--
-- Where N is the number of bits in the phase accumulator (ACC_BITS)
--
-- There will always be jitter with this type of clock source, but the
-- clock enable output duty cycle can be adjusted in increments as fine
-- as may be desired, simply by increasing N.
--
--
 
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;
 
entity dds_pwm_dac is
generic (
ACC_BITS : integer := 16 -- Bit width of DDS phase accumulator
);
port (
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Frequency setting
freq_i : in unsigned(ACC_BITS-1 downto 0);
 
-- Output
clk_en_o : out std_logic
);
end dds_pwm_dac;
 
architecture beh of dds_pwm_dac is
 
-- Signals
signal dds_phase : unsigned(ACC_BITS-1 downto 0); -- phase accumulator register
signal dds_phase_next : unsigned(ACC_BITS-1 downto 0);
signal pulse_l : std_logic;
 
-----------------------------------------------------------------------------
begin
 
dds_proc: Process(sys_rst_n,sys_clk)
begin
if (sys_rst_n = '0') then
dds_phase <= (others=>'0');
pulse_l <= '0';
elsif (sys_clk'event and sys_clk='1') then
if (sys_clk_en='1') then
dds_phase <= dds_phase_next;
if (dds_phase(dds_phase'length-1)='0' and dds_phase_next(dds_phase_next'length-1)='1') then
pulse_l <= '1';
else
pulse_l <= '0';
end if;
end if;
end if; -- sys_clk
end process dds_proc;
dds_phase_next <= dds_phase + freq_i;
clk_en_o <= pulse_l when freq_i(freq_i'length-1)='0' else not pulse_l;
 
end beh;
 
-------------------------------------------------------------------------------
-- Direct Digital Synthesizer PWM DAC - Synchronously Resettable Version
-------------------------------------------------------------------------------
--
-- Author: John Clayton
-- Update:
-- Jan. 23, 2015 Copied code from dds_pwm_dac, and added synchronous
-- phase load input and phase value inputs
--
-- Description
-------------------------------------------------------------------------------
-- This is exactly the same as dds_pwm_dac, except that a synchronous phase
-- load is provided. This was needed when using the DAC to "throttle" pixel
-- counters driving a display. By resetting the DAC's phase accumulator
-- during each retrace interval, visible "jitter" was reduced, and made
-- identical for each line of display pixels.
--
-- NOTES:
-- The accumulator increment word is:
-- increment = Fout*2^N/Fsys_clk
--
-- Where N is the number of bits in the phase accumulator (ACC_BITS)
--
-- There will always be jitter with this type of clock source, but the
-- clock enable output duty cycle can be adjusted in increments as fine
-- as may be desired, simply by increasing N.
--
--
 
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;
 
entity dds_pwm_dac_srv is
generic (
ACC_BITS : integer := 16 -- Bit width of DDS phase accumulator
);
port (
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Frequency/Phase settings
phase_load_i : in std_logic;
phase_val_i : in unsigned(ACC_BITS-1 downto 0);
freq_i : in unsigned(ACC_BITS-1 downto 0);
 
-- Output
clk_en_o : out std_logic
);
end dds_pwm_dac_srv;
 
architecture beh of dds_pwm_dac_srv is
 
-- Signals
signal dds_phase : unsigned(ACC_BITS-1 downto 0); -- phase accumulator register
signal dds_phase_next : unsigned(ACC_BITS-1 downto 0);
signal pulse_l : std_logic;
 
-----------------------------------------------------------------------------
begin
 
dds_proc: Process(sys_rst_n,sys_clk)
begin
if (sys_rst_n = '0') then
dds_phase <= (others=>'0');
pulse_l <= '0';
elsif (sys_clk'event and sys_clk='1') then
if (sys_clk_en='1') then
if (phase_load_i='1') then
dds_phase <= phase_val_i;
pulse_l <= '0';
else
dds_phase <= dds_phase_next;
if (dds_phase(dds_phase'length-1)='0' and dds_phase_next(dds_phase_next'length-1)='1') then
pulse_l <= '1';
else
pulse_l <= '0';
end if;
end if; -- phase_zero_i
end if; -- sys_clk_en
end if; -- sys_clk
end process dds_proc;
dds_phase_next <= dds_phase + freq_i;
clk_en_o <= pulse_l when freq_i(freq_i'length-1)='0' else not pulse_l;
 
end beh;
 
 
/VHDL/sd_host_pack.vhd
0,0 → 1,1564
--------------------------------------------------------------------------
-- Package containing SD Card interface modules,
-- and related support modules.
--
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
package sd_host_pack is
 
-- Constants relating to the SD Card interface
 
-- Register size constants
constant BLKSIZE_W : integer := 12;
constant BLKCNT_W : integer := 16;
 
-- cmd module interrupts
constant INT_CMD_CC : integer := 0;
constant INT_CMD_EI : integer := 1;
constant INT_CMD_CTE : integer := 2;
constant INT_CMD_CCRCE : integer := 3;
constant INT_CMD_CIE : integer := 4;
constant INT_CMD_SIZE : integer := 5; -- Size of register field, in bits
 
-- data module interrupts
constant INT_DATA_CC : integer := 0;
constant INT_DATA_CCRCE : integer := 1;
constant INT_DATA_CFE : integer := 2;
constant INT_DATA_SIZE : integer := 3; -- Size of register field, in bits
 
component sd_cmd_host
port(
sys_rst : in std_logic;
sd_clk : in std_logic;
-- Control and settings
start_i : in std_logic;
int_rst_i : in std_logic;
busy_i : in std_logic; --direct signal from data sd data input (data[0])
cmd_index_i : in unsigned(5 downto 0);
argument_i : in unsigned(31 downto 0);
timeout_i : in unsigned(15 downto 0);
int_status_o : out unsigned(4 downto 0);
response_0_o : out unsigned(31 downto 0);
response_1_o : out unsigned(31 downto 0);
response_2_o : out unsigned(31 downto 0);
response_3_o : out unsigned(31 downto 0);
-- SD/MMC card command signals
sd_cmd_i : in std_logic;
sd_cmd_o : out std_logic;
sd_cmd_oe_o : out std_logic
);
end component;
 
component sd_data_8bit_host
port(
sd_clk : in std_logic;
sys_rst : in std_logic;
--Tx Fifo
tx_dat_i : in unsigned(7 downto 0);
tx_dat_rd_o : out std_logic;
--Rx Fifo
rx_dat_o : out unsigned(7 downto 0);
rx_dat_we_o : out std_logic;
--SD data
sd_dat_siz_o : out unsigned(1 downto 0);
sd_dat_oe_o : out std_logic;
sd_dat_o : out unsigned(7 downto 0);
sd_dat_i : in unsigned(7 downto 0);
--Control signals
blksize_i : in unsigned(BLKSIZE_W-1 downto 0);
bus_size_i : in unsigned(1 downto 0);
blkcnt_i : in unsigned(BLKCNT_W-1 downto 0);
d_stop_i : in std_logic;
d_read_i : in std_logic;
d_write_i : in std_logic;
bustest_w_i : in std_logic;
bustest_r_i : in std_logic;
bustest_res_o : out unsigned(2 downto 0);
sd_dat_busy_o : out std_logic;
fsm_busy_o : out std_logic;
crc_ok_o : out std_logic
);
end component;
 
component sd_controller_8bit_bram
port (
-- WISHBONE common
wb_clk_i : in std_logic;
wb_rst_i : in std_logic;
-- WISHBONE slave (register interface)
wb_dat_i : in unsigned(31 downto 0);
wb_dat_o : out unsigned(31 downto 0);
wb_adr_i : in unsigned(3 downto 0);
wb_we_i : in std_logic;
wb_cyc_i : in std_logic;
wb_ack_o : out std_logic;
-- Dedicated BRAM port without acknowledge.
-- Access cycles must complete immediately.
-- (data to cross clock domains by this dual-ported BRAM)
bram_clk_o : out std_logic; -- Same as sd_clk_o_pad
bram_dat_o : out unsigned(7 downto 0);
bram_dat_i : in unsigned(7 downto 0);
bram_adr_o : out unsigned(31 downto 0);
bram_we_o : out std_logic;
bram_cyc_o : out std_logic;
--SD Card Interface
sd_cmd_i : in std_logic;
sd_cmd_o : out std_logic;
sd_cmd_oe_o : out std_logic;
sd_dat_i : in unsigned(7 downto 0);
sd_dat_o : out unsigned(7 downto 0);
sd_dat_oe_o : out std_logic;
sd_dat_siz_o : out unsigned(1 downto 0);
sd_clk_o_pad : out std_logic;
-- Interrupt outputs
int_cmd_o : out std_logic;
int_data_o : out std_logic
);
end component;
 
end sd_host_pack;
 
package body sd_host_pack is
end sd_host_pack;
 
-------------------------------------------------------------------------------
-- SD/MMC Command Host
-------------------------------------------------------------------------------
--
-- Author: John Clayton
-- Update: June 11, 2016 Combined sd_cmd_master with sd_cmd_serial_host from
-- the opencores.org VHDL code, in order to make this
-- unit. The reason for combining them is that eight
-- interface signals were shared only between those two
-- modules when they were instantiated, and they are not
-- needed individually.
--
-- Description
-------------------------------------------------------------------------------
-- This module handles generating the serial SD/MMC command output, and
-- receiving the SD/MMC responses from the card.
--
-- This unit runs entirely within the sd_clk_i clock domain.
--
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
library work;
use work.ucrc_pack.all;
use work.sd_host_pack.all;
 
entity sd_cmd_host is
port(
sys_rst : in std_logic;
sd_clk : in std_logic;
-- Control and settings
start_i : in std_logic;
int_rst_i : in std_logic;
busy_i : in std_logic; --direct signal from data sd data input (data[0])
cmd_index_i : in unsigned(5 downto 0);
argument_i : in unsigned(31 downto 0);
timeout_i : in unsigned(15 downto 0);
int_status_o : out unsigned(4 downto 0);
response_0_o : out unsigned(31 downto 0);
response_1_o : out unsigned(31 downto 0);
response_2_o : out unsigned(31 downto 0);
response_3_o : out unsigned(31 downto 0);
-- SD/MMC card command signals
sd_cmd_i : in std_logic;
sd_cmd_o : out std_logic;
sd_cmd_oe_o : out std_logic
);
end sd_cmd_host;
 
architecture beh of sd_cmd_host is
 
---------------Internal Constants-------------
constant INIT_DELAY : integer := 4;
constant BITS_TO_SEND : integer := 48;
constant CMD_SIZE : integer := 40;
constant RESP_SIZE : integer := 128;
 
-----------------Internal Signals-----------
signal cmd_dat_reg : std_logic;
signal resp_len : integer;
signal cmd_buff : unsigned(CMD_SIZE-1 downto 0);
signal resp_buff : unsigned(RESP_SIZE-1 downto 0);
signal resp_idx : integer;
--CRC related
signal crc_rst_n : std_logic;
signal crc_in : unsigned(6 downto 0);
signal crc_val : unsigned(6 downto 0);
signal crc_enable : std_logic;
signal crc_bit : std_logic;
signal crc_ok : std_logic;
--Internal Counters
signal counter : integer;
--State Machines
type SERIAL_STATE_TYPE is (INIT, IDLE, SETUP_CRC, WRITE, READ_WAIT, READ, FINISH_WR);
signal serial_state : SERIAL_STATE_TYPE;
type CMD_STATE_TYPE is (IDLE, EXECUTE, BUSY_WAIT);
signal cmd_state : CMD_STATE_TYPE;
 
signal expect_response : std_logic;
signal watchdog : unsigned(15 downto 0);
 
-- Signals originally from sd_cmd_master (DELETE THIS COMMENT SOON)
signal timeout_reg : unsigned(15 downto 0);
signal int_status_reg : unsigned(4 downto 0);
 
begin
 
-- Form a signal indicating when a response is expected
expect_response <= '0' when (cmd_index_i=0 or cmd_index_i=4 or cmd_index_i=15) else '1';
 
-- Command Finite State Machine
cmd_fsm_proc : process(sys_rst,sd_clk)
begin
if (sys_rst='1') then
response_0_o <= (others=>'0');
response_1_o <= (others=>'0');
response_2_o <= (others=>'0');
response_3_o <= (others=>'0');
int_status_reg <= (others=>'0');
resp_len <= 0;
watchdog <= (others=>'0');
timeout_reg <= (others=>'0');
cmd_state <= IDLE;
cmd_buff <= (others=>'0');
elsif (sd_clk'event and sd_clk='1') then
watchdog <= watchdog+1;
case (cmd_state) is
when IDLE =>
-- Only CMD2, CMD9 and CMD10 have long responses...
if (cmd_index_i=2 or cmd_index_i=9 or cmd_index_i=10) then
resp_len <= 127;
else
resp_len <= 39;
end if;
cmd_buff(39 downto 38) <= "01";
cmd_buff(37 downto 32) <= cmd_index_i;
cmd_buff(31 downto 0) <= argument_i; --CMD_Argument
timeout_reg <= timeout_i;
watchdog <= (others=>'0');
if (start_i='1') then
int_status_reg <= (others=>'0');
end if;
-- State transition
if (start_i='1') then
response_0_o <= (others=>'0');
response_1_o <= (others=>'0');
response_2_o <= (others=>'0');
response_3_o <= (others=>'0');
cmd_state <= EXECUTE;
end if;
 
when EXECUTE =>
if (watchdog > timeout_reg) then
int_status_reg(INT_CMD_CTE) <= '1';
int_status_reg(INT_CMD_EI) <= '1';
response_0_o <= to_unsigned(16#55555555#,32);
response_1_o <= to_unsigned(16#55555555#,32);
response_2_o <= to_unsigned(16#55555555#,32);
response_3_o <= to_unsigned(16#55555555#,32);
cmd_state <= IDLE;
else --Incoming New Status
if (serial_state=FINISH_WR) then --Data available
-- CMD1 has "1111111" for the CRC field...
if (cmd_index_i/=1 and crc_ok='0') then
int_status_reg(INT_CMD_CCRCE) <= '1';
int_status_reg(INT_CMD_EI) <= '1';
end if;
if (resp_len=39 and cmd_index_i/=1 and cmd_buff(37 downto 32)/=resp_buff(125 downto 120)) then
int_status_reg(INT_CMD_CIE) <= '1';
int_status_reg(INT_CMD_EI) <= '1';
end if;
int_status_reg(INT_CMD_CC) <= '1';
if (expect_response/='0') then
response_0_o <= resp_buff(119 downto 88);
response_1_o <= resp_buff(87 downto 56);
response_2_o <= resp_buff(55 downto 24);
response_3_o <= resp_buff(23 downto 0) & "00000000";
end if;
-- end
end if; --Data avaible
end if; --Status change
-- State transition
if (watchdog > timeout_reg) then
cmd_state <= IDLE;
elsif (serial_state=FINISH_WR) then
cmd_state <= BUSY_WAIT;
end if;
 
when BUSY_WAIT =>
if (watchdog > timeout_reg) then
int_status_reg(INT_CMD_CTE) <= '1';
int_status_reg(INT_CMD_EI) <= '1';
cmd_state <= IDLE;
end if;
-- State transition
if (busy_i='0') then
cmd_state <= IDLE;
end if;
 
when others =>
cmd_state <= IDLE;
 
end case;
 
if (int_rst_i='1') then
int_status_reg <= (others=>'0');
end if;
 
end if;
end process;
int_status_o <= int_status_reg;
 
 
 
--sd cmd input pad register
process(sd_clk, sys_rst) -- JLC added sys_rst to sensitivity list.
begin
if (sys_rst='1') then
cmd_dat_reg <= '0';
-- elsif (sd_clk'event and sd_clk='0') then -- use falling edge, when data is stable
elsif (sd_clk'event and sd_clk='0') then -- use rising edge, per the specification
cmd_dat_reg <= sd_cmd_i;
end if;
end process;
 
--------------------------------------------
-- CRC generator
 
crc0 : ucrc_ser
generic map (
POLYNOMIAL => "0001001",
INIT_VALUE => "0000000"
)
port map (
-- System clock and asynchronous reset
sys_clk => sd_clk,
sys_rst_n => crc_rst_n,
sys_clk_en => crc_enable,
 
-- Input and Control
clear_i => '0',
data_i => crc_bit,
flush_i => '0',
 
-- Output
match_o => open,
crc_o => crc_val
);
 
--------------------------------------------
-- This is the serial_state machine
--------------------------------------------
serial_fsm_proc : process(sd_clk, sys_rst)
begin
if (sys_rst='1') then
serial_state <= INIT;
crc_enable <= '0';
resp_idx <= 0;
sd_cmd_oe_o <= '1';
sd_cmd_o <= '1';
resp_buff <= (others=>'0');
crc_rst_n <= '0';
crc_bit <= '0';
crc_in <= (others=>'0');
crc_ok <= '0';
counter <= 0;
elsif (sd_clk'event and sd_clk='1') then
 
case (serial_state) is
 
when INIT =>
counter <= counter+1;
sd_cmd_oe_o <= '1';
sd_cmd_o <= '1';
if (counter >= INIT_DELAY) then
serial_state <= IDLE;
end if;
 
when IDLE =>
sd_cmd_oe_o <= '0'; --Put CMD to Z
counter <= 0;
crc_rst_n <= '0';
crc_enable <= '0';
resp_idx <= 0;
if (start_i='1') then
serial_state <= SETUP_CRC;
resp_buff <= (others=>'0');
end if;
 
when SETUP_CRC =>
crc_rst_n <= '1';
crc_enable <= '1';
crc_bit <= cmd_buff(CMD_SIZE-1-counter);
serial_state <= WRITE;
 
when WRITE =>
if (counter < BITS_TO_SEND-8) then -- 1->40 CMD, (41 <= CNT <=47) CRC, 48 stop_bit
sd_cmd_oe_o <= '1';
sd_cmd_o <= cmd_buff(CMD_SIZE-1-counter);
if (counter < BITS_TO_SEND-9) then --1 step ahead
crc_bit <= cmd_buff((CMD_SIZE-1-counter)-1);
else
crc_enable <= '0';
end if;
elsif (counter < BITS_TO_SEND-1) then
crc_enable <= '0';
sd_cmd_o <= crc_val(BITS_TO_SEND-counter-2);
sd_cmd_oe_o <= '1';
elsif (counter = BITS_TO_SEND-1) then
sd_cmd_oe_o <= '1';
sd_cmd_o <= '1';
else
sd_cmd_oe_o <= '0';
sd_cmd_o <= '1';
end if;
counter <= counter+1;
 
if (counter >= BITS_TO_SEND and expect_response='1') then
serial_state <= READ_WAIT;
elsif (counter >= BITS_TO_SEND) then
serial_state <= FINISH_WR;
end if;
 
when READ_WAIT =>
crc_enable <= '0';
crc_rst_n <= '0';
counter <= 1;
sd_cmd_oe_o <= '0';
resp_buff(RESP_SIZE-1) <= cmd_dat_reg;
if (cmd_dat_reg='0') then
serial_state <= READ;
end if;
 
when READ =>
crc_rst_n <= '1';
if ((resp_len/=RESP_SIZE-1) or (counter>7)) then
crc_enable <= '1';
end if;
sd_cmd_oe_o <= '0';
if (counter <= resp_len) then
if (counter < 8) then --1+1+6 (S,T,Index)
resp_buff(RESP_SIZE-1-counter) <= cmd_dat_reg;
else
resp_idx <= resp_idx + 1;
resp_buff(RESP_SIZE-9-resp_idx) <= cmd_dat_reg;
end if;
crc_bit <= cmd_dat_reg;
elsif (counter-resp_len <= 7) then
crc_in((resp_len+7)-counter) <= cmd_dat_reg;
crc_enable <= '0';
else
crc_enable <= '0';
if (crc_in = crc_val) then
crc_ok <= '1';
else
crc_ok <= '0';
end if;
end if;
counter <= counter + 1;
if (counter >= resp_len+8) then
serial_state <= FINISH_WR;
end if;
 
when FINISH_WR =>
crc_enable <= '0';
crc_rst_n <= '0';
counter <= 0;
sd_cmd_oe_o <= '0';
serial_state <= IDLE;
 
when others =>
serial_state <= INIT;
 
end case;
 
end if;
end process;
 
end beh;
 
----------------------------------------------------------------------
---- ----
---- WISHBONE SD Card Controller IP Core ----
---- ----
---- sd_data_8bit_host.vhd ----
---- ----
---- This file is part of the WISHBONE SD Card ----
---- Controller IP Core project ----
---- http:--opencores.org/project,sd_card_controller ----
---- ----
---- Description ----
---- Module resposible for sending and receiving data through ----
---- sd/mmc card data interface ----
---- ----
---- Author(s): ----
---- - John Clayton, morianton@gmail.com ----
---- ----
----------------------------------------------------------------------
---- ----
---- Copyright (C) 2016 Authors ----
---- ----
---- Based on original work by ----
---- Adam Edvardsson (adam.edvardsson@orsoc.se) ----
---- ----
---- Copyright (C) 2009 Authors ----
---- ----
---- 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 Lesser General ----
---- Public License as published by the Free Software Foundation; ----
---- either version 2.1 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 Lesser General Public License for more ----
---- details. ----
---- ----
---- You should have received a copy of the GNU Lesser General ----
---- Public License along with this source; if not, download it ----
---- from http:--www.opencores.org/lgpl.shtml ----
---- ----
-- Author: John Clayton --
-- Update: June 11, 2016 Added bustest_w_i and bustest_r_i, plus --
-- bustest_res_o result output. --
---- ----
----------------------------------------------------------------------
--
-- Explanation:
-- bustest_res_o values are:
-- 000 = BUSTEST_R (CMD14) not yet performed
-- 001 = 1 bit data width
-- 010 = 4 bit data width
-- 011 = 8 bit data width
-- 100 = Unspecified Error
--
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
library work;
use work.sd_host_pack.all;
use work.ucrc_pack.all;
 
entity sd_data_8bit_host is
port(
sd_clk : in std_logic;
sys_rst : in std_logic;
--Tx Fifo
tx_dat_i : in unsigned(7 downto 0);
tx_dat_rd_o : out std_logic;
--Rx Fifo
rx_dat_o : out unsigned(7 downto 0);
rx_dat_we_o : out std_logic;
--SD data
sd_dat_siz_o : out unsigned(1 downto 0);
sd_dat_oe_o : out std_logic;
sd_dat_o : out unsigned(7 downto 0);
sd_dat_i : in unsigned(7 downto 0);
--Control signals
blksize_i : in unsigned(BLKSIZE_W-1 downto 0);
bus_size_i : in unsigned(1 downto 0);
blkcnt_i : in unsigned(BLKCNT_W-1 downto 0);
d_stop_i : in std_logic;
d_read_i : in std_logic;
d_write_i : in std_logic;
bustest_w_i : in std_logic;
bustest_r_i : in std_logic;
bustest_res_o : out unsigned(2 downto 0);
sd_dat_busy_o : out std_logic;
fsm_busy_o : out std_logic;
crc_ok_o : out std_logic
);
end sd_data_8bit_host;
 
architecture beh of sd_data_8bit_host is
 
-- Internal constants
 
-- Internal signals
signal dat_reg : unsigned(7 downto 0);
signal data_cycles : unsigned(BLKSIZE_W+2 downto 0);
signal bus_size_reg : unsigned(1 downto 0);
--CRC16
signal crc_in : unsigned(7 downto 0);
signal crc_enable : std_logic;
signal crc_rst_n : std_logic;
type crc_out_type is
array (integer range 0 to 7) of unsigned(15 downto 0);
signal crc_out : crc_out_type;
signal crc_ok_l : std_logic;
signal transf_cnt : unsigned(BLKSIZE_W+3 downto 0);
--State Machine
type FSM_STATE_TYPE is (IDLE, WRITE_DAT, CHECK_CRC_STATUS, WRITE_BUSY,
READ_WAIT, READ_DAT, SEND_BUSTEST,
READ_BUSTEST_WAIT, READ_BUSTEST, ANALYZE_BUSTEST);
signal state : FSM_STATE_TYPE;
 
signal crc_s_cnt : unsigned(2 downto 0);
signal busy_int : std_logic;
signal blkcnt_reg : unsigned(BLKCNT_W-1 downto 0);
signal start_bit : std_logic;
signal crc_c : unsigned(4 downto 0);
signal crc_s : unsigned(3 downto 0);
signal data_index : unsigned(2 downto 0);
signal last_din : unsigned(7 downto 0);
 
signal bustest_0 : unsigned(7 downto 0);
signal bustest_1 : unsigned(7 downto 0);
signal bustest_x : unsigned(7 downto 0);
 
begin
 
--sd data input pad register
process(sd_clk)
begin
if (sd_clk'event and sd_clk='1') then
dat_reg <= sd_dat_i;
end if;
end process;
 
-- There are eight different CRC generators
sd_crc_gen : for nvar in 0 to 7 generate
begin
crc_unit : ucrc_ser
generic map (
POLYNOMIAL => "0001000000100001",
INIT_VALUE => "0000000000000000"
)
port map (
-- System clock and asynchronous reset
sys_clk => sd_clk,
sys_rst_n => crc_rst_n,
sys_clk_en => crc_enable,
 
-- Input and Control
clear_i => '0',
data_i => crc_in(nvar),
flush_i => '0',
 
-- Output
match_o => open,
crc_o => crc_out(nvar)
);
end generate;
 
crc_ok_o <= crc_ok_l;
fsm_busy_o <= '1' when (state/=IDLE) else '0';
start_bit <= '1' when (dat_reg(0)='0') else '0';
sd_dat_busy_o <= '1' when (dat_reg(0)='0') else '0';
-- Provide external bus size signals, for controlling data bus tri-states
sd_dat_siz_o <= "10" when state=SEND_BUSTEST else bus_size_i;
 
-- Create bus test analysis, by XORing the two returned patterns
-- together.
bustest_x <= bustest_0 xor bustest_1;
 
fsm_proc : process(sys_rst,sd_clk)
begin
if (sys_rst='1') then
state <= IDLE;
sd_dat_oe_o <= '0';
crc_enable <= '0';
crc_rst_n <= '0';
transf_cnt <= (others=>'0');
tx_dat_rd_o <= '0';
last_din <= (others=>'0');
crc_c <= (others=>'0');
crc_in <= (others=>'0');
sd_dat_o <= (others=>'0');
crc_s_cnt <= (others=>'0');
crc_s <= (others=>'0');
rx_dat_we_o <= '0';
rx_dat_o <= (others=>'0');
crc_ok_l <= '0';
busy_int <= '0';
data_index <= (others=>'0');
blkcnt_reg <= (others=>'0');
data_cycles <= (others=>'0');
bus_size_reg <= (others=>'0');
bustest_0 <= (others=>'0');
bustest_1 <= (others=>'0');
bustest_res_o <= (others=>'0');
elsif (sd_clk'event and sd_clk='1') then
case(state) is
when IDLE =>
sd_dat_oe_o <= '0';
sd_dat_o <= "11111111";
crc_enable <= '0';
crc_rst_n <= '0';
transf_cnt <= (others=>'0');
crc_c <= to_unsigned(16,crc_c'length);
crc_s_cnt <= (others=>'0');
crc_s <= (others=>'0');
rx_dat_we_o <= '0';
tx_dat_rd_o <= '0';
data_index <= (others=>'1');
blkcnt_reg <= blkcnt_i;
if (bus_size_i=2) then
data_cycles <= "000" & blksize_i; -- (<<0) operation
elsif (bus_size_i=1) then
data_cycles <= "00" & blksize_i & '0'; -- (<<1) operation
else
data_cycles <= blksize_i & "000"; -- (<<3) operation
end if;
bus_size_reg <= bus_size_i;
-- state transition
if (d_read_i='0' and d_write_i='1' and bustest_w_i='0' and bustest_r_i='0') then
state <= WRITE_DAT;
elsif (d_read_i='1' and d_write_i='0' and bustest_w_i='0' and bustest_r_i='0') then
state <= READ_WAIT;
elsif (d_read_i='0' and d_write_i='0' and bustest_w_i='1' and bustest_r_i='0') then
data_cycles <= to_unsigned(24,data_cycles'length);
state <= SEND_BUSTEST;
elsif (d_read_i='0' and d_write_i='0' and bustest_w_i='0' and bustest_r_i='1') then
state <= READ_BUSTEST_WAIT;
end if;
 
when SEND_BUSTEST =>
transf_cnt <= transf_cnt+1;
tx_dat_rd_o <= '0';
-- Send out start bits
if (transf_cnt = 1) then
sd_dat_oe_o <= '1';
sd_dat_o <= "00000000";
end if;
-- Send out first pattern
if (transf_cnt = 2) then
sd_dat_o <= "10101010";
end if;
-- Send out second pattern
if (transf_cnt = 3) then
sd_dat_o <= "01010101";
end if;
-- Send out zeros
if ((transf_cnt >= 4) and (transf_cnt < data_cycles)) then
sd_dat_o <= "00000000";
end if;
if (transf_cnt = data_cycles) then -- stop bits
sd_dat_o <= "11111111";
end if;
if (transf_cnt = data_cycles+1) then
sd_dat_oe_o <= '0';
end if;
-- state transition
if (transf_cnt >= data_cycles+1) then
transf_cnt <= (others=>'0');
state <= IDLE;
end if;
 
when READ_BUSTEST_WAIT =>
sd_dat_oe_o <= '0';
transf_cnt <= (others=>'0');
bustest_0 <= (others=>'0');
bustest_1 <= (others=>'0');
bustest_res_o <= (others=>'0');
-- state transition
if (start_bit='1') then
state <= READ_BUSTEST;
end if;
 
when READ_BUSTEST =>
transf_cnt <= transf_cnt+1;
if (transf_cnt = 0) then
bustest_0 <= dat_reg;
end if;
if (transf_cnt = 1) then
bustest_1 <= dat_reg;
end if;
-- state transition
-- No CRC status response is needed
-- Look for stop bits
if (dat_reg = "11111111") then
state <= ANALYZE_BUSTEST;
end if;
 
when ANALYZE_BUSTEST =>
if (bustest_x="00000001") then
bustest_res_o <= "001";
elsif (bustest_x="00001111") then
bustest_res_o <= "010";
elsif (bustest_x="11111111") then
bustest_res_o <= "011";
else
bustest_res_o <= "100";
end if;
state <= IDLE;
 
when WRITE_DAT =>
crc_ok_l <= '0';
transf_cnt <= transf_cnt+1;
tx_dat_rd_o <= '0';
-- Load values for last_din and crc_in
if (bus_size_reg=2) then
last_din <= tx_dat_i;
crc_in <= tx_dat_i;
if (transf_cnt<data_cycles-1) then
tx_dat_rd_o <= '1';
else
tx_dat_rd_o <= '0';
end if;
elsif (bus_size_reg=1) then
last_din <=
"1111" &
tx_dat_i(7-(4*to_integer(data_index(0 downto 0)))) &
tx_dat_i(6-(4*to_integer(data_index(0 downto 0)))) &
tx_dat_i(5-(4*to_integer(data_index(0 downto 0)))) &
tx_dat_i(4-(4*to_integer(data_index(0 downto 0))));
crc_in <=
"1111" &
tx_dat_i(7-(4*to_integer(data_index(0 downto 0)))) &
tx_dat_i(6-(4*to_integer(data_index(0 downto 0)))) &
tx_dat_i(5-(4*to_integer(data_index(0 downto 0)))) &
tx_dat_i(4-(4*to_integer(data_index(0 downto 0))));
if (transf_cnt<data_cycles) and (data_index(0 downto 0)=0) then
tx_dat_rd_o <= '1';
end if;
if (data_index(0 downto 0)=1) then
data_index <= (others=>'0');
else
data_index <= data_index+1;
end if;
else
last_din <= "1111111" & tx_dat_i(7-to_integer(data_index));
crc_in <= "1111111" & tx_dat_i(7-to_integer(data_index));
if (transf_cnt<data_cycles) and (data_index = 6) then
tx_dat_rd_o <= '1';
end if;
if (data_index = 7) then
data_index <= (others=>'0');
else
data_index <= data_index+1;
end if;
end if;
-- Treat first transfer differently
if (transf_cnt = 1) then
crc_rst_n <= '1';
crc_enable <= '1';
if (bus_size_reg=2) then
last_din <= tx_dat_i;
crc_in <= tx_dat_i;
elsif (bus_size_reg=1) then
last_din <= "1111" & tx_dat_i(7 downto 4);
crc_in <= "1111" & tx_dat_i(7 downto 4);
else
last_din <= "1111111" & tx_dat_i(7);
crc_in <= "1111111" & tx_dat_i(7);
end if;
sd_dat_oe_o <= '1';
if (bus_size_reg=2) then -- start bits
sd_dat_o <= "00000000";
elsif (bus_size_reg=1) then
sd_dat_o <= "11110000";
else
sd_dat_o <= "11111110";
end if;
data_index <= to_unsigned(1,data_index'length);
elsif ((transf_cnt >= 2) and (transf_cnt <= data_cycles+1)) then
sd_dat_o <= last_din;
if (transf_cnt = data_cycles+1) then
crc_enable <= '0';
end if;
elsif (transf_cnt > data_cycles+1) and (crc_c/=0) then
crc_enable <= '0';
crc_c <= crc_c-1;
sd_dat_o(0) <= crc_out(0)(to_integer(crc_c)-1);
if (bus_size_reg=2) then
sd_dat_o(7 downto 1) <= crc_out(7)(to_integer(crc_c)-1) & crc_out(6)(to_integer(crc_c)-1) &
crc_out(5)(to_integer(crc_c)-1) & crc_out(4)(to_integer(crc_c)-1) &
crc_out(3)(to_integer(crc_c)-1) & crc_out(2)(to_integer(crc_c)-1) &
crc_out(1)(to_integer(crc_c)-1);
elsif (bus_size_reg=1) then
sd_dat_o(3 downto 1) <= crc_out(3)(to_integer(crc_c)-1) & crc_out(2)(to_integer(crc_c)-1) &
crc_out(1)(to_integer(crc_c)-1);
sd_dat_o(7 downto 4) <= (others=>'1');
else
sd_dat_o(7 downto 1) <= (others=>'1');
end if;
elsif (transf_cnt = data_cycles+18) then -- stop bits
sd_dat_o <= "11111111";
elsif (transf_cnt >= data_cycles+19) then
sd_dat_oe_o <= '0';
end if;
-- state transition
-- There are two clocks of bus turnaround time, plus one extra
-- because of the data input register, then the start bit of
-- the CRC status occurs.
if (d_stop_i='1') then
state <= IDLE;
elsif (transf_cnt = data_cycles+23) then
if (start_bit='1') then
state <= CHECK_CRC_STATUS;
else
transf_cnt <= (others=>'0');
blkcnt_reg <= blkcnt_reg-1;
crc_rst_n <= '0';
crc_c <= to_unsigned(16,crc_c'length);
crc_s_cnt <= (others=>'0');
if (blkcnt_reg>1) then
state <= WRITE_DAT;
else
state <= IDLE;
end if;
end if;
end if;
 
when CHECK_CRC_STATUS =>
if (crc_s_cnt < 4) then
crc_s(to_integer(crc_s_cnt)) <= dat_reg(0);
end if;
crc_s_cnt <= crc_s_cnt+1;
busy_int <= '1';
-- state transition
if (crc_s_cnt = 4) then
if (crc_s="1010") then
crc_ok_l <= '1';
else
crc_ok_l <= '0';
end if;
state <= WRITE_BUSY;
end if;
 
when WRITE_BUSY =>
busy_int <= not dat_reg(0);
transf_cnt <= (others=>'0');
-- state transition
if (busy_int='0') then
blkcnt_reg <= blkcnt_reg-1;
crc_rst_n <= '0';
crc_c <= to_unsigned(16,crc_c'length);
crc_s_cnt <= (others=>'0');
if (blkcnt_reg>1 and crc_ok_l='1') then
state <= WRITE_DAT;
elsif (busy_int='0') then
state <= IDLE;
end if;
end if;
 
when READ_WAIT =>
crc_rst_n <= '1';
crc_enable <= '1';
crc_in <= (others=>'0');
crc_c <= to_unsigned(15,crc_c'length);-- end
transf_cnt <= (others=>'0');
-- state transition
if (start_bit='1') then
state <= READ_DAT;
end if;
 
when READ_DAT =>
transf_cnt <= transf_cnt+1;
if (transf_cnt < data_cycles) then
if (bus_size_reg=2) then
rx_dat_we_o <= '1';
rx_dat_o <= dat_reg;
elsif (bus_size_reg=1) then
if (transf_cnt(0 downto 0)=1) then
rx_dat_we_o <= '1';
else
rx_dat_we_o <= '0';
end if;
rx_dat_o(7-(4*to_integer(transf_cnt(0 downto 0)))) <= dat_reg(3);
rx_dat_o(6-(4*to_integer(transf_cnt(0 downto 0)))) <= dat_reg(2);
rx_dat_o(5-(4*to_integer(transf_cnt(0 downto 0)))) <= dat_reg(1);
rx_dat_o(4-(4*to_integer(transf_cnt(0 downto 0)))) <= dat_reg(0);
else
if (transf_cnt(2 downto 0)=7) then
rx_dat_we_o <= '1';
else
rx_dat_we_o <= '0';
end if;
rx_dat_o(7-to_integer(transf_cnt(2 downto 0))) <= dat_reg(0);
end if;
crc_in <= dat_reg;
crc_ok_l <= '1';
elsif (transf_cnt <= data_cycles+16) then
crc_enable <= '0';
last_din <= dat_reg;
rx_dat_we_o <= '0';
if (transf_cnt > data_cycles) then
crc_c <= crc_c-1;
if (crc_out(0)(to_integer(crc_c)) /= last_din(0)) then
crc_ok_l <= '0';
end if;
if (crc_out(1)(to_integer(crc_c)) /= last_din(1) and bus_size_reg>0) then
crc_ok_l <= '0';
end if;
if (crc_out(2)(to_integer(crc_c)) /= last_din(2) and bus_size_reg>0) then
crc_ok_l <= '0';
end if;
if (crc_out(3)(to_integer(crc_c)) /= last_din(3) and bus_size_reg>0) then
crc_ok_l <= '0';
end if;
if (crc_out(4)(to_integer(crc_c)) /= last_din(4) and bus_size_reg>1) then
crc_ok_l <= '0';
end if;
if (crc_out(5)(to_integer(crc_c)) /= last_din(5) and bus_size_reg>1) then
crc_ok_l <= '0';
end if;
if (crc_out(6)(to_integer(crc_c)) /= last_din(6) and bus_size_reg>1) then
crc_ok_l <= '0';
end if;
if (crc_out(7)(to_integer(crc_c)) /= last_din(7) and bus_size_reg>1) then
crc_ok_l <= '0';
end if;
if (crc_c=0) then
crc_rst_n <= '0';
end if;
end if;
end if;
-- state transition
if (d_stop_i='1') then
state <= IDLE;
elsif (transf_cnt=(data_cycles+17) and blkcnt_reg>1 and crc_ok_l='1') then
blkcnt_reg <= blkcnt_reg-1;
state <= READ_WAIT;
elsif (transf_cnt=data_cycles+17) then
state <= IDLE;
end if;
 
when others =>
null;
 
end case;
end if;
end process;
 
end beh;
 
----------------------------------------------------------------------
---- ----
---- WISHBONE SD Card Controller IP Core ----
---- ----
---- sd_controller_8bit.vhd ----
---- ----
---- This file is part of the WISHBONE SD Card ----
---- Controller IP Core project ----
---- http:--opencores.org/project,sd_card_controller ----
---- ----
---- Description ----
---- Top level entity. ----
---- This core is based on the "sd card controller" project from ----
---- http:--opencores.org/project,sdcard_mass_storage_controller ----
---- but has been largely rewritten. A lot of effort has been ----
---- made to make the core more generic and easily usable ----
---- with OSs like Linux. ----
---- - data transfer commands are not fixed ----
---- - data transfer block size is configurable ----
---- - multiple block transfer support ----
---- - R2 responses (136 bit) support ----
---- ----
---- Author(s): ----
---- - John Clayton, morianton@gmail.com ----
---- ----
----------------------------------------------------------------------
---- ----
---- Copyright (C) 2016 Authors ----
---- ----
---- Based on original work by ----
---- Adam Edvardsson (adam.edvardsson@orsoc.se) ----
---- ----
---- Copyright (C) 2009 Authors ----
---- ----
---- 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 Lesser General ----
---- Public License as published by the Free Software Foundation; ----
---- either version 2.1 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 Lesser General Public License for more ----
---- details. ----
---- ----
---- You should have received a copy of the GNU Lesser General ----
---- Public License along with this source; if not, download it ----
---- from http:--www.opencores.org/lgpl.shtml ----
---- ----
----------------------------------------------------------------------
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
library work;
use work.sd_host_pack.all;
use work.dds_pack.all;
use work.fifo_pack.all;
use work.convert_pack.all;
use work.signal_conditioning_pack.all;
 
entity sd_controller_8bit_bram is
port (
-- WISHBONE common
wb_clk_i : in std_logic; -- system clock
wb_rst_i : in std_logic; -- asynchronous
-- WISHBONE slave (register interface)
wb_dat_i : in unsigned(31 downto 0);
wb_dat_o : out unsigned(31 downto 0);
wb_adr_i : in unsigned(3 downto 0);
wb_we_i : in std_logic;
wb_cyc_i : in std_logic;
wb_ack_o : out std_logic;
-- Dedicated BRAM port without acknowledge.
-- Access cycles must complete immediately.
-- (data to cross clock domains by this dual-ported BRAM)
bram_clk_o : out std_logic; -- Same as sd_clk_o_pad
bram_dat_o : out unsigned(7 downto 0);
bram_dat_i : in unsigned(7 downto 0);
bram_adr_o : out unsigned(31 downto 0);
bram_we_o : out std_logic;
bram_cyc_o : out std_logic;
--SD Card Interface
sd_cmd_i : in std_logic;
sd_cmd_o : out std_logic;
sd_cmd_oe_o : out std_logic;
sd_dat_i : in unsigned(7 downto 0);
sd_dat_o : out unsigned(7 downto 0);
sd_dat_oe_o : out std_logic;
sd_dat_siz_o : out unsigned(1 downto 0);
sd_clk_o_pad : out std_logic;
-- Interrupt outputs
int_cmd_o : out std_logic;
int_data_o : out std_logic
);
end sd_controller_8bit_bram;
 
architecture beh of sd_controller_8bit_bram is
 
--SD clock
signal sd_clk_l : std_logic; --sd_clk used in the system
signal sd_clk_en_l : std_logic; --clock enable pulse of sd_clk
signal combo_rst : std_logic; -- combines two reset signals
signal combo_rst_n : std_logic;
signal wb_ack_r1 : std_logic;
signal wb_ack_r2 : std_logic;
 
signal cmd_start_pend : std_logic;
signal cmd_start : std_logic;
signal cmd_start_r1 : std_logic;
signal cmd_with_data : std_logic;
signal sd_data_rd : std_logic;
 
-- Related to BRAM interface port
signal bram_cyc_l : std_logic;
signal offset : unsigned(31 downto 0);
 
-- Related to data master
signal d_write : std_logic;
signal d_read : std_logic;
signal bustest_r : std_logic;
signal bustest_w : std_logic;
signal bustest_res : unsigned(2 downto 0);
signal sd_dat_busy : std_logic;
signal data_busy : std_logic;
signal data_crc_ok : std_logic;
signal bram_rd : std_logic;
signal bram_we : std_logic;
 
signal cmd_int_rst_pend : std_logic;
signal cmd_int_rst : std_logic;
signal cmd_int_rst_edge : std_logic;
signal data_int_rst_pend : std_logic;
signal data_int_rst : std_logic;
signal data_int_rst_edge : std_logic;
 
--SD Data Master State Machine
type DM_STATE_TYPE is (IDLE, WAIT_FOR_CMD_INT, DATA_TX_START, DATA_TX,
DATA_RX, BUSTEST_ACTIVE, BUSTEST_W_START);
signal dm_state : DM_STATE_TYPE;
 
-- registers
signal argument_reg : unsigned(31 downto 0);
signal cmd_index_reg : unsigned(5 downto 0);
signal blk_size_reg : unsigned(BLKSIZE_W-1 downto 0);
signal blk_count_reg : unsigned(BLKCNT_W-1 downto 0);
signal resp_0_reg : unsigned(31 downto 0);
signal resp_1_reg : unsigned(31 downto 0);
signal resp_2_reg : unsigned(31 downto 0);
signal resp_3_reg : unsigned(31 downto 0);
-- Fields of the settings register
signal bus_siz_reg : unsigned(1 downto 0);
signal sw_rst_reg : std_logic;
signal d_stop : std_logic;
signal sd_freq_reg : unsigned(31 downto 0);
signal timeout_reg : unsigned(15 downto 0);
-- Registers 0x9..0xC are interrupt related
signal cmd_int_status_reg : unsigned(4 downto 0);
signal cmd_int_enable_reg : unsigned(4 downto 0);
signal data_int_status_reg : unsigned(2 downto 0);
signal data_int_enable_reg : unsigned(2 downto 0);
-- Register holding current bus address
signal dma_adr_reg : unsigned(31 downto 0);
 
begin
 
-- Register read mux
with (to_integer(wb_adr_i)) select
wb_dat_o <=
u_resize(blk_size_reg,32) when 0,
u_resize(blk_count_reg,32) when 1,
u_resize(cmd_index_reg,32) when 2,
argument_reg when 3,
resp_0_reg when 4,
resp_1_reg when 5,
resp_2_reg when 6,
resp_3_reg when 7,
timeout_reg & "00000" & bustest_res & "000" & sw_rst_reg & "00" & bus_siz_reg when 8,
sd_freq_reg when 9,
u_resize(cmd_int_status_reg,32) when 10,
u_resize(cmd_int_enable_reg,32) when 11,
u_resize(data_int_status_reg,32) when 12,
u_resize(data_int_enable_reg,32) when 13,
dma_adr_reg when 14,
str2u("55555555",32) when others;
 
-- Register Writing Process
reg_wr_proc : process(wb_rst_i, wb_clk_i)
begin
if (wb_rst_i='1') then
argument_reg <= (others=>'0');
cmd_index_reg <= (others=>'0');
blk_size_reg <= to_unsigned(512,blk_size_reg'length);
blk_count_reg <= to_unsigned(1,blk_count_reg'length);
bus_siz_reg <= "00";
sw_rst_reg <= '0';
sd_freq_reg <= str2u("010624DD",sd_freq_reg'length); -- Set for 400 kHz default (100 MHz sys_clk)
timeout_reg <= to_unsigned(1000,timeout_reg'length);
cmd_int_rst_pend <= '0';
cmd_int_rst <= '0';
d_stop <= '0';
cmd_int_enable_reg <= (others=>'0');
data_int_rst_pend <= '0';
data_int_rst <= '0';
data_int_enable_reg <= (others=>'0');
wb_ack_r1 <= '0';
wb_ack_r2 <= '0';
cmd_start_pend <= '0';
cmd_start <= '0';
cmd_start_r1 <= '0';
dma_adr_reg <= (others=>'0');
elsif (wb_clk_i'event and wb_clk_i='1') then
-- default values, clocked on sd_clk_en_l
if (sd_clk_en_l='1') then
cmd_start <= '0';
data_int_rst <= '0';
cmd_int_rst <= '0';
d_stop <= '0';
end if;
-- signals raised on sd_clk_en_l
-- higher priority than the default
if (sd_clk_en_l='1') then
if (cmd_start_pend='1') then
cmd_start <= '1';
cmd_start_pend <= '0';
end if;
if (data_int_rst_pend='1') then
data_int_rst <= '1';
data_int_rst_pend <= '0';
end if;
if (cmd_int_rst_pend='1') then
cmd_int_rst <= '1';
cmd_int_rst_pend <= '0';
end if;
end if;
-- delayed version
cmd_start_r1 <= cmd_start;
 
if (wb_ack_r1='1' and wb_ack_r2='0') then
if (wb_we_i='1') then
case (to_integer(wb_adr_i)) is
when 0 =>
blk_size_reg <= wb_dat_i(BLKSIZE_W-1 downto 0);
 
when 1 =>
blk_count_reg <= wb_dat_i(BLKCNT_W-1 downto 0);
 
when 2 =>
cmd_index_reg <= wb_dat_i(5 downto 0);
 
when 3 =>
argument_reg <= wb_dat_i;
cmd_start_pend <= '1';
 
when 8 =>
bus_siz_reg <= wb_dat_i(1 downto 0);
sw_rst_reg <= wb_dat_i(4);
d_stop <= wb_dat_i(5); -- write only bit
timeout_reg <= wb_dat_i(31 downto 16);
 
when 9 =>
sd_freq_reg <= wb_dat_i;
 
when 10 =>
cmd_int_rst_pend <= '1';
 
when 11 =>
cmd_int_enable_reg <= wb_dat_i(cmd_int_enable_reg'length-1 downto 0);
 
when 12 =>
data_int_rst_pend <= '1';
 
when 13 =>
data_int_enable_reg <= wb_dat_i(data_int_enable_reg'length-1 downto 0);
 
when 14 =>
dma_adr_reg <= wb_dat_i;
 
when others =>
null;
end case;
end if;
end if;
-- Detect rising edge of wb_cyc_i
wb_ack_r1 <= wb_cyc_i;
wb_ack_r2 <= wb_ack_r1;
end if;
end process;
 
-- Provide Wishbone bus cycle acknowledge
wb_ack_o <= wb_ack_r1;
 
-- Form a combined reset signal
combo_rst <= wb_rst_i or sw_rst_reg;
combo_rst_n <= not combo_rst;
 
-- SD Card clock generation
-- A DDS is used.
sd_clk_dds : dds_squarewave
generic map(
ACC_BITS => sd_freq_reg'length -- Bit width of DDS phase accumulator
)
port map(
 
sys_rst_n => combo_rst_n,
sys_clk => wb_clk_i,
sys_clk_en => '1',
 
-- Frequency setting
freq_i => sd_freq_reg,
 
-- Output
pulse_o => sd_clk_en_l,
squarewave_o => sd_clk_l
);
sd_clk_o_pad <= sd_clk_l;
 
 
cmd_host_0 : sd_cmd_host
port map(
sd_clk => sd_clk_l,
sys_rst => combo_rst,
-- Control and settings
start_i => cmd_start_r1,
int_rst_i => cmd_int_rst_edge,
busy_i => sd_dat_busy,
cmd_index_i => cmd_index_reg,
argument_i => argument_reg,
timeout_i => timeout_reg,
int_status_o => cmd_int_status_reg,
response_0_o => resp_0_reg,
response_1_o => resp_1_reg,
response_2_o => resp_2_reg,
response_3_o => resp_3_reg,
-- SD/MMC card command signals
sd_cmd_i => sd_cmd_i,
sd_cmd_o => sd_cmd_o,
sd_cmd_oe_o => sd_cmd_oe_o
);
 
cmd_with_data <= '1' when cmd_index_reg=20 or cmd_index_reg=24 or cmd_index_reg=25 or
cmd_index_reg=8 or cmd_index_reg=11 or cmd_index_reg=17 or
cmd_index_reg=18 or cmd_index_reg=14 or cmd_index_reg=19 else '0';
sd_data_rd <= '1' when cmd_index_reg=8 or cmd_index_reg=11 or
cmd_index_reg=17 or cmd_index_reg=18 else '0';
 
-- SD Data Master Finite State Machine
d_read <= '1' when dm_state=IDLE and cmd_start_r1='1' and cmd_with_data='1' and sd_data_rd='1' else '0';
d_write <= '1' when dm_state=DATA_TX_START else '0';
bustest_r <= '1' when dm_state=IDLE and cmd_start_r1='1' and cmd_index_reg=14 else '0';
bustest_w <= '1' when dm_state=BUSTEST_W_START else '0';
 
dm_fsm_proc : process(combo_rst, sd_clk_l)
begin
if (combo_rst='1') then
offset <= (others=>'0');
data_int_status_reg <= (others=>'0');
dm_state <= IDLE;
elsif (sd_clk_l'event and sd_clk_l='1') then
case (dm_state) is
when IDLE =>
offset <= (others=>'0');
-- state transition
if (cmd_start_r1='1') then
if (cmd_with_data='1') then
if (cmd_index_reg=14) then -- BUSTEST_R
dm_state <= BUSTEST_ACTIVE;
elsif (sd_data_rd='1') then -- Reading
dm_state <= DATA_RX;
else
dm_state <= WAIT_FOR_CMD_INT;
end if;
end if;
end if;
 
when BUSTEST_ACTIVE =>
if (data_busy='0') then --Transfer complete
dm_state <= IDLE;
end if;
 
when BUSTEST_W_START =>
dm_state <= BUSTEST_ACTIVE;
 
when WAIT_FOR_CMD_INT =>
if (cmd_int_status_reg(INT_CMD_CC)='1') then
if (cmd_index_reg=19) then
dm_state <= BUSTEST_W_START;
else
dm_state <= DATA_TX_START;
end if;
elsif (cmd_int_status_reg(INT_CMD_EI)='1') then
dm_state <= IDLE;
end if;
 
when DATA_TX_START =>
dm_state <= DATA_TX;
 
when DATA_TX =>
if (bram_cyc_l='1') then
offset <= offset+1;
end if;
if (data_busy='0') then --Transfer complete
if (data_crc_ok='0') then --Wrong CRC
data_int_status_reg(INT_DATA_CCRCE) <= '1';
else
data_int_status_reg(INT_DATA_CC) <= '1';
end if;
dm_state <= IDLE;
end if;
 
when DATA_RX =>
if (bram_cyc_l='1') then
offset <= offset+1;
end if;
if (data_busy='0') then --Transfer complete
if (data_crc_ok='0') then --Wrong CRC
data_int_status_reg(INT_DATA_CCRCE) <= '1';
else
data_int_status_reg(INT_DATA_CC) <= '1';
end if;
dm_state <= IDLE;
end if;
 
when others =>
null;
 
end case;
 
if (data_int_rst_edge='1') then
data_int_status_reg <= (others=>'0');
end if;
end if;
end process;
 
 
sd_data_host0 : sd_data_8bit_host
port map(
sd_clk => sd_clk_l,
sys_rst => combo_rst,
--Tx Fifo
tx_dat_i => bram_dat_i,
tx_dat_rd_o => bram_rd,
--Rx Fifo
rx_dat_o => bram_dat_o,
rx_dat_we_o => bram_we,
--tristate data
sd_dat_siz_o => sd_dat_siz_o,
sd_dat_oe_o => sd_dat_oe_o,
sd_dat_o => sd_dat_o,
sd_dat_i => sd_dat_i,
--Control signals
blksize_i => blk_size_reg,
bus_size_i => bus_siz_reg,
blkcnt_i => blk_count_reg,
d_stop_i => d_stop,
d_read_i => d_read,
d_write_i => d_write,
bustest_w_i => bustest_w,
bustest_r_i => bustest_r,
bustest_res_o => bustest_res,
sd_dat_busy_o => sd_dat_busy,
fsm_busy_o => data_busy,
crc_ok_o => data_crc_ok
);
 
bram_clk_o <= not sd_clk_l;
bram_we_o <= bram_we;
bram_cyc_l <= bram_rd or bram_we;
bram_cyc_o <= bram_cyc_l;
bram_adr_o <= dma_adr_reg+offset;
 
cmd_int_rst_edge_detect : edge_detector
generic map(
DETECT_RISING => 1,
DETECT_FALLING => 0
)
port map(
-- System Clock and Clock Enable
sys_rst_n => combo_rst_n,
sys_clk => sd_clk_l,
sys_clk_en => '1',
 
-- Input Signal
sig_i => cmd_int_rst,
 
-- Output pulse
pulse_o => cmd_int_rst_edge
);
 
data_int_rst_edge_detect : edge_detector
generic map(
DETECT_RISING => 1,
DETECT_FALLING => 0
)
port map(
-- System Clock and Clock Enable
sys_rst_n => combo_rst_n,
sys_clk => sd_clk_l,
sys_clk_en => '1',
 
-- Input Signal
sig_i => data_int_rst,
 
-- Output pulse
pulse_o => data_int_rst_edge
);
 
-- provide outputs
int_cmd_o <= '1' when (cmd_int_status_reg or cmd_int_enable_reg)/=0 else '0';
int_data_o <= '1' when (data_int_status_reg or data_int_enable_reg)/=0 else '0';
 
end beh;
 
/VHDL/signal_conditioning_pack.vhd
0,0 → 1,743
--------------------------------------------------------------------------
-- Package
--
--
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;
 
package signal_conditioning_pack is
 
component edge_detector
generic(
DETECT_RISING : natural;
DETECT_FALLING : natural
);
port (
-- System Clock and Clock Enable
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Input Signal
sig_i : in std_logic;
 
-- Output pulse
pulse_o : out std_logic
 
);
end component;
 
component leaky_integrator
generic(
LEAK_FACTOR_BITS : natural;
LEAK_FACTOR : natural;
INTEGRATOR_BITS : natural -- Bits in the integrating accumulator
);
port (
-- System Clock and Clock Enable
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Settings
input : in signed(INTEGRATOR_BITS-1 downto 0);
 
-- Integration Result
integrator : out signed(INTEGRATOR_BITS-1 downto 0)
 
);
end component;
 
component leaky_integrator_with_digital_output
generic(
FACTOR_BITS : natural; -- Make this less than INTEGRATOR_BITS
HYSTERESIS_BITS : natural; -- Make this less than INTEGRATOR_BITS
INTEGRATOR_BITS : natural -- Bits in the integrating accumulator
);
port (
-- System Clock and Clock Enable
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Settings
input : in signed(INTEGRATOR_BITS-1 downto 0);
leak_factor : in signed(FACTOR_BITS-1 downto 0);
hysteresis : in unsigned(HYSTERESIS_BITS-1 downto 0);
 
-- Integration Result
integrator : out signed(INTEGRATOR_BITS-1 downto 0);
 
-- Conditioned Digital Output Signal
output : out std_logic
);
end component;
 
component multi_stage_leaky_integrator
generic(
STAGES : natural;
LEAK_FACTOR_BITS : natural; -- Inversely related to LP corner frequency. (Min=1)
HYSTERESIS_BITS : natural; -- Make this less than INTEGRATOR_BITS
INTEGRATOR_BITS : natural -- Bits in each integrating accumulator
);
port (
-- System Clock and Clock Enable
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Settings
input : in signed(INTEGRATOR_BITS-1 downto 0);
hysteresis : in unsigned(HYSTERESIS_BITS-1 downto 0);
 
-- Final Stage Integration Result
integrator : out signed(INTEGRATOR_BITS-1 downto 0);
 
-- Conditioned Digital Output Signal
output : out std_logic
);
end component;
 
component integrating_pulse_stretcher
generic(
MIN_CLKS : natural; -- pulses below this many clocks are ignored
RETRIGGERABLE : natural; -- 1=restart on new pulses. 0=decay to zero before restarting
STRETCH_FACTOR : natural; -- 0=don't stretch, 1=double, 2=triple
INITIAL_OFFSET : natural; -- Value initially loaded into integrator
INTEGRATOR_BITS : natural -- Bits in the integrating accumulator
);
port (
-- System Clock and Clock Enable
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Input
pulse_i : in std_logic;
 
-- Output
pulse_o : out std_logic
 
);
end component;
 
end signal_conditioning_pack;
 
-------------------------------------------------------------------------------
-- Edge Detector
-------------------------------------------------------------------------------
--
-- Author: John Clayton
-- Date : Nov. 1, 2013 Started Coding, drawing from various other sources.
-- Created description. Simulated it and saw that it
-- works.
--
--
-- Description
-------------------------------------------------------------------------------
-- This module is a super simple edge detector, which produces is high-going
-- pulse whenever there is an edge on the input. The type of edge is
-- selectable via generic.
--
-- The sys_clk_en affects the operation by extending the length of the pulse
-- output beyond one single sys_clk cycle, as expected.
--
-- Detecting both rising and falling edges is allowed. Detecting neither is
-- also allowed, but not recommended.
--
-- The sys_rst_n input is an asynchronous reset.
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;
 
library work;
use work.convert_pack.all;
 
entity edge_detector is
generic(
DETECT_RISING : natural := 1;
DETECT_FALLING : natural := 0
);
port (
-- System Clock and Clock Enable
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Input Signal
sig_i : in std_logic;
 
-- Output pulse
pulse_o : out std_logic
 
);
end edge_detector;
 
architecture beh of edge_detector is
 
-- Constants
 
-- Functions & associated types
 
-- Signal Declarations
signal sig_r1 : std_logic;
signal pulse_r : std_logic;
signal pulse_f : std_logic;
signal pulse_b : std_logic;
 
begin
 
process (sys_clk, sys_rst_n)
begin
if (sys_rst_n='0') then
sig_r1 <= '0';
elsif (sys_clk'event and sys_clk='1') then -- rising edge
if (sys_clk_en='1') then
sig_r1 <= sig_i;
end if;
end if;
end process;
 
-- The detection
pulse_r <= '1' when sig_i='1' and sig_r1='0' else '0';
pulse_f <= '1' when sig_i='0' and sig_r1='1' else '0';
pulse_b <= sig_i xor sig_r1;
 
-- The output
pulse_o <= pulse_b when DETECT_RISING/=0 and DETECT_FALLING/=0 else
pulse_r when DETECT_RISING/=0 else
pulse_f when DETECT_FALLING/=0 else
'0'; -- Haha! Don't go there!
 
end beh;
 
-------------------------------------------------------------------------------
-- Leaky Integrator
-------------------------------------------------------------------------------
--
-- Author: John Clayton
-- Date : Oct. 11, 2013 Started Coding, drawing from various other sources.
-- Created description. Simulated it and saw that it
-- works.
--
--
-- Description
-------------------------------------------------------------------------------
-- This module is a pretty simple digital "leaky integrator" designed to low
-- pass noisy signals by integrating them.
--
-- The first order differential equation is of the form:
--
-- dx/dt = -leak_factor*x + input
--
-- The input is discretized in both time and amplitude. A one bit digital
-- input can be mapped to the "input" signal by using a positive value for
-- '1' and a negative value for '0' Alternately, a signed DSP type signal
-- can be used directly.
--
-- The "leak_factor" is a feedback term, so that "DC gain" is inversely
-- proportional to the leak_factor.
--
-- Due to the presence of the feedback term, the integration's DC value, or
-- constant term, gets "leaked" to zero over time. This is nice because
-- the threshold centers around zero.
--
-- Hysteresis can be added so that the digital output transitions an amount
-- above or below zero, depending on the current value of the output.
--
-- Clear as mud? Well, it's similar to a low-pass filter, and the hysteresis
-- also helps remove noise on the input signal.
--
-- The sys_rst_n input is an asynchronous reset.
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;
 
library work;
use work.convert_pack.all;
 
entity leaky_integrator is
generic(
LEAK_FACTOR_BITS : natural := 10;
LEAK_FACTOR : natural := 10;
INTEGRATOR_BITS : natural := 16 -- Bits in the integrating accumulator
);
port (
-- System Clock and Clock Enable
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Settings
input : in signed(INTEGRATOR_BITS-1 downto 0);
 
-- Integration Result
integrator : out signed(INTEGRATOR_BITS-1 downto 0)
 
);
end leaky_integrator;
 
architecture beh of leaky_integrator is
 
-- Constants
 
-- Functions & associated types
 
-- Signal Declarations
signal sum : signed(INTEGRATOR_BITS-1 downto 0);
signal delta : signed(INTEGRATOR_BITS-1 downto 0);
signal m_term : signed(INTEGRATOR_BITS+LEAK_FACTOR_BITS downto 0);
 
begin
 
-- The feedback term
m_term <= sum*to_signed(LEAK_FACTOR,LEAK_FACTOR_BITS+1);
 
-- The difference term
delta <= input - s_resize_l(m_term,delta'length);
 
-- The leaky integrator
process (sys_clk, sys_rst_n)
begin
if (sys_rst_n='0') then
sum <= to_signed(0,integrator'length);
elsif (sys_clk'event and sys_clk='1') then -- rising edge
if (sys_clk_en='1') then
sum <= sum + delta;
end if;
end if;
end process;
 
-- The outputs
integrator <= sum;
 
end beh;
 
-------------------------------------------------------------------------------
-- Leaky Integrator with conditioned Digital Output
-------------------------------------------------------------------------------
--
-- Author: John Clayton
-- Date : Oct. 11, 2013 Started Coding, drawing from various other sources.
-- Created description. Simulated it and saw that it
-- works.
--
--
-- Description
-------------------------------------------------------------------------------
-- This module is a pretty simple digital "leaky integrator" designed to clean
-- up noisy repetitive signals by integrating them, and applying thresholds
-- to the integrated result.
--
-- The first order differential equation is of the form:
--
-- dx/dt = -leak_factor*x + input
--
-- The input is discretized in both time and amplitude. A one bit digital
-- input can be mapped to the "input" signal by using a positive value for
-- '1' and a negative value for '0'
--
-- The "leak_factor" is a feedback term, so that "DC gain" is inversely
-- proportional to the leak_factor.
--
-- Due to the presence of the feedback term, the integration's DC value, or
-- constant term, gets "leaked" to zero over time. This is nice because
-- the threshold centers around zero.
--
-- Hysteresis can be added so that the digital output transitions an amount
-- above or below zero, depending on the current value of the output.
--
-- Clear as mud? Well, it's similar to a low-pass filter, and the hysteresis
-- also helps remove noise on the input signal.
--
-- The sys_rst_n input is an asynchronous reset.
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;
 
library work;
use work.convert_pack.all;
 
entity leaky_integrator_with_digital_output is
generic(
FACTOR_BITS : natural := 10; -- Make this less than INTEGRATOR_BITS
HYSTERESIS_BITS : natural := 10; -- Make this less than INTEGRATOR_BITS
INTEGRATOR_BITS : natural := 16 -- Bits in the integrating accumulator
);
port (
-- System Clock and Clock Enable
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Settings
input : in signed(INTEGRATOR_BITS-1 downto 0);
leak_factor : in signed(FACTOR_BITS-1 downto 0);
hysteresis : in unsigned(HYSTERESIS_BITS-1 downto 0);
 
-- Integration Result
integrator : out signed(INTEGRATOR_BITS-1 downto 0);
 
-- Conditioned Digital Output Signal
output : out std_logic
);
end leaky_integrator_with_digital_output;
 
architecture beh of leaky_integrator_with_digital_output is
 
-- Constants
 
-- Functions & associated types
 
-- Signal Declarations
signal sum : signed(INTEGRATOR_BITS-1 downto 0);
signal delta : signed(INTEGRATOR_BITS-1 downto 0);
signal m_term : signed(INTEGRATOR_BITS+FACTOR_BITS-1 downto 0);
signal out_l : std_logic;
signal hp_term : signed(INTEGRATOR_BITS-1 downto 0);
signal hn_term : signed(INTEGRATOR_BITS-1 downto 0);
 
begin
 
-- The feedback term
m_term <= sum*leak_factor;
 
-- The difference term
delta <= input - s_resize_l(m_term,delta'length);
 
-- The leaky integrator
process (sys_clk, sys_rst_n)
begin
if (sys_rst_n='0') then
sum <= to_signed(0,integrator'length);
out_l <= '0';
elsif (sys_clk'event and sys_clk='1') then -- rising edge
if (sys_clk_en='1') then
sum <= sum + delta;
if (out_l='0') then
if (sum>hp_term) then
out_l <= '1';
end if;
else
if (sum<hn_term) then
out_l <= '0';
end if;
end if;
end if;
end if;
end process;
 
-- The hysteresis terms
hp_term <= signed(u_resize(hysteresis,INTEGRATOR_BITS));
hn_term <= not(hp_term)+1;
 
-- The outputs
integrator <= sum;
output <= out_l;
 
end beh;
 
-------------------------------------------------------------------------------
-- Multi Stage Leaky Integrator with Digital Output
-------------------------------------------------------------------------------
--
-- Author: John Clayton
-- Date : Oct. 11, 2013 Started Coding, drawing from various other sources.
-- Created description.
--
--
-- Description
-------------------------------------------------------------------------------
-- This module implements N-stages of leaky integrators. Each stage has the
-- same leak factor, which is a value fixed by generics. Use powers of two
-- to avoid inferring multipliers. The smallest value of 1 is actually a
-- pretty nice choice. The LEAK_FACTOR_BITS generic determines how small
-- the leak factor is by setting the number of bits. The integer is converted
-- as follows:
--
-- multiplicand = to_signed(LEAK_FACTOR,LEAK_FACTOR_BITS);
--
-- It seems that the smallest signed number is 2 bits wide - one for a sign
-- bit, and the other for magnitude. So, LEAK_FACTOR_BITS must be >=2.
-- Between stages, an arithmetic shift right operation is inserted, which is
-- intended to automatically scale the signal to fit the next integrator.
--
-- The hysteresis value is only applied at the final stage output, to derive
-- the conditioned digital output signal.
--
-- The "leak_factor" is a feedback term, so that "DC gain" is inversely
-- proportional to the leak_factor.
--
-- Due to the presence of the feedback term, the integration's DC value, or
-- constant term, gets "leaked" to zero over time. This is nice because
-- the threshold centers around zero.
--
-- Hysteresis can be added so that the digital output transitions an amount
-- above or below zero, depending on the current value of the output.
--
-- Clear as mud? Well, it's similar to a low-pass filter, and the hysteresis
-- also helps remove noise on the input signal.
--
-- The more stages are used, the more low-pass filtering occurs.
--
-- The sys_rst_n input is an asynchronous reset.
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;
 
library work;
use work.convert_pack.all;
use work.signal_conditioning_pack.all;
 
entity multi_stage_leaky_integrator is
generic(
STAGES : natural := 2;
LEAK_FACTOR_BITS : natural := 5; -- Inversely related to LP corner frequency. (Min=1)
HYSTERESIS_BITS : natural := 8; -- Make this less than INTEGRATOR_BITS
INTEGRATOR_BITS : natural := 16 -- Bits in each integrating accumulator
);
port (
-- System Clock and Clock Enable
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Settings
input : in signed(INTEGRATOR_BITS-1 downto 0);
hysteresis : in unsigned(HYSTERESIS_BITS-1 downto 0);
 
-- Final Stage Integration Result
integrator : out signed(INTEGRATOR_BITS-1 downto 0);
 
-- Conditioned Digital Output Signal
output : out std_logic
);
end multi_stage_leaky_integrator;
 
architecture beh of multi_stage_leaky_integrator is
 
-- Constants
-- This value has been found to preserve amplitude between stages,
-- without appreciable growth or shrinkage of sum levels.
constant STAGE_ASR : natural := LEAK_FACTOR_BITS+1;
constant LEAK_FACTOR : natural := 1;
 
-- Functions & associated types
 
-- Signal Declarations
type sum_type is array (natural range STAGES-1 downto 0) of signed(INTEGRATOR_BITS-1 downto 0);
signal sum_in : sum_type;
signal sum_out : sum_type;
signal out_l : std_logic;
signal hp_term : signed(INTEGRATOR_BITS-1 downto 0);
signal hn_term : signed(INTEGRATOR_BITS-1 downto 0);
 
begin
 
 
----------------------------------------------
leaky_gen : for nvar in 0 to STAGES-1 generate
begin
lint : leaky_integrator
generic map(
LEAK_FACTOR_BITS => LEAK_FACTOR_BITS,
LEAK_FACTOR => LEAK_FACTOR,
INTEGRATOR_BITS => INTEGRATOR_BITS
)
port map(
-- System Clock and Clock Enable
sys_rst_n => sys_rst_n,
sys_clk => sys_clk,
sys_clk_en => sys_clk_en,
 
-- Settings
input => sum_in(nvar),
 
-- Integration Result
integrator => sum_out(nvar)
 
);
end generate;
 
sum_in(0) <= input;
sum_gen : for nvar in 1 to STAGES-1 generate
begin
sum_in(nvar) <= asr_function(sum_out(nvar-1),STAGE_ASR);
end generate;
 
-- The hysteresis and digital output
process (sys_clk, sys_rst_n)
begin
if (sys_rst_n='0') then
out_l <= '0';
elsif (sys_clk'event and sys_clk='1') then -- rising edge
if (sys_clk_en='1') then
if (out_l='0') then
if (sum_out(STAGES-1)>hp_term) then
out_l <= '1';
end if;
else
if (sum_out(STAGES-1)<hn_term) then
out_l <= '0';
end if;
end if;
end if;
end if;
end process;
 
-- The hysteresis terms
hp_term <= signed(u_resize(hysteresis,INTEGRATOR_BITS));
hn_term <= not(hp_term)+1;
 
-- The outputs
integrator <= sum_out(STAGES-1);
output <= out_l;
 
end beh;
 
-------------------------------------------------------------------------------
-- Integrating Pulse Stretcher
-------------------------------------------------------------------------------
--
-- Author: John Clayton
-- Date : Oct. 24, 2013 Started Coding, drawing from various other sources.
-- Created description. Simulated it and saw that it
-- works.
--
--
-- Description
-------------------------------------------------------------------------------
-- This module is a pretty simple digital pulse stretcher. A high input pulse
-- present for more than MIN_CLKS clock cycles causes the INITIAL_OFFSET value
-- to be loaded into an accumulator. The accumulator is then incremented by
-- STRETCH_FACTOR each clock cycle that the input pulse remains high, and is
-- decremented by one for each clock cycle that the input pulse is low.
--
-- The output is driven high whenever the accumulator is positive.
--
-- The output pulse width is given by:
--
-- Tpulse_o = STRETCH_FACTOR*(Tpulse_i-MIN_CLKS) + INITIAL_OFFSET
--
-- The INITIAL_OFFSET can be used to overcome the effects of minimum input
-- pulse filtering. Also, if a negative value is used for it, then the
-- output pulse is delayed by additional clock cycles beyond the MIN_CLKS
-- of delay already present. Another use for the INITIAL_OFFSET value is
-- to "bridge together" a train of pulses which might have some jitter.
-- The INITIAL_OFFSET value allows for some slop of jitter to be covered
-- by the extra decay time, so that no "gaps" appear in the output pulse.
--
-- During the decay time, when the output is high, the arrival of a new pulse
-- will cause further charging of the accumulator. There is no minimum pulse
-- width for this to occur. The MIN_CLKS only applies to starting the unit
-- from a quiescent state.
--
-- The integrator is a signed quantity, so set INTEGRATOR_BITS accordingly,
-- because the integrator can only hold positive quantities up to
-- 2^(INTEGRATOR_BITS-1)-1.
--
-- The sys_rst_n input is an asynchronous reset.
 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
use IEEE.MATH_REAL.ALL;
 
library work;
use work.convert_pack.all;
 
entity integrating_pulse_stretcher is
generic(
MIN_CLKS : natural := 5; -- pulses below this many clocks are ignored
RETRIGGERABLE : natural := 1; -- 1=restart on new pulses. 0=decay to zero before restarting
STRETCH_FACTOR : natural := 2; -- 0=no output, 1=same size, 2=double
INITIAL_OFFSET : natural := 25; -- Value initially loaded into integrator
INTEGRATOR_BITS : natural := 16 -- Bits in the integrating accumulator
);
port (
-- System Clock and Clock Enable
sys_rst_n : in std_logic;
sys_clk : in std_logic;
sys_clk_en : in std_logic;
 
-- Input
pulse_i : in std_logic;
 
-- Output
pulse_o : out std_logic
 
);
end integrating_pulse_stretcher;
 
architecture beh of integrating_pulse_stretcher is
 
-- Constants
constant RUNT_BITS : natural := timer_width(MIN_CLKS);
 
-- Functions & associated types
 
-- Signal Declarations
signal runt_count : unsigned(RUNT_BITS-1 downto 0);
signal sum : signed(INTEGRATOR_BITS-1 downto 0);
signal pulse_i_r1 : std_logic;
signal pulse_l : std_logic;
 
begin
 
-- The integrator
process (sys_clk, sys_rst_n)
begin
if (sys_rst_n='0') then
runt_count <= to_unsigned(0,runt_count'length);
sum <= to_signed(0,sum'length);
pulse_i_r1 <= '0';
elsif (sys_clk'event and sys_clk='1') then -- rising edge
if (sys_clk_en='1') then
-- Detect rising edge of input pulse
pulse_i_r1 <= pulse_i;
-- When the pulse_i input is consecutively high, decrement the runt
-- counter until it is zero.
if (runt_count>0) then
if (pulse_i='1') then
runt_count <= runt_count-1;
else
runt_count <= to_unsigned(MIN_CLKS,runt_count'length);
end if;
end if;
-- Trigger on rising edge of pulse_i
if (pulse_i='1' and pulse_i_r1='0') then
if (pulse_l='0' or (RETRIGGERABLE=1 and pulse_l='1')) then
runt_count <= to_unsigned(MIN_CLKS,runt_count'length);
end if;
end if;
-- Load initial offset into accumulator on final runt countdown
if (runt_count=1) then
sum <= to_signed(INITIAL_OFFSET,sum'length);
end if;
-- Either accumulate or decay, depending on input state
if (pulse_i='1' and runt_count=0) then
sum <= sum+STRETCH_FACTOR;
elsif (pulse_i='0' and pulse_l='1') then
sum <= sum-1;
end if;
end if;
end if;
end process;
 
-- The output
pulse_l <= '1' when (sum>0) else '0';
pulse_o <= pulse_l;
 
end beh;
 

powered by: WebSVN 2.1.0

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