2017-08-10 3 views
1

Ich versuche, I²C-Slave mit Schreib-und Leseoperationen (8 Bit Daten) zu implementieren, und in meinem Code schreibt Teil funktioniert gut und auf der Leseseite müssen die Daten gelesen werden kommt nicht richtig, ich meine es ist alles "11111111".i2c Slave Schreiben und Lesen von Speicherplätzen in VHDL

Im Lese-Teil wird die Slave-Adresse bekommen und danach, anstatt die Registernummer zu schreiben, von der ich lesen muss, es zeigt alle "11111111" s. Ich brauche Hilfe dabei. Und sowohl das Schreiben als auch das Lesen sollte von 256 Registerstandorten aus geschehen. Wie schreibe und lese ich Daten in den Registern?

Hier in meinem Code versuche ich nur einige Register zu implementieren, anstatt alle 256 zu verwenden. Ich habe nur 10 Register verwendet. Dazu brauche ich einige Vorschläge.

Ich verwende Artix-7 Digilent Basys 3 Board und Vivado 2016.4. Hier sind meine Code- und Simulationsergebnisse.

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 schreiben:
I2C write
(zum Vergrößern klicken)

I²C zu lesen:
I2C Read
(zum Vergrößern klicken)

Antwort

0

Pflege der Testbench zu zeigen, ?

Sie haben ein Problem mit der SDA-Leitungsverbindung. Wenn dieser Kern Ihrem Desing unterlegen ist, sollten Sie verschiedene SDA_IN- und SDA_OUT-Signale verwenden und diese in eine einzelne bidirektionale Leitung auf der obersten Ebene multiplexen. Wenn diese Datei selbst eine Toplevel-Datei ist, sollten Sie SDA auf 'Z' setzen, nicht auf '0', wenn die Übertragung inaktiv ist, um diese Pin-Eingabe während dieser Zeit vorzunehmen.

Für Registerverbindungen gibt es mehrere Möglichkeiten. Zum Beispiel können Sie eine i2c-gesteuerte Zustandsmaschine machen und den ersten Opcode als eine Registernummer verwenden, und zweitens als Daten sowohl zum Lesen als auch zum Schreiben.

Und Sie verwenden data_clk ungepuffertes Signal als Uhr. Dies wird als eine schlechte Praxis für FPGA angesehen. Sie sollten alle Ihre Register/Prozesse mit einer einzigen schnellen Uhr versorgen und die Aktivierungssignale mit niedrigeren Geschwindigkeiten ausführen. Oder füttern Sie Ihr data_clk als Uhr, aber routen Sie zuerst über den globalen Uhrpuffer.

Verwandte Themen