Frequency counter
From Hamsterworks Wiki!
This FPGA Project was started and completed in October 2012.
Hackaday readers - If you want, you can grab a board and do a self paced, free (as in beer and freedom) FPGA_course.
I've been trying to find a use for my dx_display module, and I've been wanting to play with a GPS module, and found a brilliant little project - a GPS referenced 100MHz frequency counter!
If you don't have a GPS module you can still use this, but it will be referenced to the (less accurate) internal crystal. Even without the GPS module it is sensitive enough to detect when you touch a crystal (through the temperature and most probably also some capacitance effect too).
The yellow and green wires on the left are the 25,000,494Hz signal coming from the unit under test (in this case a different FPGA board). The blue jumper wire is connecting the one pulse per second input to the internal reference.
And here it is with a GPS module, measuring the accuracy of the Papilio One's own crystal:
Sorry about the photo - I had to turn the flash off for the display to be readable.
A couple of videos of it in operation are at http://youtu.be/1PwUSwkvsOM and http://youtu.be/eCEi2-8Vn_I
Contents |
Method of operation
Most GPS modules have a one pulse per second (1PPS) output, which can be highly accurate - down to around 20ns (1 in 40,000,000) absolute error from GPS's reference time, and a few nanoseconds when used as a reference for timing local events - mostly due to noise (see http://www2.iee.or.jp/ver2/honbu/14-magazine/log/2005/2005_08c_08.pdf). This project simply counts the number of leading edges that are seen between two rising edges of the reference 1PPS output and displays the numbers on the eight digit seven segment display.
To allow it count high frequency signals the input stage has to be clocked as fast as possible - in this case I use 256MHz, and it also uses a DDR input, which should be fine for signals of up to about 99MHz. The logic to send the the count to the display runs at a more sedate 32MHz,
To keep things working at this high speed I've opted to not use a 27 bit binary counter, but to use eight cascaded decimal counters, followed with delay lines to bring everything back into sync before the 32 bit BCD result is passed from the hight speed to the low speed logic. As a bonus I've added an eleventh state to the counters, allowing for the initially blank leading zeros on the seven most significant digits.
Parts needed
- For the highest accuracy use an optional GPS module with a 1PPS output - I'm waiting on my Digilent GPS Pmod to arrive
- A Papilio One FPGA board. You can use another board, but this project assumes a 32MHz on-board clock
- An eight digit seven-segment display board from Deal Extreme (http://dx.com/p/8x-digital-tube-8x-key-8x-double-color-led-module-81873)
- A few jumper wires to tie it all together
Source files
Not included below is the DCM IP block, that takes CLK32 and generates the 224MHz capture clock - just use the Clocking Wizard to generate one.
freq_counter.ucf
This file is for the Papilio One board.
If you are not using an external GPS module, just jumper Wing1C(0) to Wing1C(1), to use the internal crystal as the reference.
NET "clk32" LOC = "P89" | IOSTANDARD = LVCMOS25 | PERIOD = 31.25ns ; NET "d_data" LOC = "P18" | DRIVE = 2; # Wing A1A<0> NET "d_clk" LOC = "P23" | DRIVE = 2; # Wing A1A<1> NET "d_strobe" LOC = "P26" | DRIVE = 2; # Wing A1A<2> NET "test_sig" LOC = "P33"; # Wing A1A<3> NET "ref" LOC = "P40" | DRIVE = 2; # Wing W1A<5> NET "pps_in" LOC = "P91"; # Wing W1C<0>; NET "pps_out" LOC = "P92" | DRIVE = 2; # Wing W1C<1>;
freq_counter.vhd
Top level of the design, just ties the high speed and low speed logic together, and generates a 1 pulse per second reference.
You will need to update this module should you want to run the design with a clock speed of something other than 32MHz.
----------------------------------------------------------------------------------
-- Engineer: Mike Field <hamster@snap.net.nz>
--
-- Description: Top level of my frequency counter
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity freq_count is
Port ( clk32 : in STD_LOGIC;
test_sig : in STD_LOGIC;
d_clk : out STD_LOGIC;
d_strobe : out STD_LOGIC;
d_data : out STD_LOGIC;
ref : out STD_LOGIC;
pps_in : in STD_LOGIC;
pps_out : out STD_LOGIC);
end freq_count;
architecture Behavioral of freq_count is
COMPONENT clocking
PORT(
CLKIN_IN : IN std_logic;
CLKFX_OUT : OUT std_logic;
CLKFX180_OUT : OUT std_logic;
CLKIN_IBUFG_OUT : OUT std_logic;
CLK0_OUT : OUT std_logic;
LOCKED_OUT : OUT std_logic
);
END COMPONENT;
COMPONENT fast_domain
PORT(
clk : IN std_logic;
test_sig : IN std_logic;
pps : IN std_logic;
bcd_count : OUT std_logic_vector(31 downto 0);
new_count : OUT std_logic
);
END COMPONENT;
COMPONENT slow_domain
PORT(
clk : IN std_logic;
bcd_count : IN std_logic_vector(31 downto 0);
new_count : IN std_logic;
d_clk : OUT std_logic;
d_strobe : OUT std_logic;
d_data : OUT std_logic
);
END COMPONENT;
signal clk_fast : std_logic;
signal clk_slow : std_logic;
signal new_count : std_logic;
signal bcd_count : std_logic_vector(31 downto 0);
signal internal_ref : unsigned(24 downto 0) := (others => '0');
begin
Inst_clocking: clocking PORT MAP(
CLKIN_IN => clk32,
CLKFX_OUT => clk_fast,
CLKFX180_OUT => open,
CLKIN_IBUFG_OUT => open,
CLK0_OUT => clk_slow,
LOCKED_OUT => open
);
Inst_fast_domain: fast_domain PORT MAP(
clk => clk_fast,
test_sig => test_sig,
pps => pps_in,
bcd_count => bcd_count,
new_count => new_count
);
Inst_slow_domain: slow_domain PORT MAP(
clk => clk_slow,
bcd_count => bcd_count,
new_count => new_count,
d_clk => d_clk,
d_strobe => d_strobe,
d_data => d_data
);
process(clk_slow)
begin
if rising_edge(clk_slow) then
if internal_ref < 320000 then -- 10ms pulse
pps_out <= '1';
else
pps_out <= '0';
end if;
if internal_ref = 31999999 then -- 31999999
internal_ref <= (others => '0');
else
internal_ref <= internal_ref+1;
end if;
ref <= std_logic(internal_ref(0));
end if;
end process;
end Behavioral;
fast_domain.vhd
Runs at more than 200MHz and uses a DDR input to allow it to capture signals of up to 99.9MHz signals.
----------------------------------------------------------------------------------
-- Engineer: Mike Field <hamster@snap.net.nz>
--
-- Description: The 'fast' capture/count part of the frequency counter
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity fast_domain is
Port ( clk : in STD_LOGIC;
clkn : in STD_LOGIC;
test_sig : in STD_LOGIC;
pps : in STD_LOGIC;
bcd_count : out STD_LOGIC_VECTOR (31 downto 0);
new_count : out STD_LOGIC);
end fast_domain;
architecture Behavioral of fast_domain is
COMPONENT delay4bit
GENERIC( len : natural);
PORT(
clk : IN std_logic;
d_in : IN std_logic_vector(3 downto 0);
d_out : OUT std_logic_vector(3 downto 0)
);
END COMPONENT;
COMPONENT digit_cnt
PORT(
clk : IN std_logic;
reset_in : IN std_logic;
inc_in : IN std_logic;
reset_blank : IN std_logic;
reset_out : OUT std_logic;
inc_out : OUT std_logic;
digit : OUT std_logic_vector(3 downto 0)
);
END COMPONENT;
COMPONENT edge_detect
PORT(
clk : IN std_logic;
clkn : IN std_logic;
test_signal : IN std_logic;
rising_edge_found : OUT std_logic
);
END COMPONENT;
signal ro0,ro1,ro2,ro3,ro4,ro5,ro6,ro7 : std_logic;
signal io0,io1,io2,io3,io4,io5,io6,io7 : std_logic;
signal cnt0,cnt1,cnt2,cnt3,cnt4,cnt5,cnt6,cnt7 : std_logic_vector(3 downto 0);
signal c0,c1,c2,c3,c4,c5,c6,c7 : std_logic_vector(3 downto 0);
signal edge_found : std_logic;
signal last_count : std_logic_vector(31 downto 0) := x"12345678";
signal new_count_sr : std_logic_vector(15 downto 0) := (others => '0');
signal pps_sr : std_logic_vector(1 downto 0) := "00";
signal restart_count : std_logic;
begin
bcd_count <= last_count;
new_count <= new_count_sr(15);
Inst_edge_detect: edge_detect PORT MAP(
clk => clk,
clkn => clkn,
test_signal => test_sig,
rising_edge_found => edge_found
);
-- delays to get all the counter transistions in line
delay0 : delay4bit GENERIC MAP (len => 7) PORT MAP (clk => clk, d_in => cnt0, d_out => c0);
delay1 : delay4bit GENERIC MAP (len => 6) PORT MAP (clk => clk, d_in => cnt1, d_out => c1);
delay2 : delay4bit GENERIC MAP (len => 5) PORT MAP (clk => clk, d_in => cnt2, d_out => c2);
delay3 : delay4bit GENERIC MAP (len => 4) PORT MAP (clk => clk, d_in => cnt3, d_out => c3);
delay4 : delay4bit GENERIC MAP (len => 3) PORT MAP (clk => clk, d_in => cnt4, d_out => c4);
delay5 : delay4bit GENERIC MAP (len => 2) PORT MAP (clk => clk, d_in => cnt5, d_out => c5);
delay6 : delay4bit GENERIC MAP (len => 1) PORT MAP (clk => clk, d_in => cnt6, d_out => c6);
c7 <= cnt7;
-- the decimal counters
digit0: digit_cnt PORT MAP(clk => clk, reset_in => restart_count, inc_in => edge_found, reset_out => ro0, inc_out => io0, digit => cnt0, reset_blank => '0');
digit1: digit_cnt PORT MAP(clk => clk, reset_in => ro0, inc_in => io0, reset_out => ro1, inc_out => io1, digit => cnt1, reset_blank => '1');
digit2: digit_cnt PORT MAP(clk => clk, reset_in => ro1, inc_in => io1, reset_out => ro2, inc_out => io2, digit => cnt2, reset_blank => '1');
digit3: digit_cnt PORT MAP(clk => clk, reset_in => ro2, inc_in => io2, reset_out => ro3, inc_out => io3, digit => cnt3, reset_blank => '1');
digit4: digit_cnt PORT MAP(clk => clk, reset_in => ro3, inc_in => io3, reset_out => ro4, inc_out => io4, digit => cnt4, reset_blank => '1');
digit5: digit_cnt PORT MAP(clk => clk, reset_in => ro4, inc_in => io4, reset_out => ro5, inc_out => io5, digit => cnt5, reset_blank => '1');
digit6: digit_cnt PORT MAP(clk => clk, reset_in => ro5, inc_in => io5, reset_out => ro6, inc_out => io6, digit => cnt6, reset_blank => '1');
digit7: digit_cnt PORT MAP(clk => clk, reset_in => ro6, inc_in => io6, reset_out => ro7, inc_out => io7, digit => cnt7, reset_blank => '1');
reset_proc: process(clk)
begin
if rising_edge(clk) then
if ro6 = '1' then
last_count <= c7 & c6 & c5 & c4 & c3 & c2 &c1 & c0;
new_count_sr <= "0111111111111111";
else
new_count_sr <= new_count_sr(14 downto 0) & '0';
end if;
if pps_sr = "01" then
restart_count <= '1';
else
restart_count <= '0';
end if;
pps_sr <= pps_sr(0) & pps;
end if;
end process;
end Behavioral;
digit_cnt.vhd
This is a modified BSD counter. The extra state of 'F' is used to suppress leading zeros.
----------------------------------------------------------------------------------
-- Engineer: Mike Field <hamster@snap.net.nz>
--
-- Description: A modified BCD counter
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity digit_cnt is
Port ( clk : in STD_LOGIC;
reset_in : in STD_LOGIC;
inc_in : in STD_LOGIC;
reset_out : out STD_LOGIC;
inc_out : out STD_LOGIC;
digit : out STD_LOGIC_vector(3 downto 0);
reset_blank : in STD_LOGIC);
end digit_cnt;
architecture Behavioral of digit_cnt is
signal state : std_logic_vector(3 downto 0) := x"F";
begin
digit <= state;
process(clk)
begin
if rising_edge(clk) then
inc_out <= '0';
reset_out <= reset_in;
if reset_in = '1' then
if inc_in = '1' then
state <= x"1";
elsif reset_blank = '1' then
state <= x"F";
else
state <= x"0";
end if;
elsif inc_in = '1' then
case state is
when x"0" => state <= x"1";
when x"1" => state <= x"2";
when x"2" => state <= x"3";
when x"3" => state <= x"4";
when x"4" => state <= x"5";
when x"5" => state <= x"6";
when x"6" => state <= x"7";
when x"7" => state <= x"8";
when x"8" => state <= x"9";
when x"9" => state <= x"0"; inc_out <= '1';
when x"F" => state <= x"1";
when others => state <= x"1";
end case;
end if;
end if;
end process;
end Behavioral;
delay4bit.vhd
----------------------------------------------------------------------------------
-- Engineer: Mike Field <hamster@snap.net.nz>
--
-- Description: Generic delay for a 4bit signal
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity delay4bit is
generic (len : natural);
Port ( clk : in STD_LOGIC;
d_in : in STD_LOGIC_VECTOR (3 downto 0);
d_out : out STD_LOGIC_VECTOR (3 downto 0));
end delay4bit;
architecture Behavioral of delay4bit is
signal sr : std_logic_vector(4*len-1 downto 0);
begin
d_out <= sr(4*len-1 downto 4*(len-1));
process(clk)
begin
if rising_edge(clk) then
sr <= sr(4*len-5 downto 0) & d_in;
end if;
end process;
end Behavioral;
slow_domain.vhd
----------------------------------------------------------------------------------
-- Engineer: Mike Field <hamster@snap.net.nz>
--
-- Description: Takes the pulse count and sends it out to the display. Runs
-- at 32MHz
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity slow_domain is
Port ( clk : in STD_LOGIC;
bcd_count : in STD_LOGIC_VECTOR (31 downto 0);
new_count : in STD_LOGIC;
d_clk : out STD_LOGIC;
d_strobe : out STD_LOGIC;
d_data : out STD_LOGIC);
end slow_domain;
architecture Behavioral of slow_domain is
COMPONENT dx_display
PORT(
clk : IN std_logic;
reset : IN std_logic;
segData : IN std_logic_vector(31 downto 0);
adv : IN std_logic;
byte : OUT std_logic_vector(7 downto 0);
endCmd : OUT std_logic;
newData : OUT std_logic);
END COMPONENT;
COMPONENT dx_display_xmit
PORT(
clk : IN std_logic;
reset : IN std_logic;
byte : IN std_logic_vector(7 downto 0);
endCmd : IN std_logic;
newData : IN std_logic;
adv : OUT std_logic;
d_strobe : OUT std_logic;
d_clk : OUT std_logic;
d_data : OUT std_logic
);
END COMPONENT;
signal byte : std_logic_vector(7 downto 0);
signal endCmd : std_logic;
signal newData : std_logic;
signal adv : std_logic;
signal reset : std_logic;
signal resetShift : std_logic_vector(15 downto 0) := (others => '1');
signal newCountSr : std_logic_vector(1 downto 0) := "00";
begin
reset <= resetShift(0);
Inst_dx_display: dx_display PORT MAP(
clk => clk,
reset => reset,
byte => byte,
endCmd => endCmd,
newData => newData,
segData => bcd_count,
adv => adv
);
Inst_dx_display_xmit: dx_display_xmit PORT MAP(
clk => clk,
reset => reset,
byte => byte,
endCmd => endCmd,
newData => newData,
adv => adv,
d_strobe => d_strobe,
d_clk => d_clk,
d_data => d_data
);
reset_proc: process(clk)
begin
if rising_edge(clk) then
if newCountSr = "01" then
resetShift <= (others => '1');
else
resetShift <= '0' & resetShift(15 downto 1);
end if;
newCountSr <= newCountSr(0) & new_count;
end if;
end process;
end Behavioral;
dx_display.vhd
This code isn't my best work - I just sort of made it work. Sorry!
----------------------------------------------------------------------------------
-- Engineer: Mike Field <hamster@snap.net.nz>
--
-- Description: Driver for the DealExteme display board,
-- 8 x 7 segs
-- 8 x bi-colour LED
-- 8 x buttons
--
-- Dependencies: None
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity dx_display is
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
byte : out STD_LOGIC_VECTOR(7 downto 0);
endCmd : out STD_LOGIC;
newData : out STD_LOGIC;
segData : in STD_LOGIC_VECTOR(31 downto 0);
adv : in STD_LOGIC);
end dx_display;
architecture Behavioral of dx_display is
COMPONENT seven_seg_decode
PORT(
clk : IN std_logic;
data : IN std_logic_vector(3 downto 0);
decoded : OUT std_logic_vector(7 downto 0)
);
END COMPONENT;
signal counter : std_logic_vector(4 downto 0) := (others => '0');
signal nextcounter : unsigned(4 downto 0);
constant leds_green : std_logic_vector(7 downto 0) := (others => '0');
constant leds_red : std_logic_vector(7 downto 0) := (others => '0');
signal decode_in : std_logic_vector(3 downto 0) := (others => '0');
signal decode_out : std_logic_vector(7 downto 0) := (others => '0');
signal next_decode_in : std_logic_vector(3 downto 0) := (others => '0');
begin
nextcounter <= unsigned(counter) + 1;
Inst_seven_seg_decode: seven_seg_decode PORT MAP(
clk => clk,
data => decode_in,
decoded => decode_out
);
data_proc: process(counter,segData, decode_out)
begin
next_decode_in <= "0000";
case counter is
when "00000" => byte <= x"40"; endCmd <= '1'; newData <= '1'; -- Set address mode - auto inc
when "00001" => byte <= x"8C"; endCmd <= '1'; newData <= '1'; -- Turn display on, brightness 4 of 7
when "00010" => byte <= x"C0"; endCmd <= '0'; newData <= '1'; -- Write at the left display
next_decode_in <= segData(31 downto 28);
when "00011" => byte <= decode_out; endCmd <= '0'; newData <= '1';
when "00100" => -- LED1
byte <= "000000" & leds_red(0) & leds_green(0);
endCmd <= '0';
newData <= '1';
next_decode_in <= segData(27 downto 24);
when "00101" => byte <= decode_out; endCmd <= '0'; newData <= '1';
when "00110" => -- LED2
byte <= "000000" & leds_red(1) & leds_green(1);
endCmd <= '0';
newData <= '1';
next_decode_in <= segData(23 downto 20);
when "00111" => byte <= decode_out; endCmd <= '0'; newData <= '1';
when "01000" => -- LED3 red
byte <= "000000" & leds_red(2) & leds_green(2);
endCmd <= '0';
newData <= '1';
next_decode_in <= segData(19 downto 16);
when "01001" => byte <= decode_out; endCmd <= '0'; newData <= '1';
when "01010" => -- LED4 green
byte <= "000000" & leds_red(3) & leds_green(3);
endCmd <= '0';
newData <= '1';
next_decode_in <= segData(15 downto 12);
when "01011" => byte <= decode_out; endCmd <= '0'; newData <= '1';
when "01100" => -- LED5
byte <= "000000" & leds_red(4) & leds_green(4);
endCmd <= '0';
newData <= '1';
next_decode_in <= segData(11 downto 8);
when "01101" => byte <= decode_out; endCmd <= '0'; newData <= '1';
when "01110" => -- LED6
byte <= "000000" & leds_red(5) & leds_green(5);
endCmd <= '0';
newData <= '1';
next_decode_in <= segData(7 downto 4);
when "01111" => byte <= decode_out; endCmd <= '0'; newData <= '1';
when "10000" => -- led 7
byte <= "000000" & leds_red(6) & leds_green(6);
endCmd <= '0';
newData <= '1';
next_decode_in <= segData(3 downto 0);
when "10001" => byte <= decode_out; endCmd <= '0'; newData <= '1';
when "10010" => -- led 8
byte <= "000000" & leds_red(7) & leds_green(7);
endCmd <= '1';
newData <= '1';
when others => byte <= x"FF"; endCmd <= '1'; newData <= '0'; -- End of data / idle
end case;
end process;
clk_proc: process(clk)
begin
if rising_edge(clk) then
if reset = '1' then
counter <= (others => '0');
elsif adv = '1' and counter /= "11111" then
counter <= std_logic_vector(nextcounter);
decode_in <= next_decode_in;
end if;
end if;
end process;
end Behavioral;
seven_seg_decode.vhd
----------------------------------------------------------------------------------
-- Engineer: Mike Field <hamster@snap.net.nz>
--
-- Description: Decoding for the dx 7seg display.
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity seven_seg_decode is
Port ( clk : in std_logic;
data : in STD_LOGIC_VECTOR (3 downto 0);
decoded : out STD_LOGIC_VECTOR (7 downto 0));
end seven_seg_decode;
architecture Behavioral of seven_seg_decode is
begin
process(clk)
begin
if rising_edge(clk) then
case data is
when "0000" => decoded <= "00111111";
when "0001" => decoded <= "00000110";
when "0010" => decoded <= "01011011";
when "0011" => decoded <= "01001111";
when "0100" => decoded <= "01100110";
when "0101" => decoded <= "01101101";
when "0110" => decoded <= "01111101";
when "0111" => decoded <= "00000111";
when "1000" => decoded <= "01111111";
when "1001" => decoded <= "01100111";
when "1111" => decoded <= "00000000";
when others => decoded <= "10000000"; -- decimal point
end case;
end if;
end process;
end Behavioral;
dx_display_xmit.vhd
----------------------------------------------------------------------------------
-- Engineer: Mike Field <hamster@snap.net.nz>
--
-- Module Name: dx_display_xmit - Behavioral
-- Description: Drive the serial bus for the DX display
--
-- Revision:
-- Revision 0.01 - File Created
-- Additional Comments:
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity dx_display_xmit is
Port ( clk : in STD_LOGIC;
reset : in STD_LOGIC;
byte : in STD_LOGIC_VECTOR (7 downto 0);
endCmd : in STD_LOGIC;
newData : in STD_LOGIC;
adv : out STD_LOGIC;
d_strobe : out STD_LOGIC;
d_clk : out STD_LOGIC;
d_data : out STD_LOGIC);
end dx_display_xmit;
architecture Behavioral of dx_display_xmit is
signal thisEndCmd : std_logic;
signal thisByte : std_logic_vector(7 downto 0) := (others => '0');
signal bitsLeftToSend : std_logic_vector(6 downto 0) := (others => '0');
signal state : std_logic_vector(2 downto 0) := (others => '0');
signal divider : std_logic_vector(63 downto 0) := x"1000000000000000";
begin
clk_proc: process(clk)
begin
if rising_edge(clk) then
divider <= divider(0) & divider(63 downto 1);
adv <= '0';
if reset = '1' then
thisByte <= (others => '0');
thisEndCmd <= endCmd;
state <= (others => '0');
d_strobe <= '1';
d_clk <= '1';
d_data <= '1';
divider <= x"1000000000000000";
elsif divider(0) = '1' then
d_strobe <= '1';
d_clk <= '1';
d_data <= '1';
case state is
when "000" => -- Idle, without an open command
if newData = '1' then
state <= std_logic_vector(unsigned(state)+1);
thisByte <= byte;
thisEndCmd <= endCmd;
adv <= '1';
d_strobe <= '0';
d_clk <= '1';
d_data <= '1';
else
d_strobe <= '1';
d_clk <= '1';
d_data <= '1';
end if;
bitsLeftToSend <= (others => '1');
when "001" => -- transfer a bot
state <= std_logic_vector(unsigned(state)+1);
d_strobe <= '0';
d_clk <= '0';
d_data <= thisByte(0);
when "010" =>
if bitsLeftToSend(0) = '1' then -- Still got a bit to send?
state <= std_logic_vector(unsigned(state)-1);
elsif thisEndCmd = '1' then
state <= "011"; -- close off command
else
state <= "100"; -- keep command open
end if;
d_strobe <= '0';
d_clk <= '1';
d_data <= thisByte(0);
thisByte <= '1' & thisByte(7 downto 1);
bitsLeftToSend <= '0' & bitsLeftToSend(6 downto 1);
when "011" => --- ending the command by rasing d_strobe, the going back to idle state
state <= "000";
d_strobe <= '1';
d_clk <= '1';
d_data <= thisByte(0);
when "100" => -- Waiting for data, withan open command
d_strobe <= '0';
d_clk <= '1';
d_data <= '1';
if newData = '1' then
state <= "001"; -- start transfering bits
thisByte <= byte;
thisEndCmd <= endCmd;
adv <= '1';
bitsLeftToSend <= (others => '1');
end if;
when others => -- performa a reset
thisByte <= (others => '0');
state <= (others => '0');
d_strobe <= '1';
d_clk <= '1';
d_data <= '1';
end case;
end if;
end if;
end process;
end Behavioral;
edge_detect.vhd
----------------------------------------------------------------------------------
-- Company:
-- Engineer: Mike Field <hamster@snap.net.nz>
--
-- Description: Uses a DDR input to reliably detect a rising edge at something like
-- 1/2 clk frequency. Also syncronises the signal to the CLK domain
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library UNISIM;
use UNISIM.VComponents.all;
entity edge_detect is
Port ( clk : in STD_LOGIC;
clkn : in STD_LOGIC;
test_signal : in STD_LOGIC;
rising_edge_found : out STD_LOGIC);
end edge_detect;
architecture Behavioral of edge_detect is
signal raw : std_logic_vector(2 downto 0);
signal cooked : std_logic_vector(2 downto 0);
begin
IDDR2_inst : IDDR2
generic map(
DDR_ALIGNMENT => "NONE", INIT_Q0 => '0', INIT_Q1 => '0', SRTYPE => "SYNC")
port map (
Q0 => raw(0), Q1 => raw(1),
C0 => clkn, C1 => clk,
CE => '1', D => test_signal,
R => '0', S => '0'
);
process(clk)
begin
if rising_edge(clk) then
if cooked(2 downto 1) = "01" or cooked(1 downto 0) = "01" then
rising_edge_found <= '1';
else
rising_edge_found <= '0';
end if;
cooked <= raw;
raw(2) <= raw(0);
end if;
end process;
end Behavioral;


