Revision 982
Added by markw over 5 years ago
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
Split inout into in and out for i2c, better for internal use in fpga