library IEEE; use IEEE.std_logic_1164.all; use ieee.std_logic_arith.all; USE ieee.std_logic_unsigned.all; -- DAC -- Shift register with parallel input and serial output. -- Input bus is 16 bit. Writing -- starts the serial transfer. -- Bits 15..12 (Internal address) -- 0 DAC 0 -- 1 DAC 1 -- 2 DAC 2 -- 3 DAC 3 -- 4 DAC 4 -- 5 DAC 5 -- 6 DAC 6 -- 7 DAC 7 -- 8 CTRL 0 -- 9 CTRL 1 -- 10 preset -- 11 reserved -- 12 DAC 0 and not 1 -- 13 DAC 2 and not 3 -- 14 DAC 4 and not 5 -- 15 DAC 6 and not 7 -- -- Bits 11..0 Data -- CTRL 0 -- Bit 4 Full device power down -- Bit 3 DOUT enable -- Bit 2 R1 0, 1 - external reference -- Bit 1 R0 2, 3 - internal 1V / 2V -- Bit 0 IM - input mode - 0 straight binary, 1 two's complement -- -- Here we need internal reference! -- CTRL 1 -- Bit 7 Power Down 6 and 7 -- Bit 6 Power Down 4 and 5 -- Bit 5 Power Down 2 and 3 -- Bit 4 Power Down 0 and 1 -- -- Bit 3 Speed 6 and 7 1-fast, 0-slow -- Bit 3 Speed 4 and 5 1-fast, 0-slow -- Bit 3 Speed 2 and 3 1-fast, 0-slow -- Bit 3 Speed 0 and 1 1-fast, 0-slow entity TLV5630 is GENERIC ( WIDTH : Integer := 16 -- Width of the 'Byte' ); PORT ( CLK : IN STD_LOGIC; -- Clock, 30 or 40 MHz RESET_n : IN STD_LOGIC; -- reset CE : IN STD_LOGIC; -- Chip enable WE : IN STD_LOGIC; -- Write enable D : IN STD_LOGIC_VECTOR(WIDTH downto 0); -- Data input bus, MSB = load DAC after serial shift PQ : OUT STD_LOGIC_VECTOR(WIDTH downto 0); -- Parallel outputs LDACn : OUT STD_LOGIC; -- load dac SCLK : OUT STD_LOGIC; -- Serial Clock SDAT : OUT STD_LOGIC; -- Serial Data SSTR : OUT STD_LOGIC);-- Serial Strobe end TLV5630; architecture a of TLV5630 is SIGNAL CNT_FF : Integer range 0 to WIDTH; -- counter for the number of bits to be shifted out SIGNAL SL : STD_LOGIC; SIGNAL ldac_flag : STD_LOGIC; -- DFF_S is the shift register SIGNAL DFF_S : STD_LOGIC_VECTOR(WIDTH-1 downto 0); SIGNAL dcounter : STD_LOGIC_VECTOR(3 downto 0); signal cnt_div : std_logic; TYPE sm IS (idle, shift, sclock, strobe, loaddac, finish); -- state machine SIGNAL SERREG : sm; begin process(CLK) -- shift register begin if CLK'event and CLK='1' then if CE='1' and WE='1' then SL <= '1'; elsif serreg /= idle then SL <= '0'; end if; if SERREG=shift then if cnt_div = '1' then DFF_S <= DFF_S(WIDTH-2 downto 0) & DFF_S(WIDTH-1); end if; elsif CE='1' and WE='1' and SERREG=idle then DFF_S <= D(DFF_S'range); ldac_flag <= D(D'high); end if; end if; end process; process(clk, reset_n) begin if reset_n = '0' then cnt_div <= '0'; dcounter <= (others => '1'); elsif clk'event and clk= '1' then if SL = '0' and serreg=idle then dcounter <= (others => '1'); else dcounter <= dcounter - 1; end if; if dcounter = "0000" then cnt_div <= '1'; else cnt_div <= '0'; end if; end if; end process; process(CLK, RESET_n) -- state machine begin if RESET_n = '0' then SERREG <= idle; SSTR <= '0'; SCLK <= '0'; CNT_FF <= WIDTH; LDACn <= '1'; elsif CLK'event and CLK='1' then if cnt_div = '1' then SSTR <= '0'; SCLK <= '1'; LDACn <= '1'; CASE SERREG IS WHEN idle => CNT_FF <= WIDTH; if SL='1' then SERREG <= sclock; end if; WHEN sclock => SCLK <= '0'; SERREG <= shift; CNT_FF <= CNT_FF - 1; WHEN shift => if (CNT_FF = 0) then SERREG <= strobe; SSTR <= '1'; else SERREG <= sclock; end if; WHEN strobe => SERREG <= loaddac; SSTR <= '1'; SCLK <= '0'; WHEN loaddac => LDACn <= not ldac_flag; SERREG <= finish; WHEN finish => LDACn <= not ldac_flag; if SL='0' then SERREG <= idle; LDACn <= '1'; end if; WHEN others => SERREG <= idle; end case; end if; end if; end process; PQ <= ldac_flag & DFF_S; SDAT <= DFF_S(WIDTH-1) when SERREG /= idle else '0'; -- serial data output, MSB first end;