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.
 
 
 
 
 
 

540 lines
11 KiB

;==================================================================================================
; PCF8584/DS1307 I2C DATE AND TIME UTILITY
;==================================================================================================
;
.ECHO "rtcds7\n"
;
#INCLUDE "pcfi2c.inc"
;
.ORG 100H
;
DS7_START:
LD (DS7_STK),SP ; SETUP A
LD SP,DS7_LOC ; LOCAL STACK
;
CALL DS7_INIT ; INITIALIZE AND
JR NZ,DS7_ERR ; RETURN WITH STATUS
;
LD A,(FCB+1) ; GET FIRST COMMAND LINE CHAR
CP ' ' ; COMPARE TO BLANK. IF SO NO
JR Z,DS7_ST0 ; ARGUMENTS SO DISLAY TIME AND DATE
;
LD A,(FCB+1) ; GET FIRST CHAR
CP '/' ; IS IT INDICATING AN ARGUMENT
JR NZ,DS7_ST0 ;
;
LD A,(FCB+2) ; GET NEXT CHARACTER
CP 'D' ;
JR NZ,DS7_ST1 ;
;
; /D SET DATE
;
JR DS7_EXIT
;
DS7_ST1:
LD A,(FCB+2) ; GET NEXT CHARACTER
CP 'T' ;
JR NZ,DS7_ST2 ;
;
; /T SET TIME
;
JR DS7_EXIT
;
DS7_ST2:
LD A,(FCB+2) ; GET NEXT CHARACTER
CP 'S' ;
JR NZ,DS7_ST3 ;
;
; /S SET TIME AND DATE
;
JR DS7_EXIT
;
DS7_ST3:
;
; UNREGOGNIZED ARGUMENT
;
JR DS7_EXIT
;
DS7_ST0:
CALL DS7_RDC ; READ CLOCK DATA INTO BUFFER
CALL DS7_DISP ; DISPLAY TIME AND DATE FROM BUFFER
;
DS7_EXIT:
LD SP,(DS7_STK) ; RESTORE STACK
RET ; AND EXIT
;
DS7_ERR:
CALL PCF_INIERR ; DISPLAY ERROR
JR DS7_EXIT ; END EXIT
;
DS7_STK .DW 2 ; SAVE STACK
;
;-----------------------------------------------------------------------------
; RTC READ
;
; 1. ISSUE SLAVE ADDRESS WITH START CONDITION AND WRITE STATUS
; 2. OUTPUT THE ADDRESS TO ACCESS. (00H = START OF DS1307 REGISTERS)
; 3. OUTPUT REPEAT START TO TRANSITION TO READ PROCESS
; 4. ISSUE SLAVE ADDRESS WITH READ STATUS
; 5. DO A DUMMY READ
; 6. READ 8 BYTES STARTING AT ADDRESS PREVIOUSLY SET
; 7. END READ WITH NON-ACKNOWLEDGE
; 8. ISSUE STOP AND RELEASE BUS
;
DS7_RDC:
LD A,DS7_WRITE ; SET SLAVE ADDRESS
OUT (REGS0),A
;
CALL PCF_WAIT_FOR_BB
JP NZ,PCF_BBERR
;
CALL PCF_START ; GENERATE START CONDITION
CALL PCF_WAIT_FOR_PIN; AND ISSUE THE SLAVE ADDRESS
CALL NZ,PCF_PINERR
;
LD A,0
OUT (REGS0),A ; PUT ADDRESS MSB ON BUS
CALL PCF_WAIT_FOR_PIN
CALL NZ,PCF_PINERR
;
CALL PCF_REPSTART ; REPEAT START
;
LD A,DS7_READ ; ISSUE CONTROL BYTE + READ
OUT (REGS0),A
;
CALL PCF_READI2C ; DUMMY READ
;
LD HL,DS7_BUF ; READ 8 BYTES INTO BUFFER
LD B,8
DS7_RL1:CALL PCF_READI2C
LD (HL),A
INC HL
DJNZ DS7_RL1
;
#IF (0)
LD A,8
LD DE,DS7_BUF ; DISLAY DATA READ
CALL PRTHEXBUF ;
CALL NEWLINE
#ENDIF
;
LD A,PCF_ES0 ; END WITH NOT-ACKNOWLEDGE
OUT (REGS1),A ; AND RELEASE BUS
NOP
IN A,(REGS0)
NOP
DS7_WTPIN:
IN A,(REGS1) ; READ S1 REGISTER
BIT 7,A ; CHECK PIN STATUS
JP NZ,DS7_WTPIN
CALL PCF_STOP
;
IN A,(REGS0)
RET
;
;-----------------------------------------------------------------------------
; DISPLAY CLOCK INFORMATION FROM DATA STORED IN BUFFER
;
DS7_DISP:
LD HL,DS7_CLKTBL
DS7_CLP:LD C,(HL)
INC HL
LD D,(HL)
CALL DS7_BCD
INC HL
LD A,(HL)
OR A
RET Z
CALL COUT
INC HL
JR DS7_CLP
RET
;
DS7_CLKTBL:
.DB 04H, 00111111B, '/'
.DB 05H, 00011111B, '/'
.DB 06H, 11111111B, ' '
.DB 02H, 00011111B, ':'
.DB 01H, 01111111B, ':'
.DB 00H, 01111111B, 00H
;
DS7_BCD:PUSH HL
LD HL,DS7_BUF ; READ VALUE FROM
LD B,0 ; BUFFER, INDEXED BY A
ADD HL,BC
LD A,(HL)
AND D ; MASK OFF UNNEEDED
SRL A
SRL A
SRL A
SRL A
ADD A,30H
CALL COUT
LD A,(HL)
AND 00001111B
ADD A,30H
CALL COUT
POP HL
RET
;
DS7_BUF: .FILL 8,0 ; BUFFER FOR TIME, DATE AND CONTROL
;-----------------------------------------------------------------------------
PCF_START:
LD A,PCF_START_
OUT (REGS1),A
RET
;
;-----------------------------------------------------------------------------
PCF_REPSTART:
LD A,PCF_REPSTART_
OUT (REGS1),A
RET
;
;-----------------------------------------------------------------------------
PCF_STOP:
LD A,PCF_STOP_
OUT (REGS1),A
RET
;
;-----------------------------------------------------------------------------
;
DS7_INIT:
LD A,PCF_PIN ; S1=80H: S0 SELECTED, SERIAL
OUT (REGS1),A ; INTERFACE OFF
NOP
IN A,(REGS1) ; CHECK TO SEE S1 NOW USED AS R/W CTRL.
AND 07FH ; PCF8584 DOES THAT WHEN ESO IS ZERO
RET NZ ; PCF_INIERR
;
LD A,PCF_OWN ; LOAD OWN ADDRESS IN S0,
OUT (REGS0),A ; EFFECTIVE ADDRESS IS (OWN <<1)
NOP
IN A,(REGS0) ; CHECK IT IS REALLY WRITTEN
CP PCF_OWN
RET NZ ; PCF_SETERR
;
LD A,+(PCF_PIN | PCF_ES1) ; S1=0A0H
OUT (REGS1),A ; NEXT BYTE IN S2
NOP
IN A,(REGS1)
AND 07FH
CP PCF_ES1
RET NZ ; PCF_REGERR
;
LD A,PCF_CLK ; LOAD CLOCK REGISTER S2
OUT (REGS0),A
NOP
IN A,(REGS0) ; CHECK IT'S REALLY WRITTEN, ONLY
AND 1FH ; THE LOWER 5 BITS MATTER
CP PCF_CLK
RET NZ ; PCF_CLKERR
;
LD A,PCF_IDLE_
OUT (REGS1),A
NOP
IN A,(REGS1)
CP +(PCF_PIN | PCF_BB)
RET NZ ; PCF_IDLERR
;
XOR A
RET
;
;-----------------------------------------------------------------------------
PCF_HANDLE_LAB:
;
LD A,PCF_PIN
OUT (REGS1),A
LD A,PCF_ES0
OUT (REGS1),A
;
LD HL,PCF_LABDLY
PCF_LABLP:
LD A,H
OR L
DEC HL
JR NZ,PCF_LABLP
;
IN A,(REGS1)
RET
;
;-----------------------------------------------------------------------------
;
; RETURN A=00/Z IF SUCCESSFULL
; RETURN A=FF/NZ IF TIMEOUT
; RETURN A=01/NZ IF LOST ARBITRATION
; PCF_STATUS HOLDS LAST PCF STATUS
;
PCF_WAIT_FOR_PIN:
PUSH HL
LD HL,PCF_PINTO ; SET TIMEOUT VALUE
PCF_WFP0:
IN A,(REGS1) ; GET BUS
LD (PCF_STATUS),A ; STATUS
LD B,A
DEC HL ; HAVE WE
LD A,H ; TIMED OUT
OR L
JR Z,PCF_WFP1 ; YES WE HAVE, GO ACTION IT
LD A,B ;
AND PCF_PIN ; IS TRANSMISSION COMPLETE?
JR NZ,PCF_WFP0 ; KEEP ASKING IF NOT OR
POP HL ; YES COMPLETE (PIN=0) RETURN WITH ZERO
RET
PCF_WFP1:
LD A,B ; DID WE LOSE ARBITRATION?
AND PCF_LAB ; IF A=0 THEN NO
CPL
JR NZ,PCF_WFP2 ; NO
CALL PCF_HANDLE_LAB ; YES GO HANDLE IT
LD (PCF_STATUS),A
XOR A ; RETURN NZ, A=01H
INC A
PCF_WFP2:
POP HL ; RET NZ, A=FF IF TIMEOUT
RET
;
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,(REGS1) ; 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
;
;--------------------------------------------------------------------------------
;
; HL POINTS TO DATA
; DE = COUNT
; A = 0 LAST A=1 NOT LAST
;
;
;PCF_READBYTES: ; NOT FUNCTIONAL YET
LD (PCF_LBF),A ; SAVE LAST BYTE FLAG
;
INC DE ; INCREMENT NUMBER OF BYTES TO READ BY ONE -- DUMMY READ BYTE
LD BC,0 ; SET BYTE COUNTER
;
PCF_RBL:PUSH BC
CALL PCF_WAIT_FOR_PIN ; DO WE HAVE THE BUS?
POP BC
JR Z,PCF_RB1 ; YES
CP 01H
JR Z,PCF_RB3 ; NO - LOST ARBITRATION
JR PCF_RB2 ; NO - TIMEOUT
;
PCF_RB1:
LD A,(PCF_STATUS)
AND PCF_LRB
; IS THIS THE SECOND TO LAST BYTE TO GO?
PUSH DE ; SAVE COUNT
DEC DE ; COUNT (DE) = NUMBER OF BYTES TO READ LESS 1
EX DE,HL ; SAVE POINTER, PUT COUNT IN DE
XOR A ; CLEAR CARRY FLAG
SBC HL,BC ; DOES BYTE COUNTER = HL (NUMBER OF BYTES TO READ LESS 1)
EX DE,HL ; RESTORE POINTER
POP DE ; RESTORE COUNT
; Z = YES IT IS
; NZ = NO IT ISN'T
JR NZ,PCF_RB4
;
PCF_RB4:LD A,B ; IF FIRST READ DO A DUMMY
OR C ; READ OTHERWISE READ AND SAVE
JR NZ,PCF_RB5
IN A,(REGS0) ; DUMMY READ
JR PCF_RB6
PCF_RB5:IN A,(REGS0) ; READ AND SAVE
LD (HL),A
;
PCF_RB6: ; HAVE WE DONE ALL?
PUSH DE ; SAVE COUNT
EX DE,HL ; SAVE POINTER, PUT COUNT IN DE
XOR A ; CLEAR CARRY FLAG
SBC HL,BC ; DOES BYTE COUNTER = HL (NUMBER OF BYTES TO READ)
EX DE,HL ; RESTORE POINTER
POP DE ; RESTORE COUNT
;
INC HL ; BUFFER POINTER
INC BC ; COUNT
;
JR NZ,PCF_RBL ; REPEAT UNTIL COUNTS MATCH
RET
;
PCF_RB2: ; TIMEOUT
CALL PCF_STOP
CALL PCF_TOERR
RET
;
PCF_RB3: ; LOST ARBITRATION
CALL PCF_ARBERR
RET
;
PCF_LBF:
.DB 0 ; LAST BYTE FLAG
;
;-----------------------------------------------------------------------------
; READ ONE BYTE FROM I2C
; RETURNS DATA IN A
; Z FLAG SET IS ACKNOWLEDGE RECEIVED (CORRECT OPERATION)
;
PCF_READI2C:
IN A,(REGS1) ; READ S1 REGISTER
BIT 7,A ; CHECK PIN STATUS
JP NZ,PCF_READI2C
BIT 3,A ; CHECK LRB=0
JP NZ,PCF_RDERR
IN A,(REGS0) ; GET DATA
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,(REGS1)
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 PRTSTR
CALL NEWLINE
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$"
;
;-----------------------------------------------------------------------------
;
#INCLUDE "i2ccpm.inc"
;
.FILL 128
DS7_LOC:
;
.END