📄 i2c_master.vhd
字号:
-- **************************************************************
-- File: i2c_master.vhd
--
-- Purpose: This file implements the I2C Master for configuring
-- the DAC3550A. It is a single transmit-only master.
-- A rising edge on the START signal indicates that
-- a START condition should be generated and that
-- data in the I2C Data Register is ready to be
-- transmitted. Once the byte transmission has been
-- completed, this code sets the EOT bit. At this point,
-- the controller writes a new word into the I2C Data
-- Register. The controller is running much faster
-- than the I2C Master, therefore there are many clock
-- cycles to update the data register. Negation of the
-- START signal causes the I2C Master to generate a STOP
-- condition.
--
-- Created: 10/11/99 ALS
-- Revised: 10/14/99 ALS
-- Revised: 11-28-99 ALS
-- Revised: 12-6-99 ALS
-- Revised: 2-17-00 ALS
-- **************************************************************
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
entity i2c_master is
port(
-- I2C bus signals
sda : inout std_logic;
scl : inout std_logic;
-- interface signals from MPEG_CHIP_CONTROL
i2cd : in std_logic_vector(7 downto 0); -- I2C Data from MPEG Chip Control
start : in std_logic; -- start/stop indicator
eot : out std_logic; -- End of Byte Transfer
i2c_err : out std_logic; -- error signal
detect_stop : inout std_logic; -- stop has been generated
clock : in std_logic; -- 2 MHz system clock
reset : in std_logic -- system reset
);
end i2c_master;
library IEEE;
use IEEE.std_logic_1164.all;
architecture behave of i2c_master is
-- ******************** CONSTANT DECLARATIONS ***********************
constant CNT_400KHZ : std_logic_vector(2 downto 0) := "101"; -- number of 2MHz clocks in 400KHz
constant HIGH_CNT : std_logic_vector(1 downto 0) := "10"; -- CNT_400KHz/2 -1
constant LOW_CNT : std_logic_vector(1 downto 0) := "10"; -- CNT_400KHz/2 -1
constant HIGH_CNT_2 : std_logic_vector(1 downto 0) := "01"; -- HIGH_CNT/2
constant DATA_HOLD : std_logic_vector(1 downto 0) := "01"; -- number of 2MHz clocks in 300ns(actually 500nS)
constant START_HOLD : std_logic_vector(1 downto 0) := "10";
constant START_CNT : std_logic_vector(3 downto 0) := "0000";
constant CNT_DONE : std_logic_vector(3 downto 0) := "0111"; -- data bit count
constant ZERO_CNT : std_logic_vector(1 downto 0) := "00";
constant RESET_ACTIVE : std_logic := '1';
-- ********************* COMPONENT DECLARATIONS ************************
-- 8-bit serial load/parallel shift register
component SHIFT8
port(
clock : in std_logic; -- Clock
reset : in std_logic; -- Active low clear
data_ld : in std_logic; -- Data load enable
data_in : in std_logic_vector (7 downto 0); -- 8-bit data to load
shift_in : in std_logic; -- Serial data in
shift_en : in std_logic; -- Shift enable
shift_out : out std_logic; -- Bit to shift out
data_out : out std_logic_vector (7 downto 0)); -- 8-bit parallel out
end component;
-- Up counter - 2 bit
-- used to divide system clock to count SCL time
component UPCNT2
port(
data : in std_logic_vector (1 downto 0); -- Serial data in
cnt_en : in std_logic; -- Count enable
load : in std_logic; -- Load line enable
reset : in std_logic; -- Active low clear
clock : in std_logic; -- Clock
qout : out std_logic_vector (1 downto 0));
end component;
-- Up counter - 4 bit
component UPCNT4
port(
data : in std_logic_vector (3 downto 0); -- Serial data in
cnt_en : in std_logic; -- Count enable
load : in std_logic; -- Load line enable
reset : in std_logic; -- Active low clear
clock : in std_logic; -- Clock
qout : out std_logic_vector (3 downto 0));
end component;
-- ********************* SIGNAL DECLARATIONS ************************
type state_type is (IDLE, HEADER, ACK_HEADER, XMIT_DATA, GET_ACK_DATA, ERR);
signal state,next_state : state_type;
type scl_state_type is (SCL_IDLE, START_ST, SCL_LOW_EDGE, SCL_LOW, SCL_HIGH_EDGE,
SCL_HIGH);
signal scl_state, next_scl_state : scl_state_type;
signal scl_in : std_logic; -- sampled version of scl
signal scl_out : std_logic; -- combinatorial scl output from scl generator state machine
signal scl_not : std_logic; -- inverted SCL for use as clock
signal sda_in : std_logic; -- sampled version of sda
signal sda_out : std_logic; -- combinatorial sda output from scl generator state machine
signal sda_out_reg : std_logic; -- registered SDA_OUT signal
signal master_sda : std_logic; -- sda value when master
signal sda_oe : std_logic;
-- Shift Register and the controls
signal shift_reg : std_logic_vector(7 downto 0); -- shift register that holds I2C data
signal shift_out : std_logic;
signal shift_reg_en, shift_reg_ld : std_logic;
signal start_d1 : std_logic; -- registered version of START for edge detect
signal detect_start : std_logic; -- indicates that a START condition has been detected
signal sm_stop : std_logic;
-- from state machine
signal sm_stop_com : std_logic; -- combinatorial sm_stop
signal eot_com : std_logic; -- combinatorial EOT signal from state machine
signal gen_start : std_logic; -- indicates MPEG_CHIP_CTRL wants to generate a START
signal gen_stop : std_logic; -- indicates MPEG_CHIP_CTRL wants to generate a STOP
signal stop_scl : std_logic; -- signal in SCL state machine indicating a STOP
signal stop_scl_reg : std_logic; -- registered STOP_SCL signal
-- Bit counter 0 to 7
signal bit_cnt : std_logic_vector(3 downto 0);
signal bit_cnt_ld, bit_cnt_en : std_logic;
-- Clock Counter
signal clk_cnt : std_logic_vector (1 downto 0);
signal clk_cnt_rst : std_logic;
signal clk_cnt_en : std_logic;
-- the following signals are only here because Viewlogic's VHDL compiler won't allow a constant
-- to be used in a component instantiation
signal cnt_zero : std_logic_vector(1 downto 0);
signal cnt_start : std_logic_vector(3 downto 0);
begin
-- set SDA and SCL
sda <= '0' when sda_oe = '1' else 'Z';
scl <= '0' when scl_out = '0' else 'Z';
-- negate SCL for use as clock
scl_not <= not(scl);
-- sda_oe is set when data to be output = 0
sda_oe <= '1' when ((sda_out = '0')or stop_scl = '1') else '0';
-- the following signals are only here because Viewlogic's VHDL compiler won't allow a constant
-- to be used in a component instantiation
cnt_zero <= ZERO_CNT;
cnt_start <= START_CNT;
-- ************************ SCL_Generator Process ************************
-- This process generates SCL and SDA when in Master mode. It generates the START
-- and STOP conditions.
scl_generator_comb: process (scl_state, sm_stop, gen_stop,
gen_start, stop_scl_reg, stop_scl,
clk_cnt, bit_cnt, scl_in,
sda_out_reg, state, master_sda)
begin
-- state machine defaults
scl_out <= '1';
sda_out <= sda_out_reg;
stop_scl <= stop_scl_reg;
clk_cnt_en <= '0';
clk_cnt_rst <= '1';
next_scl_state <= scl_state;
case scl_state is
when SCL_IDLE =>
sda_out <= '1';
stop_scl <= '0';
-- leave IDLE state when gen_start
if gen_start = '1' then
next_scl_state <= START_ST;
end if;
when START_ST =>
-- generate start condition
clk_cnt_en <= '1';
clk_cnt_rst <= '0';
sda_out <= '0';
stop_scl <= '0';
if clk_cnt = START_HOLD then
next_scl_state <= SCL_LOW_EDGE;
else
next_scl_state <= START_ST;
end if;
when SCL_LOW_EDGE =>
clk_cnt_rst <= '1';
scl_out <= '0';
next_scl_state <= SCL_LOW;
stop_scl <= '0';
when SCL_LOW =>
clk_cnt_en <= '1';
clk_cnt_rst <= '0';
scl_out <= '0';
-- set SDA_OUT based on control signals
if ((sm_stop = '1' or gen_stop = '1') and
(state /= GET_ACK_DATA and state /= ACK_HEADER )) then
sda_out <= '0';
stop_scl <= '1';
elsif clk_cnt = DATA_HOLD then
sda_out <= master_sda;
stop_scl <= '0';
else
stop_scl <= '0';
end if;
-- determine next state
if clk_cnt = LOW_CNT then
next_scl_state <= SCL_HIGH_EDGE;
else
next_scl_state <= SCL_LOW;
end if;
when SCL_HIGH_EDGE =>
clk_cnt_rst <= '1';
scl_out <= '1';
if ((sm_stop = '1' or gen_stop = '1') and
(state /= GET_ACK_DATA and state /= ACK_HEADER )) then
stop_scl <= '1';
else
stop_scl <= '0';
end if;
-- this state sets SCL high
-- stay in this state until SCL_IN = 1
-- this will hold the counter in reset until all SCL drivers
-- have released SCL to 1
if scl_in = '0' then
next_scl_state <= SCL_HIGH_EDGE;
else
next_scl_state <= SCL_HIGH;
end if;
when SCL_HIGH =>
-- now all SCL drivers have set SCL to '1'
-- begin count for high time
clk_cnt_en <= '1';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -