library IEEE; use IEEE.std_logic_1164.all; use ieee.std_logic_arith.all; USE ieee.std_logic_unsigned.all; -- AD9854 -- offset -- 0 rw Data to send (bits 31.. 0) -- 1 rw Data to send (bits 47..32) => 15.. 0 -- rw Instruction (8 bits) => 23..16 -- 2 r Received data (bits 31.. 0) -- 3 r Received data (bits 47..32) => 15..0 -- 4 rw Control register -- Bits 5 4 3 2 1 0 -- DDS_FSK DDS_ShKey auto udclk DDS_UDCLK DDS_MCLK DDS_MRST -- enable -- 5 r status register (not used) entity DDS is port ( CLK : in std_logic; -- Clock, 30 or 40 MHz RESET_n : in std_logic; -- reset start : in std_logic; -- to the internal bus CE : in std_logic; WE : in std_logic; ADDR : in std_logic_vector( 7 downto 0); WDATA : in std_logic_vector(31 downto 0); RDATA : out std_logic_vector(31 downto 0); -- DDS for the 3 ADC channels AD9854 DDS_FSK : out std_logic; DDS_ShKey : out std_logic; DDS_CSn : out std_logic; DDS_SCLK : out std_logic; DDS_UDCLK : out std_logic; DDS_SDI : out std_logic; DDS_SDO : in std_logic; -- ?? DDS_IORST : out std_logic; DDS_MRST : out std_logic; DDS_MCLK : out std_logic ); end DDS; architecture a of DDS is type top_state_machine is (idle_top, send_instr, write_bytes1, write_bytes2, read_bytes1, read_bytes2, ioreset); signal sm_top : top_state_machine; type sr_state_machine is (idle, store_read, check_read, send_write, check_write, stop); signal sm_sr : sr_state_machine; signal start_sm : std_logic; signal read_flag : std_logic; signal flag2send : std_logic; signal udclk : std_logic; signal clkdivs : std_logic; --signal nbytes : std_logic_vector( 2 downto 0); signal nbytes_i : std_logic_vector( 2 downto 0); signal bytes2send : std_logic_vector(47 downto 0); signal byte2send : std_logic_vector( 7 downto 0); signal byte_send : std_logic_vector( 7 downto 0); signal byte_recv : std_logic_vector( 7 downto 0); signal iword2send : std_logic_vector( 7 downto 0); signal bytes_rcvd : std_logic_vector(47 downto 0); signal config : std_logic_vector( 7 downto 0); signal status : std_logic_vector( 7 downto 0); signal byte_counter : std_logic_vector( 2 downto 0); signal bit_counter : std_logic_vector( 2 downto 0); begin -- write to the internal registers process(clk, reset_n) begin if reset_n = '0' then bytes2send <= (others => '0'); iword2send <= (others => '0'); config <= (others => '0'); flag2send <= '0'; elsif clk'event and clk= '1' then flag2send <= '0'; if CE='1' and WE='1' then case ADDR(2 downto 0) is when "000" => bytes2send(31 downto 0) <= WDATA; when "001" => bytes2send(47 downto 32) <= WDATA(15 downto 0); iword2send <= WDATA(23 downto 16); flag2send <= '1'; when "100" => config <= WDATA(config'range); when others => NULL; end case; end if; end if; end process; DDS_MRST <= config(0) or not reset_n; DDS_MCLK <= clk when config(1)='1' else '0'; DDS_UDCLK <= config(2) or (config(3) and udclk); DDS_ShKey <= config(4); DDS_FSK <= config(5); -- read back process(bytes_rcvd, ADDR, config, bytes2send, iword2send, status) begin RDATA <= (others => '0'); case ADDR(2 downto 0) is when "000" => RDATA <= bytes2send(31 downto 0); when "001" => RDATA(23 downto 0) <= iword2send & bytes2send(47 downto 32); when "010" => RDATA <= bytes_rcvd(31 downto 0); when "011" => RDATA(15 downto 0) <= bytes_rcvd(47 downto 32); when "100" => RDATA(config'range) <= config; when "101" => RDATA(status'range) <= status; when others => RDATA <= (others => '-'); end case; end process; -- number of bytes to transfer according to the datasheet with iword2send(3 downto 0) select nbytes_i <= "001" when "1010", -- A "010" when "0000" | "0001" | "1000" | "1001" | "1011", -- 0,1,8,9,B "011" when "0110", -- 6 "100" when "0101" | "0111", -- 5,7 "110" when "0010" | "0011" | "0100", -- 2,3,4 "---" when others; -- process(clk) -- begin -- if clk'event and clk= '1' then -- if flag2send='1' then nbytes <= nbytes_i; end if; -- end if; -- end process; -- the top state machine, it controls the send-receive state machine process(clk, reset_n) begin if reset_n = '0' then sm_top <= idle_top; byte_counter <= (others => '0'); start_sm <= '0'; read_flag <= '0'; DDS_CSn <= '1'; DDS_IORST <= '1'; udclk <= '1'; elsif clk'event and clk= '1' then if sm_sr=store_read or sm_sr=send_write then start_sm <= '0'; end if; DDS_CSn <= '0'; case sm_top is when idle_top => if flag2send = '1' then sm_top <= send_instr; start_sm <= '1'; read_flag <= '0'; DDS_IORST <= '0'; else DDS_CSn <= '1'; DDS_IORST <= '1'; udclk <= '1'; end if; byte_counter <= (others => '0'); when send_instr => udclk <= '0'; if sm_sr = stop then byte_counter <= nbytes_i; if iword2send(7)='0' then sm_top <= write_bytes1; else sm_top <= read_bytes1; end if; end if; when write_bytes1 => if clkdivs='1' and sm_sr = idle then sm_top <= write_bytes2; end if; start_sm <= '1'; read_flag <= '0'; when write_bytes2 => if clkdivs='1' and sm_sr = stop then if byte_counter = "001" then sm_top <= ioreset; byte_counter <= "111"; else sm_top <= write_bytes1; byte_counter <= byte_counter - 1; end if; end if; when read_bytes1 => if clkdivs='1' and sm_sr = idle then sm_top <= read_bytes2; end if; start_sm <= '1'; read_flag <= '1'; when read_bytes2 => if clkdivs='1' and sm_sr = stop then if byte_counter = "001" then sm_top <= ioreset; byte_counter <= "111"; else sm_top <= read_bytes1; byte_counter <= byte_counter - 1; end if; end if; when ioreset => udclk <= '1'; if byte_counter = "000" then sm_top <= idle_top; else byte_counter <= byte_counter - 1; end if; end case; end if; end process; -- store the read bytes process(clk) begin if clk'event and clk= '1' then if iword2send(7)='1' and sm_top = send_instr then bytes_rcvd <= (others => '0'); elsif sm_sr = stop and sm_top = read_bytes2 then case byte_counter is when "001" => bytes_rcvd( 7 downto 0) <= byte_recv; when "010" => bytes_rcvd(15 downto 8) <= byte_recv; when "011" => bytes_rcvd(23 downto 16) <= byte_recv; when "100" => bytes_rcvd(31 downto 24) <= byte_recv; when "101" => bytes_rcvd(39 downto 32) <= byte_recv; when "110" => bytes_rcvd(47 downto 40) <= byte_recv; when others => NULL; end case; end if; end if; end process; -- select the byte to send with byte_counter select byte2send <= iword2send when "000", -- instruction bytes2send(47 downto 40) when "110", -- big/little endian??? bytes2send(39 downto 32) when "101", bytes2send(31 downto 24) when "100", bytes2send(23 downto 16) when "011", -- D A T A bytes2send(15 downto 8) when "010", bytes2send( 7 downto 0) when "001", (others => '-') when others; -- state machine send/receive Byte process(clk, reset_n) begin if reset_n = '0' then sm_sr <= idle; byte_send <= (others => '0'); byte_recv <= (others => '0'); bit_counter <= (others => '0'); DDS_SCLK <= '0'; DDS_SDI <= '0'; clkdivs <= '0'; elsif clk'event and clk= '1' then clkdivs <= not clkdivs; if clkdivs='1' then DDS_SCLK <= '0'; case sm_sr is when idle => bit_counter <= "111"; if start_sm = '1' then if read_flag = '1' then sm_sr <= store_read; else sm_sr <= send_write; byte_send <= byte2send; end if; else clkdivs <= '1'; end if; when store_read => -- clock is low bit_counter <= bit_counter - 1; DDS_SCLK <= '1'; byte_recv <= byte_recv(byte_recv'high-1 downto 0) & DDS_SDO; sm_sr <= check_read; when check_read => -- DDS_SCLK <= '0'; if bit_counter="111" then sm_sr <= stop; else sm_sr <= store_read; end if; when send_write => -- clock is low -- DDS_SCLK <= '0'; DDS_SDI <= byte_send(byte_send'high); bit_counter <= bit_counter - 1; sm_sr <= check_write; when check_write => DDS_SCLK <= '1'; byte_send <= byte_send(byte_send'high-1 downto 0) & '0'; if bit_counter="111" then sm_sr <= stop; else sm_sr <= send_write; end if; when stop => sm_sr <= idle; when others => sm_sr <= idle; end case; end if; end if; end process; end;