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