ZX81 Nixie Clock Source code

Any discussions related to the creation of new hardware or software for the ZX80 or ZX81
Post Reply
zx81user
Posts: 54
Joined: Mon Mar 25, 2013 3:14 am

ZX81 Nixie Clock Source code

Post by zx81user »

In this thread discussions about the ZX81 Nixie Clock source code. It is open source, so everyone can have a look at it and make modifications where possible. Would be nice to have a DCF77 interface connected to it, as found in the German forum. It wouldn't be of any help to me as we can't receive the signal in Australia, in fact, the only possible solution here would be through a GPS system :-(. To keep the clock accurate without a radio reference, I have implemented 6 calibration registers. The main register is 24 bits, the others are 16 bits. The values for these registers can be calculated using the BASIC program CALCLC7.P (also added in attached file). It basically calculates when a clock tick needs to be added or subtracted from the event stream. There are normally 50 or 60 ticks coming in per second, this is however not accurate at all. If you were just counting these ticks, the clock will run 7 seconds fast per 10 minutes on a 50Hz Zeddy and 9 seconds slow per 30 minutes on a 60Hz zeddy. The main calibration register roughly corrects this to an accuracy of about 5 seconds/day. The other 5 sub registers can adjust this further down to about 1.5 sec per year. However, with a normal ceramic resonator (6.5MHz) you probably won't get a better result than 1 second per day, if you change this resonator to a quartz crystal you probably get to 2 seconds per month and with a TCXO you should be able to get to 1.5 sec/year. So although the calibration routines are too complicated for most Zeddies, if you really want to, you can make a very accurate clock using this software.

Calibration is done in steps, you first measure the deviation in say 30 minutes. Fill out the data in the CALCLC7 program, enter the calibration data into the assembly file, then assemble the file using ZX-IDE, transfer the file and let the clock run for say 1 day. Measure the deviation, fill it out in the CALCLC7 program etc etc. After 2 or 3 times (say 30 minutes, then 1 day, then 1 week) you have a very accurate clock.

http://xiac.com/ZX81/ZX81NixieClock.zip

Suggestions welcome.

Michel
User avatar
PokeMon
Posts: 2264
Joined: Sat Sep 17, 2011 6:48 pm

Re: ZX81 Nixie Clock Source code

Post by PokeMon »

Well took a look at your source but it's a bit complicate.
Just three suggestions from my side:

1. You can use the variables section (printer buffer) directly when you include ZX81VARS.INC (and ZX81DEF.INC) instead of simply ZX81.INC
Then you can skip the copy of variables from BASIC line 10.
But you do this several times in your source - don't know why.

Code: Select all

CLOCK_PORT      EQU      $3F    ;EITHER $3F OR $77
SCROLL_CNT      EQU      19


; content of ZX81VARS.INC modified (variable section)
virtual at MEMST

ERR_NR  db      ?       ; error number $ff is no error
FLAGS   db      ?       ; flags of system
ERR_SP  dw      ?       ; first item of machine stack
RAMTOP  dw      ?       ; top address of ram, first non-existing memory location
MODE    db      ?       ; cursor mode (K/L,F,G)
PPC     dw      ?       ; line number currently executed

SAVE_BEGIN:              ; start address of prgrams loaded into memory

end virtual

        ORG     SAVE_BEGIN

        VERSN   db 0            ; version, 0=ZX81 BASIC
        E_PPC   dw 0            ; number of current line with cursor (in listing)
        D_FILE  dw DFILE_ADDR   ; begin of D_FILE (display file) in memory
        DF_CC   dw DFILE_ADDR+1 ; current cursor position in D_FILE (used for print routine)
        VARS    dw VARS_ADDR    ; begin of variable section in memory
        DEST    dw 0            ; address of variable in assignment
        E_LINE  dw WORKSPACE    ; address of workspace
if defined AUTORUN
        CH_ADD  dw AUTORUN      ; address of next character to be interpreted
else
        CH_ADD  dw 0            ; address of next character to be interpreted
end if
        X_PTR   dw 0            ; address of character preceeding "S" marker
        STKBOT  dw WORKSPACE    ; stack botton (top-down)
        STKEND  dw WORKSPACE    ; end of stack (top)
        BERG    db 0            ; calculators b register, possibly write error, should be BREG :-)
        MEM     dw MEMBOT       ; address for calculator's memory
        UNUSED1 db 0            ; unused variable / space
        DF_SZ   db 2            ; no. of lines in lower part of screen including 1 blank line
        S_TOP   dw 0            ; no. of top program line in automatic listings
        LAST_K  dw 0            ; last key pressed
        DEBOUNCE db 0           ; debounce status of keyboard
        MARGIN  db PAL          ; margin value, could be used PAL or NTSC
if defined AUTORUN
        NXTLIN  dw AUTORUN      ; next line to be executed
else
        NXTLIN  dw 0            ; next line to be executed
end if
        OLDPPC  dw 0            ; line to jump when executing CONT (continue)
        FLAGX   db 0            ; internal flags
        STRLEN  dw 0            ; length of string, interally used
        T_ADDR  dw 0            ; next item in syntax (token) table
        SEED    dw 0            ; seed variable set by RAND
        FRAMES  dw 0            ; counter of frames sent to TV, used by PAUSE command
        COORDS  db 0            ; x coordinate of last point plotted
                db 0            ; y coordinate of last point plotted
        PR_CC   db $BC          ; LPRINT position used with real printer
        S_POSN  db 33           ; column no. for print position
                db 24           ; line no. for print position
if defined FASTMODE
        CDFLAG  db FAST_MODE    ; compute and display flag
else
        CDFLAG  db SLOW_MODE
end if

begin_of_printer_buffer: ;($403C)

hours   db 0; equ     $403c           ;printer buffer area
mints   db 0; equ     $403d           ;
secnd   db 0; equ     $403e           ;
dummy   db 0; equ     $403f           ;

pscale1 db 0; equ     $4040           ;2Hz pre-scaler
correct db 0; equ     $4041           ;correction register to add or substract events (calibration)
psth    db 0; equ     $4042           ;pre-scaler threshold level; dependent on 50Hz or 60Hz
regcntr db 0; equ     $4043           ;used in the update calibration routine to count the processed amount of registers
cflgs   db 3 dup(0) ; equ     $4044           ;

cal1r   db 90,0,0 ; equ     $4047           ;
cal2r   db 0,0 ; equ     $404a           ;
cal3r   db 0,0 ; equ     $404c           ;
cal4r   db 0,0 ; equ     $404e           ;
cal5r   db 0,0 ; equ     $4050           ;
cal6r   db 0,0 ; equ     $4052           ;
csign   db 0 ; sign for correction (either positive (0-slow down) or negative (1-speed up))
                                ;0 for 50Hz/PAL; 1 for 60Hz/NTSC

scroll  db 0 ; equ     $4054
rotcnt  db SCROLL_CNT ; equ     $4055

resprbuf db 6 dup(0)
        MEMBOT  db 30 dup(0)    ; calculator additional memory            ???
        UNUSED2 dw 0            ; unused variable / space

BASIC_AREA:
2. You can write directly into the display file and you can fill the display file with your 8 characters easily.

Code: Select all

DFILE_ADDR:
        db      25 dup(NEWLINE)
instead write:
       db NEWLINE ; sync of picture
       dbzx '********',NEWLINE ; first line
       db 23 dup (NEWLINE) ; following lines
Just write directly into the display buffer instead of calling ROM functions.

3. I think the adjustment can be made more easily when you find out how many seconds the clock is running if one second deviation (by running clock for maybe 24 hours) and determine to add od subtract a second every 12533 seconds (if this is the deviation).

So the trick is to keep it more simple.

But your clock is a great gadget for the ZX81 - I have all respect for your development. Just a few hints when overflowing your code.
zx81user
Posts: 54
Joined: Mon Mar 25, 2013 3:14 am

Re: ZX81 Nixie Clock Source code

Post by zx81user »

Hi PokeMon, Thanks for having a look at the code.

>>>Well took a look at your source but it's a bit complicate.
Just three suggestions from my side:

1. You can use the variables section (printer buffer) directly when you include ZX81VARS.INC (and ZX81DEF.INC) instead of simply ZX81.INC
Then you can skip the copy of variables from BASIC line 10.

OK, that sounds like a plan. Yes, sure I need to copy this several times because 1 set is the set values and the other registers count down to 0 and need to be re-loaded once they reach 0.

2. You can write directly into the display file and you can fill the display file with your 8 characters easily.

That's what I had done initially, but the problem is when I return to basic, I loose these characters and so cannot run the program anymore without messing up the screen :-). That's why I print them in the code so that every time when I type RUN, the characters will be printed to the screen and I know the display memory is there.

3. I think the adjustment can be made more easily when you find out how many seconds the clock is running if one second deviation (by running clock for maybe 24 hours) and determine to add od subtract a second every 12533 seconds (if this is the deviation).

...... that is a dirty trick..... no clock builder will respect that :-). However, even that is not as simple as you think because adding/subtracting seconds means you need to check minutes for overflow, check hours for overflow and you need to define somehow when these seconds need to be added/subtracted. Once you program that, you will probably come to the conclusion that skipping clock ticks is the best and simplest way to go.

Michel
Post Reply