A ZXIO Project: Intefacting with a DS12C887
Keeping track of the current date/time on a ZX81 serves no useful purpose in 2024, thus making it the perfect project for a ZX81, the perfect project for the ZXIO V2 interface cards and the perfect use of everybbodies favourite clock chip the Dallas DS12C887.
The Dallas Semiconductor DS12C887 RTC modules are well-known in retro computing circles for their integrated real-time clock and their gradually failing battery backup. However, they remain readily available, along with the core of the module the DS12885 which offers the same functionality only requiring an external battery backup. For simplicity's sake, and because I have some functional DS12C887 modules, this ZXIO project will use a complete module.
Configuration and Schematics
- Set up the ZXIO V2 / 8255A in Mode 0 for basic I/O.
- Designate specific ports for communication with the RTC:
- Port A: Data bus to exchange data with the RTC.
- Port C: Control lines like chip select (CS), read/write (R/W), Address Strobe (AS) and Data Strobe (DS).
Interestingly, the Chip Select line on the RTC is active low, as is the Write signal on the R/W lines. I’ve chosen to invert these signals as this seems to make more sense when writing the BASIC program to control the clock. You'll notice on the schematic that I've used a CD74HC02 NOR gate to invert the signals.
As part of the Chip Select inversion, one input of the NOR gate is paired with another output from the CD74HC02, which is connected to ground. This setup creates a small delay, preventing the RTC’s memory from being cleared or reset during power cycles or resets, ensuring it retains its time and configuration data.
RTC for ZXIO V2 Circuit Schematic |
A "Functional" Clock Program
10 REM **************
15 REM ** GET TIME **
20 REM **************
25 LET Y=0
30 LET A$=""
35 LET T$=""
40 FOR X=4 TO 0 STEP -2
45 POKE 49151,128
50 POKE 49150,130
55 POKE 49148,X
60 POKE 49151,144
65 POKE 49150,132
70 LET Y=PEEK 49148
75 LET A$="0"+STR$ (10*INT (Y/16)+Y-INT (Y/16)*16)
80 LET Y=LEN A$
85 LET T$=T$+A$(Y-1 TO Y)+":"
90 NEXT X
95 PRINT AT 0,0;T$(1 TO 8)
100 GOTO 170
105 REM **************
110 REM ** SET TIME **
115 REM **************
120 LET T$="225533"
125 POKE 49151,128
130 FOR X=0 TO LEN (T$)-1 STEP 2
135 LET Y=VAL (T$(X+1 TO X+2))
140 POKE 49150,130
145 POKE 49148,LEN (T$)-X-2
150 POKE 49150,133
155 POKE 49148,Y-INT (Y/10)*10+INT (Y/10)*16
160 PRINT Y-INT (Y/10)*10+INT (Y/10)*16,LEN (T$)-X-2
165 NEXT X
170 STOP
GET TIME (Lines 10–100)
his part retrieves the current time from the RTC module and formats it into a readable string.
Initialisation:
- Lines
25–35
: VariablesY
,A$
, andT$
are initialised.T$
will hold the final formatted time.
- Lines
Reading Time Data:
- Lines
40–90
: A loop iterates through the time registers in reverse order (the RTC stores hours, minutes, and seconds in separate registers).- Line 45: Writes
128
to the control register to prepare the RTC for a read operation. - Line 50: Writes
130
to select the time register. - Line 55: Specifies which time register to read (X corresponds to seconds, minutes, or hours).
- Line 60: Executes the read operation.
- Line 70: Retrieves the register value using
PEEK
.
- Line 45: Writes
- Lines
Formatting:
- Lines
75–85
: Converts the binary-coded decimal (BCD) value from the RTC into a two-digit decimal number:Y/16
extracts the tens digit.Y-INT(Y/16)*16
extracts the units digit.- The digits are concatenated into
A$
and appended to the time stringT$
with a colon separator.
- Lines
Display:
- Line
95
: Displays the formatted time (first 8 characters) at the top-left corner of the ZX81 screen.
- Line
Repeat:
- Line
100
: Ends the routine and jumps to the time-setting routine if implemented further.
SET TIME (Lines 105–170)
This part writes a new time into the RTC module.
Initialisation:
- Line
120
: The variableT$
is hardcoded with a new time in the formatHHMMSS
(e.g., "225533" = 22:55:33).
- Line
Writing Time Data:
- Lines
130–165
: A loop iterates through the stringT$
in pairs of digits to set the hours, minutes, and seconds registers:- Line 135: Extracts two digits from
T$
and converts them into an integer. - Line 140: Prepares the RTC for a write operation by setting the appropriate control values.
- Line 145: Specifies the time register to write to.
- Line 150: Converts the decimal value into BCD format and writes it to the RTC.
- Line 135: Extracts two digits from
- Lines
Debugging/Confirmation:
- Line
160
: Displays the BCD-encoded value and the register being written to for verification.
- Line
Time Loop
With Line 100 changed to "GOTO 35," the "GET TIME" portion of the program becomes a continuously running clock—though it updates slightly slower than real time. The program, as written, takes just under 2 seconds to update. This could be sped up to some degree by only looping through the seconds and minutes as needed, rather than reading the entire time (hours, minutes, and seconds) every time. The video demonstration bellow is taken from slightly earlier version of the program and is slightly slower (slightly).
And that’s a wrap on reading and interacting with the Dallas Real-Time Clock—at least for now. We've successfully coaxed the ZX81 into telling the time (with a slight delay, of course). If we’ve learned anything, it’s that time waits for no one… except maybe for the ZX81, which could probably use a little more time to catch up.
Reference: Dallas RTC DS12C887 Module Pinout
Pin | Name | Description |
---|---|---|
1 | MOT | Motorola Timing Select. Connect to VCC for Motorola timings. |
2 | X1 | Connections for Standard 32.768kHz Quartz Crystal – Internal. |
3 | X2 | Connections for Standard 32.768kHz Quartz Crystal – Internal. |
4 | D0 | Data Bus Line 0 (part of the 8-bit data bus). |
5 | D1 | Data Bus Line 1 (part of the 8-bit data bus). |
6 | D2 | Data Bus Line 2 (part of the 8-bit data bus). |
7 | D3 | Data Bus Line 3 (part of the 8-bit data bus). |
8 | D4 | Data Bus Line 4 (part of the 8-bit data bus). |
9 | D5 | Data Bus Line 5 (part of the 8-bit data bus). |
10 | D6 | Data Bus Line 6 (part of the 8-bit data bus). |
11 | D7 | Data Bus Line 7 (part of the 8-bit data bus). |
12 | GND | Ground. |
13 | CS~ | Chip Select, active low. Selects the RTC for communication. |
14 | AS | Address Strobe. Latches address bits on the falling edge. |
15 | R/W | Read/Write input. Determines whether data is read from or written to the RTC. |
16 | GND | Ground. |
17 | DS | Data Strobe, active low. Enables reading or writing data to the RTC. |
18 | RESET | Reset input, active low. Resets the RTC registers when asserted. |
19 | IRQ~ | Interrupt Request, active low. Signals alarms or periodic events. |
20 | VBAT | Connection for a Primary Battery – Internal. |
21 | RCLR~ | Active-Low RAM Clear. Pin is internally pulled up. |
22 | NC | No Connection (not used). |
23 | SQW | Square Wave output. Outputs a programmable frequency or 1 Hz for timekeeping. |
24 | VCC | Power supply input (typically +5V). |