Project

General

Profile

« Previous | Next » 

Revision 982

Added by markw over 5 years ago

Split inout into in and out for i2c, better for internal use in fpga

View differences:

common/components/I2C_regs.vhd
bits : integer := 1
);
port (
scl : inout std_logic;
sda : inout std_logic;
scl_in : in std_logic;
sda_in : in std_logic;
scl_wen : out std_logic;
sda_wen : out std_logic;
clk : in std_logic;
rst : in std_logic;
......
SLAVE_ADDR => SLAVE_ADDR
)
port map (
scl => scl,
sda => sda,
scl_in => scl_in,
sda_in => sda_in,
scl_wen => scl_wen,
sda_wen => sda_wen,
clk => clk,
rst => rst,
common/components/I2C_slave.vhd
------------------------------------------------------------
-- Copyright (c) 2016 Peter Samarin
------------------------------------------------------------
-- Mark Watson 2020 - modified to not use inout, for simpler in fpga use
------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
......
generic (
SLAVE_ADDR : std_logic_vector(6 downto 0));
port (
scl : inout std_logic;
sda : inout std_logic;
scl_in : in std_logic;
sda_in : in std_logic;
scl_wen : out std_logic;
sda_wen : out std_logic;
clk : in std_logic;
rst : in std_logic;
-- User interface
......
begin
if rising_edge(clk) then
-- save SCL in registers that are used for debouncing
scl_reg <= scl;
sda_reg <= sda;
scl_reg <= scl_in;
sda_reg <= sda_in;
-- Delay debounced SCL and SDA by 1 clock cycle
scl_prev_reg <= scl_debounced;
......
----------------------------------------------------------
-- I2C interface
----------------------------------------------------------
sda <= sda_o_reg when sda_wen_reg = '1' else
'Z';
scl <= scl_o_reg when scl_wen_reg = '1' else
'Z';
scl_wen <= scl_wen_reg and not(scl_o_reg);
sda_wen <= sda_wen_reg and not(sda_o_reg);
----------------------------------------------------------
-- User interface
----------------------------------------------------------
common/components/i2c_master.vhd
-- Adjusted timing of SCL during start and stop conditions
-- Version 2.2 02/05/2015 Scott Larson
-- Corrected small SDA glitch introduced in version 2.1
-- 2020 Mark Watson
-- Modified to use in/out instead of inout
--
--------------------------------------------------------------------------------
......
busy : OUT STD_LOGIC; --indicates transaction in progress
data_rd : OUT STD_LOGIC_VECTOR(7 DOWNTO 0); --data read from slave
ack_error : BUFFER STD_LOGIC; --flag if improper acknowledge from slave
sda : INOUT STD_LOGIC; --serial data output of i2c bus
scl : INOUT STD_LOGIC); --serial clock output of i2c bus
scl_in : in std_logic;
sda_in : in std_logic;
scl_wen : out std_logic;
sda_wen : out std_logic
); --serial clock output of i2c bus
END i2c_master;
ARCHITECTURE logic OF i2c_master IS
......
data_clk <= '1';
WHEN divider*2 TO divider*3-1 => --third 1/4 cycle of clocking
scl_clk <= '1'; --release scl
IF(scl = '0') THEN --detect if slave is stretching clock
IF(scl_in = '0') THEN --detect if slave is stretching clock
stretch <= '1';
ELSE
stretch <= '0';
......
ack_error <= '0'; --reset acknowledge error output
END IF;
WHEN slv_ack1 => --receiving slave acknowledge (command)
IF(sda /= '0' OR ack_error = '1') THEN --no-acknowledge or previous no-acknowledge
IF(sda_in /= '0' OR ack_error = '1') THEN --no-acknowledge or previous no-acknowledge
ack_error <= '1'; --set error output if no-acknowledge
END IF;
WHEN rd => --receiving slave data
data_rx(bit_cnt) <= sda; --receive current slave data bit
data_rx(bit_cnt) <= sda_in; --receive current slave data bit
WHEN slv_ack2 => --receiving slave acknowledge (write)
IF(sda /= '0' OR ack_error = '1') THEN --no-acknowledge or previous no-acknowledge
IF(sda_in /= '0' OR ack_error = '1') THEN --no-acknowledge or previous no-acknowledge
ack_error <= '1'; --set error output if no-acknowledge
END IF;
WHEN stop =>
......
NOT data_clk_prev WHEN stop, --generate stop condition
sda_int WHEN OTHERS; --set to internal sda signal
--set scl and sda outputs
scl <= '0' WHEN (scl_ena = '1' AND scl_clk = '0') ELSE 'Z';
sda <= '0' WHEN sda_ena_n = '0' ELSE 'Z';
--set scl and sda outputs
sda_wen <= not(sda_ena_n);
scl_wen <= scl_ena AND not(scl_clk);
END logic;
common/zpu/zpu_config_regs.vhdl
USBWireOE_n :out std_logic_vector(usb-1 downto 0);
-- I2C (400k)
i2c0_sda : inout std_logic;
i2c0_scl : inout std_logic;
i2c1_sda : inout std_logic;
i2c1_scl : inout std_logic
i2c0_sda_in : in std_logic;
i2c0_scl_in : in std_logic;
i2c0_sda_wen : out std_logic;
i2c0_scl_wen : out std_logic;
i2c1_sda_in : in std_logic;
i2c1_scl_in : in std_logic;
i2c1_sda_wen : out std_logic;
i2c1_scl_wen : out std_logic
);
END zpu_config_regs;
......
-- TODO: Use real clk freq... Not that important since only used on eclaire for now anyway.
i2c_master0 : entity work.i2c_master
generic map(input_clk=>58_000_000, bus_clk=>400_000)
port map (clk=>clk,reset_n=>reset_n,ena=>i2c0_write_reg,addr=>i2c0_write_data_reg(15 downto 9),rw=>i2c0_write_data_reg(8),data_wr=>i2c0_write_data_reg(7 downto 0),busy=>i2c0_busy_next,data_rd=>i2c0_read_data,ack_error=>i2c0_error,sda=>i2c0_sda,scl=>i2c0_scl);
port map (clk=>clk,reset_n=>reset_n,ena=>i2c0_write_reg,addr=>i2c0_write_data_reg(15 downto 9),rw=>i2c0_write_data_reg(8),data_wr=>i2c0_write_data_reg(7 downto 0),busy=>i2c0_busy_next,data_rd=>i2c0_read_data,ack_error=>i2c0_error,
sda_in=>i2c0_sda_in,scl_in=>i2c0_scl_in,sda_wen=>i2c0_sda_wen,scl_wen=>i2c0_scl_wen);
i2c_master1 : entity work.i2c_master
generic map(input_clk=>58_000_000, bus_clk=>400_000)
port map (clk=>clk,reset_n=>reset_n,ena=>i2c1_write_reg,addr=>i2c1_write_data_reg(15 downto 9),rw=>i2c1_write_data_reg(8),data_wr=>i2c1_write_data_reg(7 downto 0),busy=>i2c1_busy_next,data_rd=>i2c1_read_data,ack_error=>i2c1_error,sda=>i2c1_sda,scl=>i2c1_scl);
port map (clk=>clk,reset_n=>reset_n,ena=>i2c1_write_reg,addr=>i2c1_write_data_reg(15 downto 9),rw=>i2c1_write_data_reg(8),data_wr=>i2c1_write_data_reg(7 downto 0),busy=>i2c1_busy_next,data_rd=>i2c1_read_data,ack_error=>i2c1_error,
sda_in=>i2c1_sda_in,scl_in=>i2c1_scl_in,sda_wen=>i2c1_sda_wen,scl_wen=>i2c1_scl_wen);
-- device decode
-- 0x000 - own regs (0)
common/zpu/zpucore.vhd
USBWireOE_n :out std_logic_vector(usb-1 downto 0);
-- I2C (400k)
i2c0_sda : inout std_logic;
i2c0_scl : inout std_logic;
i2c1_sda : inout std_logic;
i2c1_scl : inout std_logic
i2c0_sda_in : in std_logic := '1';
i2c0_scl_in : in std_logic := '1';
i2c0_sda_wen : out std_logic;
i2c0_scl_wen : out std_logic;
i2c1_sda_in : in std_logic := '1';
i2c1_scl_in : in std_logic := '1';
i2c1_sda_wen : out std_logic;
i2c1_scl_wen : out std_logic
);
END zpucore;
......
USBWireVMout => USBWireVMout,
USBWireOE_n => USBWireOE_n,
i2c0_sda => i2c0_sda,
i2c0_scl => i2c0_scl,
i2c1_sda => i2c1_sda,
i2c1_scl => i2c1_scl
i2c0_sda_in => i2c0_sda_in,
i2c0_scl_in => i2c0_scl_in,
i2c0_sda_wen => i2c0_sda_wen,
i2c0_scl_wen => i2c0_scl_wen,
i2c1_sda_in => i2c1_sda_in,
i2c1_scl_in => i2c1_scl_in,
i2c1_sda_wen => i2c1_sda_wen,
i2c1_scl_wen => i2c1_scl_wen
);
decode_addr1 : entity work.complete_address_decoder

Also available in: Unified diff