mirror of https://github.com/wwarthen/RomWBW.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
514 lines
8.5 KiB
514 lines
8.5 KiB
;
|
|
.ECHO "i2cscan\n"
|
|
;
|
|
; I2C BUS SCANNER
|
|
; MARCO MACCAFERRI, HTTPS://WWW.MACCASOFT.COM
|
|
; HBIOS VERSION BY PHIL SUMMERS (B1ACKMAILER) DIFFICULTLEVELHIGH@GMAIL.COM
|
|
;
|
|
PCFECB .EQU 0
|
|
PCFDUO .EQU 1
|
|
P8X180 .EQU 0
|
|
SC126 .EQU 0
|
|
SC137 .EQU 0
|
|
;
|
|
#IF (PCFECB)
|
|
I2C_BASE .EQU 0F0H
|
|
PCF_ID .EQU 0AAH
|
|
CPU_CLK .EQU 12
|
|
;
|
|
PCF_RS0 .EQU I2C_BASE
|
|
PCF_RS1 .EQU PCF_RS0+1
|
|
PCF_OWN .EQU (PCF_ID >> 1) ; PCF'S ADDRESS IN SLAVE MODE
|
|
#ENDIF
|
|
;
|
|
#IF (PCFDUO)
|
|
I2C_BASE .EQU 056H
|
|
PCF_ID .EQU 0AAH
|
|
CPU_CLK .EQU 12
|
|
;
|
|
PCF_RS0 .EQU I2C_BASE
|
|
PCF_RS1 .EQU PCF_RS0+1
|
|
PCF_OWN .EQU (PCF_ID >> 1) ; PCF'S ADDRESS IN SLAVE MODE
|
|
#ENDIF
|
|
;
|
|
#IF (P8X180)
|
|
I2C_BASE .EQU 0A0h
|
|
_sda .EQU 0
|
|
_scl .EQU 1
|
|
_idle .EQU 00000011B
|
|
#ENDIF
|
|
;
|
|
#IF (SC126)
|
|
I2C_BASE .EQU 0Ch
|
|
_sda .EQU 7
|
|
_scl .EQU 0
|
|
_idle .EQU 10001101B
|
|
#ENDIF
|
|
;
|
|
#IF (SC137)
|
|
I2C_BASE .EQU 20h
|
|
_sda .EQU 7
|
|
_scl .EQU 0
|
|
_idle .EQU 10000001B
|
|
#ENDIF
|
|
;
|
|
;-----------------------------------------------------------------------------
|
|
;
|
|
.org 100h
|
|
|
|
ld sp,stack
|
|
|
|
ld hl,signon
|
|
call _strout
|
|
|
|
ld c,' '
|
|
call _cout
|
|
call _cout
|
|
call _cout
|
|
|
|
; display x axis header 00-0F
|
|
|
|
xor a
|
|
ld (x),a
|
|
ld b, 16
|
|
lp1: ld c,' '
|
|
call _cout
|
|
ld a,(x)
|
|
ld c,a
|
|
inc a
|
|
ld (x),a
|
|
call _hexout
|
|
djnz lp1
|
|
call _eolout
|
|
|
|
; start of line loop 00-07
|
|
|
|
xor a ; display
|
|
ld (y),a ; y-axis
|
|
ld (addr),a ; prefix
|
|
ld d,8
|
|
lp3b: ld a,(y)
|
|
ld c,a
|
|
add a,10h
|
|
ld (y),a
|
|
call _hexout
|
|
ld c,':'
|
|
call _cout
|
|
|
|
; set up x axis loop
|
|
|
|
xor a
|
|
ld (x),a
|
|
ld e,16
|
|
lp2b: push de
|
|
|
|
ld c,' '
|
|
call _cout
|
|
|
|
; i2c challenge
|
|
; . issue device start command
|
|
; . write address to device
|
|
; . issue device stop command.
|
|
; . delay
|
|
; . display response
|
|
|
|
; call _i2c_start
|
|
; ld a,(addr)
|
|
; ld c,a
|
|
; call _i2c_write
|
|
; ld (rc),a
|
|
; call _i2c_stop
|
|
|
|
CALL PCF_WAIT_FOR_BB
|
|
JP NZ,PCF_BBERR
|
|
;
|
|
LD A,(addr)
|
|
OUT (PCF_RS0),A
|
|
CALL PCF_START ; GENERATE START CONDITION
|
|
;
|
|
ld bc,100 ; delay
|
|
lp6: nop
|
|
dec bc
|
|
ld a,c
|
|
or b
|
|
jr nz,lp6
|
|
|
|
CALL PCF_WAIT_FOR_ACK; AND ISSUE THE SLAVE ADDRESS
|
|
or a
|
|
jp nz,lp4f
|
|
|
|
ld c,'-' ; display no
|
|
call _cout ; response
|
|
call _cout
|
|
jp lp5f
|
|
|
|
lp4f: ld a,(addr) ; adjust address
|
|
ld c,a ; and display it
|
|
srl c
|
|
call _hexout
|
|
|
|
lp5f: ld a,(addr) ; next address
|
|
add a,2 ; adjust for
|
|
ld (addr),a ; 7-bit
|
|
|
|
CALL PCF_STOP
|
|
|
|
pop de ; check if
|
|
dec e ; reached end
|
|
jp nz,lp2b ; of line
|
|
call _eolout
|
|
|
|
dec d ; loop until
|
|
jp nz,lp3b ; all done
|
|
|
|
jp 0
|
|
|
|
signon: .db "I2C Bus Scanner"
|
|
#IF (PCFECB)
|
|
.DB " - PCF8584 (ECB)"
|
|
#ENDIF
|
|
#IF (PCFDUO)
|
|
.DB " - PCF8584 (Duodyne)"
|
|
#ENDIF
|
|
#IF (SC126)
|
|
.DB " - SC126"
|
|
#ENDIF
|
|
#IF (SC137)
|
|
.DB " - SC137"
|
|
#ENDIF
|
|
.db 13, 10, 13, 10, 0, "$"8
|
|
|
|
_strout:
|
|
st1: ld a,(hl) ; display
|
|
CP '$' ; zero
|
|
ret z ; terminated
|
|
ld c,a ; string
|
|
call _cout
|
|
inc hl
|
|
jp st1
|
|
|
|
_hexout: ; display
|
|
ld a,c ; A in hex
|
|
srl a
|
|
srl a
|
|
srl a
|
|
srl a
|
|
add a,30h
|
|
cp 3Ah
|
|
jp c,h1
|
|
add a,7
|
|
h1: ld h,a
|
|
ld a,c
|
|
and 0Fh
|
|
add a,30h
|
|
cp 3Ah
|
|
jp c,h2
|
|
add a,7
|
|
h2: ld l,a
|
|
ld c,h
|
|
call _cout
|
|
ld c,l
|
|
call _cout
|
|
ret
|
|
|
|
_eolout: ; newline
|
|
ld c,13
|
|
call _cout
|
|
ld c,10
|
|
call _cout
|
|
ret
|
|
|
|
_cout: ; character
|
|
push af ; output
|
|
push bc
|
|
push de
|
|
push hl
|
|
ld e,c
|
|
ld c,02h
|
|
call 5
|
|
pop hl
|
|
pop de
|
|
pop bc
|
|
pop af
|
|
ret
|
|
|
|
;-----------------------------------------------------------------------------
|
|
#IF (PCFECB | PCFDUO)
|
|
_i2c_start:
|
|
PCF_START:
|
|
LD A,PCF_START_
|
|
OUT (PCF_RS1),A
|
|
RET
|
|
#ELSE
|
|
;_i2c_start:
|
|
ld a,_idle ; issue
|
|
out (I2C_BASE),a ; start
|
|
; command
|
|
res _sda,a
|
|
out (I2C_BASE),a
|
|
nop
|
|
nop
|
|
res _scl,a
|
|
out (I2C_BASE),a
|
|
|
|
ld (oprval),a
|
|
ret
|
|
#ENDIF
|
|
;
|
|
;-----------------------------------------------------------------------------
|
|
;
|
|
; CONTROL REGISTER BITS
|
|
;
|
|
PCF_PIN .EQU 10000000B
|
|
PCF_ES0 .EQU 01000000B
|
|
PCF_ES1 .EQU 00100000B
|
|
PCF_ES2 .EQU 00010000B
|
|
PCF_EN1 .EQU 00001000B
|
|
PCF_STA .EQU 00000100B
|
|
PCF_STO .EQU 00000010B
|
|
PCF_ACK .EQU 00000001B
|
|
;
|
|
; STATUS REGISTER BITS
|
|
;
|
|
;PCF_PIN .EQU 10000000B
|
|
PCF_INI .EQU 01000000B ; 1 if not initialized
|
|
PCF_STS .EQU 00100000B
|
|
PCF_BER .EQU 00010000B
|
|
PCF_AD0 .EQU 00001000B
|
|
PCF_LRB .EQU 00001000B
|
|
PCF_AAS .EQU 00000100B
|
|
PCF_LAB .EQU 00000010B
|
|
PCF_BB .EQU 00000001B
|
|
;
|
|
PCF_START_ .EQU (PCF_PIN | PCF_ES0 | PCF_STA | PCF_ACK)
|
|
PCF_STOP_ .EQU (PCF_PIN | PCF_ES0 | PCF_STO | PCF_ACK)
|
|
;
|
|
; TIMEOUT AND DELAY VALUES (ARBITRARY)
|
|
;
|
|
PCF_PINTO .EQU 65000
|
|
PCF_ACKTO .EQU 65000
|
|
PCF_BBTO .EQU 65000
|
|
PCF_LABDLY .EQU 65000
|
|
;
|
|
PCF_STATUS .DB 00H
|
|
;
|
|
;--------------------------------------------------------------------------------
|
|
;
|
|
; RETURN NZ/FF IF TIMEOUT ERROR
|
|
; RETURN NZ/01 IF FAILED TO RECEIVE ACKNOWLEDGE
|
|
; RETURN Z/00 IF RECEIVED ACKNOWLEDGE
|
|
;
|
|
PCF_WAIT_FOR_ACK:
|
|
PUSH HL
|
|
LD HL,PCF_ACKTO
|
|
;
|
|
PCF_WFA0:
|
|
IN A,(PCF_RS1) ; READ PIN
|
|
LD (PCF_STATUS),A ; STATUS
|
|
LD B,A
|
|
;
|
|
DEC HL ; SEE IF WE HAVE TIMED
|
|
LD A,H ; OUT WAITING FOR PIN
|
|
OR L ; EXIT IF
|
|
JR Z,PCF_WFA1 ; WE HAVE
|
|
;
|
|
LD A,B ; OTHERWISE KEEP LOOPING
|
|
AND PCF_PIN ; UNTIL WE GET PIN
|
|
JR NZ,PCF_WFA0 ; OR TIMEOUT
|
|
;
|
|
LD A,B ; WE GOT PIN SO NOW
|
|
AND PCF_LRB ; CHECK WE HAVE
|
|
LD A,1
|
|
JR Z,PCF_WFA2 ; RECEIVED ACKNOWLEDGE
|
|
XOR A
|
|
JR PCF_WFA2
|
|
PCF_WFA1:
|
|
CPL ; TIMOUT ERROR
|
|
PCF_WFA2:
|
|
POP HL ; EXIT WITH NZ = FF
|
|
RET
|
|
;
|
|
;-----------------------------------------------------------------------------
|
|
;
|
|
; POLL THE BUS BUSY BIT TO DETERMINE IF BUS IS FREE.
|
|
; RETURN WITH A=00H/Z STATUS IF BUS IS FREE
|
|
; RETURN WITH A=FFH/NZ STATUS IF BUS
|
|
;
|
|
; AFTER RESET THE BUS BUSY BIT WILL BE SET TO 1 I.E. NOT BUSY
|
|
;
|
|
PCF_WAIT_FOR_BB:
|
|
LD HL,PCF_BBTO
|
|
PCF_WFBB0:
|
|
IN A,(PCF_RS1)
|
|
AND PCF_BB
|
|
RET Z ; BUS IS FREE RETURN ZERO
|
|
DEC HL
|
|
LD A,H
|
|
OR L
|
|
JR NZ,PCF_WFBB0 ; REPEAT IF NOT TIMED OUT
|
|
CPL ; RET NZ IF TIMEOUT
|
|
RET
|
|
;
|
|
;-----------------------------------------------------------------------------
|
|
; DISPLAY ERROR MESSAGES
|
|
;
|
|
PCF_RDERR:
|
|
PUSH HL
|
|
LD HL,PCF_RDFAIL
|
|
JR PCF_PRTERR
|
|
;
|
|
PCF_INIERR:
|
|
PUSH HL
|
|
LD HL,PCF_NOPCF
|
|
JR PCF_PRTERR
|
|
;
|
|
PCF_SETERR:
|
|
PUSH HL
|
|
LD HL,PCF_WRTFAIL
|
|
JR PCF_PRTERR
|
|
;
|
|
PCF_REGERR:
|
|
PUSH HL
|
|
LD HL,PCF_REGFAIL
|
|
JR PCF_PRTERR
|
|
;
|
|
PCF_CLKERR:
|
|
PUSH HL
|
|
LD HL,PCF_CLKFAIL
|
|
JR PCF_PRTERR
|
|
;
|
|
PCF_IDLERR:
|
|
PUSH HL
|
|
LD HL,PCF_IDLFAIL
|
|
JR PCF_PRTERR
|
|
;
|
|
PCF_ACKERR:
|
|
PUSH HL
|
|
LD HL,PCF_ACKFAIL
|
|
JR PCF_PRTERR
|
|
;
|
|
PCF_RDBERR:
|
|
PUSH HL
|
|
LD HL,PCF_RDBFAIL
|
|
JR PCF_PRTERR
|
|
;
|
|
PCF_TOERR:
|
|
PUSH HL
|
|
LD HL,PCF_TOFAIL
|
|
JR PCF_PRTERR
|
|
;
|
|
PCF_ARBERR:
|
|
PUSH HL
|
|
LD HL,PCF_ARBFAIL
|
|
JR PCF_PRTERR
|
|
;
|
|
PCF_PINERR:
|
|
PUSH HL
|
|
LD HL,PCF_PINFAIL
|
|
JR PCF_PRTERR
|
|
;
|
|
PCF_BBERR:
|
|
PUSH HL
|
|
LD HL,PCF_BBFAIL
|
|
JR PCF_PRTERR
|
|
;
|
|
PCF_PRTERR:
|
|
CALL _strout
|
|
CALL _eolout
|
|
POP HL
|
|
RET
|
|
;
|
|
PCF_NOPCF .DB "NO DEVICE FOUND$"
|
|
PCF_WRTFAIL .DB "SETTING DEVICE ID FAILED$"
|
|
PCF_REGFAIL .DB "CLOCK REGISTER SELECT ERROR$"
|
|
PCF_CLKFAIL .DB "CLOCK SET FAIL$"
|
|
PCF_IDLFAIL .DB "BUS IDLE FAILED$"
|
|
PCF_ACKFAIL .DB "FAILED TO RECEIVE ACKNOWLEDGE$"
|
|
PCF_RDFAIL .DB "READ FAILED$"
|
|
PCF_RDBFAIL .DB "READBYTES FAILED$"
|
|
PCF_TOFAIL .DB "TIMEOUT ERROR$"
|
|
PCF_ARBFAIL .DB "LOST ARBITRATION$"
|
|
PCF_PINFAIL .DB "PIN FAIL$"
|
|
PCF_BBFAIL .DB "BUS BUSY$"
|
|
;
|
|
;-----------------------------------------------------------------------------
|
|
#IF (PCFECB | PCFDUO)
|
|
_i2c_stop:
|
|
PCF_STOP:
|
|
LD A,PCF_STOP_ ; issue
|
|
OUT (PCF_RS1),A ; stop
|
|
RET ; command
|
|
#ELSE
|
|
;_i2c_stop:
|
|
ld a,(oprval)
|
|
res _scl,a
|
|
res _sda,a
|
|
out (I2C_BASE),a
|
|
|
|
set _scl,a
|
|
out (I2C_BASE),a
|
|
nop
|
|
nop
|
|
set _sda,a
|
|
out (I2C_BASE),a
|
|
|
|
ld (oprval),a
|
|
ret
|
|
;
|
|
_i2c_write: ; write
|
|
ld a,(oprval) ; to i2c
|
|
; bus
|
|
ld b,8
|
|
i2c1: res _sda,a
|
|
rl c
|
|
jr nc,i2c2
|
|
set _sda,a
|
|
i2c2: out (I2C_BASE),a
|
|
set _scl,a
|
|
out (I2C_BASE),a
|
|
|
|
#IF (SC126=0)
|
|
ld d,a
|
|
i2c3: in a,(I2C_BASE)
|
|
bit _scl,a
|
|
jr z,i2c3
|
|
ld a,d
|
|
#ENDIF
|
|
res _scl,a
|
|
out (I2C_BASE),a
|
|
djnz i2c1
|
|
|
|
set _sda,a
|
|
out (I2C_BASE),a
|
|
set _scl,a
|
|
out (I2C_BASE),a
|
|
|
|
ld d,a
|
|
i2c4: in a,(I2C_BASE)
|
|
#IF (SC126=0)
|
|
bit _scl,a
|
|
jr z,4b
|
|
#ENDIF
|
|
ld c,a
|
|
ld a,d
|
|
|
|
res _scl,a
|
|
out (I2C_BASE),a
|
|
ld (oprval),a
|
|
|
|
xor a
|
|
bit _sda,c
|
|
ret z
|
|
inc a
|
|
|
|
ret
|
|
#ENDIF
|
|
oprval: .db 0
|
|
x: .db 0
|
|
y: .db 0
|
|
addr: .db 0
|
|
rc: .db 0
|
|
|
|
.fill 128
|
|
stack:
|
|
.end
|
|
|