Hi,
At around 1300 bytes this is hardly a "snippet", but it has been cut and edited from a thread in the Active Forum, before it disappears under the weight of new posts. The original program was intended to check for the existence of a few I2C chips under rather specific conditions, so I have adapted it to be a more "Universal" program. It should work with all M2 PICaxes (and perhaps a few others) and includes additional Bus tests to hopefully trap the most common Hardware construction Issues.
The 10,000 character forum limit won't allow me to add much explanation here, but most details should be documented within the comments. Basically, the top few text lines need to be edited to suit the Hardware configuration (PICaxe type, etc.) and in principle the single 6-pin header shown in the "ASCII Art" could check any breakout module having 4 sequential in-line pins, provided that SDA and SCL are adjacent. However, there might be issues if trying to use the SerOut pin (c.0) of an 08M2 to select the power supply to the breakout board. Any general questions might be best asked in the Active Forum thread linked above.
Cheers, Alan.
At around 1300 bytes this is hardly a "snippet", but it has been cut and edited from a thread in the Active Forum, before it disappears under the weight of new posts. The original program was intended to check for the existence of a few I2C chips under rather specific conditions, so I have adapted it to be a more "Universal" program. It should work with all M2 PICaxes (and perhaps a few others) and includes additional Bus tests to hopefully trap the most common Hardware construction Issues.
The 10,000 character forum limit won't allow me to add much explanation here, but most details should be documented within the comments. Basically, the top few text lines need to be edited to suit the Hardware configuration (PICaxe type, etc.) and in principle the single 6-pin header shown in the "ASCII Art" could check any breakout module having 4 sequential in-line pins, provided that SDA and SCL are adjacent. However, there might be issues if trying to use the SerOut pin (c.0) of an 08M2 to select the power supply to the breakout board. Any general questions might be best asked in the Active Forum thread linked above.
Code:
; ** Find Slaves on I2C Bus : IDENTIFY-003 Revised by AllyCat September 2020 **
; Prog --@-----\/\/\-----+ 100k "Universal" I2C header
; | ,----_----, | SO ,-,
; Vdd ---|--| V+ 0V |--@-- 0V | +----|O| PWR/GND
; +->| SI C.0 |>---------@-|--@-|O| GND/pwr
; +--<>| C.4 C.1 |<>-- SCL ---|--|-|O| SCL
; | ->| C.3 C.2 |<>-- SDA ---|--|-|O| SDA
; | '---------' @--|-|O| PWR/GND
; +---------------------------+ +-|O| GND/pwr
; '-'
; Some Breakout boards include pull-up resistors for SDA and SCL
; This Program Enables the PICaxe's internal pull-ups if external pull-ups are missing
#define picaxe08 ; ** Choose 08,14,18 or 20 suffix and PWR/GND output pins if used **
#no_data ; Speeds up the Programming
#terminal 4800 ; Activate the Terminal Emulator after programming
;#define simulating ; Can use with PE5, Automatic with PE6
Symbol SADDE = $DE ; Address of any "expected" but not found Slave (Uncomment the Patch)
#ifdef picaxe08
#picaxe 08m2
#define ok
Symbol SCL = C.1 : Symbol pinSCL = pinC.1 ; Leg 6
Symbol SDA = C.2 : Symbol pinSDA = pinC.2 ; Leg 5
;Symbol PWR = C.4 ; Leg 3 (Uncomment to Enable output)
;Symbol GND = C.0 ; Leg 7 Defaults to GND (& used for SerOut)
Symbol MINVOLTS = 240 ; Minimum Suppy in Tens of mV (for 08M2)
#endif
#ifdef Picaxe14
#Picaxe 14M2
#define ok
Symbol SCL = B.3 : Symbol pinSCL = pinB.3 ; Leg 10
Symbol SDA = B.4 : Symbol pinSDA = pinB.4 ; Leg 9
;Symbol PWR = B.5 ; Leg 8 (Uncomment to Enable output)
;Symbol GND = B.2 ; Leg 11 (Uncomment to Enable output)
Symbol MINVOLTS = 190 ; Minimum Suppy in Tens of mV (for 14M2)
#endif
#ifdef Picaxe18
#Picaxe 18M2
#define ok
Symbol SCL = B.4 : Symbol pinSCL = pinB.4 ; Leg 10
Symbol SDA = B.1 : Symbol pinSDA = pinB.1 ; Leg 7
;Symbol PWR = B.0 ; Leg 6 (Uncomment to Enable output)
;Symbol GND = B.7 ; Leg 13 (Uncomment to Enable output)
Symbol MINVOLTS = 190 ; Minimum Suppy in Tens of mV (for 18M2)
#endif
#ifdef picaxe20
#picaxe 20m2
#define ok
Symbol SCL = B.7 : Symbol pinSCL = pinB.7 ; Leg 11 (eg. Linked to B.4 Leg 14)
Symbol SDA = B.5 : Symbol pinSDA = pinB.5 ; Leg 13
;Symbol PWR = B.6 ; Leg 12 (Uncomment to Enable output)
;Symbol GND = B.2 ; Leg 16 (Uncomment to Enable output)
Symbol MINVOLTS = 190 ; Minimum Suppy in Tens of mV (for 20M2)
#endif
#ifNdef ok
SerTxd("Sorry,Pinout not Programmed")
Symbol SCL = 0 : Symbol pinSCL = pin0 ; Dummy values to avoid syntax errors
Symbol SDA = 0 : Symbol pinSDA = pin0
Symbol MINVOLTS = 0
Stop
#endif
Symbol GND = 0 ; Uncomment if not defined (Editor reports error if already defined)
Symbol PWR = 0 ; Uncomment if not defined (Editor reports error if already defined)
Symbol MAXVOLTS = 550 ; Maximum Supply rail in Tens of mV
SerTxd(CR,LF,"SCL= ",#SCL," SDA= ",#SDA," V+= ",#PWR," GND=",#GND,CR,LF)
; ** Main Program **
PowerOnReset:
Pause 1000
Do
Gosub VoltCheck
b0 = PWR ; Can't compare constants (eg PWR = GND)
If b0 <> GND then ; enable PWR/GND output pins
High PWR
Low GND
Endif
Gosub BusCheck ; And enable pullups if required
Pause 100
; hi2csetup i2cmaster,SADDE,i2cslow,i2cbyte ; Optional Patch, E.G. for MCP1740
; hi2cin 0,(b0) ; Sometimes needed to "Wake Up" a chip
Main:
SerTxd( CR, LF, "Looking for Devices ...", CR, LF )
Gosub FindDevices
Pullup OFF
Pause 4000
Loop
; ** Check PSU Voltage and Bus hardware **
VoltCheck:
Do
#ifdef simulating
w0 = 500 ; Nominal 5v power supply
#else
Calibadc10 w0
w0 = w0 / 2 + 52378 / w0
Calibadc10 w1 ; Sample again to average and give 10mV resolution
w0 = 52378 / w1 + w0
#endif
b11 = w0 // 10 ; Hundredths
b12 = w0 / 10 // 10 ; Tenths
b13 = w0 / 100 ; Units
SerTxd( CR,LF,"Vpsu = ",#b13,".",#b12,#b11," Volts")
Select Case w0
Case < MINVOLTS : SerTxd( ": Supply too Low", CR, LF )
Case > MAXVOLTS : SerTxd( ": Supply too High", CR, LF )
End Select
Pause 500
Loop Until w0 >= MINVOLTS AND w0 =< MAXVOLTS ; Only Return when supply rail is valid
Return
BusCheck:
Pullup OFF
Low SDA ; Make Low now to catch a SDA to SCL bridge
Low SCL
Input SCL ; Float pin
Call Wait10
If pinSCL = 0 then
Gosub pullups ; PULLUP command cannot use a variable (PE6 can use #define)
If pinSCL = 0 then
SerTxd(CR,LF,"SCL held Low")
Else
SerTxd(CR,LF,"No SCL Pullup")
Endif
Pullup OFF
Endif
Input SDA
Call Wait10
If pinSDA = 0 then
Gosub pullups
If pinSDA = 0 then
SerTxd(CR,LF,"SDA held Low")
Else
SerTxd(CR,LF,"No SDA Pullup")
Endif
Endif ; Now fall into pullups in case SCL needs a pullup
Pullups:
#ifdef picaxe08
Pullup %110
#endif
#ifdef picaxe14
Pullup %11000
#endif
#ifdef picaxe18
Pullup %10010
#endif
#ifdef picaxe20
Pullup %10100000
#endif
Call Wait10
Return
; ** Search For Devices **
FindDevices:
bptr = 20
@bptr = 0
SerTxd( CR, LF, " ")
For b0 = $00 To $1F Step 2
If b0 = $10 Then
SerTxd( " " )
End If
SerTxd( " " ) : Gosub HexLsd
Next
b10 = $00 ; Address to try
b12 = $00 ; Address found
Do
b0 = b10 AND $1F
Select Case b0
Case $00
SerTxd( CR, LF )
b0 = b10 / $10 : Gosub HexLsd
Case $10
SerTxd( " " )
b0 = b10 / $10 : Gosub HexLsd
End Select
If b10 < $10 OR b10 >= $F0 Then
SerTxd( " XX" )
Else
Gosub CheckForDevice
End If
b10 = b10 + 2
Loop Until b10 = 0
SerTxd( CR, LF, CR, LF )
bptr = 20
b0 = @bptrinc AND 254
If b0 = 0 then
SerTxd( "No devices found" )
Else
Do
SerTxd ( "Device found at " )
Gosub Hex
SerTxd(" = ")
Select Case b0
Case $40 to $4E : SerTxd ( "Expander PCF8574" )
Case $78 : SerTxd ( "SSD1306 OLED" )
Case $70 to $7E : SerTxd ( "Expander PCF8574A" )
Case $A4 : SerTxd ( "Wii Controller" )
Case $A6 : SerTxd ( "Wii Motion Plus" )
Case $A0 to $AE : SerTxd ( "EEPROM 24LCxxx" )
; Case $A0 to $AE : SerTxd ( "RAM PCF8570 256 bytes" )
Case $C6 : SerTxd ( "AXE033 (Rev.Ed.)" )
Case $D0 : SerTxd ( "RTC (Maxim)" )
Case $DE : SerTxd ( "RTC (MCP7940)" )
Else
SerTxd ( " (Unknown)" )
End Select
SerTxd( CR, LF )
b0 = @bptrinc AND 254
Loop until b0 = 0
Endif
Return
CheckForDevice:
; Gosub ResetBus
Gosub SendStart
b0 = b10 OR 1 ; Read bit
Gosub SendByte
Gosub ReadAck
; Gosub SendStop
If b0 = 0 Then
; Ack
@bptrinc = b10
@bptr = 0
SerTxd( " " ) : b0 = b10 : Gosub Hex
Else
; Nak
SerTxd( " --" )
End If
Gosub ReadByte
Gosub SendNack
Gosub SendStop
Return
; ** Low-Level I2C Routines **
SendStart:
Input SCL ; SCL = 1
Gosub Stretch
Input SDA ; SDA = 1
Low SDA ; SDA = 0
Low SCL ; SCL = 0
Return
ResetBus:
Input SDA ; SDA = 1
Low SCL ; SCL = 0
For b1 = 0 To 8
Input SCL ; SCL = 1
Low SCL ; SCL = 0
Next
SendStop:
Low SDA ; SDA = 0
Low SCL ; SCL = 0
Input SCL ; SCL = 1
Gosub Stretch
Input SDA ; SDA = 1
Return
SendByte:
For b1 = 0 To 7
If bit7 = 0 Then
Low SDA ; SDA = 0
Else
Input SDA ; SDA = 1
End If
Input SCL ; SCL = 1
Gosub Stretch
Low SCL ; SCL = 0
b0 = b0 + b0
Next
Return
ReadByte:
Low SCL ; SCL = 0
Input SDA ; SDA = 1
For b1 = 0 To 7
Input SCL ; SCL = 1
Gosub Stretch
b0 = b0 + b0 + pinSDA
Low SCL ; SCL = 0
Next
Return
ReadAck:
Input SDA ; SDA = 1
Input SCL ; SCL = 1
Gosub Stretch
b0 = pinSDA
Low SCL ; SCL = 0
Return
SendAck:
Low SDA ; SDA = 0
Input SCL ; SCL = 1
Gosub Stretch
Low SCL ; SCL = 0
Return
SendNack:
Input SDA ; SDA = 1
Input SCL ; SCL = 1
Gosub Stretch
Low SCL ; SCL = 0
Return
Stretch:
Do : Loop While pinSCL = 0
Return
Wait10: ; May be needed with Higher pullup resitances or bus capacitance
Pause 7 ; 10 ms pause
Return
; ** Display Output Routines **
Hex:
b1 = b0 / $10 : Gosub Nibble
HexLsd:
b1 = b0
Nibble:
b1 = b1 AND $0F + "0"
If b1 > "9" Then : b1 = b1 + 7 : End If
SerTxd( b1 )
Return
; ** End Of Program **