Firmware Emulation of An I2c Slave Device 12
Firmware Emulation of An I2c Slave Device 12
Firmware Emulation of An I2c Slave Device 12
The I2C standard is covered by patents owned by the Philips Semiconductor spin-off,
NXP, created in 2006. In October 2000, Philips was aggressively enforcing these patents,
filing a lawsuit against six semiconductor companies. However, according to NXP’s
website, "I²C licenses under the remaining patents in the program will be free of any
royalties, for any use of the patents after October 1, 2006, without any prejudice to any
claims for past use whatsoever. Also the fee for obtaining an I²C slave address allocation
will not be affected and will continue to apply until further notice.”
I2C Overview
The I2C interface is a shared two-wire serial bus. The bus allows communication
between a single master and a single slave at any given time, but multiple masters and
slaves can share the same bus. CPU devices are typically masters and peripheral devices
are usually slaves. The master device initiates the transaction and provides the clock. The
slave devices are identified by a 7-bit address, theoretically allowing up to 127 slave
devices on any I2C bus. Fig. 1 shows the I2C bus topology.
VCC
SCL
SDA
I2C defines two special bus conditions called START and STOP see Fig. 2). START
occurs when there is a falling edge on SDA with SCL held high. After the START
condition, the master drives SCL low, and then sends the address byte. A STOP condition
is the opposite of START, a rising edge on SDA with SCL high. During normal DATA
and ACK transmission, the data bus is stable when SCL is high, transitioning when SCL
is low. The bus is idle when both lines are 1 (VCC).
SCL and SDA are both wired-or signals implemented with open-collector/open-drain I/O
cells. Open collector signals are driven low, but not driven high. The bus is pulled high
by a resistor attached to VCCIO. This allows multiple devices to share the bus at the
same time and minimizes concerns about transitions between transmission and reception.
The use of wired-or signals even allows multiple master devices to collide on the bus
without damaging each other’s drivers.
START
SDA STOP
SCL
Data changes
Clock pulse:
Data stable
The primitives defined in Fig. 3 will be used by the higher-layer code below.
Init()
{ OEA &= ~bmSDA; OEA &= ~bmSCL; // float the i/os
SDA = 0; SCL = 0;} // Drive 0 when on
Drive1()
{ OEA &= ~bmSDA; } // Allow pullup to work
Drive0()
{ OEA |= bmSDA; } // Drive to 0
On a slave device, the bit-level protocol is the hardest part of I2C to implement because
of the strict timing requirements in the spec. In a 100-kHz device the master can begin
sending SCL pulses 4 µs after START. In a 400-kHz device this limit is just 600 ns!
Another option is to engineer your ISR so that it can operate with a starting point in the
acceptable region shown below. This adds one SCL low time to your latency for a total
of 8.7 µs at 100 kHz. Once you have seen the START, you can either stay in the ISR to
process the data, or trigger another ISR on the rising edge of SCL. This ISR will also
have to be very low latency, since the data are only guaranteed to be stable when SCL is
high. This tHIGH parameter is 4 µs at 100 kHz, but only 600 ns at 400 kHz. In this
example implementation, we remain in a loop watching SCL and SDA until STOP.
START
400kHz = 600nSec
100kHz = 4 uSec
Best ISR latency
SDA
SCL
If your device cannot always meet these requirements and you can change the master
device, there are two options in the spec to allow for longer timing. One is for the host to
transmit a dummy address (0000 0001) called a start byte to allow the ISR to start. This
start byte is not used as an address by any device. This increases the allowable latency to
a full START+BYTE+ACK time, almost 10 SCL clocks. Another option is to build
retransmission capability into the master driver. If the slave device fails to ACK its
address the first time, simply issue another START and transmit the address again.
enable_SDA_interrupt();
return;
}
Fig. 5: SDA ISR Detects START, Then Reads Or Sends Data As Needed
Once a START has been detected, the next task is to read the address sent by the master
and compare it to our slave address. This is done by a generic read routine that can read
addresses or data. The only difference between reading an address and reading data is
that the slave device should only ACK its own address, while it should ACK all data it
receives. This routine returns a WORD rather than a BYTE to allow special conditions
(STOP, START) to be returned.
The readI2CSlaveByte() routine shown in Fig. 6 waits for the clock to become high,
signaling that the data line is stable and can be read. The data bit is stored, and the routine
waits for another low to high transition on SCL until 8 bits have been read. While SCL is
high, SDA is monitored for START or STOP conditions.
return retval;
}
0 STOP or
Addr mismatch
1
WAIT FOR RECEIVE
START ADDRESS
Addr match,
STOP rw bit = 0
Addr match,
START rw bit = 1
STOP START
3 2
SEND RECEIVE
DATA DATA
SCL pulses
SCL pulses
References