PDA

View Full Version : Small I2C driver



deSilva
01-22-2008, 06:27 AM
I have looked through the current I2C drivers and found them all - well - quite corpulent...
So I decided to post my "small footprint driver" - including a test program exercising the well known PCF8574A port expander. (Note the PCF8574 has a different device address; I have A-types as they were a bargain....)

It is still "version 1", so I should be grateful for problem reports..



'' MPE_I2C_001 (mod)
'' Minimal I2C driver 2008-01 by deSilva


' ----- The following section is a test routine
_clkmode = xtal1 + pll8x
_xinfreq = 10_000_000
EEPROM = $A0
DEVICE = $70
LEDPIN = 25

PUB checkOut | x , status
{
This checks my minimal I2C driver, using a PCF8574A port expander
When an LED is connected from LEDPIN to Vcc it will indicate a device error.

+───A───────┐
+───B─────┐ │
+───C───┐ │ │
+─  ─┐ │ │ │
│ │ │ │
+ D C I │ │ │ │
┌┴─┴─┴─┴─┴─┴─┴─┴┐
│(8574) 7 6 5 4│
│ 0 1 2 3 │
└┬─┬─┬─┬─┬─┬─┬─┬┘
- - -     -
C B A

I/O 4,5,6,7 of the PCF will be configured as OUTPUT (0)
I/O 0,1,2,3 as INPUT / active low
Connect LEDs to 4,5,6 (resistors to high, as this is a kind of open drain chip)
Each of them will light when I/O 1,2,3 resp. are set LOW
As those pins are just opposite, I reversed the bits to make it look better

I/O 0 is special: As long as it's low a 1.5 kHz signal is output at I/O 7
and I/O 4,5,6 are all three on.

Note that inputs are HIGH by default as with the old TTLs
}

REPEAT
REPEAT
engage
status := snd(DEVICE)
status |= snd(%0000_1111|(x><8)) ' 8 I/O pins:
' 0: output (driven low)
' 1: input (tri-state)
'release

engage
status |= snd(DEVICE+1)
x := rcv
'release
DIRA[LEDPIN]:=status
WHILE x&1


engage
snd(DEVICE)
REPEAT 1500
snd(%1000_1111)
snd(%0000_1111)
release



' ===========Here starts deSilva's small I2C driver
CON
SCL = 28
SDA = 29

PUB engage
' Pulls SDA to LOW whilst CLK is HIGH

dira[SCL]~~
outa[SDA]~
'The former two instructions need be done only once, if all is o.k.

outa[SCL]~~
dira[SDA]~ ' Pulse SDA; HIGH by pullup (default)
dira[SDA]~~ ' Enable = LOW
outa[SCL]~ ' Keep SCL LOW

PUB snd(by) : status
' Send a byte (and get status: 0: ACK 1: NAK)

by := (!by) >< 8 ' Reverse bits and invert pattern
REPEAT 8
dira[SDA] := by
outa[SCL]~~ ' Transfer on rising edge
by >>= 1
outa[SCL]~

' Returns "acknowledge bit": 0 = ACK, 1 = NAK.
dira[SDA]~ ' release SDA
outa[SCL]~~ ' puls-in ACK
status := ina[SDA]
outa[SCL]~ ' keep CLK low

PUB release
' Assert stop condition.
' SDA transits from LOW to HIGH whilst SCL is HIGH
dira[SDA]~~ ' LOW
outa[SCL]~~
dira[SDA]~ ' release SDA (HIGH)

PUB rcv : val
' Get a byte
REPEAT 8
outa[SCL]~~ ' Request bit
val <<= 1
val |= ina[SDA]
outa[SCL]~ ' Keep CLK low

PUB nak
' Send ackbit
dira[SDA]~~ ' LOW
outa[SCL]~~ ' Pulse SCL
outa[SCL]~ ' keep CLK low
dira[SDA]~ ' release SDA

PUB ack
' Send ackbit
dira[SDA]~ ' HIGH
outa[SCL]~~ ' Pulse SCL
outa[SCL]~ ' keep CLK low
dira[SDA]~ ' release SDA

Post Edited (deSilva) : 1/22/2008 12:46:14 AM GMT

Rayman
01-22-2008, 08:07 AM
Nice, but I'm not sure it's any better than my stripped down version of Mike Green's code:
http://www.rayslogic.com/propeller/Programming/i2c/i2c.htm

Rayman
01-22-2008, 08:12 AM
Well, it may be a bit smaller...

PS:· The PCA9554 (http://www.nxp.com/acrobat_download/datasheets/PCA9554_9554A_7.pdf)·is a newer device with the same pinout but better in several ways...

Post Edited (Rayman) : 1/22/2008 1:21:22 AM GMT

deSilva
01-22-2008, 08:38 AM
@Rayman: I am sure, your driver is fine. My idea was more educational: To have it all "in a nutshell". It had also furthered my own understanding.. As I am just converting it to ASM; I needed a reference to program it straight forwardly.

I am aware that the PCA9554 is newer, but I miss its true advantages. The 8574 is extremely versatile and most simple to program... And as I said, I got a lot of them for little money http://forums.parallax.com/images/smilies/smile.gif

Rayman
01-22-2008, 08:25 PM
The 8574 is much simpler... I was going to stick with it, but I found it had a fatal flaw for me: Bad commands make the I/O on all pins go bezerk. I'm trying to recall what made it go crazy... I think it was trying to do a read while one of the pins was set low... The project I needed it for had to be bullet-proof, so I had to switch to PCA9554.

deSilva
01-23-2008, 12:27 AM
Just thinkinkg about it: The 8574 behaves very similar as the Propeller without an OUTA register!!
You have an INA, giving you all the pin states, and a DIRA, allowing you to select either high impedance, or driving an external resistor low @15 mA.

For some projects it could be a problem not being able to drive from high.. Also 100 kHz might be slow. As seen I can generate 1.5 kHz square waves at the moment. Even with machine code this will not exceed 5 kHz (100kHz clock /10 clocks /2). The 9554 on the other hand could sample 40 kHz.