RTC 12:00 = 0:00 in 12 hour mode

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
azblue
Member
Member
Posts: 147
Joined: Sat Feb 27, 2010 8:55 pm

RTC 12:00 = 0:00 in 12 hour mode

Post by azblue »

I keep getting a result of 0 when reading the hour from the RTC in 12 hour mode in Virtual Box. According to the wiki I should get 0 at midnight in 24 hour mode, but I should get 12 in 12 hour mode. I could just add 12 to the hour if I get 0, but that feels like a "magic fix"; if I'm doing something wrong or not understanding something correctly that needs to be addressed.

I've tried to strip down the code to the relevant portions:

Code: Select all

#define rtcRegisterSelect 0x70
#define rtcData 0x71
#define rtcStatus 0xb
//bit2: 0 = bcd, 1 = binary
//bit 1 0 = 12, 1 = 24
#define rtcStatusA 0xa

void initRTC()
{
unsigned char k;
unsigned char s;
k = readRTC(rtcStatus);
k = k & 0xfd; //clear bit 1
k = k | 4;  //set bit 2
writeRTC(rtcStatus, k);
return;
}
void waitRTC()
{
//wait until rtc is valid to read
unsigned char k = 0;
while(k ==0)
{k = readRTC(rtcStatusA) & 0x80;}
//now an update is in progress
while(k ==0x80)
{k = readRTC(rtcStatusA) & 0x80;}
//now the update is over
return;
}
unsigned char readRTC(unsigned char index)
{
outb(rtcRegisterSelect, index);
return inb(rtcData);
}

void writeRTC(unsigned char index, unsigned char value)
{
outb(rtcRegisterSelect, index);
outb(rtcData, value);
return;
}


unsigned char readHours()
{
return readRTC(rtcHours);
}
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: RTC 12:00 = 0:00 in 12 hour mode

Post by Brendan »

Hi,
azblue wrote:

Code: Select all

void initRTC()
{
    unsigned char k;
    unsigned char s;
    k = readRTC(rtcStatus);
    k = k & 0xfd; //clear bit 1
    k = k | 4;  //set bit 2
    writeRTC(rtcStatus, k);
    return;
}
This code sets bit 2 of Register B; which enables "binary mode". When you do this 2 things happen:
  • The current contents of the time and date registers becomes trash and have to be set properly before they can be read
  • The next time the computer boots, the firmware (which is expecting "BCD mode") will get all confused and will probably do something silly (like decide that your CMOS is corrupt and reset all BIOS setting to default)

Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
azblue
Member
Member
Posts: 147
Joined: Sat Feb 27, 2010 8:55 pm

Re: RTC 12:00 = 0:00 in 12 hour mode

Post by azblue »

Brendan wrote:
  • The next time the computer boots, the firmware (which is expecting "BCD mode") will get all confused and will probably do something silly (like decide that your CMOS is corrupt and reset all BIOS setting to default)
I hadn't thought of that.
Alright, I'll refrain from messing with the mode and just read it as-is and convert it to the format I want.
Brendan wrote: This code sets bit 2 of Register B; which enables "binary mode". When you do this 2 things happen:
  • The current contents of the time and date registers becomes trash and have to be set properly before they can be read
Before doing things the above-mentioned correct way I wanted to get this old code working, just be sure I really understand what's going on. Short story: It worked! Thanks!

I read the old time and converted it to 12 hour binary, then changed the mode to 12 hour binary, then read the time and got a correct reading. Thanks Brenden!
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: RTC 12:00 = 0:00 in 12 hour mode

Post by Brendan »

Hi,
azblue wrote:I read the old time and converted it to 12 hour binary, then changed the mode to 12 hour binary, then read the time and got a correct reading. Thanks Brenden!
When you do change the RTC's mode to "binary"; 2 things happen:
  • The current contents of the time and date registers becomes trash and have to be set properly before they can be read.
  • The next time the computer boots, the firmware (which is expecting "BCD mode") will get all confused and will probably do something silly (like decide that your CMOS is corrupt and reset all BIOS setting to default)
You have fixed the first problem.

For the second problem, the CMOS in Qemu isn't persistent (the emulator creates it when the emulator starts, and doesn't save/load the previous CMOS contents), so you don't notice the second problem. For a real computer (unlike Qemu), the CMOS is persistent - its contents don't disappear when the computer is turned off and any changes you've made are still there when the computer boots again.

Basically; for a real computer (but not for Qemu) your OS will still cause problems. You should not change the RTC's "12 hour or 24 hour" mode and you should not change the RTC's "BCD or binary" mode.

In addition; an OS should use the RTC's periodic IRQ or the PIT chip or HPET or something else to keep track of time internally (e.g. "ticks since epoch"), because this is much more precise and has less overhead (and makes it easier to handle things like converting time between UTC and various time zone/s). Reading the RTC's time and date so that you can change the RTC's mode and then never reading the RTC's time and date after you've changed the mode (because you only needed to read it once and you've already read it) doesn't make much sense... ;)


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
azblue
Member
Member
Posts: 147
Joined: Sat Feb 27, 2010 8:55 pm

Re: RTC 12:00 = 0:00 in 12 hour mode

Post by azblue »

Brendan wrote:Hi,

For the second problem, the CMOS in Qemu isn't persistent (the emulator creates it when the emulator starts, and doesn't save/load the previous CMOS contents), so you don't notice the second problem. For a real computer (unlike Qemu), the CMOS is persistent - its contents don't disappear when the computer is turned off and any changes you've made are still there when the computer boots again.

Basically; for a real computer (but not for Qemu) your OS will still cause problems. You should not change the RTC's "12 hour or 24 hour" mode and you should not change the RTC's "BCD or binary" mode.
I know, that's why I wrote "Alright, I'll refrain from messing with the mode and just read it as-is and convert it to the format I want."

My second comment where I was changing the mode was just to be sure I correctly understood what you said and how things worked; it's not code I plan on keeping.

However, it occurred to me later all I really did was write a value and then read back what I wrote.

I wrote new code that changes to 12 hour binary mode (again, not something I'd want to do on a real computer, as you've explained) and wrote 11:59:59 to the RTC. When I wait and read it back, again I get 0 for the hour.

Since I need to be able to read whatever mode the RTC is in, I need to correctly interpret 12 hour binary mode, since that may be the mode it's in, which I'm clearly not doing since I'm getting a 0 (both Ralf Brown and the Wiki says in 12 hour mode I should get numbers from 1-12). I don't want to be too quick to chalk it up to a buggy Virtual Box when it seems more probable my code is bad.
Post Reply