More on I²C
This topic a continuation of the discussion started in Sending and Receiving Data.
I²C (and many existing variations on it) relies on a single data line (called "SDA") for data transmission in both directions. The DO and DI lines of an SSI channel must be joined together. On devices with unidirectional I/O lines, the ssi.zmode property must be set to 1 — PL_SSI_ZMODE_ENABLED_ON_ZERO (not required on devices with bidirectional I/O lines). The DO line will then operate in the following manner:
- To set the DO line HIGH, your device will disable the output buffer. The line will then float HIGH (because of "weak pull-ups" in the device). In this state, the slave SSI device can safely output its own data onto the SDA.
- To set the DO line LOW, your device will enable the output buffer and set the output to LOW.
It follows then, that if your DO and DI lines are joined together and you want to receive data from the slave device, you should keep your own output at "all 1s" while the slave device is supposed to send data, like this:
...
ssi.str("\x40\x12\xFF",1) 'we anticipate that the slave device will reply after we output two bytes of our own data
...
Each I²C transaction requires so-called start and stop sequences — the ssi. object won't handle this, so you need to implement this in code. Below is a snippet from a real application. Notice how necessary transitions on the SDA line are performed by setting the DO line LOW and then enabling/disabling its output buffer.
...
i2c_start()
ssi.str("\x40\x12\xFF",1) 'output data, with acknowledgements enabled
i2c_stop()
...
'------------------------------------------------------------
Sub i2c_start()
io.lineset(SSI_CLK,HIGH)
io.num=SSI_DO 'set SDA to HIGH first so we can have HIGH->LOW transition
io.state=LOW 'we are manipulating data line through the OE register
io.enabled=NO
io.enabled=YES 'this will set the data output to LOW
End Sub
'------------------------------------------------------------
Sub i2c_stop()
io.lineset(SSI_CLK,LOW) 'this will remove the ack bit
io.num=SSI_DO 'set SDA to LOW first so we can have LOW->HIGH transition
io.state=LOW 'we are manipulating data line through the OE register
io.enabled=YES
io.lineset(SSI_CLK,HIGH)
io.enabled=NO 'this will set the data output to HIGH
End Sub