?? i2c_slave.vhd
字號(hào):
--------------------------------------------
-- 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 --------------------------------------
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -