Files
oldlinux-files/study/sabre/os/files/MiscHW/RealTimeClock.txt
2024-02-19 00:25:23 -05:00

264 lines
8.7 KiB
Plaintext

Some remarks on the usage of the Real Time Clock (RTC) MC 146818 of the AT.
Not as comprehensive as The_Serial_Port, but I'm working on it :-).
Chris
--------------------------------------------------------------------------
You should use the BIOS interrupt 1Ah to program the RTC. If you don't
like this or if you want to use some special features, here is how to
access the registers directly:
Reading an RTC register
-----------------------
cli ; make sure no interrupt wants to access the RTC in the mean time
mov al,address
out 70h,al
in al,71h
sti
_disable();
outp(0x70,address);
x=inp(0x71);
_enable();
Writing an RTC register
-----------------------
cli
mov al,address
out 70h,al
mov al,value
out 71h,al
sti
_disable();
outp(0x70,address);
outp(0x71,value);
_enable();
Make sure you rewrite the address before every access, even if it's identical
with the previous access! CPU interrupts should be disabled during your
access, but of course you don't need to do that explicitly every time if they
are disabled anyway (eg. in an interrupt handler).
The RTC generates interrupt 70h. You must enable level 2 of the master ICU and
level 0 of the slave ICU. (Clear bit 2 of port 21h and bit 0 of port 0A1h;
both registers are read/write). Both master and slave ICU expect an EOI (write
20h to 20h and 0A0h).
And these are the registers:
Address Function
--------------------------------------
0 actual second
1 alarm second
2 actual minute
3 alarm minute
4 actual hour
5 alarm hour
6 day of week (not used by the BIOS nor DOS)
7 day of month
8 month
9 year
A status A
B status B
C status C
D status D
E - 3F buffered memory that holds the BIOS setup
40 - 7F buffered memory available with some clones
status A (Control 1)
--------
Bit 0-3: interrupt frequency (PC: 0110b = 1024 ints per second)
4-6: xtal frequency (PC: 010b = 32,768 kHz)
7: UIP (update in progess: if 1, time is invalid)
UIP tells you when you can't read the registers 0, 2, 4, 6 - 9 at the
moment. It is usually high for less than a millisecond.
You can change bits 0-6. These are the values that produce useful results
in a PC:
Bits 6-4
--------
010 use 32,768 Hz xtal
others don't do anything useful in PCs, really...
Bits 3-0
--------
0000 seems to inhibit the whole RTC
0001 divides xtal by 128 (PC: 256 ints per second)
0010 divides xtal by 256 (PC: 128 ints per second)
0011 divides xtal by 4 (PC: 8192 ints per second)
0100 divides xtal by 8 (PC: 4096 ints per second)
0101 divides xtal by 16 (PC: 2048 ints per second)
0110 divides xtal by 32 (PC: 1024 ints per second)
0111 divides xtal by 64 (PC: 512 ints per second)
1000 divides xtal by 128 (PC: 256 ints per second)
1001 divides xtal by 256 (PC: 128 ints per second)
1010 divides xtal by 512 (PC: 64 ints per second)
1011 divides xtal by 1024 (PC: 32 ints per second)
1100 divides xtal by 2048 (PC: 16 ints per second)
1101 divides xtal by 4096 (PC: 8 ints per second)
1110 divides xtal by 8192 (PC: 4 ints per second)
1111 divides xtal by 16384 (PC: 2 ints per second)
Obviously you should only use values 0011 - 1111. Note also that
8192 ints per second is an awful lot for slow computers.
status B (Control 2)
--------
Bit 0: 1=daylight savings flag (German "Sommerzeit"-"summer time")
1: 0=12hr, 1=24hr mode (PC: 1)
2: 0=BCD, 1=binary mode (PC: 0)
3: 1=square wave generator on (PC: 0)
4: 1=generate time update interrupts (every second) (PC: 0)
5: 1=alarm interrupt (int when alarm time reached) (PC: 0)
6: 1=generate periodic interrupt (see status A) (PC: 0)
7: 1=inhibit time increment (while setting the clock)
status C (interrupt cause)
--------
Bit 4: 1=time changed (generated every second)
5: 1=alarm time reached
6: 1=periodic int
others not defined
status D (battery)
--------
Bit 7: 1=battery OK, 0=battery weak
others undefined
When servicing interrupts, you MUST read status C! That's the chip's inter-
rupt acknowledge. Make sure to read this register after programming the
interrupt control register (status B), or you won't get any interrupts.
The Day Of Week - Counter counts from 1 to 7 and restarts with 1 again. When
0, it is not incremented. On a PC, it's always 0 if you don't set it to a
specific value. (Ralf Brown says 1=sunday, but not with my PCs.)
Using the BIOS instead
======================
[sneaked from Ralf Brown's interrupt list version 31]
----------1A02-------------------------------
INT 1A - TIME - GET REAL-TIME CLOCK TIME (AT,XT286,PS)
AH = 02h
Return: CF clear if successful
CH = hour (BCD)
CL = minutes (BCD)
DH = seconds (BCD)
DL = daylight savings flag (00h standard time, 01h daylight time)
CF set on error (i.e. clock not running or in middle of update)
SeeAlso: AH=00h
----------1A03-------------------------------
INT 1A - TIME - SET REAL-TIME CLOCK TIME (AT,XT286,PS)
AH = 03h
CH = hour (BCD)
CL = minutes (BCD)
DH = seconds (BCD)
DL = daylight savings flag (00h standard time, 01h daylight time)
SeeAlso: AH=01h
----------1A04-------------------------------
INT 1A - TIME - GET REAL-TIME CLOCK DATE (AT,XT286,PS)
AH = 04h
Return: CF clear if successful
CH = century (BCD)
CL = year (BCD)
DH = month (BCD)
DL = day (BCD)
CF set on error
SeeAlso: AH=02h,AH=05h,INT 21/AH=2Ah
----------1A05-------------------------------
INT 1A - TIME - SET REAL-TIME CLOCK DATE (AT,XT286,PS)
AH = 05h
CH = century (BCD)
CL = year (BCD)
DH = month (BCD)
DL = day (BCD)
SeeAlso: AH=04h,INT 21/AH=2Bh
----------1A06-------------------------------
INT 1A - TIME - SET ALARM (AT,XT286,PS)
AH = 06h
CH = hour (BCD)
CL = minutes (BCD)
DH = seconds (BCD)
Return: CF set on error (alarm already set or clock stopped for update)
CF clear if successful
Note: the alarm occurs every 24 hours until turned off, invoking INT 4A each
time
SeeAlso: AH=07h,INT 4A
----------1A07-------------------------------
INT 1A - TIME - CANCEL ALARM (AT,XT286,PS)
AH = 07h
Return: alarm disabled
Note: does not disable the real-time clock's IRQ
SeeAlso: AH=06h,INT 70
If you wish to reset the system clock according to the RTC, call int 21h
function 2Dh. Note that starting with DOS 3.3, this also influences the
RTC!! See below.
----------212C-------------------------------
INT 21 - DOS 1+ - GET SYSTEM TIME
AH = 2Ch
Return: CH = hour
CL = minute
DH = second
DL = 1/100 seconds
Note: on most systems, the resolution of the system clock is about 5/100sec,
so returned times generally do not increment by 1
on some systems, DL may always return 00h
SeeAlso: AH=2Ah,AH=2Dh,AH=E7h,INT 1A/AH=00h,INT 1A/AH=02h,INT 1A/AH=FEh
SeeAlso: INT 2F/AX=120Dh
----------212D-------------------------------
INT 21 - DOS 1+ - SET SYSTEM TIME
AH = 2Dh
CH = hour
CL = minute
DH = second
DL = 1/100 seconds
Return: AL = result
00h successful
FFh invalid time, system time unchanged
Note: DOS 3.3+ also sets CMOS clock
SeeAlso: AH=2Bh"DOS",AH=2Ch,INT 1A/AH=01h,INT 1A/AH=03h,INT 1A/AH=FFh"AT&T"
A better method to reset the system clock is to calculate the number of
timer clicks since midnight and write it to the BIOS variable 0h:46Ch
(or call int 1Ah). This does not affect the precision of the RTC like calls
to 212D do.
0h:46Ch DWORD Timer ticks since midnight
0h:470h BYTE Timer overflow, non-zero if has counted past midnight
----------1A00-------------------------------
INT 1A - TIME - GET SYSTEM TIME
AH = 00h
Return: CX:DX = number of clock ticks since midnight
AL = midnight flag, nonzero if midnight passed since time last read
Notes: there are approximately 18.2 clock ticks per second, 1800B0h per 24 hrs
IBM and many clone BIOSes set the flag for AL rather than incrementing
it, leading to loss of a day if two consecutive midnights pass
without a request for the time (e.g. if the system is on but idle)
SeeAlso: AH=01h,AH=02h,INT 21/AH=2Ch
----------1A01-------------------------------
INT 1A - TIME - SET SYSTEM TIME
AH = 01h
CX:DX = number of clock ticks since midnight
SeeAlso: AH=00h,AH=03h,INT 21/AH=2Dh
BTW: the exact value is 18.2064819335 clicks per second (or 1193180/65536).
You can calculate these values without floating point arithmetics!
Ralf Brown's interrupt list is available from several ftp sites. Ask an archie
server for "prog inter3". I think the actual version is 38.