I2C slave

F

Frank Buss

Guest
I've written a I2C slave core:

http://www.frank-buss.de/vhdl/i2c_slave-0.1.zip

It should work with 100 kB and 400 kB master devices and it supports
sending and receiving multiple bytes and the repeated start condition.
Stretching clock cycles is not supported, the host which uses the core must
be fast enough.

Currently I've tested it in a simulator, only, maybe someone could test it
on real hardware, e.g. with the included testdevice and a hardware master,
like built-in in some microcontrollers.

I'm not sure about the communication concept: Currently it doesn't use
handshaking, but the slave entity signals, that a byte was received and
some cycles later releases this signal. I think it is easier to use, but
maybe a more standard interface like Wishbone would be better?

The licence is BSD and if you have bugfixes or other improvments, I'll add
it and publish it again. When it is mature, I'll plan to submit it to
opencores.org.

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
 
Frank Buss wrote:
I've written a I2C slave core:

http://www.frank-buss.de/vhdl/i2c_slave-0.1.zip

It should work with 100 kB and 400 kB master devices and it supports
sending and receiving multiple bytes and the repeated start condition.
Stretching clock cycles is not supported, the host which uses the core must
be fast enough.

Currently I've tested it in a simulator, only, maybe someone could test it
on real hardware, e.g. with the included testdevice and a hardware master,
like built-in in some microcontrollers.

I'm not sure about the communication concept: Currently it doesn't use
handshaking, but the slave entity signals, that a byte was received and
some cycles later releases this signal. I think it is easier to use, but
maybe a more standard interface like Wishbone would be better?

The licence is BSD and if you have bugfixes or other improvments, I'll add
it and publish it again. When it is mature, I'll plan to submit it to
opencores.org.

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Hi Frank

I'll drop it in and test it on real hardware in a couple of weeks (when
I get the latest and greatest back from fab and stuffing).

One thing I did note: the SDA output should be either Hi Z or 0 - it
should never be driven high. The standard actually specifies open
collector, but Hi Z for high works the same way :)

Cheers

PeteS
 
PeteS wrote:

I'll drop it in and test it on real hardware in a couple of weeks (when
I get the latest and greatest back from fab and stuffing).
Thanks.

One thing I did note: the SDA output should be either Hi Z or 0 - it
should never be driven high. The standard actually specifies open
collector, but Hi Z for high works the same way :)
I don't see a problem. In the ports section I've defined this:

sda_io: inout std_logic;

And then in the architecture this:

signal sda_o: std_logic := '1';
signal sda_i: std_logic := '0';

....

begin

....

sda_io <= sda_o when sda_o = '0' else 'Z';
sda_i <= '1' when sda_io /= '0' else '0';
read_mode_o <= read_mode;

At least this worked for my 1-wire implementation with Xilinx (
http://www.frank-buss.de/vhdl/spartan3e.html ), which I've tested with real
hardware, so I assume the synthesis tool infers something compatible with
open collector for it, but I'm a VHDL beginner, so maybe there is a better
solution.

BTW: is there any drawback to define "scl_i: in std_logic"? It's a I2C
slave, only and I don't support clock stretching, so I hope it is ok to
define it just as input.

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
 
Frank Buss wrote:
PeteS wrote:

I'll drop it in and test it on real hardware in a couple of weeks (when
I get the latest and greatest back from fab and stuffing).

Thanks.

One thing I did note: the SDA output should be either Hi Z or 0 - it
should never be driven high. The standard actually specifies open
collector, but Hi Z for high works the same way :)

I don't see a problem. In the ports section I've defined this:

sda_io: inout std_logic;

And then in the architecture this:

signal sda_o: std_logic := '1';
signal sda_i: std_logic := '0';

...

begin

...

sda_io <= sda_o when sda_o = '0' else 'Z';
sda_i <= '1' when sda_io /= '0' else '0';
read_mode_o <= read_mode;

At least this worked for my 1-wire implementation with Xilinx (
http://www.frank-buss.de/vhdl/spartan3e.html ), which I've tested with real
hardware, so I assume the synthesis tool infers something compatible with
open collector for it, but I'm a VHDL beginner, so maybe there is a better
solution.

BTW: is there any drawback to define "scl_i: in std_logic"? It's a I2C
slave, only and I don't support clock stretching, so I hope it is ok to
define it just as input.

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Hi Frank
My oops :)

I was looking at the logical assignemtns, not the IO assignment at the
end.

As to SCL - it should be just an input as you don't support clock
stretch, and that looks fine to me. Note I am more comfortable in 'that
other HDL language' but as far as I can see this unit looks good.

I'll drop it into my design and testbench tonight and see what happens!

Cheers

PeteS
 
PeteS wrote:
Frank Buss wrote:

PeteS wrote:


I'll drop it in and test it on real hardware in a couple of weeks (when
I get the latest and greatest back from fab and stuffing).

Thanks.


One thing I did note: the SDA output should be either Hi Z or 0 - it
should never be driven high. The standard actually specifies open
collector, but Hi Z for high works the same way :)

I don't see a problem. In the ports section I've defined this:

sda_io: inout std_logic;

And then in the architecture this:

signal sda_o: std_logic := '1';
signal sda_i: std_logic := '0';

...

begin

...

sda_io <= sda_o when sda_o = '0' else 'Z';
sda_i <= '1' when sda_io /= '0' else '0';
read_mode_o <= read_mode;

At least this worked for my 1-wire implementation with Xilinx (
http://www.frank-buss.de/vhdl/spartan3e.html ), which I've tested with real
hardware, so I assume the synthesis tool infers something compatible with
open collector for it, but I'm a VHDL beginner, so maybe there is a better
solution.

BTW: is there any drawback to define "scl_i: in std_logic"? It's a I2C
slave, only and I don't support clock stretching, so I hope it is ok to
define it just as input.

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de


Hi Frank
My oops :)

I was looking at the logical assignemtns, not the IO assignment at the
end.

As to SCL - it should be just an input as you don't support clock
stretch, and that looks fine to me. Note I am more comfortable in 'that
other HDL language' but as far as I can see this unit looks good.

I'll drop it into my design and testbench tonight and see what happens!

Cheers

PeteS

I dropped this into a design I am doing (only at simulation stage as of
yet) and all seems to operate properly.

The one thing I notice is when I push the speed I get invalid data (but
that's at a few 10s of Mb/s, which is _way_ beyond the spec). Might be
useful to set a constraint or two to see if I can get more speed out of
it. Of course, there's a lot of other stuff in the device I am
simulating, so that's a pretty common issue.

I will note that I usually push such things (I2C, SMBus, SPI etc) to at
least 20x normal speed in simulation to account for PCB capacitance. If
it still operates Post PAR at that, I know it'll operate properly at
'normal' rates.

If you don't mind, I might add some conditionals for SMBus (which has
timeouts that can be useful in hotswap). I2C can lock up in such
situations where SMBus can recover.

Cheers

PeteS


Cheers

PeteS
 
PeteS wrote:

The one thing I notice is when I push the speed I get invalid data (but
that's at a few 10s of Mb/s, which is _way_ beyond the spec).
I think you'll get many problems with I2C at this speed, because you need
very low resistors to load the parasitic capacitance in the open collector
cicuit, but the I2C spec defines a special HS-mode up to 3.4 Mbit/s and
gives some advice how to design the circuit for it. But there might be
still problems if there are not enough FPGA clock cycles per I2C clock
cycles (e.g. you have to delete the data hold counter section, which is
needed for low speed, improve the bit and logic level handshaking speed
etc.).

If you don't mind, I might add some conditionals for SMBus (which has
timeouts that can be useful in hotswap). I2C can lock up in such
situations where SMBus can recover.
I've read the SMBus specification and looks like it has some advantages,
e.g. lowest speed is 10 kHz, which allows fast timeouts, so you can add it.

But I don't think that it is absolute necessary to avoid lock ups, because
for the slave a start or a stop signal resets the transfer state,
regardless in which state it is. And for the master the I2C specification
says, that if it doesn't receive an ACK, it should send a repeated start or
a stop signal.

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
 
Frank Buss wrote:
PeteS wrote:


The one thing I notice is when I push the speed I get invalid data (but
that's at a few 10s of Mb/s, which is _way_ beyond the spec).


I think you'll get many problems with I2C at this speed, because you need
very low resistors to load the parasitic capacitance in the open collector
cicuit, but the I2C spec defines a special HS-mode up to 3.4 Mbit/s and
gives some advice how to design the circuit for it. But there might be
still problems if there are not enough FPGA clock cycles per I2C clock
cycles (e.g. you have to delete the data hold counter section, which is
needed for low speed, improve the bit and logic level handshaking speed
etc.).


If you don't mind, I might add some conditionals for SMBus (which has
timeouts that can be useful in hotswap). I2C can lock up in such
situations where SMBus can recover.


I've read the SMBus specification and looks like it has some advantages,
e.g. lowest speed is 10 kHz, which allows fast timeouts, so you can add it.

But I don't think that it is absolute necessary to avoid lock ups, because
for the slave a start or a stop signal resets the transfer state,
regardless in which state it is. And for the master the I2C specification
says, that if it doesn't receive an ACK, it should send a repeated start or
a stop signal.

The issue is that I2C will send the repeated start / stop but never
return to the idle state without a valid transition. SMBus incorporates
a timeout to alleviate this issue. I've had to deal with this on real
boards, so I know it's a real problem.

I'll do that stuff tomorrow :)

Cheers

PeteS
 
Frank Buss wrote:

Currently I've tested it in a simulator, only, maybe someone could test it
on real hardware, e.g. with the included testdevice and a hardware master,
like built-in in some microcontrollers.
Today I tested it with real hardware and the I2C address was detected with
a reliability of about 20% only. And I discussed the code with a workmate
and he excoriate the code, expecially the very long and complicated state
machines. But don't worry, currently I'm rewriting it with many more simple
processes instead of two big ones and the address detection works already
with about 100% reliability :)

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
 
Hi Frank,

I am trying to simulate it with ModelsimDesigner.

Where do I get the UNISIM library from ?

Rgds
André
 
ALuPin@web.de wrote:

I am trying to simulate it with ModelsimDesigner.

Where do I get the UNISIM library from ?
You don't need it, this was a copy-and-paste error from another project.

I've updated the project and I think the code is better now. A non-I2C
conforming (but useful in real systems) timeout is included, to avoid
lowering SDA too long. To filter out spikes (the I2C specification says 50
ns has to be filtered) a 4 bit shift register accumulates SCL and SDA and
rising and falling edges are detected only, if the shift register contains
"1100" or "0011". I2C master writing to the slave worked on my new T-Rex.

For testing writing, reading and combinations with repeated start, I've
implemented a PCA9555 GPIO in VHDL and enhanced the testbench, which
worked. Tomorrow I can test it with a hardware master, which already
communicates with a PCA9555 chip.

The new version:

http://www.frank-buss.de/vhdl/i2c_slave-0.2.zip

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
 
Frank Buss wrote:

Tomorrow I can test it with a hardware master, which already
communicates with a PCA9555 chip.
There were still some bugs, which I didn't detect with the testbench, but
now it works with real hardware: I've tested it in fast mode with a master
of an ARM PXA and in standard mode with a master of a HCS08. The HCS08 test
program is included, I've organized the directory structure to the
recommendations of OpenCores, added some documentation with logic analyzer
samples and commented the VHDL code a bit better. The new version:

http://www.frank-buss.de/vhdl/i2c_slave-0.3.zip

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
 
A new version:

http://www.frank-buss.de/vhdl/i2c_slave-0.4.zip

While integrating it in a production system, I found a bug when the slave
was sending multiple bytes: only the first data request was signaled by the
i2c_slave core. After fixing it, sending and receiving 128 bytes in an
endless loop, together with other devices on the same bus, works without
problems.

And I've added and tested a Spartan 3 Start Kit project for the PCA9555
test implementation.

Today my OpenCores account was approved, the next release will be at
www.opencores.org.

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
 

Welcome to EDABoard.com

Sponsor

Back
Top