Frequency counter

From Hamsterworks Wiki!

Jump to: navigation, search

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!

Freq counter block.png

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).

Freq counter.png


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:

Freq counter gps.png

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

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;

Personal tools