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
|
||
Split inout into in and out for i2c, better for internal use in fpga