📄 wishbone_i2c_master.vhd
字号:
nxt_state := st_ack; icore_cmd := CMD_READ; else ishift := '1';-- icore_txd := sr(7); end if; end if; when st_read => if (core_ack = '1') then idcnt := dcnt -1; -- count down Data_counter ishift := '1'; if (dcnt = 0) then nxt_state := st_ack; icore_cmd := CMD_WRITE; icore_txd := ack_in; end if; end if; when st_ack => if (core_ack = '1') then -- generate command acknowledge signal ihost_ack := '1'; -- Perform an additional shift, needed for 'read' (store last received bit in shift register) ishift := '1'; -- check for stop; Should a STOP command be generated ? if (stop = '1') then nxt_state := st_stop; icore_cmd := CMD_STOP; else nxt_state := st_idle; icore_cmd := CMD_NOP; end if; end if; when st_stop => if (core_ack = '1') then nxt_state := st_idle; icore_cmd := CMD_NOP; end if; when others => -- illegal states nxt_state := st_idle; icore_cmd := CMD_NOP; end case; -- generate registers if (nReset = '0') then core_cmd <= CMD_NOP; core_txd <= '0'; shift <= '0'; ld <= '0'; dcnt <= "111"; host_ack <= '0'; state <= st_idle; elsif (clk'event and clk = '1') then if (rst = '1') then core_cmd <= CMD_NOP; core_txd <= '0'; shift <= '0'; ld <= '0'; dcnt <= "111"; host_ack <= '0'; state <= st_idle; else state <= nxt_state; dcnt <= idcnt; shift <= ishift; ld <= iload; core_cmd <= icore_cmd; core_txd <= icore_txd; host_ack <= ihost_ack; end if; end if; end process nxt_state_decoder; end block statemachine;end architecture structural;----------------------------------------- Bit controller section---------------------------------------- Translate simple commands into SCL/SDA transitions-- Each command has 5 states, A/B/C/D/idle---- start: SCL ~~~~~~~~~~\____-- SDA ~~~~~~~~\______-- x | A | B | C | D | i---- repstart SCL ____/~~~~\___-- SDA __/~~~\______-- x | A | B | C | D | i---- stop SCL ____/~~~~~~~~-- SDA ==\____/~~~~~-- x | A | B | C | D | i----- write SCL ____/~~~~\____-- SDA ==X=========X=-- x | A | B | C | D | i----- read SCL ____/~~~~\____-- SDA XXXX=====XXXX-- x | A | B | C | D | i---- Timing: Normal mode Fast mode------------------------------------------------------------------- Fscl 100KHz 400KHz-- Th_scl 4.0us 0.6us High period of SCL-- Tl_scl 4.7us 1.3us Low period of SCL-- Tsu:sta 4.7us 0.6us setup time for a repeated start condition-- Tsu:sto 4.0us 0.6us setup time for a stop conditon-- Tbuf 4.7us 1.3us Bus free time between a stop and start condition--library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_arith.all;entity bit_ctrl is port ( clk : in std_logic; rst : in std_logic; nReset : in std_logic; clk_cnt : in unsigned(15 downto 0); -- clock prescale value ena : in std_logic; -- core enable signal cmd : in std_logic_vector(2 downto 0); cmd_ack : out std_logic; busy : out std_logic; Din : in std_logic; Dout : out std_logic; -- i2c lines SCLin : in std_logic; -- I2C clock line SCLout : out std_logic; SDAin : in std_logic; -- I2C data line SDAout : out std_logic );end entity bit_ctrl;architecture structural of bit_ctrl is constant CMD_NOP : std_logic_vector(2 downto 0) := "000"; constant CMD_START : std_logic_vector(2 downto 0) := "010"; constant CMD_STOP : std_logic_vector(2 downto 0) := "011"; constant CMD_READ : std_logic_vector(2 downto 0) := "100"; constant CMD_WRITE : std_logic_vector(2 downto 0) := "101"; type cmds is (idle, start_a, start_b, start_c, start_d, stop_a, stop_b, stop_c, rd_a, rd_b, rd_c, rd_d, wr_a, wr_b, wr_c, wr_d); signal state : cmds; signal SCLo, SDAo : std_logic; -- internal I2C lines signal sSCL, sSDA : std_logic; -- synchronized SCL and SDA inputs signal txd : std_logic; -- transmit bit signal clk_en, slave_wait :std_logic; -- clock generation signals-- signal cnt : unsigned(15 downto 0) := clk_cnt; -- clock divider counter (simulation) signal cnt : unsigned(15 downto 0); -- clock divider counter (synthesis)begin -- synchronize SCL and SDA inputs synch_SCL_SDA: process(clk) begin if (clk'event and clk = '1') then sSCL <= SCLin; sSDA <= SDAin; end if; end process synch_SCL_SDA; -- whenever the slave is not ready it can delay the cycle by pulling SCL low slave_wait <= '1' when ( (SCLo = '1') and (sSCL = '0') ) else '0'; -- generate clk enable signal gen_clken: process(clk, nReset) begin if (nReset = '0') then cnt <= (others => '0'); clk_en <= '1'; elsif (clk'event and clk = '1') then if (rst = '1') then cnt <= (others => '0'); clk_en <= '1'; else if ( (cnt = 0) or (ena = '0') ) then clk_en <= '1'; cnt <= clk_cnt; else if (slave_wait = '0') then cnt <= cnt -1; end if; clk_en <= '0'; end if; end if; end if; end process gen_clken; -- generate bus status controller bus_status_ctrl: block signal dSDA : std_logic; signal sta_condition : std_logic; signal sto_condition : std_logic; signal ibusy : std_logic; begin -- detect start condition => detect falling edge on SDA while SCL is high -- detect stop condition => detect rising edge on SDA while SCL is high det_sta_sto: process(clk) begin if (clk'event and clk = '1') then dSDA <= sSDA; -- generate a delayed version of sSDA sta_condition <= (not sSDA and dSDA) and sSCL; sto_condition <= (sSDA and not dSDA) and sSCL; end if; end process det_sta_sto; -- generate bus busy signal gen_busy: process(clk, nReset) begin if (nReset = '0') then ibusy <= '0'; elsif (clk'event and clk = '1') then if (rst = '1') then ibusy <= '0'; else ibusy <= (sta_condition or ibusy) and not sto_condition; end if; end if; end process gen_busy; -- assign output busy <= ibusy; end block bus_status_ctrl; -- generate statemachine nxt_state_decoder : process (clk, nReset, state, cmd) variable nxt_state : cmds; variable icmd_ack, store_sda : std_logic; variable itxd : std_logic; begin nxt_state := state; icmd_ack := '0'; -- default no acknowledge store_sda := '0'; itxd := txd; case (state) is -- idle when idle => case cmd is when CMD_START => nxt_state := start_a; icmd_ack := '1'; -- command completed when CMD_STOP => nxt_state := stop_a; icmd_ack := '1'; -- command completed when CMD_WRITE => nxt_state := wr_a; icmd_ack := '1'; -- command completed itxd := Din; when CMD_READ => nxt_state := rd_a; icmd_ack := '1'; -- command completed when others => nxt_state := idle;-- don't acknowledge NOP command icmd_ack := '1'; -- command completed end case; -- start when start_a => nxt_state := start_b; when start_b => nxt_state := start_c; when start_c => nxt_state := start_d; when start_d => nxt_state := idle; -- stop when stop_a => nxt_state := stop_b; when stop_b => nxt_state := stop_c; when stop_c => nxt_state := idle; -- read when rd_a => nxt_state := rd_b; when rd_b => nxt_state := rd_c; when rd_c => nxt_state := rd_d; store_sda := '1'; when rd_d => nxt_state := idle; -- write when wr_a => nxt_state := wr_b; when wr_b => nxt_state := wr_c; when wr_c => nxt_state := wr_d; when wr_d => nxt_state := idle; end case; -- generate regs if (nReset = '0') then state <= idle; cmd_ack <= '0'; txd <= '0'; Dout <= '0'; elsif (clk'event and clk = '1') then if (rst = '1') then state <= idle; cmd_ack <= '0'; txd <= '0'; Dout <= '0'; else if (clk_en = '1') then state <= nxt_state; txd <= itxd; if (store_sda = '1') then Dout <= sSDA; end if; end if; cmd_ack <= icmd_ack and clk_en; end if; end if; end process nxt_state_decoder; -- -- convert states to SCL and SDA signals -- output_decoder: process (clk, nReset, state) variable iscl, isda : std_logic; begin case (state) is when idle => iscl := SCLo; -- keep SCL in same state isda := sSDA; -- keep SDA in same state -- start when start_a => iscl := SCLo; -- keep SCL in same state (for repeated start) isda := '1'; -- set SDA high when start_b => iscl := '1'; -- set SCL high isda := '1'; -- keep SDA high when start_c => iscl := '1'; -- keep SCL high isda := '0'; -- sel SDA low when start_d => iscl := '0'; -- set SCL low isda := '0'; -- keep SDA low -- stop when stop_a => iscl := '0'; -- keep SCL disabled isda := '0'; -- set SDA low when stop_b => iscl := '1'; -- set SCL high isda := '0'; -- keep SDA low when stop_c => iscl := '1'; -- keep SCL high isda := '1'; -- set SDA high -- write when wr_a => iscl := '0'; -- keep SCL low isda := Din; when wr_b => iscl := '1'; -- set SCL high isda := Din; when wr_c => iscl := '1'; -- keep SCL high isda := Din; when wr_d => iscl := '0'; -- set SCL low isda := Din; -- read when rd_a => iscl := '0'; -- keep SCL low isda := '1'; -- tri-state SDA when rd_b => iscl := '1'; -- set SCL high isda := '1'; -- tri-state SDA when rd_c => iscl := '1'; -- keep SCL high isda := '1'; -- tri-state SDA when rd_d => iscl := '0'; -- set SCL low isda := '1'; -- tri-state SDA end case; -- generate registers if (nReset = '0') then SCLo <= '1'; SDAo <= '1'; elsif (clk'event and clk = '1') then if (rst = '1') then SCLo <= '1'; SDAo <= '1'; else if (clk_en = '1') then SCLo <= iscl; SDAo <= isda; end if; end if; end if; end process output_decoder; -- assign outputs SCLout <= SCLo; SDAout <= SDAo;end architecture structural;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -