Hi All,
When I built my CF card interface, I added a DS1302 Real Time clock to provide file date/time stamping. The chip is easy to work with and, using a coin battery, provides a great time of day reference.
Last week, I found a small module on ebay that uses the DS1302 and though it would be a great addition for those wanting a time of day clock.
Here's a link:
http://www.ebay.com/itm/201172366130Attachment:
$_57.jpg [ 61.34 KiB | Viewed 2375 times ]
At $0.99 (including battery!), its a great deal.
For those interested, you can use any three port pins on a 6522 to access the clock. The /RST pin on the board is actually the CE pin. I am including my driver code to access the chip. The code uses 6502 opcodes. I have a WDC65C02 version that takes advantage of the TRB and TSB commands if anyone is interested.
Here's the code:
Code:
;***********************************************;
; DS1302 Real Time Clock Driver for 6502 ;
; v1.0 1/11/2015 ;
; Written by Daryl Rictor ;
;***********************************************
;-----------------------------------------------
; IO Device labels
;-----------------------------------------------
RTC_CE_DDR = $0283 ; VIA1DDRA
RTC_CE_DP = $0281 ; VIA1DRA
RTC_CE_B = $01 ; PA0
RTC_SC_DDR = $0283 ; VIA1DDRA
RTC_SC_DP = $0281 ; VIA1DRA
RTC_SC_B = $02 ; PA1
RTC_IO_DDR = $0283 ; VIA1DDRA
RTC_IO_DP = $0281 ; VIA1DRA
RTC_IO_B = $04 ; PA2
;-----------------------------------------------
; RAM Data location for Date/Time values
;-----------------------------------------------
rtcSec = $7FF0 ; sec
rtcMin = $7FF1 ; min
rtcHR = $7FF2 ; hr
rtcDay = $7FF3 ; day
rtcMon = $7FF4 ; month
rtcDOW = $7FF5 ; day of week
rtcYR = $7FF6 ; yr
rtcPR = $7FF7 ; Write protect
;-----------------------------------------------
; Write a cmd/data combo from x,a to the RTC.
;-----------------------------------------------
WrCmd pha ; save data
lda RTC_CE_DP
ora #RTC_CE_B
sta RTC_CE_DP ; set CE to 1
txa ; move cmd to A
jsr WrByte ; write cmd to RTC
lda RTC_IO_DDR
ora #RTC_IO_B
sta RTC_IO_DDR ; set IO pin to output
pla ; restore data byte
jsr WrByte ; write data to RTC
lda RTC_CE_DP
and #255-RTC_CE_B
sta RTC_CE_DP ; set CE = 0
lda RTC_IO_DDR
ora #RTC_IO_B
sta RTC_IO_DDR ; set IO to output
rts
;-----------------------------------------------
; Clock out the byte in A to the RTC.
; Data is clocked out starting with bit 0.
; Data is clocked into the RTC on the rising edge.
;-----------------------------------------------
WrByte ldy #8 ; 8 bits to clock out.
WrByte1 lsr ; rotate bit 0 into C
pha ; save data
bcc WrByte2 ; if bit = 0
lda RTC_IO_DP
ora #RTC_IO_B
sta RTC_IO_DP ; set IO bit to 1
jmp WrByte3
WrByte2 lda RTC_IO_DP
and #255-RTC_IO_B ; set IO bit to 0
sta RTC_IO_DP
WrByte3 lda RTC_SC_DP
ora #RTC_SC_B
sta RTC_SC_DP ; set sc to 1
dey
beq WrByte4 ; do 8 bits
lda RTC_SC_DP
and #255-RTC_SC_B
sta RTC_SC_DP ; set sc to 0
pla ; restore data
jmp WrByte1
WrByte4 pla ; restore stack
lda RTC_IO_DDR
and #255-RTC_IO_B
sta RTC_IO_DDR ; set data to input
lda RTC_IO_DP
and #255-RTC_IO_B
sta RTC_IO_DP ; set data to 0
lda RTC_SC_DP
and #255-RTC_SC_B
sta RTC_SC_DP ; set SC to 0
rts
;-----------------------------------------------
; Read a byte following write of command byte.
; command in A, data returned in A
;-----------------------------------------------
RdCmd pha ; save command
lda RTC_CE_DP
ora #RTC_CE_B
sta RTC_CE_DP ; set CE to 1
pla ; restore command
jsr WrByte
jsr RdByte
pha ; save data
lda RTC_CE_DP
and #255-RTC_CE_B
sta RTC_CE_DP ; set CE = 0
lda RTC_IO_DDR
ora #RTC_IO_B
sta RTC_IO_DDR ; set IO to output
pla ; restore data
rts
;-----------------------------------------------
; read in a byte from the RTC to A
;-----------------------------------------------
RdByte ldx #$00 ; data byte
ldy #8
RdByte1 lda RTC_IO_DP ; read IO
and #RTC_IO_B ; mask IO bit
clc ; Clear carry.
beq RDByte2
sec ; Set Carry Flag
RDByte2 txa ; get data
ror ; Rotate data into bit.
tax ; save data
lda RTC_SC_DP
ora #RTC_SC_B
sta RTC_SC_DP ; set sc to 1
nop
nop
lda RTC_SC_DP
and #255-RTC_SC_B
sta RTC_SC_DP ; set sc to 0
dey ; 8 bits
bne RdByte1
txa ; put data in A
rts
;-----------------------------------------------
; Read calendar in burst mode
; Saves data read to RAM locates defined above
;-----------------------------------------------
RdCal lda RTC_CE_DP
ora #RTC_CE_B
sta RTC_CE_DP ; set CE to 1
lda #$BF ; burts mode read calendar
jsr WrByte
jsr RdByte
sta rtcSec ; sec
jsr RdByte
sta rtcMin ; min
jsr RdByte
sta rtcHR ; hr
jsr RdByte
sta rtcDay ; day
jsr RdByte
sta rtcMon ; month
jsr RdByte
sta rtcDOW ; dow
jsr RdByte
sta rtcYR ; yr
jsr RdByte
sta rtcPR ; WP
lda RTC_CE_DP
and #255-RTC_CE_B
sta RTC_CE_DP ; set CE = 0
lda RTC_IO_DDR
ora #RTC_IO_B
sta RTC_IO_DDR ; set IO to output
rts
;-----------------------------------------------
; Write calendar in burst mode
; gets values from RAM locates defined above
;-----------------------------------------------
WrCal ldx #$8E ; write WP byte
lda #$00 ; turn WP off
jsr WrCmd
lda RTC_CE_DP
ora #RTC_CE_B
sta RTC_CE_DP ; set CE to 1
lda #$BE ; burts mode write calendar
jsr WrByte
lda RTC_IO_DDR
ora #RTC_IO_B
sta RTC_IO_DDR ; set IO to output
lda rtcSec ; secs
jsr WrByte
lda RTC_IO_DDR
ora #RTC_IO_B
sta RTC_IO_DDR ; set IO to output
lda rtcMin ; mins
jsr WrByte
lda RTC_IO_DDR
ora #RTC_IO_B
sta RTC_IO_DDR ; set IO to output
lda rtcHR ; hrs
jsr WrByte
lda RTC_IO_DDR
ora #RTC_IO_B
sta RTC_IO_DDR ; set IO to output
lda rtcDay ; day
jsr WrByte
lda RTC_IO_DDR
ora #RTC_IO_B
sta RTC_IO_DDR ; set IO to output
lda rtcMon ; month
jsr WrByte
lda RTC_IO_DDR
ora #RTC_IO_B
sta RTC_IO_DDR ; set IO to output
lda rtcDow ; dow
jsr WrByte
lda RTC_IO_DDR
ora #RTC_IO_B
sta RTC_IO_DDR ; set IO to output
lda rtcYR ; yr
jsr WrByte
lda RTC_IO_DDR
ora #RTC_IO_B
sta RTC_IO_DDR ; set IO to output
lda rtcPR ; write protect
jsr WrByte
lda RTC_CE_DP
and #255-RTC_CE_B
sta RTC_CE_DP ; set CE = 0
lda RTC_IO_DDR
ora #RTC_IO_B
sta RTC_IO_DDR ; set IO to output
rts
;-----------------------------------------------
; Initialize the DS1302
;-----------------------------------------------
ds1302_init lda RTC_CE_DDR
ora #RTC_CE_B
sta RTC_CE_DDR ; set CE to output
lda RTC_CE_DP
ora #RTC_CE_B
sta RTC_CE_DP ; set CE = 1
lda RTC_SC_DDR
ora #RTC_SC_B
sta RTC_SC_DDR ; set SC to output
lda RTC_SC_DP
and #255-RTC_SC_B
sta RTC_SC_DP ; set CE = 0
lda RTC_IO_DDR
ora #RTC_IO_B
sta RTC_IO_DDR ; set data to output
lda RTC_IO_DP
and #255-RTC_IO_B
sta RTC_IO_DP ; set data to 0
lda RTC_CE_DP
and #255-RTC_CE_B
sta RTC_CE_DP ; set CE = 1
ldx #$90 ; write charger control reg
lda #$00 ; turn trickle charger off
jsr WrCmd ;
ldx #$8E ; write WP byte
lda #$00 ; turn WP off
jsr WrCmd
lda #$81 ; read seconds
jsr RDCmd
and #$7F ; turn off clk halt bit
ldx #$80 ; seconds
jsr WrCmd ; enable clock
ldx #$8E ; write WP byte
lda #$80 ; turn WP off
jsr WrCmd
rts
;-----------------------------------------------
; END
;-----------------------------------------------
You only need to run the DS1320_init code once after the battery is installed. It just gets the clock running and turns off the trickle charging circuits.
The data bytes are BCD coded. To set the clock, enter the date and time in the RAM locations and call the WrCal routine.
Calling the RdCal routine will copy the date and time to the RAM locations where your code can use it.
Here are the valid ranges for the data bytes:
rtcSec - 0-59
rtcMin - 0-59
rtcHR - 1-12 or 0-23 (0-23 is entered directly - see data sheet for using a 12 hour clock)
rtcDay - 1-31
rtcMon - 1-12
rtcDOW - 1-7 (you can set any reference you like 1-SUN, 1-MON, etc. - it just cycles through the range)
rtcYR - 00-99
rtcPR - $80 (leave this set to $80)
I hope someone finds this useful.
Daryl
_________________
Please visit my website ->
https://sbc.rictor.org/