---------------------------------------------------------------------------------- -- Company: -- Engineer: -- -- Create Date: 10:24:46 08/25/2010 -- Design Name: -- Module Name: Modem - Behavioral -- Project Name: -- Target Devices: -- Tool versions: -- Description: -- -- Dependencies: -- -- Revision: -- Revision 0.01 - File Created -- Additional Comments: -- ---------------------------------------------------------------------------------- -- Uncomment the following library declaration if using -- arithmetic functions with Signed or Unsigned values -- Uncomment the following library declaration if instantiating -- any Xilinx primitives in this code. library UNISIM; use UNISIM.VComponents.all; -- VHDL HART Modem -- Stephen D. Anderson, October 18, 1999 -- Analog Services, Inc. -- Copyright 1999, Analog Services, Inc. -- This is a VHDL source file for a HART (Highway Addressable Remote Transducer) -- Modem. For further information on HART or how to use this file, including a -- complete description and theory of operation, go to the Analog Services, Inc. -- website. It is located at www.analogservices.com. library ieee; use ieee.std_logic_1164.all; --use work.std_arith.all; use IEEE.NUMERIC_STD.ALL; use IEEE.std_logic_unsigned.all; entity Modem is port ( clk : in std_logic; -- clock for both modulator and demodulator. must be 32.768 kHz. txd : in std_logic; -- transmit digital data in. not_rts : in std_logic; -- /(request to send) (when low changes txa from tri-state to ON.) rxa : in std_logic; -- receive modulated data (FSK) in. loopback : in std_logic; -- when high connects txa to rxa internally. rxd : out std_logic; -- receive digital data out. txa : out std_logic -- transmit modulated data (FSK) out. ); end Modem; architecture modem of Modem is --Modulator signals and constants. signal adder_out : std_logic_vector(7 downto 0); -- output of adder. signal reg_out : std_logic_vector(7 downto 0); -- output of register. constant add6 : std_logic_vector(3 downto 0) := "0110"; --6. constant add11 : std_logic_vector(3 downto 0) := "1011"; --11. constant max_add : std_logic_vector(7 downto 0) := "10100100"; --164. --Demodulator signals and constants. signal rxa1 : std_logic; -- last 2 samples of rxa. signal rxa2 : std_logic; signal edge : std_logic; -- output of edge detector. signal ssr : std_logic_vector(0 to 14); --sample shift register. alias ssr_out : std_logic_vector(0 to 8) is ssr(0 to 8); signal interval_value : std_logic_vector(2 downto 0); --decoded sample shift register value. signal interval_hold : std_logic_vector(2 downto 0); --stored interval value. type xy is array(0 to 15) of std_logic_vector(2 downto 0); -- filter shift register. signal filter: xy; subtype ss is std_logic_vector(6 downto 0); signal i_sum : ss; --intermediate sum for filter. signal sum_hold: ss; --register for filter adder. -- attribute synthesis_off of i_sum:signal is true; constant one_hundred_twenty: ss := "1111000"; constant eight : ss := "0001000"; constant seven : ss := "0000111"; constant six : ss := "0000110"; constant five : ss := "0000101"; constant four : ss := "0000100"; constant three : ss := "0000011"; constant two : ss := "0000010"; constant one : ss := "0000001"; constant zero : ss := "0000000"; constant minus_one : ss := "1111111"; constant minus_two : ss := "1111110"; constant minus_three : ss := "1111101"; constant minus_four : ss := "1111100"; constant minus_five : ss := "1111011"; constant minus_six : ss := "1111010"; constant minus_seven : ss := "1111001"; signal f_val : std_logic_vector(5 downto 0); signal rxa_in : std_logic; signal ctxd : std_logic; signal txa_out : std_logic; signal filter_sum : ss; begin --Start of Modulator. -- Synchronize txd to the clock. sync_txd: process (clk) begin if clk'event and clk = '1' then ctxd <= txd; end if; end process sync_txd; -- implement the numerically controlled oscillator with modulo-164 adder. modulate: process (clk) begin if clk'event and clk = '1' then if adder_out < max_add then reg_out <= adder_out; else reg_out <= adder_out - max_add; end if; end if; end process modulate; -- Add next phase increment. adder_out <= (reg_out + add6) when (ctxd = '1') else (reg_out + add11); -- Decode the 8-bit register output. Set txa to 0 if register value is 0 to 81. -- Set txa to 1 if register value is 82 to 163. txa_out <= '0' when (reg_out < "01010010") else '1'; --82. --End of modulator. --Start of Loopback. --When loopback is asserted the modulator output is fed to the demodulator input --and rxa is not used. Else the demodulator input is rxa. lpback: process(loopback, txa_out, rxa) begin if loopback = '1' then rxa_in <= txa_out; else rxa_in <= rxa; end if; end process lpback; --End of loopback. --Start of /RTS. --Determines whether modulator output is high-Z or active. req_to_send: process(not_rts, txa_out) begin if not_rts = '1' then txa <= 'Z'; else txa <= txa_out; end if; end process req_to_send; --Start of Demodulator. -- Implement the edge detector. This just stores two samples of rxa and -- compares them. edge equals 1 if they are different. edge_detect: process (clk) begin if clk'event and clk = '1' then rxa2 <= rxa1; rxa1 <= rxa_in; end if; end process edge_detect; edge <= rxa1 xor rxa2; -- implement the sample shift register. samp_shreg: process (clk) -- define the 9 shift register positions just ahead of the last one. alias ssr_mid: std_logic_vector(0 to 8) is ssr(5 to 13); -- define the 5 shift register positions at front of shift register. alias ssr_start: std_logic_vector(0 to 4) is ssr(0 to 4); begin if clk'event and clk = '1' then -- shift on each clock. for i in 14 downto 1 loop ssr(i) <= ssr(i-1); end loop; -- decide what to put into the shift register, based on what's -- there now. if ((ssr_start = "00000") and (ssr_mid = "000000000")) then -- need a 1 to prevent shift reg from becoming all 0's. ssr(0) <= '1'; elsif (ssr_start > 0) then -- need a 0 to prevent 1's too close together. ssr(0) <= '0'; else -- normal signal from edge detector. ssr(0) <= edge; end if; end if; end process samp_shreg; -- interval measurement. The interval measurement is a count of the number -- of zeros between ones in the sample shift register. It has meaning only -- when a one is in the last position (14) of the sample shift register. It -- isn't necessary to check for zeros in positions 9, 10, 11, 12, and 13 -- because these must be zero if there is a one in position 14. interval_value <= "111" when std_match(ssr_out, "-00000000") = true else "110" when std_match(ssr_out, "-10000000") = true else "101" when std_match(ssr_out, "--1000000") = true else "100" when std_match(ssr_out, "---100000") = true else "011" when std_match(ssr_out, "----10000") = true else "010" when std_match(ssr_out, "-----1000") = true else "001" when std_match(ssr_out, "------100") = true else "000"; --interval of 14 or 15. --interval of 13. --12. --11. --10. --9. --8. --6 and 7. interval_store: process (clk) begin if clk'event and clk = '1' then if ssr(14) = '1' then interval_hold <= interval_value; end if; end if; end process interval_store; -- Implement the 16-tap filter shift register. filt: process (clk) begin if clk'event and clk = '1' then for i in 15 downto 1 loop filter(i) <= filter(i-1); end loop; filter(0) <= interval_hold; end if; end process filt; -- Filter using 'rolling average'. Add value at front end and subtract at -- back end. Values are biased by 8. Output of adder is limited to 8 and 120. -- These are 0001000 and 1111000. So a number < 8 is present if upper 4 bits -- are all 0's and a number > or equal to 120 is present if upper 4 bits are -- all ones. f_val <= interval_hold & filter(15); with f_val select i_sum <= seven when "111000", six when "111001", five when "111010", four when "111011", three when "111100", two when "111101", one when "111110", six when "110000", five when "110001", four when "110010", three when "110011", two when "110100", one when "110101", minus_one when "110111", five when "101000", four when "101001", three when "101010", two when "101011", one when "101100", minus_one when "101110", minus_two when "101111", four when "100000", three when "100001", two when "100010", one when "100011", minus_one when "100101", minus_two when "100110", minus_three when "100111", three when "011000", two when "011001", one when "011010", minus_one when "011100", minus_two when "011101", minus_three when "011110", minus_four when "011111", two when "010000", one when "010001", minus_one when "010011", minus_two when "010100", minus_three when "010101", minus_four when "010110", minus_five when "010111", one when "001000", minus_one when "001010", minus_two when "001011", minus_three when "001100", minus_four when "001101", minus_five when "001110", minus_six when "001111", minus_one when "000001", minus_two when "000010", minus_three when "000011", minus_four when "000100", minus_five when "000101", minus_six when "000110", minus_seven when "000111", zero when others; filter_sum <= sum_hold + i_sum; --find full sum. -- update the filter accumulator. filt1: process (clk) alias fsum: std_logic_vector(3 downto 0) is filter_sum(6 downto 3); begin if clk'event and clk = '1' then if (fsum = 15) then --sum bits 3 through 6 all ones? sum_hold <= one_hundred_twenty; elsif (fsum = 0) then --sum bits 3 through 6 all zeros? sum_hold <= eight; else sum_hold <= filter_sum; end if; end if; end process filt1; -- Clock comparator output into rxd output register. A "1" is clocked in if sum_hold -- is greater than or equal to 56 (0111000). Else a "0" is clocked in. rxd_out: process (clk) alias xrxd: std_logic_vector(2 downto 0) is sum_hold(5 downto 3); begin if clk'event and clk = '1' then if (xrxd = 7) or (sum_hold(6) = '1') then rxd <= '1'; else rxd <= '0'; end if; end if; end process rxd_out; --End of demodulator. end Modem;