⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c_slave.vhd

📁 IIC的IP.这是经过验证的源代码
💻 VHD
📖 第 1 页 / 共 2 页
字号:
--------------------------------------------
-- Input De-Mux
inmux :process(clk,rst_l)
begin 
 if (rst_l = '0') then 
   in_reg <= "00000000";
 elsif(rising_edge(clk)) then
   if (in_reg_enable = '1') then 
     case bit_counter is
       when "0000" =>
          in_reg(7) <= sda_reg_delayed;
       when "0001" =>
          in_reg(6) <= sda_reg_delayed;
       when "0010" =>
          in_reg(5) <= sda_reg_delayed;
       when "0011" =>
          in_reg(4) <= sda_reg_delayed;
       when "0100" =>
          in_reg(3) <= sda_reg_delayed;
       when "0101" =>
          in_reg(2) <= sda_reg_delayed;
       when "0110" =>
          in_reg(1) <= sda_reg_delayed;
       when "0111" =>
          in_reg(0) <= sda_reg_delayed;
       when others =>
          in_reg <= in_reg;
     end case;
   else
     in_reg <= in_reg;
   end if;
 end if;
end process;

--------------------------------------------


--------------------------------------------
-- I2C Slave State Machine
slave_state_machine : process(clk,rst_l)
variable L:line;
variable cnt : std_logic_vector(7 downto 0);
begin 

  if (rst_l = '0') then 
      current_state  <= idle;
      next_state     <= idle;
      r_w_bit        <= '0';
      out_reg        <= "00000000";
      out_en         <= '0'; -- disable output
      bit_counter    <= "0000";
      word_address   <= "00000000"; -- initialize byte #
      word_add_flag  <= '0';
      ack_flag       <= '0';
      in_reg_enable  <= '0';
      temp_add_upper <= "0000000";
      temp_add_lower <= "00000000";
      read_10_flag   <= '0';
      hit_10_upper   <= '0';
      hit_10_lower   <= '0';
      hit_7          <= '0';
      sda_out2       <= '0';

-- initialize the mem array
    write(L,now, justified => right, field=>10,unit=>ns);
    write(L,string'(" Initializing Memory "));
    writeline(output,L);   
    cnt := "00000000";
    for I in 0 to 255 loop
      mem(I) <= cnt;  
      cnt := cnt + '1';
    end loop;
-- initialize the mem array
    write(L,now, justified => right, field=>10,unit=>ns);
    write(L,string'(" Done Initializing Memory "));
    writeline(output,L);   

  elsif(rising_edge(clk)) then
    case current_state is
      when idle =>
              sda_out2 <= '0';
              if (start_detect = '1' and scl1 = '1') then 
                current_state <= start;
              else
                current_state <= idle;
                in_reg_enable <= '0';
              end if;
      when start =>
              sda_out2 <= '0';
              if (start_detect = '1' and scl1 = '1') then 
                current_state <= start;
              end if;
        
              if (stop_detect = '1' and scl1 = '1') then
                current_state <= idle;

              elsif (scl_pulse = '1') then
                  bit_counter <= "0000";
                  in_reg_enable <= '1';

              elsif (in_reg_enable = '1') then
                  in_reg_enable <= '0'; 
                  bit_counter <= bit_counter + '1';
                  current_state <= address;
-- clear all the address hit flags
                  hit_7 <= '0';
                  hit_10_upper <= '0';
                  hit_10_lower <= '0';
                  word_add_flag <= '0';
                  ack_flag <= '0';
              end if;

      when address =>
        
                if (start_detect = '1' and scl1 = '1') then 
                  current_state <= start;
                  ack_ctrl <= '0';
                  sda_out2 <= '0' after 2 ns;
        
                elsif (stop_detect = '1' and scl1 = '1') then
                  current_state <= idle;
                  ack_ctrl <= '0';
                  sda_out2 <= '0' after 2 ns;
 
                elsif (scl_pulse = '1' and (bit_counter <= "1000")) then                
                  in_reg_enable <= '1';
                  ack_ctrl <= '0';
                  sda_out2 <= '0' after 2 ns;
        
                elsif (in_reg_enable = '1') then 
                  in_reg_enable <= '0'; 
                  bit_counter <= bit_counter + '1';
                  current_state <= address;
                  ack_ctrl <= '0';
                  sda_out2 <= '0' after 2 ns;
        
                elsif (bit_counter = "1000" and address_mode = seven_bit) then 
-- determine if r or w and set r_w_bit
                  if (in_reg(7 downto 1) = address_reg_7) then 
                    r_w_bit <= in_reg(0);
                    current_state <= ack;
                    hit_7 <= '1';
                    ack_flag <= '0'; -- used in ack state
                    ack_ctrl <= '0';
                    sda_out2 <= '0' after 2 ns;
                  else 
-- the address is not for this slave                 
                    ack_ctrl <= '1';
                    sda_out2 <= '1' after 2 ns;
                    current_state <= idle;
                  end if;
        
-- check if upper address byte is a hit in 10 bit addressing
                elsif (bit_counter = "1000" and address_mode = ten_bit and hit_10_upper = '0') then
-- first time checking upper hit
                  if (in_reg(7 downto 1) = address_reg_10_upper) then 
                    ack_ctrl <= '0';
                    sda_out2 <= '0' after 2 ns;
                    r_w_bit <= in_reg(0);
                    current_state <= ack;
                    hit_10_upper <= '1';
                    ack_flag <= '0'; -- used in ack state
                    if (in_reg(0) = '0') then
                      temp_add_upper <= in_reg(7 downto 1);
                      read_10_flag <= '0'; -- clear
                    elsif ((in_reg(0) = '1') and (temp_add_upper = in_reg(7 downto 1))
                            and (temp_add_lower = address_reg_10_lower) ) then
-- This flag is set because the last 10 bit addressing 
-- mode write was for this slave, so this read only 
-- requires a match of the first byte of addressing
                      read_10_flag <= '1'; -- set             
                    end if;
                  else 
-- the address is not for this slave
                    ack_ctrl <= '1';
                    sda_out2 <= '1' after 2 ns;
                    current_state <= idle;
                    temp_add_upper <= in_reg(7 downto 1); -- holds value of last
                                                  -- upper add
                    read_10_flag <= '0'; -- clear
                  end if;

        
-- check if lower address byte is a hit in 10 bit addressing
                elsif (bit_counter = "1000" and address_mode = ten_bit and hit_10_upper = '1') then
-- is the lower address a hit?
                  if (in_reg(7 downto 0) = address_reg_10_lower) then
                    current_state <= ack;
                    hit_10_lower <= '1';
                    ack_flag <= '0'; -- used in ack state
                    temp_add_lower <= in_reg(7 downto 0);
                    ack_ctrl <= '0';
                    sda_out2 <= '0' after 2 ns;
                  else 
-- the address is not for this slave
                    ack_ctrl <= '1';
                    sda_out2 <= '1' after 2 ns;
                    current_state <= idle;
                    temp_add_lower <= in_reg(7 downto 0);
                  end if; 
                end if;  
 
      when ack =>
-- starts with scl high
          ack_ctrl <= '0';
          sda_out2 <= '0' after 2 ns;   
-- if we get a start goto start
              if (start_detect = '1' and scl1 = '1') then
                  current_state <= start;


-- if there is a stop goto idle
              elsif (stop_detect = '1' and scl1 = '1') then
                  current_state <= idle;

-- if there is an address hit acknowledge the address 
              elsif (((hit_7 = '1') or (hit_10_upper = '1') or (hit_10_lower = '1')) 
                       and scl_neg_pulse = '1' and ack_flag = '0') then 
                 out_en <= '1' after 2 ns; -- turn on OE
                 ack_flag <= '1';
        
-- once the acknowledge is presented turn off the OE
-- print the address, and goto address or data depending on
-- addressing mode
              elsif (((hit_7 = '1') or (hit_10_upper = '1') or (hit_10_lower = '1')) 
                       and scl_neg_pulse = '1' and ack_flag = '1' ) then 
                 out_en <= '0' after 2 ns; -- turn off OE
                 bit_counter <= "0000";

                 
                 if (hit_10_upper = '1' and hit_10_lower = '0') then
                 write(L,now, justified => right, field=>10,unit=>ns);
                 write(L,string'(" 10 bit addressing Upper address is "));
                 write(L, in_reg);
                 writeline(output,L);   

                  if (read_10_flag = '0') then 
                    current_state <= address;
                  elsif (read_10_flag = '1') then
-- going to the data state because a read in 10 bit
-- addressing only requires a hit on the upper address if
-- the last write was a hit.
                    current_state <= data;
                  end if;
                 elsif (hit_7 = '1' or hit_10_lower = '1') then
-- hit_10_lower or hit_7 
                  current_state <= data;
                  if (hit_10_lower = '1') then
                    write(L,now, justified => right, field=>10,unit=>ns);
                    write(L,string'(" 10 bit addressing Lower address is  "));
                    write(L, in_reg);
                    writeline(output,L);   

                  elsif (hit_7 = '1') then
                    write(L,now, justified => right, field=>10,unit=>ns);
                    write(L,string'(" 7 bit addressing & address is "));
                    write(L, in_reg);
                    writeline(output,L);   
                  end if;
                 end if;                 
 
-- if there is no hit, return to idle
              elsif (hit_7 = '0' and hit_10_upper = '0' and hit_10_lower = '0') then
-- no_ack
                 out_en <= '0' after 2 ns;
                 bit_counter <= "0000";
                 current_state <= idle;

              end if;
 
      when data =>
              ack_ctrl <= '0';
              sda_out2 <= '0' after 2 ns; 
-- starts with scl low
              if (start_detect = '1' and scl1 = '1') then
                  current_state <= start;
        
              elsif (stop_detect = '1' and scl1 = '1') then
                current_state <= idle;

-- write data
              else -- outer else
                if (r_w_bit = '0' and scl_pulse = '1' and (bit_counter <= "1000") ) then
-- write
                  in_reg_enable <= '1';
                elsif (r_w_bit = '0' and in_reg_enable = '1' and (bit_counter <= "1000")) then
-- write more
                  in_reg_enable <= '0'; 
                  bit_counter <= bit_counter + '1';
                  current_state <= data;
                elsif (r_w_bit = '0' and (bit_counter = "1000")) then
-- write last bit
                   in_reg_enable <= '0'; -- disable
                   current_state <= data_ack;
                   ack_flag <= '0'; -- used in data_ack state
                   if (word_add_flag = '0') then 
                     word_address <= in_reg;
                     word_add_flag <= '1'; -- set the flag
                   else 
                     mem(to_integer(unsigned(word_address))) <= in_reg;
                     word_address <= word_address + '1';
                   end if;
-- read data
                elsif (r_w_bit = '1' and (bit_counter = "0000") and scl_neg_pulse = '0') then 
-- read first bit of word
-- scl is low at start of read
                   out_en <= '1' after 2 ns; -- turn on OE
                   out_reg <= mem(to_integer(unsigned(word_address)));
                elsif (r_w_bit = '1' and (bit_counter < "0111") and scl_neg_pulse = '1') then 
-- set up next bit
                    bit_counter <= bit_counter + '1';
                elsif (r_w_bit = '1' and (bit_counter = "0111") and scl_neg_pulse = '1') then 
-- we already output the last bit
                  bit_counter <= "0000";
                  out_en <= '0' after 2 ns; -- turn off OE
                  word_address <= word_address + '1';
                  current_state <= data_ack;
                  ack_flag <= '0'; -- used in data_ack state
                end if;
              end if; -- outer else
 
      when data_ack =>

              if (start_detect = '1' and scl1 = '1') then
                  current_state <= start;
                  ack_ctrl <= '0';
                  sda_out2 <= '0' after 2 ns; 
              elsif (stop_detect = '1' and scl1 = '1') then
                  current_state <= idle;
                  ack_ctrl <= '0';
                  sda_out2 <= '0' after 2 ns;
-- starts with scl high on write
              elsif ( r_w_bit = '0' and scl_neg_pulse = '1' and ack_flag = '0') then
                 write(L,now, justified => right, field=>10,unit=>ns);
                 write(L,string'(" Slave Data Received on write is "));
                 write(L, in_reg);
                 writeline(output,L);   
                 out_en <= '1' after 2 ns; -- turn on OE
                 ack_ctrl <= '1';
                 sda_out2 <= '0' after 2 ns;
                 ack_flag <= '1';
              elsif ( r_w_bit = '0' and scl_neg_pulse = '1' and ack_flag = '1' ) then
                 out_en <= '0' after 2 ns; -- turn off OE
                 ack_ctrl <= '1';
                 sda_out2 <= '1' after 2 ns;
                 bit_counter <= "0000";
                 current_state <= data; 
        
-- starts with scl low on read
              elsif (r_w_bit = '1' and scl_pulse = '1') then 
-- check sda for ack now
                 write(L,now, justified => right, field=>10,unit=>ns);
                 write(L,string'(" Slave Data transmitted on read is "));
                 write(L, out_reg);
                 writeline(output,L);   
                 ack_ctrl <= '0';
                 sda_out2 <= '0' after 2 ns;

                   if (sda1 = '0') then
                     next_state <= data;
                     bit_counter <= "0000";
                     write(L,now, justified => right, field=>10,unit=>ns);
                     write(L,string'(" Master ACK'd on a Data Read, returning to Data "));
                     writeline(output,L);   

                     ack_flag <= '1';
                   elsif (sda1 = '1') then
                     write(L,now, justified => right, field=>10,unit=>ns);
                     write(L,string'(" No ACK on a Data Read, returning to Idle "));
                     writeline(output,L);   
                     next_state <= idle;
                     ack_flag <= '1';
                   end if;
                elsif (r_w_bit = '1' and ack_flag = '0') then
                  out_en <= '0' after 2 ns; -- turn off OE
                elsif (r_w_bit = '1' and scl_neg_pulse = '1') then
                  current_state <= next_state;
                end if;
 
      when others =>
                ack_ctrl <= '0';
                sda_out2 <= '0' after 2 ns; 
                if (start_detect = '1' and scl1 ='1') then
                  current_state <= start;
                elsif (stop_detect = '1' and scl1 = '1') then
                  current_state <= idle;
                else 
                  current_state <= idle;
                  write(L,now, justified => right, field=>10,unit=>ns);
                  write(L,string'(" Something is broken is the SM returning to idle "));
                  writeline(output,L);   
                end if;
    end case;
  end if;
end process;

end behave;

--------------------------------- E O F --------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -