URL
https://opencores.org/ocsvn/i2c/i2c/trunk
Subversion Repositories i2c
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 14 to Rev 15
- ↔ Reverse comparison
Rev 14 → Rev 15
/trunk/rtl/vhdl/wishbone_i2c_master.vhd
File deleted
/trunk/rtl/vhdl/i2c_master_byte_ctrl.vhd
0,0 → 1,361
--------------------------------------------------------------------- |
---- ---- |
---- WISHBONE revB2 compl. I2C Master Core; byte-controller ---- |
---- ---- |
---- ---- |
---- Author: Richard Herveille ---- |
---- richard@asics.ws ---- |
---- www.asics.ws ---- |
---- ---- |
---- Downloaded from: http://www.opencores.org/projects/i2c/ ---- |
---- ---- |
--------------------------------------------------------------------- |
---- ---- |
---- Copyright (C) 2000 Richard Herveille ---- |
---- richard@asics.ws ---- |
---- ---- |
---- This source file may be used and distributed without ---- |
---- restriction provided that this copyright statement is not ---- |
---- removed from the file and that any derivative work contains ---- |
---- the original copyright notice and the associated disclaimer.---- |
---- ---- |
---- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ---- |
---- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ---- |
---- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ---- |
---- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ---- |
---- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ---- |
---- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ---- |
---- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ---- |
---- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ---- |
---- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ---- |
---- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ---- |
---- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ---- |
---- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ---- |
---- POSSIBILITY OF SUCH DAMAGE. ---- |
---- ---- |
--------------------------------------------------------------------- |
|
-- CVS Log |
-- |
-- $Id: i2c_master_byte_ctrl.vhd,v 1.1 2001-11-05 12:02:33 rherveille Exp $ |
-- |
-- $Date: 2001-11-05 12:02:33 $ |
-- $Revision: 1.1 $ |
-- $Author: rherveille $ |
-- $Locker: $ |
-- $State: Exp $ |
-- |
-- Change History: |
-- $Log: not supported by cvs2svn $ |
|
|
|
|
-- |
------------------------------------------ |
-- Byte controller section |
------------------------------------------ |
-- |
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.std_logic_arith.all; |
|
entity i2c_master_byte_ctrl is |
generic( |
Tcq : time := 1 ns |
); |
port ( |
clk : in std_logic; |
rst : in std_logic; -- synchronous active high reset (WISHBONE compatible) |
nReset : in std_logic; -- asynchornous active low reset (FPGA compatible) |
ena : in std_logic; -- core enable signal |
|
clk_cnt : in unsigned(15 downto 0); -- 4x SCL |
|
-- input signals |
start, |
stop, |
read, |
write, |
ack_in : std_logic; |
din : in std_logic_vector(7 downto 0); |
|
-- output signals |
cmd_ack : out std_logic; |
ack_out : out std_logic; |
i2c_busy : out std_logic; |
dout : out std_logic_vector(7 downto 0); |
|
-- i2c lines |
scl_i : in std_logic; -- i2c clock line input |
scl_o : out std_logic; -- i2c clock line output |
scl_oen : out std_logic; -- i2c clock line output enable, active low |
sda_i : in std_logic; -- i2c data line input |
sda_o : out std_logic; -- i2c data line output |
sda_oen : out std_logic -- i2c data line output enable, active low |
); |
end entity i2c_master_byte_ctrl; |
|
architecture structural of i2c_master_byte_ctrl is |
component i2c_master_bit_ctrl is |
generic( |
Tcq : time := Tcq |
); |
port ( |
clk : in std_logic; |
rst : in std_logic; |
nReset : in std_logic; |
ena : in std_logic; -- core enable signal |
|
clk_cnt : in unsigned(15 downto 0); -- clock prescale value |
|
cmd : in std_logic_vector(3 downto 0); |
cmd_ack : out std_logic; |
busy : out std_logic; |
|
din : in std_logic; |
dout : out std_logic; |
|
-- i2c lines |
scl_i : in std_logic; -- i2c clock line input |
scl_o : out std_logic; -- i2c clock line output |
scl_oen : out std_logic; -- i2c clock line output enable, active low |
sda_i : in std_logic; -- i2c data line input |
sda_o : out std_logic; -- i2c data line output |
sda_oen : out std_logic -- i2c data line output enable, active low |
); |
end component i2c_master_bit_ctrl; |
|
-- commands for bit_controller block |
constant I2C_CMD_NOP : std_logic_vector(3 downto 0) := "0000"; |
constant I2C_CMD_START : std_logic_vector(3 downto 0) := "0001"; |
constant I2C_CMD_STOP : std_logic_vector(3 downto 0) := "0010"; |
constant I2C_CMD_READ : std_logic_vector(3 downto 0) := "0100"; |
constant I2C_CMD_WRITE : std_logic_vector(3 downto 0) := "1000"; |
|
-- signals for bit_controller |
signal core_cmd : std_logic_vector(3 downto 0); |
signal core_ack, core_txd, core_rxd : std_logic; |
|
-- signals for shift register |
signal sr : std_logic_vector(7 downto 0); -- 8bit shift register |
signal shift, ld : std_logic; |
|
-- signals for state machine |
signal go, host_ack : std_logic; |
signal dcnt : unsigned(2 downto 0); -- data counter |
signal cnt_done : std_logic; |
|
begin |
-- hookup bit_controller |
u1: i2c_master_bit_ctrl port map( |
clk => clk, |
rst => rst, |
nReset => nReset, |
ena => ena, |
clk_cnt => clk_cnt, |
cmd => core_cmd, |
cmd_ack => core_ack, |
busy => i2c_busy, |
din => core_txd, |
dout => core_rxd, |
scl_i => scl_i, |
scl_o => scl_o, |
scl_oen => scl_oen, |
sda_i => sda_i, |
sda_o => sda_o, |
sda_oen => sda_oen |
); |
|
-- generate host-command-acknowledge |
cmd_ack <= host_ack; |
|
-- generate go-signal |
go <= (read or write or stop) and not host_ack; |
|
-- assign Dout output to shift-register |
dout <= sr; |
|
-- generate shift register |
shift_register: process(clk, nReset) |
begin |
if (nReset = '0') then |
sr <= (others => '0') after Tcq; |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
sr <= (others => '0') after Tcq; |
elsif (ld = '1') then |
sr <= din after Tcq; |
elsif (shift = '1') then |
sr <= (sr(6 downto 0) & core_rxd) after Tcq; |
end if; |
end if; |
end process shift_register; |
|
-- generate data-counter |
data_cnt: process(clk, nReset) |
begin |
if (nReset = '0') then |
dcnt <= (others => '0') after Tcq; |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
dcnt <= (others => '0') after Tcq; |
elsif (ld = '1') then |
dcnt <= (others => '1') after Tcq; -- load counter with 7 |
elsif (shift = '1') then |
dcnt <= dcnt -1 after Tcq; |
end if; |
end if; |
end process data_cnt; |
|
cnt_done <= '1' when (dcnt = 0) else '0'; |
|
-- |
-- state machine |
-- |
statemachine : block |
type states is (st_idle, st_start, st_read, st_write, st_ack, st_stop); |
signal c_state : states; |
begin |
-- |
-- command interpreter, translate complex commands into simpler I2C commands |
-- |
nxt_state_decoder: process(clk, nReset) |
begin |
if (nReset = '0') then |
core_cmd <= I2C_CMD_NOP after Tcq; |
core_txd <= '0' after Tcq; |
|
shift <= '0' after Tcq; |
ld <= '0' after Tcq; |
|
host_ack <= '0' after Tcq; |
c_state <= st_idle after Tcq; |
|
ack_out <= '0' after Tcq; |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
core_cmd <= I2C_CMD_NOP after Tcq; |
core_txd <= '0' after Tcq; |
|
shift <= '0' after Tcq; |
ld <= '0' after Tcq; |
|
host_ack <= '0' after Tcq; |
c_state <= st_idle after Tcq; |
|
ack_out <= '0' after Tcq; |
else |
-- initialy reset all signal |
core_txd <= sr(7) after Tcq; |
|
shift <= '0' after Tcq; |
ld <= '0' after Tcq; |
|
host_ack <= '0' after Tcq; |
|
case c_state is |
when st_idle => |
if (go = '1') then |
if (start = '1') then |
c_state <= st_start after Tcq; |
core_cmd <= I2C_CMD_START after Tcq; |
elsif (read = '1') then |
c_state <= st_read after Tcq; |
core_cmd <= I2C_CMD_READ after Tcq; |
elsif (write = '1') then |
c_state <= st_write after Tcq; |
core_cmd <= I2C_CMD_WRITE after Tcq; |
else -- stop |
c_state <= st_stop after Tcq; |
core_cmd <= I2C_CMD_STOP after Tcq; |
|
host_ack <= '1' after Tcq; -- generate acknowledge signal |
end if; |
|
ld <= '1' after Tcq; |
end if; |
|
when st_start => |
if (core_ack = '1') then |
if (read = '1') then |
c_state <= st_read after Tcq; |
core_cmd <= I2C_CMD_READ after Tcq; |
else |
c_state <= st_write after Tcq; |
core_cmd <= I2C_CMD_WRITE after Tcq; |
end if; |
|
ld <= '1' after Tcq; |
end if; |
|
when st_write => |
if (core_ack = '1') then |
if (cnt_done = '1') then |
c_state <= st_ack after Tcq; |
core_cmd <= I2C_CMD_READ after Tcq; |
else |
c_state <= st_write after Tcq; -- stay in same state |
core_cmd <= I2C_CMD_WRITE after Tcq; -- write next bit |
|
shift <= '1' after Tcq; |
end if; |
end if; |
|
when st_read => |
if (core_ack = '1') then |
if (cnt_done = '1') then |
c_state <= st_ack after Tcq; |
core_cmd <= I2C_CMD_WRITE after Tcq; |
else |
c_state <= st_read after Tcq; -- stay in same state |
core_cmd <= I2C_CMD_READ after Tcq; -- read next bit |
end if; |
|
shift <= '1' after Tcq; |
core_txd <= ack_in after Tcq; |
end if; |
|
when st_ack => |
if (core_ack = '1') then |
-- check for stop; Should a STOP command be generated ? |
if (stop = '1') then |
c_state <= st_stop after Tcq; |
core_cmd <= I2C_CMD_STOP after Tcq; |
else |
c_state <= st_idle after Tcq; |
core_cmd <= I2C_CMD_NOP after Tcq; |
end if; |
|
-- assign ack_out output to core_rxd (contains last received bit) |
ack_out <= core_rxd after Tcq; |
|
-- generate command acknowledge signal |
host_ack <= '1' after Tcq; |
|
core_txd <= '1' after Tcq; |
else |
core_txd <= ack_in after Tcq; |
end if; |
|
when st_stop => |
if (core_ack = '1') then |
c_state <= st_idle after Tcq; |
core_cmd <= I2C_CMD_NOP after Tcq; |
end if; |
|
when others => -- illegal states |
c_state <= st_idle after Tcq; |
core_cmd <= I2C_CMD_NOP after Tcq; |
report ("Byte controller entered illegal state."); |
|
end case; |
|
end if; |
end if; |
end process nxt_state_decoder; |
|
end block statemachine; |
|
end architecture structural; |
|
/trunk/rtl/vhdl/i2c_master_bit_ctrl.vhd
0,0 → 1,428
--------------------------------------------------------------------- |
---- ---- |
---- WISHBONE revB2 compl. I2C Master Core; bit-controller ---- |
---- ---- |
---- ---- |
---- Author: Richard Herveille ---- |
---- richard@asics.ws ---- |
---- www.asics.ws ---- |
---- ---- |
---- Downloaded from: http://www.opencores.org/projects/i2c/ ---- |
---- ---- |
--------------------------------------------------------------------- |
---- ---- |
---- Copyright (C) 2000 Richard Herveille ---- |
---- richard@asics.ws ---- |
---- ---- |
---- This source file may be used and distributed without ---- |
---- restriction provided that this copyright statement is not ---- |
---- removed from the file and that any derivative work contains ---- |
---- the original copyright notice and the associated disclaimer.---- |
---- ---- |
---- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ---- |
---- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ---- |
---- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ---- |
---- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ---- |
---- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ---- |
---- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ---- |
---- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ---- |
---- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ---- |
---- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ---- |
---- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ---- |
---- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ---- |
---- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ---- |
---- POSSIBILITY OF SUCH DAMAGE. ---- |
---- ---- |
--------------------------------------------------------------------- |
|
-- CVS Log |
-- |
-- $Id: i2c_master_bit_ctrl.vhd,v 1.1 2001-11-05 12:02:33 rherveille Exp $ |
-- |
-- $Date: 2001-11-05 12:02:33 $ |
-- $Revision: 1.1 $ |
-- $Author: rherveille $ |
-- $Locker: $ |
-- $State: Exp $ |
-- |
-- Change History: |
-- $Log: not supported by cvs2svn $ |
|
|
-- |
------------------------------------- |
-- Bit controller section |
------------------------------------ |
-- |
-- Translate simple commands into SCL/SDA transitions |
-- Each command has 5 states, A/B/C/D/idle |
-- |
-- start: SCL ~~~~~~~~~~\____ |
-- SDA ~~~~~~~~\______ |
-- x | A | B | C | D | i |
-- |
-- repstart SCL ____/~~~~\___ |
-- SDA __/~~~\______ |
-- x | A | B | C | D | i |
-- |
-- stop SCL ____/~~~~~~~~ |
-- SDA ==\____/~~~~~ |
-- x | A | B | C | D | i |
-- |
--- write SCL ____/~~~~\____ |
-- SDA ==X=========X= |
-- x | A | B | C | D | i |
-- |
--- read SCL ____/~~~~\____ |
-- SDA XXXX=====XXXX |
-- x | A | B | C | D | i |
-- |
|
-- Timing: Normal mode Fast mode |
----------------------------------------------------------------- |
-- Fscl 100KHz 400KHz |
-- Th_scl 4.0us 0.6us High period of SCL |
-- Tl_scl 4.7us 1.3us Low period of SCL |
-- Tsu:sta 4.7us 0.6us setup time for a repeated start condition |
-- Tsu:sto 4.0us 0.6us setup time for a stop conditon |
-- Tbuf 4.7us 1.3us Bus free time between a stop and start condition |
-- |
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.std_logic_arith.all; |
|
entity i2c_master_bit_ctrl is |
generic( |
Tcq : time := 1 ns |
); |
port ( |
clk : in std_logic; |
rst : in std_logic; |
nReset : in std_logic; |
ena : in std_logic; -- core enable signal |
|
clk_cnt : in unsigned(15 downto 0); -- clock prescale value |
|
cmd : in std_logic_vector(3 downto 0); |
cmd_ack : out std_logic; |
busy : out std_logic; |
|
din : in std_logic; |
dout : out std_logic; |
|
-- i2c lines |
scl_i : in std_logic; -- i2c clock line input |
scl_o : out std_logic; -- i2c clock line output |
scl_oen : out std_logic; -- i2c clock line output enable, active low |
sda_i : in std_logic; -- i2c data line input |
sda_o : out std_logic; -- i2c data line output |
sda_oen : out std_logic -- i2c data line output enable, active low |
); |
end entity i2c_master_bit_ctrl; |
|
architecture structural of i2c_master_bit_ctrl is |
constant I2C_CMD_NOP : std_logic_vector(3 downto 0) := "0000"; |
constant I2C_CMD_START : std_logic_vector(3 downto 0) := "0001"; |
constant I2C_CMD_STOP : std_logic_vector(3 downto 0) := "0010"; |
constant I2C_CMD_READ : std_logic_vector(3 downto 0) := "0100"; |
constant I2C_CMD_WRITE : std_logic_vector(3 downto 0) := "1000"; |
|
type states is (idle, start_a, start_b, start_c, start_d, stop_a, stop_b, stop_c, rd_a, rd_b, rd_c, rd_d, wr_a, wr_b, wr_c, wr_d); |
signal c_state : states; |
|
signal iscl_oen, isda_oen : std_logic; -- internal I2C lines |
signal sSCL, sSDA : std_logic; -- synchronized SCL and SDA inputs |
|
signal clk_en, slave_wait :std_logic; -- clock generation signals |
-- signal cnt : unsigned(15 downto 0) := clk_cnt; -- clock divider counter (simulation) |
signal cnt : unsigned(15 downto 0); -- clock divider counter (synthesis) |
|
begin |
-- synchronize SCL and SDA inputs |
synch_scl_sda: process(clk) |
begin |
if (clk'event and clk = '1') then |
sSCL <= scl_i after Tcq; |
sSDA <= sda_i after Tcq; |
end if; |
end process synch_SCL_SDA; |
|
-- whenever the slave is not ready it can delay the cycle by pulling SCL low |
slave_wait <= iscl_oen and not sSCL; |
|
-- generate clk enable signal |
gen_clken: process(clk, nReset) |
begin |
if (nReset = '0') then |
cnt <= (others => '0') after Tcq; |
clk_en <= '1' after Tcq; |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
cnt <= (others => '0') after Tcq; |
clk_en <= '1' after Tcq; |
else |
if ( (cnt = 0) or (ena = '0') ) then |
clk_en <= '1' after Tcq; |
cnt <= clk_cnt after Tcq; |
else |
if (slave_wait = '0') then |
cnt <= cnt -1 after Tcq; |
end if; |
clk_en <= '0' after Tcq; |
end if; |
end if; |
end if; |
end process gen_clken; |
|
|
-- generate bus status controller |
bus_status_ctrl: block |
signal dSDA : std_logic; |
signal sta_condition : std_logic; |
signal sto_condition : std_logic; |
|
signal ibusy : std_logic; |
begin |
-- detect start condition => detect falling edge on SDA while SCL is high |
-- detect stop condition => detect rising edge on SDA while SCL is high |
detect_sta_sto: process(clk) |
begin |
if (clk'event and clk = '1') then |
dSDA <= sSDA; -- generate a delayed version of sSDA |
|
sta_condition <= (not sSDA and dSDA) and sSCL; |
sto_condition <= (sSDA and not dSDA) and sSCL; |
end if; |
end process detect_sta_sto; |
|
-- generate bus busy signal |
gen_busy: process(clk, nReset) |
begin |
if (nReset = '0') then |
ibusy <= '0' after Tcq; |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
ibusy <= '0' after Tcq; |
else |
ibusy <= (sta_condition or ibusy) and not sto_condition after Tcq; |
end if; |
end if; |
end process gen_busy; |
|
-- assign output |
busy <= ibusy; |
end block bus_status_ctrl; |
|
|
-- generate statemachine |
nxt_state_decoder : process (clk, nReset, c_state, cmd) |
variable nxt_state : states; |
variable icmd_ack, store_sda : std_logic; |
begin |
|
nxt_state := c_state; |
|
icmd_ack := '0'; -- default no acknowledge |
|
store_sda := '0'; |
|
case (c_state) is |
-- idle |
when idle => |
case cmd is |
when I2C_CMD_START => |
nxt_state := start_a; |
|
when I2C_CMD_STOP => |
nxt_state := stop_a; |
|
when I2C_CMD_WRITE => |
nxt_state := wr_a; |
|
when I2C_CMD_READ => |
nxt_state := rd_a; |
|
when others => -- NOP command |
nxt_state := idle; |
end case; |
|
-- start |
when start_a => |
nxt_state := start_b; |
|
when start_b => |
nxt_state := start_c; |
|
when start_c => |
nxt_state := start_d; |
|
when start_d => |
nxt_state := idle; |
icmd_ack := '1'; -- command completed |
|
-- stop |
when stop_a => |
nxt_state := stop_b; |
|
when stop_b => |
nxt_state := stop_c; |
|
when stop_c => |
nxt_state := idle; |
icmd_ack := '1'; -- command completed |
|
-- read |
when rd_a => |
nxt_state := rd_b; |
|
when rd_b => |
nxt_state := rd_c; |
|
when rd_c => |
nxt_state := rd_d; |
store_sda := '1'; |
|
when rd_d => |
nxt_state := idle; |
icmd_ack := '1'; -- command completed |
|
-- write |
when wr_a => |
nxt_state := wr_b; |
|
when wr_b => |
nxt_state := wr_c; |
|
when wr_c => |
nxt_state := wr_d; |
|
when wr_d => |
nxt_state := idle; |
icmd_ack := '1'; -- command completed |
|
end case; |
|
-- generate regs |
if (nReset = '0') then |
c_state <= idle after Tcq; |
cmd_ack <= '0' after Tcq; |
Dout <= '0' after Tcq; |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
c_state <= idle after Tcq; |
cmd_ack <= '0' after Tcq; |
Dout <= '0' after Tcq; |
else |
if (clk_en = '1') then |
c_state <= nxt_state after Tcq; |
|
if (store_sda = '1') then |
dout <= sSDA after Tcq; |
end if; |
end if; |
|
cmd_ack <= icmd_ack and clk_en; |
end if; |
end if; |
end process nxt_state_decoder; |
|
-- |
-- convert states to SCL and SDA signals |
-- |
output_decoder: process (clk, nReset, c_state, iscl_oen, isda_oen, din) |
variable iscl, isda : std_logic; |
begin |
case (c_state) is |
when idle => |
iscl := iscl_oen; -- keep SCL in same state |
isda := isda_oen; -- keep SDA in same state |
|
-- start |
when start_a => |
iscl := iscl_oen; -- keep SCL in same state (for repeated start) |
isda := '1'; -- set SDA high |
|
when start_b => |
iscl := '1'; -- set SCL high |
isda := '1'; -- keep SDA high |
|
when start_c => |
iscl := '1'; -- keep SCL high |
isda := '0'; -- sel SDA low |
|
when start_d => |
iscl := '0'; -- set SCL low |
isda := '0'; -- keep SDA low |
|
-- stop |
when stop_a => |
iscl := '0'; -- keep SCL disabled |
isda := '0'; -- set SDA low |
|
when stop_b => |
iscl := '1'; -- set SCL high |
isda := '0'; -- keep SDA low |
|
when stop_c => |
iscl := '1'; -- keep SCL high |
isda := '1'; -- set SDA high |
|
-- write |
when wr_a => |
iscl := '0'; -- keep SCL low |
isda := din; -- set SDA |
|
when wr_b => |
iscl := '1'; -- set SCL high |
isda := din; -- keep SDA |
|
when wr_c => |
iscl := '1'; -- keep SCL high |
isda := din; -- keep SDA |
|
when wr_d => |
iscl := '0'; -- set SCL low |
isda := din; -- keep SDA |
|
-- read |
when rd_a => |
iscl := '0'; -- keep SCL low |
isda := '1'; -- tri-state SDA |
|
when rd_b => |
iscl := '1'; -- set SCL high |
isda := '1'; -- tri-state SDA |
|
when rd_c => |
iscl := '1'; -- keep SCL high |
isda := '1'; -- tri-state SDA |
|
when rd_d => |
iscl := '0'; -- set SCL low |
isda := '1'; -- tri-state SDA |
end case; |
|
-- generate registers |
if (nReset = '0') then |
iscl_oen <= '1' after Tcq; |
isda_oen <= '1' after Tcq; |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
iscl_oen <= '1' after Tcq; |
isda_oen <= '1' after Tcq; |
else |
if (clk_en = '1') then |
iscl_oen <= iscl after Tcq; |
isda_oen <= isda after Tcq; |
end if; |
end if; |
end if; |
end process output_decoder; |
|
-- assign outputs |
scl_o <= '0'; |
scl_oen <= iscl_oen; |
sda_o <= '0'; |
sda_oen <= isda_oen; |
end architecture structural; |
/trunk/rtl/vhdl/i2c_master_top.vhd
0,0 → 1,342
--------------------------------------------------------------------- |
---- ---- |
---- WISHBONE revB2 compl. I2C Master Core; top level ---- |
---- ---- |
---- ---- |
---- Author: Richard Herveille ---- |
---- richard@asics.ws ---- |
---- www.asics.ws ---- |
---- ---- |
---- Downloaded from: http://www.opencores.org/projects/i2c/ ---- |
---- ---- |
--------------------------------------------------------------------- |
---- ---- |
---- Copyright (C) 2000 Richard Herveille ---- |
---- richard@asics.ws ---- |
---- ---- |
---- This source file may be used and distributed without ---- |
---- restriction provided that this copyright statement is not ---- |
---- removed from the file and that any derivative work contains ---- |
---- the original copyright notice and the associated disclaimer.---- |
---- ---- |
---- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ---- |
---- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ---- |
---- TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ---- |
---- FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ---- |
---- OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ---- |
---- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ---- |
---- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ---- |
---- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ---- |
---- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ---- |
---- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ---- |
---- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ---- |
---- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ---- |
---- POSSIBILITY OF SUCH DAMAGE. ---- |
---- ---- |
--------------------------------------------------------------------- |
|
-- CVS Log |
-- |
-- $Id: i2c_master_top.vhd,v 1.1 2001-11-05 12:02:33 rherveille Exp $ |
-- |
-- $Date: 2001-11-05 12:02:33 $ |
-- $Revision: 1.1 $ |
-- $Author: rherveille $ |
-- $Locker: $ |
-- $State: Exp $ |
-- |
-- Change History: |
-- $Log: not supported by cvs2svn $ |
|
|
library ieee; |
use ieee.std_logic_1164.all; |
use ieee.std_logic_arith.all; |
|
entity i2c_master_top is |
generic( |
ARST_LVL : std_logic := '0'; -- asynchronous reset level |
|
-- Register timing parameters. |
-- Last parameters in list for |
-- verilog compatibility |
Tcq : time := 1 ns -- Clock to output delay |
); |
port ( |
-- wishbone signals |
wb_clk_i : in std_logic; -- master clock input |
wb_rst_i : in std_logic := '0'; -- synchronous active high reset |
arst_i : in std_logic := not ARST_LVL; -- asynchronous reset |
wb_adr_i : in unsigned(2 downto 0); -- lower address bits |
wb_dat_i : in std_logic_vector(7 downto 0); -- Databus input |
wb_dat_o : out std_logic_vector(7 downto 0); -- Databus output |
wb_we_i : in std_logic; -- Write enable input |
wb_stb_i : in std_logic; -- Strobe signals / core select signal |
wb_cyc_i : in std_logic; -- Valid bus cycle input |
wb_ack_o : out std_logic; -- Bus cycle acknowledge output |
wb_inta_o : out std_logic; -- interrupt request output signal |
|
-- i2c lines |
scl_pad_i : in std_logic; -- i2c clock line input |
scl_pad_o : out std_logic; -- i2c clock line output |
scl_padoen_o : out std_logic; -- i2c clock line output enable, active low |
sda_pad_i : in std_logic; -- i2c data line input |
sda_pad_o : out std_logic; -- i2c data line output |
sda_padoen_o : out std_logic -- i2c data line output enable, active low |
); |
end entity i2c_master_top; |
|
architecture structural of i2c_master_top is |
component i2c_master_byte_ctrl is |
generic( |
Tcq : time := Tcq |
); |
port ( |
clk : in std_logic; |
rst : in std_logic; -- synchronous active high reset (WISHBONE compatible) |
nReset : in std_logic; -- asynchornous active low reset (FPGA compatible) |
ena : in std_logic; -- core enable signal |
|
clk_cnt : in unsigned(15 downto 0); -- 4x SCL |
|
-- input signals |
start, |
stop, |
read, |
write, |
ack_in : std_logic; |
din : in std_logic_vector(7 downto 0); |
|
-- output signals |
cmd_ack : out std_logic; |
ack_out : out std_logic; |
i2c_busy : out std_logic; |
dout : out std_logic_vector(7 downto 0); |
|
-- i2c lines |
scl_i : in std_logic; -- i2c clock line input |
scl_o : out std_logic; -- i2c clock line output |
scl_oen : out std_logic; -- i2c clock line output enable, active low |
sda_i : in std_logic; -- i2c data line input |
sda_o : out std_logic; -- i2c data line output |
sda_oen : out std_logic -- i2c data line output enable, active low |
); |
end component i2c_master_byte_ctrl; |
|
-- registers |
signal prer : unsigned(15 downto 0); -- clock prescale register |
signal ctr : std_logic_vector(7 downto 0); -- control register |
signal txr : std_logic_vector(7 downto 0); -- transmit register |
signal rxr : std_logic_vector(7 downto 0); -- receive register |
signal cr : std_logic_vector(7 downto 0); -- command register |
signal sr : std_logic_vector(7 downto 0); -- status register |
|
-- internal reset signal |
signal rst_i : std_logic; |
|
-- done signal: command completed, clear command register |
signal done : std_logic; |
|
-- command register signals |
signal sta, sto, rd, wr, ack, iack : std_logic; |
|
-- core enable signal |
signal core_en : std_logic; |
signal ien : std_logic; |
|
-- status register signals |
signal irxack, rxack : std_logic; -- received aknowledge from slave |
signal tip : std_logic; -- transfer in progress |
signal irq_flag : std_logic; -- interrupt pending flag |
signal i2c_busy : std_logic; -- bus busy (start signal detected) |
|
begin |
-- generate internal reset signal |
rst_i <= arst_i xor ARST_LVL; |
|
-- generate acknowledge output signal |
wb_ack_o <= wb_cyc_i and wb_stb_i; -- because timing is always honored |
|
-- assign wb_dat_o |
assign_dato : process(wb_adr_i, prer, ctr, txr, cr, rxr, sr) |
begin |
case wb_adr_i is |
when "000" => |
wb_dat_o <= std_logic_vector(prer( 7 downto 0)); |
|
when "001" => |
wb_dat_o <= std_logic_vector(prer(15 downto 8)); |
|
when "010" => |
wb_dat_o <= ctr; |
|
when "011" => |
wb_dat_o <= rxr; -- write is transmit register TxR |
|
when "100" => |
wb_dat_o <= sr; -- write is command register CR |
|
-- Debugging registers: |
-- These registers are not documented. |
-- Functionality could change in future releases |
|
when "101" => |
wb_dat_o <= txr; |
|
when "110" => |
wb_dat_o <= cr; |
|
when "111" => |
wb_dat_o <= (others => '0'); |
|
when others => |
wb_dat_o <= (others => 'X'); -- for simulation only |
|
end case; |
end process assign_dato; |
|
|
-- registers block |
regs_block: process(rst_i, wb_clk_i) |
begin |
if (rst_i = '0') then |
prer <= (others => '0') after Tcq; |
ctr <= (others => '0') after Tcq; |
txr <= (others => '0') after Tcq; |
cr <= (others => '0') after Tcq; |
elsif (wb_clk_i'event and wb_clk_i = '1') then |
if (wb_rst_i = '1') then |
prer <= (others => '0') after Tcq; |
ctr <= (others => '0') after Tcq; |
txr <= (others => '0') after Tcq; |
cr <= (others => '0') after Tcq; |
else |
if (wb_cyc_i = '1' and wb_stb_i = '1' and wb_we_i = '1') then |
if (wb_adr_i(2) = '0') then |
case wb_adr_i(1 downto 0) is |
when "00" => prer( 7 downto 0) <= unsigned(wb_dat_i) after Tcq; |
when "01" => prer(15 downto 8) <= unsigned(wb_dat_i) after Tcq; |
when "10" => ctr <= wb_dat_i after Tcq; |
when "11" => txr <= wb_dat_i after Tcq; |
|
-- illegal cases, for simulation only |
when others => |
report ("Illegal write address, setting all registers to unknown."); |
prer <= (others => 'X'); |
ctr <= (others => 'X'); |
txr <= (others => 'X'); |
end case; |
elsif ( (core_en = '1') and (wb_adr_i(1 downto 0) = 0) ) then |
-- only take new commands when i2c ore enabled |
-- pending commands are finished |
cr <= wb_dat_i after Tcq; |
end if; |
else |
-- clear command bits when done |
if (done = '1') then |
cr(7 downto 4) <= (others => '0') after Tcq; |
end if; |
|
-- reserved bits |
cr(2 downto 1) <= (others => '0') after Tcq; |
|
-- clear iack when irq_flag cleared |
cr(0) <= cr(0) and irq_flag; |
end if; |
end if; |
end if; |
end process regs_block; |
|
-- decode command register |
sta <= cr(7); |
sto <= cr(6); |
rd <= cr(5); |
wr <= cr(4); |
ack <= cr(3); |
iack <= cr(0); |
|
-- decode control register |
core_en <= ctr(7); |
ien <= ctr(6); |
|
-- hookup byte controller block |
u1: i2c_master_byte_ctrl port map ( |
clk => wb_clk_i, |
rst => wb_rst_i, |
nReset => rst_i, |
ena => core_en, |
clk_cnt => prer, |
start => sta, |
stop => sto, |
read => rd, |
write => wr, |
ack_in => ack, |
i2c_busy => i2c_busy, |
din => txr, |
cmd_ack => done, |
ack_out => irxack, |
dout => rxr, |
scl_i => scl_pad_i, |
scl_o => scl_pad_o, |
scl_oen => scl_padoen_o, |
sda_i => sda_pad_i, |
sda_o => sda_pad_o, |
sda_oen => sda_padoen_o |
); |
|
|
-- status register block + interrupt request signal |
st_irq_block : block |
begin |
-- generate status register bits |
gen_sr_bits: process (wb_clk_i, rst_i) |
begin |
if (rst_i = '0') then |
rxack <= '0' after Tcq; |
tip <= '0' after Tcq; |
irq_flag <= '0' after Tcq; |
elsif (wb_clk_i'event and wb_clk_i = '1') then |
if (wb_rst_i = '1') then |
rxack <= '0' after Tcq; |
tip <= '0' after Tcq; |
irq_flag <= '0' after Tcq; |
else |
rxack <= irxack after Tcq; |
tip <= (rd or wr) after Tcq; |
|
-- interrupt request flag is always generated |
irq_flag <= (done or irq_flag) and not iack after Tcq; |
end if; |
end if; |
end process gen_sr_bits; |
|
-- generate interrupt request signals |
gen_irq: process (wb_clk_i, rst_i) |
begin |
if (rst_i = '0') then |
wb_inta_o <= '0' after Tcq; |
elsif (wb_clk_i'event and wb_clk_i = '1') then |
if (wb_rst_i = '1') then |
wb_inta_o <= '0' after Tcq; |
else |
-- interrupt signal is only generated when IEN (interrupt enable bit) is set |
wb_inta_o <= irq_flag and ien after Tcq; |
end if; |
end if; |
end process gen_irq; |
|
-- assign status register bits |
sr(7) <= rxack; |
sr(6) <= i2c_busy; |
sr(5 downto 2) <= (others => '0'); -- reserved |
sr(1) <= tip; |
sr(0) <= irq_flag; |
end block; |
|
end architecture structural; |
|
|
|
|
|
|