timer irq

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
northfuse

timer irq

Post by northfuse »

i'm trying to setup a timer using irq line 0. I remapped the IRQ's to 0x20 and 0x28. what would the best way of doing this be? thanks
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:timer irq

Post by Brendan »

Hi,
northfuse wrote: i'm trying to setup a timer using irq line 0. I remapped the IRQ's to 0x20 and 0x28. what would the best way of doing this be? thanks
This depends what you intend using the timer for. Some OS's use it to increase a system timer, for e.g. it could be used to increment a counter 1000 times per second. Then the OS would use this counter for delay loops and timing.

It's also possible to dynamically change the frequency of the timer, so that on a slow computer (or when there's lots of CPU load) it generates less interrupts than on faster computers (or when there isn't much CPU load). In general there's a trade-off between the overhead and accuracy of the timer. This method is more complex but can be used to find the best trade-off (so that on slow computers you get less overhead and less accuracy, but on fast computers you get more overhead and more accuracy). Here's some formulas for calculating accuracy and overhead:

Code: Select all

  overhead = (IRQspeed*frequency) / CPUspeed
  accuracy = 1/frequency

Where,
  overhead = the amount of CPU time spent handling the timer IRQ
  accuracy = the maximum amount of error the value in the counter may be
  CPUspeed = the number of cycles the CPU can execute in a second (on average)
  IRQspeed = the number of cycles executed to handle the IRQ
  frequency = the frequency of the timer
For example, if you assume the timer IRQ will consume 100 cycles, the timer is set to 1Mhz and the CPU is capable of doing 100,000,000 cycles per second (an 80486), then:

Code: Select all

 overhead = (100*10000000) / 100000000 = 1 (or 100% of CPU time spent handling the timer IRQ)
If the CPU was capable of doing 3000,000,000 cycles per second (a Pentium 4), then:

Code: Select all

 overhead = (100*10000000) / 3000000000 = 0.03333 (or 3% of CPU time spent handling the timer IRQ)
As you can see the same timer frequency is not suitable for both CPUs. You could re-arrange the formulas, so that the overhead is always the same (but accuracy isn't):

Code: Select all

  frequency = (overhead*CPUspeed) / IRQspeed
So if you want the timer to use 1% of CPU time and it consumes 100 cycles per IRQ, then:

Code: Select all

  frequency = 0.01 * CPUspeed / 100 = CPUspeed / 10000

..and therefore:

  accuracy = 10000 / CPUspeed
If the OS set the timer according to these formulas then for the slow CPU above the timer would run at 10 Khz and would be accurate to 100 uS. For the fast CPU above the timer would run at 300 Khz and would be accurate to 3.33 uS. Of course the overhead would always be roughly 1%.

The previous version of my OS used similar formulas to calculate the timer frequency and the amount of time a thread received from the scheduler (qTime). In this way for fast computers the scheduler was very smooth and the amount of time attributed to each thread (called time accounting) was very accurate. On slow computers the scheduler wasn't as smooth and the time accounting wasn't as accurate (but overhead wasn't excessive).

It's also possible to use the timer as a "one shot" timer. Here you'd program the timer for the delay you want each time you need a delay. I've seen schedulers use this method, so that the amount of time taken before IRQ0 (and therefore the amount of time a thread got) depends on the priority of the thread.


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.
northfuse

Re:timer irq

Post by northfuse »

thanks for the insight. But, right now, i'm trying to figure out how to setup the code in the idt and unmask the interrupt. I'm pretty sure that I installed it right in the idt, but i don't know how to unmask the interrupt to allow it to fire interrupt requests.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:timer irq

Post by Brendan »

Hi,
northfuse wrote: thanks for the insight. But, right now, i'm trying to figure out how to setup the code in the idt and unmask the interrupt. I'm pretty sure that I installed it right in the idt, but i don't know how to unmask the interrupt to allow it to fire interrupt requests.
Unmasking IRQ0 in the PIC is easy...

Code: Select all

%define PIC1   0x20
%define PIC2   0xa0

    in al,PIC1+1
    and al,11111110b
    out PIC1+1,al
Even if you don't program the timer it should work, as you don't need to tell the timer chip that the IRQ was received (so it'd still be running at 18.2 Hz like it was in real mode).

Depending how you disabled interrupts (ie. if you only do a "cli" before entering protected mode), you may have to do "out 0x20, 0x20" and "out 0xA0, 0x20" to clear any stale IRQs that weren't acknowledged.

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.
northfuse

Re:timer irq

Post by northfuse »

Thanks! it works. how would i go about reprogramming it to a different frequency (i.e. 100 Hz instead of 18.6 Hz)? or, if there is any documentation that you know of, that would be a help too. thanks again
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re:timer irq

Post by Brendan »

Hi,
northfuse wrote: Thanks! it works. how would i go about reprogramming it to a different frequency (i.e. 100 Hz instead of 18.6 Hz)? or, if there is any documentation that you know of, that would be a help too. thanks again
You'd need to set the timer mode and it's frequency. Here's some basic code:

Code: Select all

%define PITchnl0   0x40
%define PITcntrl   0x43

   mov al,0x34      ;Init timer 0 using mode 2
   out PITcntrl,al

   mov bx,[divisor]

   mov al,bl      ;Set the PIT channel 0 frequency
   out PITchnl0,al
   mov al,bh
   out PITchnl0,al
To figure out what the value sent to PITcntrl is (and what mode 2 is) you'll need to read some documentation. Best I've found is:
http://www.cin.ufpe.br/~if118/projeto/PCtim003.txt

In general the above code sets timer channel 0 to mode 2 (rate generator), sets the divisor to expect a low byte then a high byte and makes sure it's not using BCD.

The timer frequency depends on it's base clock frequency (roughly 1.193 Mhz), it's divisor and it's mode. If you use mode 2 then:

frequency = 3579545 / (3 * divisor)
divisor = 3579545 / (3 * frequency)

So, for 100 Hz the divisor would need to be "3579545 / 300" but it has to be an integer, which makes 11932 the closest value (which would actually be 99.9984635 Hz). You'd seperate this into a high byte and a low byte and use it to set the timer 0 divisor, so the code above becomes:

Code: Select all

%define PITchnl0   0x40
%define PITcntrl   0x43

   mov al,0x34      ;Init timer 0 using mode 2
   out PITcntrl,al

   mov al,(11932 & 0xFF)   ;Set the PIT channel 0 frequency to about 100 Hz
   out PITchnl0,al
   mov al,(11932 >> 8)
   out PITchnl0,al

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.
Post Reply