RTC: Difference between revisions

893 bytes added ,  15 years ago
no edit summary
[unchecked revision][unchecked revision]
No edit summary
Line 1:
 
{{In Progress}}
 
====Introduction====
Line 14:
<pre>
disable_ints(); //important that no interrupts happen, including NMI
outportb(0x70, 0x0A); //write to index
outportb(0x71, 0x20); //write to actual RAM
enable_ints();
</pre>
Line 30:
outportb(0x70, 0x0B); //set the index to register B
char prev=inportb(0x71); //read the current value of register B
outportb(0x70, 0x0B); //set the index again(a read will reset the index to register D)
outportb(0x71, prev | 0x40); //write the previous value or'd with 0x40. This turns on bit 6 of register D
enable_ints();
Line 40:
Changing the output divider changes the interrupt rate, *without* interferring with the RTC's ability to keep proper time. The lower 4 bits of register A are the interrupt divider. The default is 0110b, or 6. The frequency must be a value from 1 to 15. A value of 0 disables the interrupt. To calculate a new frequency, you would do
<pre>
frequency = 32768 >> (rate-1);
</pre>
Rate is the divider. If you select a rate of 1 or 2, the RTC will have problems and "roll over" so that it generates interrupts of .81 mS and 3.91 mS, rather than the expected interrupts of 61.0 uS or 30.5 uS. So, the fastest rate you can select is 3. This will generate interrupts of 8 kHz or 122 uS.This is how to change the rate:
<pre>
rate &= 0x0F; //rate must be above 2 and not over 15. (this is a safe-guard to be sure it isn't over 15)
disable_ints();
outportb(0x70, 0x0A); //set index to register A
char prev=inportb(0x71); //get initial value of register A
outportb(0x70, 0x0A); //reset index to A
outportb(0x71, (prev & 0xF0) | rate); //write only our rate to A. Note, rate is the bottom 4 bits.
enable_ints();
</pre>
 
 
====Interrupts and Register C====
It is important to know that upon a IRQ 8, register C will contain a bitmask telling which interrupt happened. The RTC is capable of producing a periodic interrupt(what we use), an update ended, and a alarm interrupt. If you are only using the RTC as a simple timer, this is not important. What is important is that if register C is not read after an IRQ 8, then the interrupt will not happen again. So, even if you don't care about what type of interrupt it is, just attach this code to the bottom of your IRQ handler.
<pre>
outportb(0x70, 0x0C); //select register C
inportb(0x71); //just throw away contents.
</pre>
 
====Possible Uses====
Now, you may be wondering what is so useful about this. Well, there are quite a few possible uses for this. You could use just the RTC and not use the PIC (the RTC is easier to program in my opinion). My favorite use is to use the RTC for my main kernel clock (controls scheduling and all), and then use the PIC to provide a more accurate wait() function. A wait function that can work in certain degrees of micro-seconds.
 
 
Line 59 ⟶ 71:
 
[http://www.nondot.org/sabre/os/files/MiscHW/CMOSTimer.html Using the 1024 HZ Timer Interrupt]
 
[[Category:Common Devices]]
Anonymous user