i2c slave从vhdl中的内存位置写入和读取

时间:2017-08-10 14:21:56

标签: vhdl i2c vivado

我正在尝试使用写入和读取操作(8位数据)实现I²C从器件,并且在我的代码写入部分工作正常,在读取端需要读取的数据不正确,我的意思是它所有“11111111”的。

在读取部分中,它获取从属地址,然后在此之后,而不是写入我需要读取的寄存器号,它显示所有“11111111”。我需要帮助。写入和读取都应该发生在256个寄存器位置。如何在寄存器上写入和读取数据?

在我的代码中,我只是尝试实现一些寄存器,而不是使用全部256个,我只使用了10个寄存器。我需要一些建议。

我正在使用Artix-7 Digilent Basys 3板和Vivado 2016.4。这是我的代码和模拟结果。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.NUMERIC_STD.ALL;

-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity I2C is

  Port (clk : in std_logic;
        rst : in std_logic;
        ena : in std_logic;
        rw  : in std_logic;
        state_cnt : out std_logic_vector(3 downto 0);
        data_read : out std_logic_vector(7 downto 0);
        sda : inout std_logic;
        scl : out std_logic );

end I2C;

architecture Behavioral of I2C is

type machine is (ready,start,slave_addr,slv_ack1,reg_num,act_data,read_data,slv_ack2,mas_ack,stop,slv_ack3);
signal pre_state,next_state : machine;

signal data_clk : std_logic;
signal scl_clk : std_logic;
signal scl_ena : std_logic := '0';
signal sda_int : std_logic := '1';
signal sda_ena : std_logic;
signal addr_rw : std_logic_vector(7 downto 0);
signal data_tx : std_logic_vector(7 downto 0);
signal data_rx : std_logic_vector(7 downto 0);
signal bit_count : integer range 0 to 7 := 7;

signal addr : std_logic_vector(6 downto 0) := "1010000";
signal data_wr : std_logic_vector(7 downto 0) := "01010110";--"11110000";
--signal data_rd : std_logic_vector(7 downto 0) := "01010110";
signal wr_addr : std_logic_vector(7 downto 0) := "00000001"; 
signal count : integer range 0 to 250;

type slv_array is array (0 to 9) of std_logic_vector (7 downto 0);
signal reg_array : slv_array;

begin

reg_array(0) <= "00000000";
reg_array(1) <= "00000001";
reg_array(2) <= "00000010";
reg_array(3) <= "00000011";
reg_array(4) <= "00000100";
reg_array(5) <= "00000101";
reg_array(6) <= "00000110";
reg_array(7) <= "00000111";
reg_array(8) <= "00001000";
reg_array(9) <= "00001001";

process (clk, rst)
begin
    if (rst = '1') then
        count <= 0;
     elsif (rising_edge(clk))then
        if (count = 249) then
--            temp <= not temp;
            count <= 0;
        else
            count <= count + 1;
        end if;
        end if;
end process;
--scl_clk <= temp;
process (clk,rst,count) 
begin
    if (rst = '1') then
        scl_clk <= '0';
        data_clk <= '0';
     elsif (rising_edge(clk)) then
        case count is 
            when 0 to 62 =>
                scl_clk <= '0';
                data_clk <= '0';

            when 63 to 124 =>
                scl_clk <= '0';
                data_clk <= '1';

            when 125 to 187 =>
                scl_clk <= '1';
                data_clk <= '1';

            when 188 to 249 =>
                scl_clk <= '1';
                data_clk <= '0';

            when others => null;
        end case;
    end if;
end process;

process (clk,rst)
begin
    if (rst = '1') then
        pre_state  <= ready;
     elsif (rising_edge(clk))then
        pre_state <= next_state;
    end if;
end process;

process(data_clk,rst)
begin
    if (rst = '1') then
        next_state <= ready;
        scl_ena <= '0';
        sda_int <= '1';
        bit_count <= 7;
        data_read <= "00000000";
        state_cnt <= "1111";
      elsif (rising_edge(data_clk)) then
        case pre_state is
            when ready =>
                state_cnt <= "0001";
                if (ena ='1') then
                    addr_rw <= addr & rw;
                    data_tx <= wr_addr;  
                    next_state <= start;
                else                 
                    next_state <= ready;
                end if;

            when start =>
                state_cnt <= "0010";
                scl_ena <= '1';
                sda_int <= addr_rw(bit_count);
                next_state <= slave_addr;

            when slave_addr =>
                state_cnt <= "0011";
                if (bit_count = 0) then
                    sda_int <= '1';
                    bit_count <= 7;
                    next_state <= slv_ack1;
                else
                    bit_count <= bit_count - 1;
                    sda_int <= addr_rw(bit_count -1);
                    next_state <= slave_addr;
                end if;

            when slv_ack1 =>
                state_cnt <= "0100";
                if (addr_rw(0) = '0') then
                    sda_int <= data_tx(bit_count);
                    next_state <= reg_num;
                else
                    sda_int <= '1';
                    next_state <= read_data; 
                end if;

            when reg_num =>
                state_cnt <= "0101";
                if (bit_count = 0) then
                    sda_int <= '1';
                    bit_count <= 7;
                    next_state <= slv_ack2;
                else
                    bit_count <= bit_count - 1;
                    sda_int <= data_tx(bit_count -1);
                    next_state <= reg_num;
                end if;

            when slv_ack2 =>
                state_cnt <= "0110";
                if (ena ='1') then
                    data_tx <= data_wr;
                    sda_int <= data_wr(bit_count);  
                    next_state <= act_data;
                else
                    scl_ena <= '0';
                    next_state <= stop;  
                end if;

            when act_data =>
                state_cnt <= "0111";
                    if (bit_count =0) then
                        sda_int <= '1';
                        bit_count <= 7;
                        next_state <= slv_ack3;  
                    else
                        bit_count <= bit_count - 1;
                        sda_int <= data_tx(bit_count-1);
                        next_state <= act_data;
                    end if;

            when slv_ack3 =>
                state_cnt <= "1000";
                scl_ena <= '0';
                next_state <= stop;

           when stop =>
               state_cnt <= "1001";
                    if (rw = '1') then
                        next_state <= ready;  
                    else
                        next_state <= stop;
                    end if;


            when read_data =>
                state_cnt <= "1010"; 
                    if (bit_count = 0) then
                        if (ena ='1' and rw ='1') then
                            sda_int <= '0';
                        else
                            sda_int <= '1';
                        end if;

                        data_read(0) <= sda;
                        data_read(7 downto 1) <= data_rx(7 downto 1); 
                        bit_count <= 7;
                        next_state <= stop; 
                    else
                        data_rx(bit_count) <= sda;
                        bit_count <= bit_count - 1;
                        next_state <= read_data;
                    end if;    

            when mas_ack => 
                state_cnt <= "1011";
                    if (ena = '1') then
                        addr_rw <= addr & rw;
                        data_tx <= data_wr;
                            if (rw = '0') then
                                next_state <= start;
                            else
                                sda_int <= '1';
                                next_state <= read_data;
                            end if;
                    else
                        scl_ena <='0';
                        next_state <= stop;
                    end if;

            when others => null;
        end case;    
    end if;
end process;


WITH pre_state select 
    sda_ena <= data_clk when start,
               not data_clk when stop,
               sda_int when others;

    scl <= scl_clk; 
    sda <= '0' when sda_ena = '0' else sda_ena;                               


end Behavioral;

I²C写道:
I2C write
(点击放大)

I²C读:
I2C Read
(点击放大)

1 个答案:

答案 0 :(得分:0)

小心展示你的测试平台?

您遇到SDA线路连接问题。如果这个内核不如你的设计,你应该使用差分SDA_IN和SDA_OUT信号,并将它们复用到顶层的单个双向线。如果此文件本身是顶层文件,则应将SDA设置为&#39; Z&#39;而不是设置为&#39; 0&#39;当传输无效时,在此期间输入该引脚。

对于寄存器连接,有多种方法可以实现。例如,您可以创建i2c控制的状态机,并使用第一个操作码作为寄存器编号,第二个作为读取和写入的数据。

您正在使用data_clk无缓冲信号作为时钟。这被认为是FPGA的不良做法。您应该使用单个高速时钟为所有寄存器/进程提供信号,并使用启用信号以较低的速度执行。或者将data_clk作为时钟提供,但首先通过全局时钟缓冲器进行路由。