The Software for Minimal I2C
The Software for Minimal I2C
Are you an I2C noob? If so, check out this article before trying to port the source code.
Before we actually get into the software, these diagrams show how the bus is hooked up to the CPU.
If the CPU has the capability of driving open collector output lines and reading their state directly, then the I2C hardware connection couldn't be easier. The 5k pullup resistors make the two bus lines float high if no device on the bus is pulling them low. There is a tradeoff between the resistor value and the capacitance load on the lines. If the resistance is too high, then more devices on the bus tend to increase capacitance, and the signals are less square, leading eventually to failures. If the resistance is too low, then the weakest devices on the bus will not be able to sink enough current to drive the lines to logical 0.
If open collector lines are not available, it would be possible to use 2 outputs, and 2 input lines to accomplish the same thing. The diodes simply prevent the Out0 and Out1 output lines from driving the I2C lines high.
C - language Source code for Minimal I2C
The following source code is an example of a minimal I2C implementation. It was actually translated from FORTH, so this may contain some small mistakes.
CPU-Dependent Primitives
The following bits are implementation-dependent code, which will vary depending on which CPU is being used.
#define SCLOUT( val ) set_p0_state( val ) /* CPU Dependent function to set p0 to low-state val=0, or float val=1 */
#define SDAOUT( val ) set_p1_state( val )
#define SCL_IN get_p0_state() /* Returns 1 if p0 is high, or 0 if p0 is low. */
#define SDA_IN get_p1_state()
#define MSEC_DELAY(usec) cpu_dependent_delay(usec) /* Waste time for some microseconds (not milliseconds) */
typedef unsigned char BYTE
Initialization
The first software step is to initialize the io ports to be open collector outputs, and then put the bus into an idle state. An idle state is where both lines are high. It may also be a good idea to generate aSTOP condition on the bus before putting it idle.
void i2c_setup()
{
set_p0_open_collector(); /* Implementation dependent - must be made to match your CPU */
set_p1_open_collector();
SCLOUT(0); /* Generate a STOP condition */
SDAOUT(0);
SCLOUT(1); /* SCL is high */
MSEC_DELAY(10); /* Wait */
SDAOUT(1); /* Now cause a low-to-high transistion on SDA */
}
I2C Start and Stop Conditions
The following code implements the I2C Start and Stop conditions using the primitives defined above.
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\\ void i2c_do_stop(void) \\ puts data low, then clock low, \\ then clock high, then data high. \\ This should cause a stop, which \\ should idle the bus, I.E. both clk and data are high. \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ void i2c_do_stop(void) { SCLOUT(0); MSEC_DELAY(10); SDAOUT(0); MSEC_DELAY(10); SCLOUT(1); MSEC_DELAY(10); SDAOUT(1); } \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ \\ void i2c_do_start(void) \\ Sets clock high, then data high. This will do a stop if data was low. \\ Then sets data low, which should be a start condition. \\ After executing, data is left low, while clock is left high \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ void i2c_do_start(void) { SCLOUT(1); SDAOUT(1); MSEC_DELAY(10); SDAOUT(0); MSEC_DELAY(10); \\ waste time }
Next - More I2c Source Code
|
Last Updated on Sunday, 17 May 2009 13:52 |