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