| |
FreeCore Function #5:
I2C Controller
Module name: I2C
Current release: version 3.0, January 29, 1998
Contributed by: Rune Baeverrud
Changes since version 2.0
- The I2C Controller now operates on a "fine-grain" time scale, speeding up I2C
bus transfers significantly. I've been doing a lot of simulations on this controller now,
and I believe the timing to comply 100% with the I2C standard.
- It should not be possible to violate any I2C bus timing standard by exercising the
inputs in any way.
- The I2C Controller now instantiates the div_by_n module internally, which has to be
version 2.0 or later.
- The BaudGen input has been removed - there's now a clk_en input instead.
- It is now possible to instantiate and use the I2C controller directly - without using an
external div_by_n module. In this case you would tie clk_en to VCC and supply a suitable
DIVISOR parameter value.
- It is very difficult to simulate the SDA and SCL signals on the I2C port, because these
are bidirectional signals using external pull-up resistors. Doing some minor modifications
in the source file, as explained in the source file, you can now compile two different
versions of the I2C Controller - one model suitable for target simulation - and one model
suitable for target physical device.
Changes since version 1.0
- Fixed Status signal. Status sometimes misbehaved, caused by an error in the
implementation. This may also have caused problems for anyone who tried to use the
repeated start condition, since the same signal was used internally.
- Fixed wait state generation. The slave device was not able to slow down the bus
(inserting wait states) by pulling SCL low during stop and repeated start conditions.
- DValid and DEnable no longer goes high when the last data bit has been transferred - but
instead when the acknowledge bit has been transferred. This makes interfacing to the I2C
Controller easier.
- Added asynchronous reset.
- Added simulation file with full documentation, explaining everything that could possibly
go on.
Clock speed and resource usage in I2C Controller version 3.0
I compiled this with with the following options:
- MAX+PLUS II version 8.1
- Target EPF10K10LC84-3
- NORMAL synthesis style
- Speed/Area slider set to "10"
- Applying timing constraints
- DIVISOR parameter value set to 25
Achieved results:
- 86 Logic Cells resource usage
- 84 MHz system clock speed.
Description
Shown below is the I2C ("I squared C") controller module.
The controller has the following key features:
- Designed for Master operation in Single Master systems. Multiple masters are not
supported.
- Wait states are supported by slaves forcing SCL low.
- Repeated start condition is supported.
- Status & Control signals are provided for easy interfacing with logic or
microcontroller.
- All I2C timing complies with the I2C bus standard.
You will probably find that this controller is stable and very easy to use.
Pin and Parameters Description
PARAMETERS |
DIVISOR |
The DIVISOR value should be set to ((the input frequency on clk_en) /
(400kHz)). For instance: If your system clock frequency is 50MHz, and you use the div_by_n
module externally to generate a 10MHz clock enable signal, you could apply this 10MHz
signal to clk_en. You should then set the divisor value to 10MHz / 400kHz = 25. This would
be equivalent to using a 10MHz system clock frequency and tie clk_en to VCC. |
INPUT PORTS |
SysClk |
System clock input. |
clk_en |
Clock Enable input. Can be tied to VCC if using an appropriate DIVISOR
parameter value. |
/reset |
Asynchronous reset of all registers within the I2C Controller. |
Din[7..0] |
Parallel data input. |
Ack_Tx |
Acknowledge to send, when in receiver mode. |
Cmd_Stop |
Generate STOP condition on I2C port. |
Cmd_Start |
Generate START condition and send slave address on I2C port. |
Cmd_Send |
Send a byte to I2C port. |
Cmd_Receive |
Receive a byte from I2C port. |
Execute |
After Execute goes to logic high then on the next positive edge of SysClk,
Din[], Ack_Tx, Cmd_Stop, Cmd_Start, Cmd_Send, Cmd_Receive will be sampled, and execution
will start. |
OUTPUT PORTS |
Dout[7..0] |
Parallel data output. Always reflects the internal transmission shift
register, so it's value is not always valid. |
Ack_Rx |
Last received acknowledge. |
Status |
I2C bus has been claimed. Logic high between START and STOP conditions. |
DValid |
Logic high when Dout[] is valid. Goes active immediately after the
acknowledge bit has been transferred. |
DEnable |
Like DValid, but remains high for one system clock (SysClk) period only. |
Busy |
While Busy is high, no new commands are accepted. In fact, Execute has to
go low for Busy to go low, so that new commands can be accepted. |
SDA |
I2C data |
SCL |
I2C clock |
Explaining the Operation
Output signals DValid, DEnable, Ack_Rx and Dout[] are also active during
send mode, so these signals may be used for implementing the logic or microprocessor
interface. When in send mode, the sent data will also be received at the same time.
The Busy output must be low when the Execute input is pulled high, or else
the command will not be accepted. The Busy output will remain high as long as Execute
remains high or a command is in execution.
When Busy is low, and Execute goes high, then on the next SysClk rising
edge the Din[], Ack_Tx, Cmd_Stop, Cmd_Start, Cmd_Send, Cmd_Receive will be sampled. Only one
of of the Cmd_* lines are allowed to be logic high, or else the operation of the
controller will be unpredictable. The value of Ack_Tx is only meaningful if the
Cmd_Receive command is issued.
When using the I2C module in a MAX device, you
will need to issue a stop condition as the first command after a system reset, for the SDA
and SCL lines to go high impedance (external pull-up) state. This is not necessary in a
FLEX device. The reason for this is that inverted outputs are unsupported in MAX, so a NOT
gate pushback occurs during compilation for these devices.
Instruction Set
INSTRUCTION |
DESCRIPTION |
Cmd_Start |
Generates a START condition on the I2C port, and continues to send the byte loaded on
the Din[] input port. The value of the Din[] port should therefore be the correct slave
address with the R/W bit set accordingly. This command will automatically generate a
repeated start condition if the I2C bus was already claimed and a Cmd_Stop command was not
issued prior to Cmd_Start. |
Cmd_Stop |
Generates a STOP condition on the I2C port. |
Cmd_Send |
Send data from the Din[] input port to the I2C port. |
Cmd_Receive |
Receive a byte from the I2C port and present it on the Dout[] port. |
Simulations
In the simulations below I've only been interested in simulating different
physical conditions, and higher level protocols determining what is a slave address, data
byte, R/W bit and so on is of no interest here. For more information on the I2C standard
and how to use it, I suggest you download the Philips application note "The I2C-bus
and how to use it" (3114.PDF) from the Philips web site. Last time I checked - I
found it at this web address: http://www-us.semiconductors.philips.com/cgi-bin/searchcat?cat=3999&code=16
The following section will hopefully clarify any question you might have
about the functionality of the I2C Controller core. I suggest you download the I2C.SCF
file - which you can open in the MAX+PLUS II Waveform Editor. Alternatively, you can look
at the simulation in the images below. To download the I2C.SCF file, click
Please be aware that simulation of an external pull-up bus like the I2C
bus is very difficult with MAX+PLUS II. If you try to change anything in the simulation
file - you must first run one simulation, and then fix the bus contention errors by
setting the SDA and SCL inputs (NOT the SDA and SCL outputs) to appropriate high, low or
tristate values. This is very tedious. The reason for this diffuculty is that you cannot
define an input to be weak high - like you would with an external pull-up resistor.
Instead you must impose a tristate on the input when the output is driving low, and impose
a high or low on the input when the output is not driving low.
This is how the the SDA and SCL ports really looks like when compiling for
a physical device target:
The reason for the inverters before and after the register, is that the
device powers up with all registers cleared. By doing it this way, the I2C bus will power
up with both SDA and SCL high.
When compiling for a simulation target, the SDA and SCL ports looks like
this, easing simulation tremendously:
When compiling for a simulation target, there is also two additional
output signals available:
- baudout shows the internal clock enable to which all I2C bus activity is synchronized.
This signal is generated by the div_by_n module, and it's counter value can be reset at
any time by pulling sclr high. This feature is used when a slave forces wait states by
pulling SCL low, and the next baudout event will then be delayed accordingly.
- sclr is the signal that clears the div_by_n module internal counter.
Simulation File Description
Please note that the simulations below has been performed using functional simulation
only, so they should be easy to recreate.
TIME |
EVENT |
0.0us |
I2C bus is idle. |
10.8us |
Execute goes high. All other inputs must be stable at this time. A start
command is given. H’55 is present at the Din[] input, to be sent onto the I2C
bus immediately after the start condition. |
10.9us |
All inputs are sampled at the first SysClk edge. Busy goes high, meaning
no more commands will be accepted until Busy goes low again. |
12.6us |
Status goes high – indicating that the I2C bus has been claimed
by the I2C controller. |
12.6 – 17.6us |
The start condition is presented on the I2C bus. |
20.1 – 107.6us |
H’55 is sent onto the I2C bus |
27.6 – 105.1us |
SDA is sampled on the falling edge of SCL, in both send and receive
modes. You can see this on Dout[] which always reflects the current value of the
transmission shift register. When you send data, you should be
‘receiving’ the data you send at the same time. At 105.0us –
you can see that H’55 has been ‘received’ or read back from
the I2C bus into the I2C controller. This could be a good debugging tool when your I2C bus
does not behave like expected. |
48.5 – 60.0us |
The slave is forcing wait states by pulling SCL low. |
47.5 – 102.5us |
Various activity on Execute, Cmd_stop, Cmd_start, Cmd_send or Cmd_receive
have absolutely no effect while Busy is high. |
115.1us |
The acknowledge bit present on the I2C bus is sampled, and the value
sampled on SDA will immediately be available on the Ack_rx line. DValid goes high
– indicating that valid data is present at the Dout[] output. DEnable goes high
for one system clock period – very useful for interfacing to external interface
logic, generating interrupts, etc. |
155.0us |
Execute is taken low. It is not necessary to keep Execute high for long
periods of time. It is only necessary to pulse Execute high – long enough for it
to be sampled on the next system clock (SysClk) pulse. In this case – with a
SysClk frequency of 10MHz – a 100ns pulse would be more than sufficient. |
155.1us |
Busy goes low. Busy will not go low until both these conditions are met:
- The current instruction has finished execution.
- Execute is taken low after the instruction has finished.
In this case - the high state of Execute forced Busy to remain high after the
instruction itself had finished execution. If Execute had been taken low before the
instruction itself had finished, Busy would have gone low at 117.6us. |
164.4us |
The stop command is given. |
164.5us |
Busy goes high. DValid goes low – indicating that data present
at the Dout[] output is no longer valid. |
172.6us |
Status goes low – the I2C bus is now free. |
173.0us |
The start command is given, and H’AA at the Din[] input will be
sent onto the I2C bus. |
173.1us |
Inputs are sampled and Busy goes high. |
175.1us |
Status goes high again – indicating that the I2C bus has been
claimed. |
175.1 – 180.1us |
The start condition is presented on the I2C bus. |
182.6 – 262.6us |
H’AA is transmitted on the I2C bus. |
270.1us |
The acknowledge bit present on the I2C bus is sampled, and Dout[],
Ack_rx, DValid and DEnable will all be valid. |
282.5us |
Another start command is given – without first supplying a stop
command. |
292.6 – 297.6us |
Since no stop command was given – a repeated start condition is
presented on the I2C bus, and H’11 will be sent on the I2C bus. |
390.0 – 410.0us |
The slave device is forcing SCL low. |
399.6us |
Yet another start command is given – without first issuing a
stop command. |
415.1 – 420.1us |
The repeated start condition is presented on the I2C bus, but is being
delayed by the slave forcing SCL low. |
524.0us |
A Send command is given, and H’33 will be sent onto the I2C
bus. |
654.0us |
A receive command is given. This time it is important to set the value of
the Ack_tx input before issuing the command! This value will be the I2C acknowledge from
the I2C controller to the slave after the data has been received from the slave on the I2C
bus. |
694.0 – 712.0us |
The slave is slowing down the I2C bus (forcing wait states) by pulling
SCL low. |
764.5 – 793.5us |
The slave is slowing down the I2C bus (forcing wait states) by pulling
SCL low. |
776.5us |
A Stop command is given, but the execution is delayed caused by the slave
forcing SCL low. |
793.5 – 798.6us |
The stop condition is presented onto the I2C bus. |
815.0us |
Another Start Command is given, and H’55 is scheduled to be
sent onto the I2C bus. |
880.0us |
/reset goes low – all registers are cleared and all activity is
reset to a known default state. |
Simulation 0.0 - 300.0us:
Simulation 250.0 - 550.0us:
Simulation 500.0 - 800.0us:
Simulation 700.0 - 1000.0us:
??
| |
|