; ;================================================================================================== ; DALLAS SEMICONDUCTOR DS1302 RTC DRIVER ;================================================================================================== ; ; PROGRAMMING NOTES: ; - ALL SIGNALS ARE ACTIVE HIGH ; - DATA OUTPUT (HOST -> RTC) ON RISING EDGE ; - DATA INPUT (RTC -> HOST) ON FALLING EDGE ; - SIMPLIFIED TIMING CONSTRAINTS: ; @ 50MHZ, 1 TSTATE IS WORTH 20NS, 1 NOP IS WORTH 80NS, 1 EX (SP), IX IS WORTH 23 460NS ; 1) AFTER CHANGING CE, WAIT 1US (2 X EX (SP), IX) ; 2) AFTER CHANGING CLOCK, WAIT 250NS (3 X NOP) ; 3) AFTER SETTING A DATA BIT, WAIT 50NS (1 X NOP) ; 4) PRIOR TO READING A DATA BIT, WAIT 200NS (3 X NOP) ; ; COMMAND BYTE: ; ; 7 6 5 4 3 2 1 0 ; +-----+-----+-----+-----+-----+-----+-----+-----+ ; | 1 | RAM | A4 | A3 | A2 | A1 | A0 | RD | ; | | ~CK | | | | | | ~WR | ; +-----+-----+-----+-----+-----+-----+-----+-----+ ; ; REGISTER ADDRESSES (HEX / BCD): ; ; RD WR D7 D6 D5 D4 D3 D2 D1 D0 RANGE ; +----+----+----+----+----+----+----+----+----+----+-----------+ ; | 81 | 80 | CH | 10 SECS | SEC | 00-59 | ; +----+----+----+----+----+----+----+----+----+----+-----------+ ; | 83 | 82 | | 10 MINS | MIN | 00-59 | ; +----+----+----+----+----+----+----+----+----+----+-----------+ ; | 85 | 84 | TF | 00 | PM | 10 | HOURS | 1-12/0-23 | ; +----+----+----+----+----+----+----+----+----+----+-----------+ ; | 87 | 86 | 00 | 00 | 10 DATE | DATE | 1-31 | ; +----+----+----+----+----+----+----+----+----+----+-----------+ ; | 89 | 88 | 00 | 10 MONTHS | MONTH | 1-12 | ; +----+----+----+----+----+----+----+----+----+----+-----------+ ; | 8B | 8A | 00 | 00 | 00 | 00 | DAY | 1-7 | ; +----+----+----+----+----+----+----+----+----+----+-----------+ ; | 8D | 8C | 10 YEARS | YEAR | 0-99 | ; +----+----+----+----+----+----+----+----+----+----+-----------+ ; | 8F | 8E | WP | 00 | 00 | 00 | 00 | 00 | 00 | 00 | | ; +----+----+----+----+----+----+----+----+----+----+-----------+ ; | 91 | 90 | TCS | DS | RS | | ; +----+----+----+----+----+----+----+----+----+----+-----------+ ; | BF | BE | *CLOCK BURST* | ; +----+----+----+----+----+----+----+----+----+----+-----------+ ; | C1 | C0 | | | ; | .. | .. | *RAM* | | ; | FD | FC | | | ; +----+----+----+----+----+----+----+----+----+----+-----------+ ; | FF | FE | *RAM BURST* | | ; +----+----+----+----+----+----+----+----+----+----+-----------+ ; ; CH=CLOCK HALT (1=CLOCK HALTED & OSC STOPPED) ; TF=12 HOUR (1) OR 24 HOUR (0) ; PM=IF 24 HOURS, 0=AM, 1=PM, ELSE 10 HOURS ; WP=WRITE PROTECT (1=PROTECTED) ; TCS=TRICKLE CHARGE ENABLE (1010 TO ENABLE) ; DS=TRICKLE CHARGE DIODE SELECT ; RS=TRICKLE CHARGE RESISTOR SELECT ; ; CONSTANTS ; ; RTC LATCH WRITE ; --------------- ; ; BIT SBC RCBUS SBC-004 MFPIC K80W N8 N8-CSIO MK4 SC126 SC130 SC131 SC140 SC503 SC722 MBC RPH ; ----- ------- ------- ------- ------- ------- ------- ------- ------- --------------- ------- ------- ------- ------- ------- ------- ------- ; D7 RTC_OUT RTC_OUT RTC_OUT -- -- RTC_OUT RTC_OUT RTC_OUT RTC_OUT,I2C_SDA -- -- -- -- -- RTC_OUT RTC_OUT ; D6 RTC_CLK RTC_CLK RTC_CLK -- -- RTC_CLK RTC_CLK RTC_CLK RTC_CLK -- -- -- -- -- RTC_CLK RTC_CLK ; D5 /RTC_WE /RTC_WE /RTC_WE -- -- /RTC_WE /RTC_WE /RTC_WE /RTC_WE -- -- -- -- -- /RTC_WE /RTC_WE ; D4 RTC_CE RTC_CE RTC_CE -- -- RTC_CE RTC_CE RTC_CE RTC_CE -- -- -- -- -- RTC_CE RTC_CE ; D3 NC NC CLKSEL /RTC_CE /RTC_CE NC NC NC /SPI_CS2 -- -- -- -- -- CLKSEL -- ; D2 NC NC SPK RTC_CLK RTC_CLK SPI_CS SPI_CS NC /SPI_CS1 /SPI_CS1/SPI_CS1/SPI_CS1/SPI_CS1/SPI_CS1SPK -- ; D1 -- -- -- RTC_WE RTC_WE SPI_CLK NC NC FS -- -- -- -- -- LED1 -- ; D0 -- -- -- RTC_OUT RTC_OUT SPI_DI NC NC I2C_SCL -- -- -- -- -- LED0 -- ; ; RTC LATCH LATCH READ ; -------------------- ; ; D7 -- -- -- -- -- -- -- -- I2C_SDA -- -- -- -- -- -- -- ; D6 CFG -- CFG -- -- SPI_DO CFG -- -- -- -- -- -- -- CFG -- ; D5 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ; D4 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ; D3 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ; D2 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ; D1 -- -- -- -- -- -- -- -- -- -- -- -- -- -- CLKSEL -- ; D0 RTC_IN RTC_IN RTC_IN RTC_IN RTC_IN RTC_IN RTC_IN RTC_IN RTC_IN -- -- -- -- -- RTC_IN RTC_IN ; DEVECHO "DSRTC: MODE=" ; #IF (DSRTCMODE == DSRTCMODE_STD) ; DSRTC_IO .EQU RTCIO ; RTC PORT ; DSRTC_DATA .EQU %10000000 ; BIT 7 IS RTC DATA OUT DSRTC_CLK .EQU %01000000 ; BIT 6 IS RTC CLOCK (CLK) DSRTC_RD .EQU %00100000 ; BIT 5 IS DATA DIRECTION (/WE) DSRTC_CE .EQU %00010000 ; BIT 4 IS CHIP ENABLE (CE) ; DSRTC_MASK .EQU %11110000 ; MASK FOR BITS WE OWN IN RTC LATCH PORT DSRTC_IDLE .EQU %00100000 ; QUIESCENT STATE ; RTCDEF .SET RTCDEF | DSRTC_IDLE ; FOR HBIOS MAINLINE ; #DEFINE DSRTC_OPRVAL HB_RTCVAL ; DEVECHO "STD" ; #ENDIF ; #IF (DSRTCMODE == DSRTCMODE_MFPIC) ; DSRTC_IO .EQU $13 ; RTC PORT ON MF/PIC ; DSRTC_DATA .EQU %00000001 ; BIT 0 IS RTC DATA OUT DSRTC_CLK .EQU %00000100 ; BIT 2 IS RTC CLOCK (CLK) DSRTC_WR .EQU %00000010 ; BIT 1 IS DATA DIRECTION (WE) DSRTC_CE .EQU %00001000 ; BIT 3 CHIP ENABLE (/CE) ; DSRTC_MASK .EQU %00001111 ; MASK FOR BITS WE OWN IN RTC LATCH PORT DSRTC_IDLE .EQU %00001000 ; QUIESCENT STATE ; #DEFINE DSRTC_OPRVAL DSRTC_RTCVAL ; DEVECHO "MFPIC" ; #ENDIF ; #IF (DSRTCMODE == DSRTCMODE_K80W) ; DSRTC_IO .EQU RTCIO ; RTC PORT ; DSRTC_DATA .EQU %00000001 ; BIT 0 IS RTC DATA OUT DSRTC_CLK .EQU %00000100 ; BIT 2 IS RTC CLOCK (CLK) DSRTC_WR .EQU %00000010 ; BIT 1 IS DATA DIRECTION (WE) DSRTC_CE .EQU %00001000 ; BIT 3 CHIP ENABLE (/CE) ; DSRTC_MASK .EQU %00001111 ; MASK FOR BITS WE OWN IN RTC LATCH PORT DSRTC_IDLE .EQU %00001000 ; QUIESCENT STATE ; #DEFINE DSRTC_OPRVAL HB_RTCVAL ; DEVECHO "K80W" ; #ENDIF ; DEVECHO ", IO=" DEVECHO DSRTC_IO DEVECHO "\n" ; ; VALUES FOR DIFFERENT BATTERY OR SUPERCAPACITOR CHARGE RATES ; DS1d2k .EQU %10100101 ; 1 DIODE 2K RESISTOR (DEFAULT) DS1d4k .EQU %10100110 ; 1 DIODE 4K RESISTOR DS1d8k .EQU %10100111 ; 1 DOIDE 8K RESISTOR DS2d2k .EQU %10101001 ; 2 DIODES 2K RESISTOR DS2d4k .EQU %10101010 ; 2 DIODES 4K RESISTOR DS2d8k .EQU %10101011 ; 2 DIODES 8K RESISTOR ; DSRTC_BUFSIZ .EQU 7 ; 7 BYTE BUFFER (YYMMDDHHMMSSWW) ; ; RTC DEVICE PRE-INITIALIZATION ENTRY ; DSRTC_PREINIT: ; ;; SET RELEVANT BITS IN RTC LATCH SHADOW REGISTER ;; TO THEIR QUIESENT STATE ;LD A,(DSRTC_OPRVAL) ; GET CURRENT SHADOW REG VAL ;AND ~DSRTC_MASK ; CLEAR OUR BITS ;OR DSRTC_IDLE ; SET OUR IDLE BITS ;LD (DSRTC_OPRVAL),A ; SAVE IT ; XOR A ; ZERO LD (DSRTC_STAT),A ; CLEAR STATUS CALL DSRTC_DETECT ; HARDWARE DETECTION LD (DSRTC_STAT),A ; SAVE RESULT RET NZ ; ABORT IF ERROR ; ; CHECK FOR CLOCK HALTED CALL DSRTC_TSTCLK JR Z,DSRTC_PREINIT1 ;PRTS(" INIT CLOCK $") LD HL,DSRTC_TIMDEF CALL DSRTC_TIM2CLK LD HL,DSRTC_BUF CALL DSRTC_WRCLK ; DSRTC_PREINIT1: XOR A ; SIGNAL SUCCESS RET ; DONE ; ; RTC DEVICE INITIALIZATION ENTRY ; DSRTC_INIT: LD A,(RTC_DISPACT) ; RTC DISPATCHER ALREADY SET? OR A ; SET FLAGS RET NZ ; IF ALREADY ACTIVE, ABORT ; CALL NEWLINE ; FORMATTING PRTS("DSRTC: MODE=$") ; #IF (DSRTCMODE == DSRTCMODE_STD) PRTS("STD$") #ENDIF #IF (DSRTCMODE == DSRTCMODE_MFPIC) PRTS("MFPIC$") #ENDIF #IF (DSRTCMODE == DSRTCMODE_K80W) PRTS("K80W$") #ENDIF ; ; PRINT RTC LATCH PORT ADDRESS PRTS(" IO=0x$") ; LABEL FOR IO ADDRESS LD A,DSRTC_IO ; GET IO ADDRESS CALL PRTHEXBYTE ; PRINT IT ; ; CHECK PRESENCE STATUS LD A,(DSRTC_STAT) ; GET DEVICE STATUS OR A ; SET FLAGS JR Z,DSRTC_INIT1 ; IF ZERO, ALL GOOD PRTS(" NOT PRESENT$") ; NOT ZERO, H/W NOT PRESENT OR $FF ; SIGNAL FAILURE RET ; BAIL OUT ; DSRTC_INIT1: ; DISPLAY CURRENT TIME CALL PC_SPACE LD HL,DSRTC_BUF CALL DSRTC_RDCLK LD HL,DSRTC_TIMBUF CALL DSRTC_CLK2TIM LD HL,DSRTC_TIMBUF CALL PRTDT ; #IF DSRTCCHG ; FORCE_RTC_CHARGE_ENABLE LD C,$90 ; ACCESS CHARGE REGISTER LD E,DS1d2k ; STD CHARGE VALUES CALL DSRTC_WRBYTWP #ENDIF ; PRTS(" CHARGE=$") ; DISPLAY CALL DSRTC_TSTCHG ; CHARGING JR NZ,NOCHG1 ; STATUS PRTS("ON$") JR NOCHG2 NOCHG1: PRTS("OFF$") NOCHG2: ; LD BC,DSRTC_DISPATCH CALL RTC_SETDISP ; XOR A ; SIGNAL SUCCESS RET ; ; RTC DEVICE FUNCTION DISPATCH ENTRY ; A: RESULT (OUT), 0=OK, Z=OK, NZ=ERR ; B: FUNCTION (IN) ; DSRTC_DISPATCH: LD A,B ; GET REQUESTED FUNCTION AND $0F ; ISOLATE SUB-FUNCTION JP Z,DSRTC_GETTIM ; GET TIME DEC A JP Z,DSRTC_SETTIM ; SET TIME DEC A JP Z,DSRTC_GETBYT ; GET NVRAM BYTE VALUE DEC A JP Z,DSRTC_SETBYT ; SET NVRAM BYTE VALUE DEC A JP Z,DSRTC_GETBLK ; GET NVRAM DATA BLOCK VALUES DEC A JP Z,DSRTC_SETBLK ; SET NVRAM DATA BLOCK VALUES DEC A JP Z,DSRTC_GETALM ; GET ALARM DEC A JP Z,DSRTC_SETALM ; SET ALARM DEC A JP Z,DSRTC_DEVICE ; REPORT RTC DEVICE INFO SYSCHKERR(ERR_NOFUNC) RET ; ; NVRAM FUNCTIONS ARE NOT AVAILABLE IN SIMULATOR ; DSRTC_GETBLK: DSRTC_SETBLK: DSRTC_GETALM: DSRTC_SETALM: SYSCHKERR(ERR_NOTIMPL) RET ; ; RTC GET TIME ; A: RESULT (OUT), 0=OK, Z=OK, NZ=ERR ; HL: DATE/TIME BUFFER (OUT) ; BUFFER FORMAT IS BCD: YYMMDDHHMMSS ; 24 HOUR TIME FORMAT IS ASSUMED ; DSRTC_GETTIM: LD A,(DSRTC_STAT) ; GET DEVICE STATUS OR A ; SET FLAGS RET NZ ; BAIL OUT ON ERROR ; PUSH HL ; SAVE ADR OF OUTPUT BUF ; ; READ THE CLOCK LD HL,DSRTC_BUF ; POINT TO CLOCK BUFFER CALL DSRTC_RDCLK ; READ THE CLOCK LD HL,DSRTC_TIMBUF ; POINT TO TIME BUFFER CALL DSRTC_CLK2TIM ; CONVERT CLOCK TO TIME ; ; NOW COPY TO REAL DESTINATION (INTERBANK SAFE) LD A,BID_BIOS ; COPY FROM BIOS BANK LD (HB_SRCBNK),A ; SET IT LD A,(HB_INVBNK) ; COPY TO CURRENT USER BANK LD (HB_DSTBNK),A ; SET IT LD HL,DSRTC_TIMBUF ; SOURCE ADR POP DE ; DEST ADR LD BC,6 ; LENGTH IS 6 BYTES #IF (INTMODE == 1) DI #ENDIF CALL HB_BNKCPY ; COPY THE CLOCK DATA #IF (INTMODE == 1) EI #ENDIF ; ; CLEAN UP AND RETURN XOR A ; SIGNAL SUCCESS RET ; AND RETURN ; ; RTC SET TIME ; A: RESULT (OUT), 0=OK, Z=OK, NZ=ERR ; HL: DATE/TIME BUFFER (IN) ; BUFFER FORMAT IS BCD: YYMMDDHHMMSS ; 24 HOUR TIME FORMAT IS ASSUMED ; DSRTC_SETTIM: LD A,(DSRTC_STAT) ; GET DEVICE STATUS OR A ; SET FLAGS RET NZ ; BAIL OUT ON ERROR ; ; COPY INCOMING TIME DATA TO OUR TIME BUFFER LD A,(HB_INVBNK) ; COPY FROM CURRENT USER BANK LD (HB_SRCBNK),A ; SET IT LD A,BID_BIOS ; COPY TO BIOS BANK LD (HB_DSTBNK),A ; SET IT LD DE,DSRTC_TIMBUF ; DEST ADR LD BC,6 ; LENGTH IS 6 BYTES #IF (INTMODE == 1) DI #ENDIF CALL HB_BNKCPY ; COPY THE CLOCK DATA #IF (INTMODE == 1) EI #ENDIF ; ; WRITE TO CLOCK LD HL,DSRTC_TIMBUF ; POINT TO TIME BUFFER CALL DSRTC_TIM2CLK ; CONVERT TO CLOCK FORMAT LD HL,DSRTC_BUF ; POINT TO CLOCK BUFFER CALL DSRTC_WRCLK ; WRITE TO THE CLOCK ; ; CLEAN UP AND RETURN XOR A ; SIGNAL SUCCESS RET ; AND RETURN ; ; RTC GET NVRAM BYTE ; C: INDEX ; E: VALUE (OUTPUT) ; DSRTC_GETBYT: LD A,(DSRTC_STAT) ; GET DEVICE STATUS OR A ; SET FLAGS RET NZ ; BAIL OUT ON ERROR LD A,C ; INDEX SLA A ; SHIFT TO INDEX BITS ADD A,$C1 ; CMD OFFSET LD C,A ; SAVE READ CMD BYTE CALL DSRTC_RDBYT ; DO IT XOR A ; SIGNAL SUCCESS RET ; DONE ; ; RTC SET NVRAM BYTE ; C: INDEX ; E: VALUE ; DSRTC_SETBYT: LD A,(DSRTC_STAT) ; GET DEVICE STATUS OR A ; SET FLAGS RET NZ ; BAIL OUT ON ERROR LD A,C ; INDEX SLA A ; SHIFT TO INDEX BITS ADD A,$C0 ; CMD OFFSET LD C,A ; SAVE WRITE CMD BYTE CALL DSRTC_WRBYTWP ; DO IT XOR A ; SIGNAL SUCCESS RET ; DONE ; ; REPORT RTC DEVICE INFO ; DSRTC_DEVICE: LD D,RTCDEV_DS ; D := DEVICE TYPE LD E,0 ; E := PHYSICAL DEVICE NUMBER LD H,DSRTCMODE ; H := MODE LD L,DSRTC_IO ; L := BASE I/O ADDRESS XOR A ; SIGNAL SUCCESS RET ; ; CONVERT DATA IN CLOCK BUFFER TO TIME BUFFER AT HL ; DSRTC_CLK2TIM: LD A,(DSRTC_YR) LD (HL),A INC HL LD A,(DSRTC_MON) LD (HL),A INC HL LD A,(DSRTC_DT) LD (HL),A INC HL LD A,(DSRTC_HR) LD (HL),A INC HL LD A,(DSRTC_MIN) LD (HL),A INC HL LD A,(DSRTC_SEC) LD (HL),A RET ; ; CONVERT DATA IN TIME BUFFER AT HL TO CLOCK BUFFER ; DSRTC_TIM2CLK: PUSH HL LD A,(HL) LD (DSRTC_YR),A INC HL LD A,(HL) LD (DSRTC_MON),A INC HL LD A,(HL) LD (DSRTC_DT),A INC HL LD A,(HL) LD (DSRTC_HR),A INC HL LD A,(HL) LD (DSRTC_MIN),A INC HL LD A,(HL) LD (DSRTC_SEC),A POP HL CALL TIMDOW INC A ; CONVERT FROM 0-6 TO 1-7 LD (DSRTC_DAY),A RET ; ; TEST CLOCK FOR CHARGE DATA ; DSRTC_TSTCHG: LD C,$91 ; CHARGE RESISTOR & DIODE VALUES CALL DSRTC_RDBYT ; GET VALUE LD A,E ; VALUE TO A AND %11110000 ; CHECK FOR CP %10100000 ; ... ENABLED FLAG RET ; ; DETECT RTC HARDWARE PRESENCE ; DSRTC_DETECT: LD C,30 ; NVRAM INDEX 30 CALL DSRTC_GETBYT ; GET VALUE LD A,E ; TO ACCUM LD (DSRTC_TEMP),A ; SAVE IT XOR $FF ; FLIP ALL BITS LD E,A ; TO E LD C,30 ; NVRAM INDEX 30 CALL DSRTC_SETBYT ; WRITE IT LD C,30 ; NVRAM INDEX 30 CALL DSRTC_GETBYT ; GET VALUE LD A,(DSRTC_TEMP) ; GET SAVED VALUE XOR $FF ; FLIP ALL BITS CP E ; COMPARE WITH VALUE READ LD A,0 ; ASSUME OK JR Z,DSRTC_DETECT1 ; IF MATCH, GO AHEAD LD A,$FF ; ELSE STATUS IS ERROR DSRTC_DETECT1: PUSH AF ; SAVE STATUS LD A,(DSRTC_TEMP) ; GET SAVED VALUE LD C,30 ; NVRAM INDEX 30 CALL DSRTC_SETBYT ; SAVE IT POP AF ; RECOVER STATUS OR A ; SET FLAGS RET ; DONE ; ; TEST CLOCK FOR VALID DATA ; READ CLOCK HALT BIT AND RETURN ZF BASED ON BIT VALUE ; 0 = RUNNING ; 1 = HALTED ; DSRTC_TSTCLK: LD C,$81 ; SECONDS REGISTER HAS CLOCK HALT FLAG CALL DSRTC_RDBYT ; GET REGISTER VALUE LD A,E ; VALUE TO A AND %10000000 ; HIGH ORDER BIT IS CLOCK HALT RET ; ; READ RAW BYTE ; C=READ CMD BYTE ; E=VALUE (OUTPUT) ; DSRTC_RDBYT: CALL DSRTC_START LD E,C CALL DSRTC_CMD CALL DSRTC_GET CALL DSRTC_END RET ; ; WRITE RAW BYTE ; C=WRITE CMD BYTE ; E=VALUE ; DSRTC_WRBYT: CALL DSRTC_START PUSH DE ; SAVE VALUE TO WRITE LD E,C ; CMD TO E CALL DSRTC_CMD POP DE ; RESTORE VALUE CALL DSRTC_PUT CALL DSRTC_END RET ; ; WRITE RAW BYTE W/ WRITE PROTECT BRACKETING ; C=WRITE CMD BYTE ; E=VALUE ; DSRTC_WRBYTWP: LD D,C ; WRITE CMD TO D PUSH DE ; SAVE PARMS ; ; TURN OFF WRITE PROTECT LD C,$8E ; CMD LD E,0 ; WRITE PROTECT OFF CALL DSRTC_WRBYT ; DO IT ; ; WRITE THE VALUE POP DE ; RESTORE INPUTS LD C,D ; WRITE CMD BACK TO C CALL DSRTC_WRBYT ; DO IT ; ; TURN WRITE PROTECT BACK ON LD C,$8E ; WRITE CMD TO D LD E,$80 ; WRITE PROTECT ON CALL DSRTC_WRBYT ; DO IT ; RET ; ; BURST READ CLOCK DATA INTO BUFFER AT HL ; DSRTC_RDCLK: CALL DSRTC_START LD E,$BF ; COMMAND = $BF TO BURST READ CLOCK CALL DSRTC_CMD ; SEND COMMAND TO RTC LD B,DSRTC_BUFSIZ ; B IS LOOP COUNTER DSRTC_RDCLK1: PUSH BC ; PRESERVE BC CALL DSRTC_GET ; GET NEXT BYTE LD (HL),E ; SAVE IN BUFFER INC HL ; INC BUF POINTER POP BC ; RESTORE BC DJNZ DSRTC_RDCLK1 ; LOOP IF NOT DONE JP DSRTC_END ; FINISH IT ; ; BURST WRITE CLOCK DATA FROM BUFFER AT HL ; DSRTC_WRCLK: CALL DSRTC_START LD E,$8E ; COMMAND = $8E TO WRITE CONTROL REGISTER CALL DSRTC_CMD ; SEND COMMAND LD E,$00 ; $00 = UNPROTECT CALL DSRTC_PUT ; SEND VALUE TO CONTROL REGISTER CALL DSRTC_END ; FINISH IT ; LD E,$BE ; COMMAND = $BE TO BURST WRITE CLOCK CALL DSRTC_CMD ; SEND COMMAND TO RTC LD B,DSRTC_BUFSIZ ; B IS LOOP COUNTER DSRTC_WRCLK1: PUSH BC ; PRESERVE BC LD E,(HL) ; GET NEXT BYTE TO WRITE CALL DSRTC_PUT ; PUT NEXT BYTE INC HL ; INC BUF POINTER POP BC ; RESTORE BC DJNZ DSRTC_WRCLK1 ; LOOP IF NOT DONE LD E,$80 ; ADD CONTROL REG BYTE, $80 = PROTECT ON CALL DSRTC_PUT ; WRITE REQUIRED 8TH BYTE JP DSRTC_END ; FINISH IT ; ; SEND COMMAND IN E TO RTC ; ALL RTC SEQUENCES MUST CALL THIS FIRST TO SEND THE RTC COMMAND. ; THE COMMAND IS SENT VIA A PUT. CE AND CLK ARE LEFT ASSERTED! THIS ; IS INTENTIONAL BECAUSE WHEN THE CLOCK IS LOWERED, THE FIRST BIT ; WILL BE PRESENTED TO READ (IN THE CASE OF A READ CMD). ; ; N.B. REGISTER A CONTAINS WORKING VALUE OF LATCH PORT AND MUST NOT ; BE MODIFIED BETWEEN CALLS TO DSRTC_CMD, DSRTC_PUT, AND DSRTC_GET. ; ; 0) ASSUME ALL LINES UNDEFINED AT ENTRY ; 1) DEASSERT ALL LINES (CE, RD, CLOCK, & DATA) ; 2) WAIT 1US ; 3) SET CE HI ; 4) WAIT 1US ; 5) PUT COMMAND ; DSRTC_CMD: LD A,(DSRTC_OPRVAL) ; INIT A WITH QUIESCENT STATE OUT (DSRTC_IO),A ; WRITE TO PORT CALL DLY2 ; DELAY 2 * 27 T-STATES #IF ((DSRTCMODE == DSRTCMODE_MFPIC) | (DSRTCMODE == DSRTCMODE_K80W)) AND ~DSRTC_CE ; ASSERT CE (LOW) #ELSE OR DSRTC_CE ; ASSERT CE (HIGH) #ENDIF OUT (DSRTC_IO),A ; WRITE TO RTC PORT CALL DLY2 ; DELAY 2 * 27 T-STATES CALL DSRTC_PUT ; WRITE IT RET ; ; WRITE BYTE IN E TO THE RTC ; WRITE BYTE IN E TO THE RTC. CE IS IMPLICITY ASSERTED AT ; THE START. CE AND CLK ARE LEFT ASSERTED AT THE END IN CASE ; NEXT ACTION IS A READ. ; ; 0) ASSUME ENTRY WITH CE HI, OTHERS UNDEFINED ; 1) SET CLK LO ; 2) WAIT 250NS ; 3) SET DATA ACCORDING TO BIT VALUE ; 4) SET CLOCK HI ; 5) WAIT 250NS (CLOCK READS DATA BIT FROM BUS) ; 6) LOOP FOR 8 DATA BITS ; 7) EXIT WITH CE,CLK HI ; DSRTC_PUT: LD B,8 ; LOOP FOR 8 BITS #IF ((DSRTCMODE == DSRTCMODE_MFPIC) | (DSRTCMODE == DSRTCMODE_K80W)) OR DSRTC_WR ; SET WRITE MODE #ELSE AND ~DSRTC_RD ; SET WRITE MODE #ENDIF DSRTC_PUT1: AND ~DSRTC_CLK ; SET CLOCK LOW OUT (DSRTC_IO),A ; DO IT CALL DLY1 ; DELAY 27 T-STATES #IF ((DSRTCMODE == DSRTCMODE_MFPIC) | (DSRTCMODE == DSRTCMODE_K80W)) RRA ; PREP ACCUM TO GET DATA BIT IN CARRY RR E ; ROTATE NEXT BIT TO SEND INTO CARRY RLA ; ROTATE BITS BACK TO CORRECT POSTIIONS #ELSE RLA ; PREP ACCUM TO GET DATA BIT IN CARRY RR E ; ROTATE NEXT BIT TO SEND INTO CARRY RRA ; ROTATE BITS BACK TO CORRECT POSTIIONS #ENDIF OUT (DSRTC_IO),A ; ASSERT DATA BIT ON BUS OR DSRTC_CLK ; SET CLOCK HI OUT (DSRTC_IO),A ; DO IT CALL DLY1 ; DELAY 27 T-STATES DJNZ DSRTC_PUT1 ; LOOP IF NOT DONE RET ; ; READ BYTE FROM RTC, RETURN VALUE IN E ; READ THE NEXT BYTE FROM THE RTC INTO E. CE IS IMPLICITLY ; ASSERTED AT THE START. CE AND CLK ARE LEFT ASSERTED AT ; THE END. CLOCK *MUST* BE LEFT ASSERTED FROM DSRTC_CMD! ; ; 0) ASSUME ENTRY WITH CE HI, OTHERS UNDEFINED ; 1) SET RD HI AND CLOCK LOW ; 3) WAIT 250NS (CLOCK PUTS DATA BIT ON BUS) ; 4) READ DATA BIT ; 5) SET CLOCK HI ; 6) WAIT 250NS ; 7) LOOP FOR 8 DATA BITS ; 8) EXIT WITH CE,CLK,RD HI ; DSRTC_GET: LD E,0 ; INITIALIZE WORKING VALUE TO 0 LD B,8 ; LOOP FOR 8 BITS #IF ((DSRTCMODE == DSRTCMODE_MFPIC) | (DSRTCMODE == DSRTCMODE_K80W)) AND ~DSRTC_WR ; SET READ MODE #ELSE OR DSRTC_RD ; SET READ MODE #ENDIF DSRTC_GET1: AND ~DSRTC_CLK ; SET CLK LO OUT (DSRTC_IO),A ; WRITE TO RTC PORT CALL DLY1 ; DELAY 2 * 27 T-STATES PUSH AF ; SAVE PORT VALUE IN A,(DSRTC_IO) ; READ THE RTC PORT RRA ; DATA BIT TO CARRY RR E ; SHIFT INTO WORKING VALUE POP AF ; RESTORE PORT VALUE OR DSRTC_CLK ; CLOCK BACK TO HI OUT (DSRTC_IO),A ; WRITE TO RTC PORT CALL DLY1 ; DELAY 27 T-STATES DJNZ DSRTC_GET1 ; LOOP IF NOT DONE (13) RET ; ; START A COMMAND SEQUENCE ; INITIATES A COMMAND SEQUENCE ; DOES NOT DESTROY ANY REGISTERS. ; ; 1) CAPTURE RTC LATCH BITS ; DSRTC_START: ; SET RELEVANT BITS IN RTC LATCH SHADOW REGISTER ; TO THEIR QUIESENT STATE PUSH AF LD A,(DSRTC_OPRVAL) ; GET CURRENT SHADOW REG VAL AND ~DSRTC_MASK ; CLEAR OUR BITS OR DSRTC_IDLE ; SET OUR IDLE BITS LD (DSRTC_OPRVAL),A ; SAVE IT POP AF RET ; ; COMPLETE A COMMAND SEQUENCE ; FINISHES UP A COMMAND SEQUENCE. ; DOES NOT DESTROY ANY REGISTERS. ; ; 1) SET ALL LINES BACK TO QUIESCENT STATE ; DSRTC_END: ;PUSH AF LD A,(DSRTC_OPRVAL) ; INIT A WITH QUIESCENT STATE OUT (DSRTC_IO),A ; WRITE TO PORT ;POP AF RET ; RETURN ; ; WORKING VARIABLES ; DSRTC_STAT .DB 0 ; DEVICE STATUS (0=OK) DSRTC_TEMP .DB 0 ; TEMP VALUE STORAGE ; #IF ((DSRTCMODE == DSRTCMODE_MFPIC) | (DSRTCMODE == DSRTCMODE_K80W)) DSRTC_RTCVAL .DB DSRTC_IDLE ; LOCAL LATCH SHADOW FOR MFPIC #ENDIF ; ; DSRTC_BUF IS USED FOR BURST READ/WRITE OF CLOCK DATA TO DS-1302 ; FIELDS BELOW MATCH ORDER OF DS-1302 FIELDS (BCD) ; DSRTC_BUF: DSRTC_SEC .DB 0 ; SECOND DSRTC_MIN .DB 0 ; MINUTE DSRTC_HR .DB 0 ; HOUR DSRTC_DT .DB 0 ; DATE DSRTC_MON .DB 0 ; MONTH DSRTC_DAY .DB 0 ; DAY OF WEEK DSRTC_YR .DB 0 ; YEAR ; ; DSRTC_TIMBUF IS TEMP BUF USED TO STORE TIME TEMPORARILY TO DISPLAY ; IT. ; DSRTC_TIMBUF .FILL 6,0 ; 6 BYTES FOR GETTIM ; ; DSRTC_TIMDEF IS DEFAULT TIME VALUE TO INITIALIZE CLOCK IF IT IS ; NOT RUNNING. ; DSRTC_TIMDEF: ; DEFAULT TIME VALUE TO INIT CLOCK .DB $00,$01,$01 ; 2000-01-01 .DB $00,$00,$00 ; 00:00:00