CMOS: Difference between revisions

2,744 bytes added ,  12 years ago
Replaced "read all RTC time and date" example code
[unchecked revision][unchecked revision]
m (Century determination when no century register is present)
(Replaced "read all RTC time and date" example code)
Line 246:
</source>
 
=== Reading All RTC Time and Date Registers ===
<source lang="asmc">
#define CURRENT_YEAR 2011 // Change this each year!
%define RTCaddress 0x70
%define RTCdata 0x71
 
int century_register = 0x00; // Set by ACPI table parsing code if possible
;Get time and date from RTC -- values may be binary or BCD
 
unsigned char second;
.l1: mov al,10 ;Get RTC register A
unsigned char minute;
out RTCaddress,al
unsigned char hour;
in al,RTCdata
unsigned char day;
test al,0x80 ;Is update in progress?
unsigned char month;
jne .l1 ; yes, keep polling
unsigned int year;
 
void out_byte(int port, int value);
mov al,0 ;Get seconds (00 to 59)
int in_byte(int port);
out RTCaddress,al
in al,RTCdata
mov [RTCtimeSecond],al
 
enum {
mov al,0x02 ;Get minutes (00 to 59)
cmos_address = 0x70,
out RTCaddress,al
cmos_data = 0x71
in al,RTCdata
};
mov [RTCtimeMinute],al
 
mov al,0x04 ;Get hours (value may be 12hr or 24hr format)
out RTCaddress,al
in al,RTCdata
mov [RTCtimeHour],al
 
int get_update_in_progress_flag() {
mov al,0x07 ;Get day of month (01 to 31)
out_byte(cmos_address, 0x0A);
out RTCaddress,al
return (in_byte(cmos_data) & 0x80);
in al,RTCdata
}
mov [RTCtimeDay],al
 
mov al,0x08 ;Get month (01 to 12)
out RTCaddress,al
in al,RTCdata
mov [RTCtimeMonth],al
 
unsigned char get_RTC_register(int register) {
mov al,0x09 ;Get year (00 to 99)
out_byte(cmos_address, register);
out RTCaddress,al
return in_byte(cmos_data);
in al,RTCdata
}
mov [RTCtimeYear],al
 
 
ret
void read_rtc() {
unsigned char century;
unsigned char last_second;
unsigned char last_minute;
unsigned char last_hour;
unsigned char last_day;
unsigned char last_month;
unsigned char last_year;
unsigned char last_century;
unsigned char registerB;
 
// Note: This uses the "read registers until you get the same values twice in a row" technique
// to avoid getting dodgy/inconsistent values due to RTC updates
 
while (get_update_in_progress_flag()); // Make sure an update isn't in progress
second = get_RTC_register(0x00);
minute = get_RTC_register(0x02);
hour = get_RTC_register(0x04);
day = get_RTC_register(0x07);
month = get_RTC_register(0x08);
year = get_RTC_register(0x09);
if(century_register != 0) {
century = get_RTC_register(century_register);
}
 
do {
last_second = second;
last_minute = minute;
last_hour = hour;
last_day = day;
last_month = month;
last_year = year;
last_century = century;
 
while (get_update_in_progress_flag()); // Make sure an update isn't in progress
second = get_RTC_register(0x00);
minute = get_RTC_register(0x02);
hour = get_RTC_register(0x04);
day = get_RTC_register(0x07);
month = get_RTC_register(0x08);
temp_year = get_RTC_register(0x09);
if(century_register != 0) {
century = get_RTC_register(century_register);
}
} while( (last_second == second) && (last_minute == minute) && (last_hour == hour) &&
(last_day == day) && (last_month == month) && (last_year == year) &&
(last_century == century) );
 
registerB = get_RTC_register(0x0B);
 
// Convert BCD to binary values if necessary
 
if (!(registerB & 0x04)) {
second = (second & 0x0F) + ((second / 16) * 10);
minute = (minute & 0x0F) + ((minute / 16) * 10);
hour = ( (hour & 0x0F) + (((hour & 0x70) / 16) * 10) ) | (hour & 0x80);
day = (day & 0x0F) + ((day / 16) * 10);
month = (month & 0x0F) + ((month / 16) * 10);
temp_year = (year & 0x0F) + ((year / 16) * 10);
if(century_register != 0) {
century = (century & 0x0F) + ((century / 16) * 10);
}
}
 
// Convert 12 hour clock to 24 hour clock if necessary
 
if (!(registerB & 0x02) && (time[2] & 0x80)) {
time[2] = ((time[2] & 0x7F) + 12) % 24;
}
 
// Calculate the full (4-digit) year
 
if(century_register != 0) {
year += century * 100;
} else {
year += (CURRENT_YEAR / 100) * 100;
if(year < CURRENT_YEAR) year += 100;
}
}
</source>
 
250

edits