URL
https://opencores.org/ocsvn/i2c/i2c/trunk
Subversion Repositories i2c
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 30 to Rev 31
- ↔ Reverse comparison
Rev 30 → Rev 31
/trunk/rtl/vhdl/i2c_master_byte_ctrl.vhd
37,10 → 37,10
|
-- CVS Log |
-- |
-- $Id: i2c_master_byte_ctrl.vhd,v 1.2 2002-11-30 22:24:37 rherveille Exp $ |
-- $Id: i2c_master_byte_ctrl.vhd,v 1.3 2002-12-26 16:05:47 rherveille Exp $ |
-- |
-- $Date: 2002-11-30 22:24:37 $ |
-- $Revision: 1.2 $ |
-- $Date: 2002-12-26 16:05:47 $ |
-- $Revision: 1.3 $ |
-- $Author: rherveille $ |
-- $Locker: $ |
-- $State: Exp $ |
47,6 → 47,9
-- |
-- Change History: |
-- $Log: not supported by cvs2svn $ |
-- Revision 1.2 2002/11/30 22:24:37 rherveille |
-- Cleaned up code |
-- |
-- Revision 1.1 2001/11/05 12:02:33 rherveille |
-- Split i2c_master_core.vhd into separate files for each entity; same layout as verilog version. |
-- Code updated, is now up-to-date to doc. rev.0.4. |
83,9 → 86,10
din : in std_logic_vector(7 downto 0); |
|
-- output signals |
cmd_ack : out std_logic; |
cmd_ack : out std_logic; -- command done |
ack_out : out std_logic; |
i2c_busy : out std_logic; |
i2c_busy : out std_logic; -- arbitration lost |
i2c_al : out std_logic; -- i2c bus busy |
dout : out std_logic_vector(7 downto 0); |
|
-- i2c lines |
109,8 → 113,9
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; |
cmd_ack : out std_logic; -- command done |
busy : out std_logic; -- i2c bus busy |
al : out std_logic; -- arbitration lost |
|
din : in std_logic; |
dout : out std_logic; |
135,6 → 140,7
-- signals for bit_controller |
signal core_cmd : std_logic_vector(3 downto 0); |
signal core_ack, core_txd, core_rxd : std_logic; |
signal al : std_logic; |
|
-- signals for shift register |
signal sr : std_logic_vector(7 downto 0); -- 8bit shift register |
147,7 → 153,7
|
begin |
-- hookup bit_controller |
u1: i2c_master_bit_ctrl port map( |
bit_ctrl: i2c_master_bit_ctrl port map( |
clk => clk, |
rst => rst, |
nReset => nReset, |
156,6 → 162,7
cmd => core_cmd, |
cmd_ack => core_ack, |
busy => i2c_busy, |
al => al, |
din => core_txd, |
dout => core_rxd, |
scl_i => scl_i, |
165,6 → 172,7
sda_o => sda_o, |
sda_oen => sda_oen |
); |
i2c_al <= al; |
|
-- generate host-command-acknowledge |
cmd_ack <= host_ack; |
230,7 → 238,7
c_state <= st_idle; |
ack_out <= '0'; |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
if (rst = '1' or al = '1') then |
core_cmd <= I2C_CMD_NOP; |
core_txd <= '0'; |
shift <= '0'; |
/trunk/rtl/vhdl/i2c_master_bit_ctrl.vhd
37,10 → 37,10
|
-- CVS Log |
-- |
-- $Id: i2c_master_bit_ctrl.vhd,v 1.4 2002-11-30 22:24:37 rherveille Exp $ |
-- $Id: i2c_master_bit_ctrl.vhd,v 1.5 2002-12-26 16:05:47 rherveille Exp $ |
-- |
-- $Date: 2002-11-30 22:24:37 $ |
-- $Revision: 1.4 $ |
-- $Date: 2002-12-26 16:05:47 $ |
-- $Revision: 1.5 $ |
-- $Author: rherveille $ |
-- $Locker: $ |
-- $State: Exp $ |
47,6 → 47,9
-- |
-- Change History: |
-- $Log: not supported by cvs2svn $ |
-- Revision 1.4 2002/11/30 22:24:37 rherveille |
-- Cleaned up code |
-- |
-- Revision 1.3 2002/10/30 18:09:53 rherveille |
-- Fixed some reported minor start/stop generation timing issuess. |
-- |
68,25 → 71,25
-- 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 |
-- start: SCL ~~~~~~~~~~~~~~\____ |
-- SDA XX/~~~~~~~\______ |
-- x | A | B | C | D | i |
-- |
-- repstart 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 |
-- stop SCL _______/~~~~~~~~~~~ |
-- SDA ==\___________/~~~~~ |
-- x | A | B | C | D | i |
-- |
--- write SCL ____/~~~~\____ |
-- SDA ==X=========X= |
-- x | A | B | C | D | i |
--- write SCL ______/~~~~~~~\____ |
-- SDA XXX===============XX |
-- x | A | B | C | D | i |
-- |
--- read SCL ____/~~~~\____ |
-- SDA XXXX=====XXXX |
-- x | A | B | C | D | i |
--- read SCL ______/~~~~~~~\____ |
-- SDA XXXXXXX=XXXXXXXXXXX |
-- x | A | B | C | D | i |
-- |
|
-- Timing: Normal mode Fast mode |
113,8 → 116,9
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; |
cmd_ack : out std_logic; -- command completed |
busy : out std_logic; -- i2c bus busy |
al : out std_logic; -- arbitration lost |
|
din : in std_logic; |
dout : out std_logic; |
141,23 → 145,15
signal c_state : states; |
|
signal iscl_oen, isda_oen : std_logic; -- internal I2C lines |
signal sda_chk : std_logic; -- check SDA status (multi-master arbitration) |
signal dscl_oen : std_logic; -- delayed scl_oen signals |
signal sSCL, sSDA : std_logic; -- synchronized SCL and SDA inputs |
signal dscl_oen : std_logic; -- delayed scl_oen signals |
|
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; |
sSDA <= sda_i; |
end if; |
end process synch_SCL_SDA; |
|
-- whenever the slave is not ready it can delay the cycle by pulling SCL low |
-- delay scl_oen |
process (clk) |
begin |
165,8 → 161,6
dscl_oen <= iscl_oen; |
end if; |
end process; |
|
-- whenever the slave is not ready it can delay the cycle by pulling SCL low |
slave_wait <= dscl_oen and not sSCL; |
|
-- generate clk enable signal |
181,8 → 175,13
clk_en <= '1'; |
else |
if ( (cnt = 0) or (ena = '0') ) then |
clk_en <= '1'; |
cnt <= clk_cnt; |
if (slave_wait = '0') then |
cnt <= clk_cnt; |
clk_en <= '1'; |
else |
cnt <= cnt; |
clk_en <= '0'; |
end if; |
else |
if (slave_wait = '0') then |
cnt <= cnt -1; |
196,25 → 195,35
|
-- generate bus status controller |
bus_status_ctrl: block |
signal dSDA : std_logic; |
signal sta_condition : std_logic; |
signal sto_condition : std_logic; |
signal dSCL, dSDA : std_logic; -- delayes sSCL and sSDA |
signal sta_condition : std_logic; -- start detected |
signal sto_condition : std_logic; -- stop detected |
signal cmd_stop, dcmd_stop : std_logic; -- STOP command |
signal ibusy : std_logic; -- internal busy signal |
begin |
-- synchronize SCL and SDA inputs |
synch_scl_sda: process(clk) |
begin |
if (clk'event and clk = '1') then |
sSCL <= scl_i; |
sSDA <= sda_i; |
|
signal ibusy : std_logic; |
begin |
dSCL <= sSCL; |
dSDA <= sSDA; |
end if; |
end process synch_SCL_SDA; |
|
-- 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 |
-- generate i2c-bus busy signal |
gen_busy: process(clk, nReset) |
begin |
if (nReset = '0') then |
227,9 → 236,33
end if; |
end if; |
end process gen_busy; |
busy <= ibusy; |
|
-- assign output |
busy <= ibusy; |
|
-- generate arbitration lost signal |
gen_al: process(clk) |
begin |
if (clk'event and clk = '1') then |
if (cmd = I2C_CMD_STOP) then |
cmd_stop <= '1'; |
else |
cmd_stop <= '0'; |
end if; |
dcmd_stop <= cmd_stop; |
|
al <= (sda_chk and not sSDA and isda_oen) or (sto_condition and not dcmd_stop); |
end if; |
end process gen_al; |
|
-- generate dout signal, store dout on rising edge of SCL |
gen_dout: process(clk) |
begin |
if (clk'event and clk = '1') then |
if (sSCL = '1' and dSCL = '0') then |
dout <= sSDA; |
end if; |
end if; |
end process gen_dout; |
end block bus_status_ctrl; |
|
|
239,16 → 272,16
if (nReset = '0') then |
c_state <= idle; |
cmd_ack <= '0'; |
dout <= '0'; |
iscl_oen <= '1'; |
isda_oen <= '1'; |
sda_chk <= '0'; |
elsif (clk'event and clk = '1') then |
if (rst = '1') then |
c_state <= idle; |
cmd_ack <= '0'; |
dout <= '0'; |
iscl_oen <= '1'; |
isda_oen <= '1'; |
sda_chk <= '0'; |
else |
cmd_ack <= '0'; -- default no acknowledge |
|
266,6 → 299,7
|
iscl_oen <= iscl_oen; -- keep SCL in same state |
isda_oen <= isda_oen; -- keep SDA in same state |
sda_chk <= '0'; -- don't check SDA |
|
-- start |
when start_a => |
272,21 → 306,25
c_state <= start_b; |
iscl_oen <= iscl_oen; -- keep SCL in same state (for repeated start) |
isda_oen <= '1'; -- set SDA high |
sda_chk <= '0'; -- don't check SDA |
|
when start_b => |
c_state <= start_c; |
iscl_oen <= '1'; -- set SCL high |
isda_oen <= '1'; -- keep SDA high |
sda_chk <= '0'; -- don't check SDA |
|
when start_c => |
c_state <= start_d; |
iscl_oen <= '1'; -- keep SCL high |
isda_oen <= '0'; -- set SDA low |
sda_chk <= '0'; -- don't check SDA |
|
when start_d => |
c_state <= start_e; |
iscl_oen <= '1'; -- keep SCL high |
isda_oen <= '0'; -- keep SDA low |
sda_chk <= '0'; -- don't check SDA |
|
when start_e => |
c_state <= idle; |
293,22 → 331,26
cmd_ack <= '1'; -- command completed |
iscl_oen <= '0'; -- set SCL low |
isda_oen <= '0'; -- keep SDA low |
sda_chk <= '0'; -- don't check SDA |
|
-- stop |
when stop_a => |
c_state <= stop_b; |
iscl_oen <= '0'; -- keep SCL disabled |
iscl_oen <= '0'; -- keep SCL low |
isda_oen <= '0'; -- set SDA low |
sda_chk <= '0'; -- don't check SDA |
|
when stop_b => |
c_state <= stop_c; |
iscl_oen <= '1'; -- set SCL high |
isda_oen <= '0'; -- keep SDA low |
sda_chk <= '0'; -- don't check SDA |
|
when stop_c => |
c_state <= stop_d; |
iscl_oen <= '1'; -- keep SCL high |
isda_oen <= '0'; -- keep SDA low |
sda_chk <= '0'; -- don't check SDA |
|
when stop_d => |
c_state <= idle; |
315,6 → 357,7
cmd_ack <= '1'; -- command completed |
iscl_oen <= '1'; -- keep SCL high |
isda_oen <= '1'; -- set SDA high |
sda_chk <= '0'; -- don't check SDA |
|
-- read |
when rd_a => |
321,17 → 364,19
c_state <= rd_b; |
iscl_oen <= '0'; -- keep SCL low |
isda_oen <= '1'; -- tri-state SDA |
sda_chk <= '0'; -- don't check SDA |
|
when rd_b => |
c_state <= rd_c; |
iscl_oen <= '1'; -- set SCL high |
isda_oen <= '1'; -- tri-state SDA |
sda_chk <= '0'; -- don't check SDA |
|
when rd_c => |
c_state <= rd_d; |
dout <= sSDA; |
iscl_oen <= '1'; -- keep SCL high |
isda_oen <= '1'; -- tri-state SDA |
sda_chk <= '0'; -- don't check SDA |
|
when rd_d => |
c_state <= idle; |
338,6 → 383,7
cmd_ack <= '1'; -- command completed |
iscl_oen <= '0'; -- set SCL low |
isda_oen <= '1'; -- tri-state SDA |
sda_chk <= '0'; -- don't check SDA |
|
-- write |
when wr_a => |
344,16 → 390,19
c_state <= wr_b; |
iscl_oen <= '0'; -- keep SCL low |
isda_oen <= din; -- set SDA |
sda_chk <= '0'; -- don't check SDA (SCL low) |
|
when wr_b => |
c_state <= wr_c; |
iscl_oen <= '1'; -- set SCL high |
isda_oen <= din; -- keep SDA |
sda_chk <= '1'; -- check SDA |
|
when wr_c => |
c_state <= wr_d; |
iscl_oen <= '1'; -- keep SCL high |
isda_oen <= din; -- keep SDA |
sda_chk <= '1'; -- check SDA |
|
when wr_d => |
c_state <= idle; |
360,6 → 409,7
cmd_ack <= '1'; -- command completed |
iscl_oen <= '0'; -- set SCL low |
isda_oen <= din; -- keep SDA |
sda_chk <= '0'; -- don't check SDA (SCL low) |
|
when others => |
|
/trunk/rtl/vhdl/i2c_master_top.vhd
37,10 → 37,10
|
-- CVS Log |
-- |
-- $Id: i2c_master_top.vhd,v 1.3 2002-11-30 22:24:37 rherveille Exp $ |
-- $Id: i2c_master_top.vhd,v 1.4 2002-12-26 16:05:47 rherveille Exp $ |
-- |
-- $Date: 2002-11-30 22:24:37 $ |
-- $Revision: 1.3 $ |
-- $Date: 2002-12-26 16:05:47 $ |
-- $Revision: 1.4 $ |
-- $Author: rherveille $ |
-- $Locker: $ |
-- $State: Exp $ |
47,6 → 47,9
-- |
-- Change History: |
-- $Log: not supported by cvs2svn $ |
-- Revision 1.3 2002/11/30 22:24:37 rherveille |
-- Cleaned up code |
-- |
-- Revision 1.2 2001/11/10 10:52:44 rherveille |
-- Changed PRER reset value from 0x0000 to 0xffff, conform specs. |
-- |
106,6 → 109,7
cmd_ack : out std_logic; |
ack_out : out std_logic; |
i2c_busy : out std_logic; |
i2c_al : out std_logic; |
dout : out std_logic_vector(7 downto 0); |
|
-- i2c lines |
129,6 → 133,9
-- internal reset signal |
signal rst_i : std_logic; |
|
-- wishbone write access |
signal wb_wacc : std_logic; |
|
-- internal acknowledge signal |
signal iack_o : std_logic; |
|
138,15 → 145,15
-- command register signals |
signal sta, sto, rd, wr, ack, iack : std_logic; |
|
-- core enable signal |
signal core_en : std_logic; |
signal ien : std_logic; |
signal core_en : std_logic; -- core enable signal |
signal ien : std_logic; -- interrupt enable signal |
|
-- 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) |
signal tip : std_logic; -- transfer in progress |
signal irq_flag : std_logic; -- interrupt pending flag |
signal i2c_busy : std_logic; -- i2c bus busy (start signal detected) |
signal i2c_al, al : std_logic; -- arbitration lost |
|
begin |
-- generate internal reset signal |
159,10 → 166,12
iack_o <= wb_cyc_i and wb_stb_i and not iack_o; -- because timing is always honored |
end if; |
end process gen_ack_o; |
|
wb_ack_o <= iack_o; |
|
|
-- generate wishbone write access signal |
wb_wacc <= wb_cyc_i and wb_stb_i and wb_we_i; |
|
|
-- assign wb_dat_o |
assign_dato : process(wb_clk_i) |
begin |
186,58 → 195,63
end process assign_dato; |
|
|
-- registers block |
regs_block: process(rst_i, wb_clk_i) |
-- generate registers (CR, SR see below) |
gen_regs: process(rst_i, wb_clk_i) |
begin |
if (rst_i = '0') then |
prer <= (others => '1'); |
ctr <= (others => '0'); |
txr <= (others => '0'); |
cr <= (others => '0'); |
elsif (wb_clk_i'event and wb_clk_i = '1') then |
if (wb_rst_i = '1') then |
prer <= (others => '1'); |
ctr <= (others => '0'); |
txr <= (others => '0'); |
cr <= (others => '0'); |
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); |
when "01" => prer(15 downto 8) <= unsigned(wb_dat_i); |
when "10" => ctr <= wb_dat_i; |
when "11" => txr <= wb_dat_i; |
elsif (wb_wacc = '1') then |
case wb_adr_i is |
when "000" => prer( 7 downto 0) <= unsigned(wb_dat_i); |
when "001" => prer(15 downto 8) <= unsigned(wb_dat_i); |
when "010" => ctr <= wb_dat_i; |
when "011" => txr <= wb_dat_i; |
|
-- 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; |
end if; |
else |
-- clear command bits when done |
if (done = '1') then |
cr(7 downto 4) <= (others => '0'); |
end if; |
-- 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; |
end if; |
end if; |
end process gen_regs; |
|
-- reserved bits |
cr(2 downto 1) <= (others => '0'); |
|
-- clear iack when irq_flag cleared |
cr(0) <= cr(0) and irq_flag; |
end if; |
-- generate command register |
gen_cr: process(rst_i, wb_clk_i) |
begin |
if (rst_i = '0') then |
cr <= (others => '0'); |
elsif (wb_clk_i'event and wb_clk_i = '1') then |
if (wb_rst_i = '1') then |
cr <= (others => '0'); |
elsif (wb_wacc = '1') then |
if ( (core_en = '1') and (wb_adr_i = 4) ) then |
-- only take new commands when i2c core enabled |
-- pending commands are finished |
cr <= wb_dat_i; |
end if; |
else |
if (done = '1' or i2c_al = '1') then |
cr(7 downto 4) <= (others => '0'); -- clear command bits when command done |
-- or arbitration lost |
end if; |
|
cr(2 downto 1) <= (others => '0'); -- reserved bits, always '0' |
cr(0) <= '0'; -- clear IRQ_ACK bit |
end if; |
end if; |
end process regs_block; |
end process gen_cr; |
|
|
-- decode command register |
sta <= cr(7); |
sto <= cr(6); |
251,7 → 265,7
ien <= ctr(6); |
|
-- hookup byte controller block |
u1: i2c_master_byte_ctrl port map ( |
byte_ctrl: i2c_master_byte_ctrl port map ( |
clk => wb_clk_i, |
rst => wb_rst_i, |
nReset => rst_i, |
263,6 → 277,7
write => wr, |
ack_in => ack, |
i2c_busy => i2c_busy, |
i2c_al => i2c_al, |
din => txr, |
cmd_ack => done, |
ack_out => irxack, |
283,20 → 298,23
gen_sr_bits: process (wb_clk_i, rst_i) |
begin |
if (rst_i = '0') then |
al <= '0'; |
rxack <= '0'; |
tip <= '0'; |
irq_flag <= '0'; |
elsif (wb_clk_i'event and wb_clk_i = '1') then |
if (wb_rst_i = '1') then |
al <= '0'; |
rxack <= '0'; |
tip <= '0'; |
irq_flag <= '0'; |
else |
al <= i2c_al or (al and not sta); |
rxack <= irxack; |
tip <= (rd or wr); |
|
-- interrupt request flag is always generated |
irq_flag <= (done or irq_flag) and not iack; |
irq_flag <= (done or i2c_al or irq_flag) and not iack; |
end if; |
end if; |
end process gen_sr_bits; |