timer irq
Re:timer irq
Hi,
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:
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:
If the CPU was capable of doing 3000,000,000 cycles per second (a Pentium 4), then:
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):
So if you want the timer to use 1% of CPU time and it consumes 100 cycles per IRQ, then:
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
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.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
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
Code: Select all
overhead = (100*10000000) / 100000000 = 1 (or 100% of CPU time spent handling the timer IRQ)
Code: Select all
overhead = (100*10000000) / 3000000000 = 0.03333 (or 3% of CPU time spent handling the timer IRQ)
Code: Select all
frequency = (overhead*CPUspeed) / IRQspeed
Code: Select all
frequency = 0.01 * CPUspeed / 100 = CPUspeed / 10000
..and therefore:
accuracy = 10000 / CPUspeed
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.
Re:timer irq
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.
Re:timer irq
Hi,
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
Unmasking IRQ0 in the PIC is easy...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.
Code: Select all
%define PIC1 0x20
%define PIC2 0xa0
in al,PIC1+1
and al,11111110b
out PIC1+1,al
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.
Re:timer irq
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
Re:timer irq
Hi,
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:
Cheers,
Brendan
You'd need to set the timer mode and it's frequency. Here's some basic code: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
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
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.