' ' Program: FOX SRAM Expansion Module #1 ' Author: (c) 2007 by A Fox Consulting & Design ' http://www.afox-consulting.com ' Date: 10/26/2007 ' ' Playing with 1k x 8 PCF8570 I2C SRAM array ' 2 mins 47 secs to execute on a BS2 (22.56 bytes/sec). ' 1 min 1 sec to execute on a BS2p (76.42 bytes/sec). ' 0 min 12 sec to execute on a BS2p with native I2C commands (426.67 bytes/sec). ' {$STAMP BS2p} ' {$PBASIC 2.5} ' -----[ I/O Definitions ]------------------------------------------------- _SDA PIN 0 ' I2C data line _SCL PIN 1 ' I2C clock line ' -----[ Constants ]------------------------------------------------------- PCF8570P CON %1010 << 4 ' device ID Ack CON 0 ' acknowledge bit Nak CON 1 ' no ack bit BlockSize CON 16 ' 16 bytes/block ' -----[ Variables ]------------------------------------------------------- block VAR Byte offset VAR Byte wrdAddr VAR Word test VAR Nib outVal VAR Byte inVal VAR Byte fails VAR Word ' Number of failed writes/block passes VAR Byte ' Number of good blocks i2cData VAR Byte ' data to/from device i2cWork VAR Byte ' work byte for TX routine i2cAck VAR Bit ' Ack bit from device ' -----[ Initialization ]-------------------------------------------------- Setup: DEBUG CLS,"Oh, look! We have a I2C SRAM memory module.", CR, "Let's test it to see how big it is!",CR,CR ' -----[ Program Code ]---------------------------------------------------- Main: fails = 0 passes = 0 wrdAddr = 0 FOR block = 0 TO (1024/BlockSize)-1 wrdAddr = block*BlockSize fails = 0 DEBUG CRSRXY, 0, 3+wrdAddr.BYTE1, DEC4 wrdaddr, " ... " FOR test = 0 TO 3 ' use four patterns LOOKUP test, [$FF, $AA, $55, $00], outVal FOR offset = 0 TO BlockSize - 1 wrdAddr = block*BlockSize+offset I2COUT _SDA, PCF8570P | (wrdAddr.BYTE1 << 1), wrdAddr.BYTE0, [outVal] ' GOSUB Write_Byte I2CIN _SDA, PCF8570P | (wrdAddr.BYTE1 << 1), wrdAddr.BYTE0, [inVal] ' GOSUB Read_Byte IF (inVal <> outVal) THEN fails = fails + 1 NEXT NEXT IF wrdAddr.BYTE0 = 255 THEN DEBUG CRSRXY,0,3+wrdAddr.BYTE1, "BANK ", DEC wrdAddr.BYTE1," (",DEC4 wrdAddr - 255,"-",DEC4 wrdAddr,") " ENDIF IF fails = 0 THEN DEBUG "OK" passes = passes + 1 ELSE DEBUG "BAD" ENDIF NEXT DEBUG CR, "CROSS-WIRE TEST..." FOR test = 0 TO 3 OutVal = test FOR offset = 0 TO 255 wrdAddr = test*256+offset I2COUT _SDA, PCF8570P | (wrdAddr.BYTE1 << 1), wrdAddr.BYTE0, [outVal] ' GOSUB Write_Byte NEXT DEBUG "*" NEXT FOR test = 0 TO 3 FOR offset = 0 TO 255 wrdAddr = test*256+offset I2CIN _SDA, PCF8570P | (wrdAddr.BYTE1 << 1), wrdAddr.BYTE0, [inVal] ' GOSUB Read_Byte IF InVal <> test THEN DEBUG "FAILURE IN BANK ",DEC test," @ ", DEC4 wrdAddr,": ", DEC InVal,CR ENDIF NEXT DEBUG "*" NEXT DEBUG CR, CR, "Done! ", DEC (passes * BlockSize), " BYTES SRAM AVAILABLE." END ' -----[ Subroutines ]----------------------------------------------------- ' =====[ High Level I2C Subroutines]======================================= ' location write for array of PCF8570P sevices Write_Byte: GOSUB I2C_Start ' send Start i2cWork = PCF8570P | (wrdAddr.BYTE1 << 1) ' send slave ID (write) GOSUB I2C_TX_Byte IF (i2cAck = Nak) THEN Write_Byte ' wait until not busy i2cWork = wrdAddr.BYTE0 ' send word address (0) GOSUB I2C_TX_Byte i2cWork = OutVal ' send data GOSUB I2C_TX_Byte GOSUB I2C_Stop RETURN ' location read for array of PCF8570P sevices Read_Byte: GOSUB I2C_Start ' send Start i2cWork = PCF8570P | (wrdAddr.BYTE1 << 1) ' send slave ID (write) GOSUB I2C_TX_Byte IF (i2cAck = Nak) THEN Read_Byte ' wait until not busy i2cWork = wrdAddr.BYTE0 ' send word address (0) GOSUB I2C_TX_Byte GOSUB I2C_Start i2cWork = PCF8570P | (wrdAddr.BYTE1 << 1) | %0001 ' send slave ID (read) GOSUB I2C_TX_Byte GOSUB I2C_RX_Byte_Nak GOSUB I2C_Stop InVal = i2cWork RETURN ' -----[ Low Level I2C Subroutines ]--------------------------------------- ' *** Start Sequence *** I2C_Start: ' I2C start bit sequence INPUT _SDA INPUT _SCL LOW _SDA Clock_Hold: DO : LOOP UNTIL (_SCL = 1) ' wait for clock release RETURN ' *** Transmit Byte *** I2C_TX_Byte: SHIFTOUT _SDA, _SCL, MSBFIRST, [i2cWork\8] ' send byte to device SHIFTIN _SDA, _SCL, MSBPRE, [i2cAck\1] ' get acknowledge bit RETURN ' *** Receive Byte *** I2C_RX_Byte_Nak: i2cAck = Nak ' no Ack = high GOTO I2C_RX I2C_RX_Byte: i2cAck = Ack ' Ack = low I2C_RX: SHIFTIN _SDA, _SCL, MSBPRE, [i2cWork\8] ' get byte from device SHIFTOUT _SDA, _SCL, LSBFIRST, [i2cAck\1] ' send ack or nak RETURN ' *** Stop Sequence *** I2C_Stop: ' I2C stop bit sequence LOW _SDA INPUT _SCL INPUT _SDA RETURN