Treiber für I2C-Bus
'SCL und SDA sind noch anzugeben.
'Mit I2CDelay kann die Busgeschwindigkeit eingestellt werden.
'Beachte das hier die vom langsamsten Busteilnehmer hinein muss.
CON
SCL = ? ' pin ? I2C SCL
SDA = ? ' pin ? I2C SDA
ACK = 0 ' I2C Acknowledge
NAK = 1 ' I2C No Acknowledge
Xmit = 0 ' I2C Direction Transmit
Recv = 1 ' I2C Direction Receive
I2CDelay = 100_000 ' delay to lower speed to 100KHz
I2CDelayS = 10_000 ' clock stretch delay
PRI Initialize ' An I2C device may be left in an
outa[SCL] := 1 ' reinitialized. Drive SCL high.
dira[SCL] := 1
dira[SDA] := 0 ' Set SDA as input
repeat 9
outa[SCL] := 0 ' Put out up to 9 clock pulses
outa[SCL] := 1
repeat 9
outa[SCL] := 0 ' Put out up to 9 clock pulses
outa[SCL] := 1
if ina[SDA] ' Repeat if SDA not driven high
quit ' by the EEPROM
dira[SCL]~ ' Now let them float
dira[SDA]~ ' If pullups present, they'll stay HIGH
PRI Start ' SDA goes HIGH to LOW with SCL HIGH
outa[SCL]~~ ' Initially drive SCL HIGH
dira[SCL]~~
outa[SDA]~~ ' Initially drive SDA HIGH
dira[SDA]~~
outa[SDA]~ ' Now drive SDA LOW
outa[SCL]~ ' Leave SCL LOW
PRI ReStart ' SDA goes HIGH to LOW with SCL HIGH
outa[SDA]~~ ' Initially drive SDA HIGH
dira[SDA]~~
outa[SCL]~~ ' Initially drive SCL HIGH
outa[SDA]~ ' Now drive SDA LOW
outa[SCL]~ ' Leave SCL LOW
PRI Stop ' SDA goes LOW to HIGH with SCL High
outa[SCL]~~ ' Drive SCL HIGH
outa[SDA]~~ ' then SDA HIGH
dira[SCL]~ ' Now let them float
dira[SDA]~ ' If pullups present, they'll stay HIGH
PRI WriteNS(data) : ackbit
'' Write i2c data. Data byte is output MSB first, SDA data line is valid
'' only while the SCL line is HIGH. Data is always 8 bits (+ ACK/NAK).
'' SDA is assumed LOW and SCL and SDA are both left in the LOW state.
'' Doesn't do clock stretching so would work without pull-up on SCL
ackbit := 0
data <<= 24
repeat 8 ' Output data to SDA
outa[SDA] := (data <-= 1) & 1
outa[SCL]~~ ' Toggle SCL from LOW to HIGH to LOW
outa[SCL]~
dira[SDA]~ ' Set SDA to input for ACK/NAK
outa[SCL]~~
ackbit := ina[SDA] ' Sample SDA when SCL is HIGH
outa[SCL]~
dira[SCL]~~
outa[SDA]~ ' Leave SDA driven LOW
dira[SDA]~~
PRI ReadNS(ackbit): data | b
'' Read in i2c data, Data byte is output MSB first, SDA data line is
'' valid only while the SCL line is HIGH. SCL and SDA left in LOW state.
'' Doesn't do clock stretching so would work without pull-up on SCL
data := 0
dira[SDA]~ ' Make SDA an input
repeat 8 ' Receive data from SDA
outa[SCL]~~ ' Sample SDA when SCL is HIGH
b := ina[SDA]
outa[SCL]~
data := (data << 1) | b
outa[SDA] := ackbit ' Output ACK/NAK to SDA
dira[SDA]~~
dira[SCL]~ ' Toggle SCL from LOW to HIGH to LOW
dira[SCL]~~
outa[SDA]~ ' Leave SDA driven LOW
PRI Write(data) : ackbit | wait
'' Write i2c data. Data byte is output MSB first, SDA data line is valid
'' only while the SCL line is HIGH. Data is always 8 bits (+ ACK/NAK).
'' SDA is assumed LOW and SCL and SDA are both left in the LOW state.
'' Requires pull-up on SCL
ackbit := 0
data <<= 24
repeat 8 ' Output data to SDA
outa[SDA] := (data <-= 1) & 1
dira[SCL]~ ' Toggle SCL from LOW to HIGH to LOW
dira[SCL]~~
dira[SDA]~ ' Set SDA to input for ACK/NAK
dira[SCL]~
wait := cnt
repeat while 0 == ina[SCL]
if (cnt-wait) > clkfreq/I2CDelayS
quit
ackbit := ina[SDA] ' Sample SDA when SCL is HIGH
dira[SCL]~~
outa[SDA]~ ' Leave SDA driven LOW
dira[SDA]~~
PRI Read(ackbit):data | wait
'' Read in i2c data, Data byte is output MSB first, SDA data line is
'' valid only while the SCL line is HIGH. SCL and SDA left in LOW state.
'' Requires pull-up on SCL
data := 0
dira[SDA]~ ' Make SDA an input
repeat 8 ' Receive data from SDA
dira[SCL]~ ' Sample SDA when SCL is HIGH
wait := cnt
repeat while 0 == ina[SCL]
if (cnt-wait) > clkfreq/I2CDelayS
quit
data := (data << 1) | ina[SDA]
dira[SCL]~~
outa[SDA] := ackbit ' Output ACK/NAK to SDA
dira[SDA]~~
dira[SCL]~ ' Toggle SCL from LOW to HIGH to LOW
wait := cnt
repeat while 0 == ina[SCL]
if (cnt-wait) > clkfreq/I2CDelayS
quit
dira[SCL]~~
outa[SDA]~ ' Leave SDA driven LOW
PRI ReadChar : data | ackbit
'' Read in i2c data, Data byte is output MSB first, SDA data line is
'' valid only while the SCL line is HIGH. SCL and SDA left in LOW state.
data := 0
dira[SDA]~ ' Make SDA an input
repeat 8 ' Receive data from SDA
waitcnt(clkfreq / I2CDelay + cnt)
outa[SCL]~~ ' Sample SDA when SCL is HIGH
waitcnt(clkfreq / I2CDelay + cnt)
data := (data << 1) | ina[SDA]
outa[SCL]~
if data == 0
ackbit := NAK
else
ackbit := ACK
outa[SDA] := ackbit ' Output ACK/NAK to SDA
dira[SDA]~~
outa[SCL]~~ ' Toggle SCL from LOW to HIGH to LOW
waitcnt(clkfreq / I2CDelay + cnt)
outa[SCL]~
outa[SDA]~ ' Leave SDA driven LOW
PRI ReadPage(devSel, addrReg, dataPtr, count) : ackbit
'' Read in a block of i2c data. Device select code is devSel. Device starting
'' address is addrReg. Data address is at dataPtr. Number of bytes is count.
'' The device select code is modified using the upper 3 bits of the 19 bit addrReg.
'' Return zero if no errors or the acknowledge bits if an error occurred.
devSel |= addrReg >> 15 & %1110
Start ' Select the device & send address
ackbit := Write(devSel | Xmit)
ackbit := (ackbit << 1) | Write(addrReg >> 8 & $FF)
ackbit := (ackbit << 1) | Write(addrReg & $FF)
reStart ' Reselect the device for reading
ackbit := (ackbit << 1) | Write(devSel | Recv)
repeat count - 1
byte[dataPtr++] := Read(ACK)
byte[dataPtr++] := Read(NAK)
Stop
return ackbit
PRI ReadByte(devSel, addrReg) : data
'' Read in a single byte of i2c data. Device select code is devSel. Device
'' starting address is addrReg. The device select code is modified using the
'' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred.
if ReadPage(devSel, addrReg, @data, 1)
return -1
PRI ReadWord(devSel, addrReg) : data
'' Read in a single word of i2c data. Device select code is devSel. Device
'' starting address is addrReg. The device select code is modified using the
'' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred.
if ReadPage(devSel, addrReg, @data, 2)
return -1
PRI ReadLong(devSel, addrReg) : data
'' Read in a single long of i2c data. Device select code is devSel. Device
'' starting address is addrReg. The device select code is modified using the
'' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred.
'' Note that you can't distinguish between a return value of -1 and true error.
if ReadPage(devSel, addrReg, @data, 4)
return -1
PRI WritePage(devSel, addrReg, dataPtr, count) : ackbit
'' Write out a block of i2c data. Device select code is devSel. Device starting
'' address is addrReg. Data address is at dataPtr. Number of bytes is count.
'' The device select code is modified using the upper 3 bits of the 19 bit addrReg.
'' Most devices have a page size of at least 32 bytes, some as large as 256 bytes.
'' Return zero if no errors or the acknowledge bits if an error occurred. If
'' more than 31 bytes are transmitted, the sign bit is "sticky" and is the
'' logical "or" of the acknowledge bits of any bytes past the 31st.
devSel |= addrReg >> 15 & %1110
Start ' Select the device & send address
ackbit := Write(devSel | Xmit)
ackbit := (ackbit << 1) | Write(addrReg >> 8 & $FF)
ackbit := (ackbit << 1) | Write(addrReg & $FF)
repeat count ' Now send the data
ackbit := ackbit << 1 | ackbit & $80000000 ' "Sticky" sign bit
ackbit |= Write(byte[dataPtr++])
Stop
return ackbit
PRI WriteByte(devSel, addrReg, data)
'' Write out a single byte of i2c data. Device select code is devSel. Device
'' starting address is addrReg. The device select code is modified using the
'' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred.
if WritePage(devSel, addrReg, @data, 1)
return true
' james edit - wait for 5ms for page write to complete (80_000 * 5 = 400_000)
waitcnt(400_000 + cnt)
return false
PRI WriteWord(devSel, addrReg, data)
'' Write out a single word of i2c data. Device select code is devSel. Device
'' starting address is addrReg. The device select code is modified using the
'' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred.
'' Note that the word value may not span an EEPROM page boundary.
if WritePage(devSel, addrReg, @data, 2)
return true
' james edit - wait for 5ms for page write to complete (80_000 * 5 = 400_000)
waitcnt(400_000 + cnt)
return false
PRI WriteLong(devSel, addrReg, data)
'' Write out a single long of i2c data. Device select code is devSel. Device
'' starting address is addrReg. The device select code is modified using the
'' upper 3 bits of the 19 bit addrReg. This returns true if an error occurred.
'' Note that the long word value may not span an EEPROM page boundary.
if WritePage(devSel, addrReg, @data, 4)
return true
' james edit - wait for 5ms for page write to complete (80_000 * 5 = 400_000)
waitcnt(400_000 + cnt)
return false
PRI WriteWait(devSel, addrReg) : ackbit
'' Wait for a previous write to complete. Device select code is devSel. Device
'' starting address is addrReg. The device will not respond if it is busy.
'' The device select code is modified using the upper 3 bits of the 18 bit addrReg.
'' This returns zero if no error occurred or one if the device didn't respond.
devSel |= addrReg >> 15 & %1110
Start
ackbit := Write(devSel | Xmit)
Stop
return ackbit
' *************** JAMES'S Extra BITS *********************
PRI devicePresent(deviceAddress) : ackbit
' send the deviceAddress and listen for the ACK
Start
ackbit := Write(deviceAddress | 0)
Stop
if ackbit == ACK
return true
else
return false
PRI writeLocation(device_address, register, value)
start
write(device_address)
write(register)
write(value)
stop
PRI readLocation(device_address, register) : value
start
write(device_address | 0)
write(register)
restart 'note change to restart from start, SCP1000 doesnt work without this change and so far works with other devices
write(device_address | 1)
value := read(NAK)
stop
return value
PRI readLocation16(device_address, register) : value
start
write(device_address | 0)
write(register)
restart
write(device_address | 1)
value := read(ACK)
value <<= 8
value |= (read(NAK) & $ff)
stop
return value
PRI readLocation24(device_address, register) : value
start
write(device_address | 0)
write(register)
restart
write(device_address | 1)
value := read(ACK)
value <<= 8
value |= (read(ACK) & $ff)
value <<= 8
value |= (read(NAK) & $ff)
stop
return value
PRI writeValue(device_address, value)
start
write(device_address)
result := write(value)
stop
PRI readValue24(device_address) : value
start
write(device_address | 1)
value := read(ACK)
value <<= 8
value |= (read(ACK) & $ff)
value <<= 8
value |= (read(NAK) & $ff)
stop
return value
PRI readValue16(device_address) : value
start
write(device_address | 1)
value := read(ACK)
value <<= 8
value |= (read(NAK) & $ff)
stop
return value
PRI readValue8(device_address) : value
start
write(device_address | 1)
value := read(NAK)
stop
return value