Welcome to PLD World! ??????????????! http://pld.126.com

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.

f5_1.gif (1959 bytes)

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

arrow.gif (4190 bytes) here

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:

i2cport1.gif (1686 bytes)

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:

i2cport2.gif (2453 bytes)

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:

i2csima.gif (16375 bytes)

Simulation 250.0 - 550.0us:

i2csimb.gif (15987 bytes)

Simulation 500.0 - 800.0us:

i2csimc.gif (15113 bytes)

Simulation 700.0 - 1000.0us:

i2csimd.gif (14159 bytes)

??


 ????: ??  ????: ??? Copyright 1999-2000 PLD World    http://pld.126.com