Can Someone Help Me Write an I2C Controller

OP #3105255
Rate this post
useful
not useful
1
LIBRARY ieee;
2
USE ieee.std_logic_1164.all;
3
USE ieee.std_logic_unsigned.all;
4

5
ENTITY i2c_master IS
6
  GENERIC(
7
    input_clk : INTEGER := 50_000_000; --input clock speed from user logic in Hz
8
    bus_clk   : INTEGER := 400_000);   --speed the i2c bus (scl) will run at in Hz
9
  PORT(
10
    clk       : IN     STD_LOGIC;                    --system clock
11
    reset_n   : IN     STD_LOGIC;                    --active low reset
12
    ena       : IN     STD_LOGIC;                    --latch in command
13
    addr      : IN     STD_LOGIC_VECTOR(6 DOWNTO 0); --address of target slave
14
    rw        : IN     STD_LOGIC;                    --'0' is write, '1' is read
15
    data_wr   : IN     STD_LOGIC_VECTOR(7 DOWNTO 0); --data to write to slave
16
    busy      : OUT    STD_LOGIC;                    --indicates transaction in progress
17
    data_rd   : OUT    STD_LOGIC_VECTOR(7 DOWNTO 0); --data read from slave
18
    ack_error : BUFFER STD_LOGIC;                    --flag if improper acknowledge from slave
19
    sda       : INOUT  STD_LOGIC;                    --serial data output of i2c bus
20
    scl       : INOUT  STD_LOGIC);                   --serial clock output of i2c bus
21
END i2c_master;
22

23
ARCHITECTURE logic OF i2c_master IS
24
  CONSTANT divider  :  INTEGER := (input_clk/bus_clk)/4; --number of clocks in 1/4 cycle of scl
25
  TYPE machine IS(ready, start, command, slv_ack1, wr, rd, slv_ack2, mstr_ack, stop); --needed states
26
  SIGNAL  state     :  machine;                          --state machine
27
  SIGNAL  data_clk  :  STD_LOGIC;                        --clock edges for sda
28
  SIGNAL  scl_clk   :  STD_LOGIC;                        --constantly running internal scl
29
  SIGNAL  scl_ena   :  STD_LOGIC := '0';                 --enables internal scl to output
30
  SIGNAL  sda_int   :  STD_LOGIC := '1';                 --internal sda
31
  SIGNAL  sda_ena_n :  STD_LOGIC;                        --enables internal sda to output
32
  SIGNAL  addr_rw   :  STD_LOGIC_VECTOR(7 DOWNTO 0);     --latched in address and read/write
33
  SIGNAL  data_tx   :  STD_LOGIC_VECTOR(7 DOWNTO 0);     --latched in data to write to slave
34
  SIGNAL  data_rx   :  STD_LOGIC_VECTOR(7 DOWNTO 0);     --data received from slave
35
  SIGNAL  bit_cnt   :  INTEGER RANGE 0 TO 7 := 7;        --tracks bit number in transaction
36
  SIGNAL  stretch   :  STD_LOGIC := '0';                 --identifies if slave is stretching scl
37
BEGIN
38

39
  --generate the timing for the bus clock (scl_clk) and the data clock (data_clk)
40
  PROCESS(clk, reset_n)
41
    VARIABLE count : INTEGER RANGE 0 TO divider*4; --timing for clock generation
42
  BEGIN
43
    IF(reset_n = '0') THEN               --reset asserted
44
      stretch <= '0';
45
      count := 0;
46
    ELSIF(clk'EVENT AND clk = '1') THEN
47
      IF(count = divider*4-1) THEN       --end of timing cycle
48
        count := 0;                      --reset timer
49
      ELSIF(stretch = '0') THEN          --clock stretching from slave not detected
50
        count := count + 1;              --continue clock generation timing
51
      END IF;
52
      CASE count IS
53
        WHEN 0 TO divider-1 =>           --first 1/4 cycle of clocking
54
          scl_clk <= '0';
55
          data_clk <= '0';
56
        WHEN divider TO divider*2-1 =>   --second 1/4 cycle of clocking
57
          scl_clk <= '0';
58
          data_clk <= '1';
59
        WHEN divider*2 TO divider*3-1 => --third 1/4 cycle of clocking
60
          scl_clk <= 'Z';                --release scl
61
          IF(scl = '0') THEN             --detect if slave is stretching clock
62
            stretch <= '1';
63
          ELSE
64
            stretch <= '0';
65
          END IF;
66
          data_clk <= '1';
67
        WHEN OTHERS =>                   --last 1/4 cycle of clocking
68
          scl_clk <= 'Z';
69
          data_clk <= '0';
70
      END CASE;
71
    END IF;
72
  END PROCESS;
Guest #3112851
Rate this post
useful
not useful
>Russian roulette...
You mean, we all can die from a bad coding?

I have a question about this subject: Does anybody know about I2C 
patents a license issues? I recently was told I2C was under protection 
and has to b licensed for commercial use.
Guest #3128628
Rate this post
useful
not useful
Hi,

I've got an i2c single master-only engine ready, but it kinda requires a 
soft CPU to be useful. Basically it is a module of a System on Chip 
design.

Example access (from the soft CPU core firmware):
1
int i2c_write16(unsigned int addr, unsigned int data)
2
{
3
  MMR(I2C_Ctrl)      = 1-1; // One byte per transaction
4
  MMR(I2C_SlaveAddr) = (addr >> 15) & ~1; // Write address
5
  MMR(I2C_WData)     = (addr >> 8) & 0xff;
6
  wait_ready();
7
  MMR(I2C_WData)     = addr & 0xff;
8
  wait_ready();
9
  MMR(I2C_WData)     = data >> 8;
10
  wait_ready();
11
  MMR(I2C_WData)     = data;
12
  wait_ready();
13

14
  while ((MMR(I2C_Stat) & INACK)); // wait until stop phase reached
15
  if (MMR(I2C_Stat) & NAK) return -1; 
16

17
  return 0;
18
}

In order to draft some pecuniary house numbers of the support expenses, 
you might have to post more about the requirements (what HW it should 
support, what soft core you'd be using, etc. )
BTW: No need to worry about any licensing issues, the patent has expired 
a while ago.

Greetings,

Butze
Guest #3152069
Rate this post
useful
not useful
is this project still open? i could provide you with a working scalable 
iwc controller offering a dynamic number of inputs and outputs 
configurable by genererics, data is stored in brams

it comes complete with testbench and implementation example for both 
xilinx and altera devices

Reply

Please log in before posting.

or

Log in with Google account

Registration is free and takes only a minute.

Register now