Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

dos timer problem!

45 views
Skip to first unread message

Quakel

unread,
May 29, 2008, 5:30:15 AM5/29/08
to
Hi, everybody.

I need a timer under MS-DOS6.22, and i use dos16 by watcom.
but I cannot get into the timer interrupt.How?

Thank you.

Source:

long timer_counter;
void (_interrupt far *Old_Time_Isr)();
void timer_program(void);
void _interrupt Timer(void);

////////////////////////////////////////////////////////////////


extern void Change_Timer(unsigned short new_count)
{
outp(CTRL_8253,CTRL_WORD);
outp(COUNTER_0,LO_BYTE(new_count));
outp(COUNTER_0,HI_BYTE(new_count));
}

////////////////////////////////////////////////////////////////

extern void install_timer(int Hz)
{
short time_hz;
time_hz=(short)(1193180/Hz);
timer_counter=0;
Change_Timer(time_hz);
Old_Time_Isr=_dos_getvect(TIME_INT);
_dos_setvect(TIME_INT,Timer);
}

////////////////////////////////////////////////////////////////

extern void uninstall_timer()
{
Change_Timer(TIME_18HZ);
_dos_setvect(TIME_INT,Old_Time_Isr);
}


void timer_program(void)
{
//.........
}

////////////////////////////////////////////////////////////////

extern void _interrupt Timer(void)
{
timer_program();
timer_counter++;
Old_Time_Isr();
}

////////////////////////////////////////////////////////////////
void main()
{
install_timer(5);
memset(&inbuf,0,sizeof(inbuf));

while(c!=27)
{
// ...

if(kbhit())
{
c=getch();
}
}

uninstall_timer();

}


Arkady V.Belousov

unread,
May 29, 2008, 10:07:43 AM5/29/08
to
Hi!

Quakel 29.05.08 13:30 wrote:

> I need a timer under MS-DOS6.22, and i use dos16 by watcom.
> but I cannot get into the timer interrupt.How?

Source below is incomplete - you not show relevant parts like values
for CTRL_8253 and CTRL_WORD.

> long timer_counter;
> void (_interrupt far *Old_Time_Isr)();
> void timer_program(void);
> void _interrupt Timer(void);

> extern void Change_Timer(unsigned short new_count)
> {
> outp(CTRL_8253,CTRL_WORD);
> outp(COUNTER_0,LO_BYTE(new_count));
> outp(COUNTER_0,HI_BYTE(new_count));
> }

> extern void install_timer(int Hz)
> {
> short time_hz;
> time_hz=(short)(1193180/Hz);
> timer_counter=0;
> Change_Timer(time_hz);
> Old_Time_Isr=_dos_getvect(TIME_INT);
> _dos_setvect(TIME_INT,Timer);

Around reprogramming system (!) timer you should disable interrupts
(see _disable() and _enable()). More generic: around any code, which
initializes interrupt source and installs its handler, interrupts should be
disabled.

> }
> extern void uninstall_timer()
> {
> Change_Timer(TIME_18HZ);
> _dos_setvect(TIME_INT,Old_Time_Isr);

Same as above.

> }
> extern void _interrupt Timer(void)
> {
> timer_program();
> timer_counter++;
> Old_Time_Isr();

Because you reprogram system timer at different frequency, than default
value, you should adjust frequency of calls to previous handler. For
example, if your frequency is twice faster, you should call old interrupt
only each second interrupt. When ratio of new and old frequencies is not
integer, call to old handler should be irregular. Do you read "FAQ /
Application notes: Timing on the PC family under DOS"?

> }
> void main()
> {
> install_timer(5);

First, you shouldn't reprogram system timer at frequency, which lower
than default.

Also, let count, what you get. In install_timer() you evaluate
11931780/5=2386356=2469B4h. After converting this values to 16-bit short
value, you get 69B4h=27060 (or 11931780/27060=~441 Hz).

> memset(&inbuf,0,sizeof(inbuf));

What is `inbuf'? If it used by timer handler, you should initialize
this variable before installing handler.

Quakel

unread,
May 30, 2008, 4:31:09 AM5/30/08
to
Actually if I do not change the timer frequency, the program may work
when I put "printf()" sentence in timerfunction or the main while dead cycle
respectively,
But when put "printf()" sentence in both the two functions. The program will
die.

If I call another large function in the timer function, the program may
will die before the while()
cycle begin and the timer will not take use, why and how?

"Arkady V.Belousov" <arkady....@gmail.com> >

Steve Fabian

unread,
May 30, 2008, 9:32:32 AM5/30/08
to
Quakel wrote:
| Actually if I do not change the timer frequency, the program may work
| when I put "printf()" sentence in timerfunction or the main while
| dead cycle respectively,
| But when put "printf()" sentence in both the two functions. The
| program will die.
|
| If I call another large function in the timer function, the program
| may will die before the while()
| cycle begin and the timer will not take use, why and how?

The basic rule for interrupt handlers is to do the absolute minimum required
in the handler itself, and to trigger an ordinary program not running as an
interrupt handler to do all the interpretation. Timer interrupt handlers are
especially sensitive. This rule is valid for all hardware and all OS. You
need to restructure your design, if you do not want to miss interrupts.
--
Steve

Bartosz Polednia

unread,
May 30, 2008, 11:19:42 AM5/30/08
to
Quakel pisze:

> Actually if I do not change the timer frequency, the program may work
> when I put "printf()" sentence in timerfunction or the main while dead cycle
> respectively,
> But when put "printf()" sentence in both the two functions. The program will
> die.
[ciach]

You have to call from interrupt handler only short, realy fast functions
which ARE REENTRANT and have chance to end before next interrupt.

Bartosz.

Arkady V.Belousov

unread,
May 30, 2008, 12:24:06 PM5/30/08
to
Hi!

Quakel 30.05.08 12:31 wrote:

> Actually if I do not change the timer frequency, the program may work
> when I put "printf()" sentence in timerfunction

*NEVER*, NEVER DO THIS.

First, this is very time-eating action. You shouldn't do time-complex
actions in interrupt handlers or in interrupts disabled state. I already
explain this for you in previous letters. Reread my letter under subject
"Re: Why "_disable()" doesn't return and work?".

Second, printf() calls DOS to output, but DOS not reentrant, whereas
timer interrupt is asynchronous and its handler may be called when DOS
already in called state. Reread my letter with subject "Re: High Speed IRQ
Timer/Clock in C" in answer to Andrew Wan - Andrew was also try to call
printf() in timer interrupt.

> or the main while dead cycle
> respectively,

? I not understand this part. But you shouldn't touch system resources,
including timer, because system hardly depends on it. At least, you
shouldn't touch them without big care.

If you just need to do some work at some frequency, lower than system
frequency (18 Hz), you not need to reprogram system timer - you just need
trap INT1C and perform your actions there, skipping some calls. For example,
to do some work at 15 Hz, you may do so:

#if 0 /*----------*/
#define YOURFREQ 15
#define PIT_FREQ 1193182ul /* PIT frequency */
#define PIT_FREQ_DIV 65536ul /* PIT frequency divisor */

function should be called T = YOURFREQ/(PIT_FREQ/PIT_FREQ_DIV) =
15*65536/1193182 = ~0.8238 times per tick. For this, add to counter value of
T and perform your work when counter cross 1.0 value (after this 1.0 should
be subtracted from counter). To eliminate non-integer calculations, multiply
T and 1.0 by 65536 - in given case, this makes T=53994.

Also, because we can't guarantee 16-bit counter (after all, this is C
language, it not allows to make portable programs), below used conservative
pessimistic arithmetic with subtraction from 65536*1.0 toward zero (instead
addition from zero toward 1.0*65536).
#endif /*----------*/

#define T 53994
#define T1 (T-1)
<yourfunction>() {
static unsigned short callcounter = 65535;
if (callcounter < T) {
...your work...
callcounter = callcounter + (65535 - T1);
} else
callcounter = callcounter - T;
}


> But when put "printf()" sentence in both the two functions. The program will
> die.

Of course. Because both call DOS.

> If I call another large function in the timer function, the program may
> will die before the while()
> cycle begin and the timer will not take use, why and how?

I can't answer this question because I don't know what your "large
function" does. May be, it again calls DOS. Or, it relies on some not yet
initialized variables...

JimS

unread,
May 30, 2008, 8:41:11 PM5/30/08
to
On Thu, 29 May 2008 18:07:43 +0400, "Arkady V.Belousov"
<arkady....@gmail.com> wrote:

> First, you shouldn't reprogram system timer at frequency, which lower
>than default.
>
> Also, let count, what you get. In install_timer() you evaluate
>11931780/5=2386356=2469B4h. After converting this values to 16-bit short
>value, you get 69B4h=27060 (or 11931780/27060=~441 Hz).

The PIC frequency is 1193180 not 11931780.
1193180/65536 = 18.2Hz.

JimS

JimS

unread,
May 30, 2008, 8:45:21 PM5/30/08
to
On Fri, 30 May 2008 16:31:09 +0800, "Quakel" <quak...@263.net> wrote:

>Actually if I do not change the timer frequency, the program may work
>when I put "printf()" sentence in timerfunction or the main while dead cycle
>respectively,
>But when put "printf()" sentence in both the two functions. The program will
>die.
>
>If I call another large function in the timer function, the program may
>will die before the while()
>cycle begin and the timer will not take use, why and how?

You can't call printf or many other C library functions in the
interrupt handler (ISR). I also don't remember any guarantee that the
OW C library is threadsafe.

You should make sure your ISR does as little as possible - setting
flags or incrementing counters, copying small amounts of data - and
then exiting. The real processing should be done in the main loop.

You should also attempt to call the original ISR at the correct rate.
eg. If you reprogrammed the PIT to be 36.4Hz instead of the default
18.2Hz, then you should only call the original DOS ISR every other
interrupt otherwise the system clock will go too fast.

JimS

Arkady V.Belousov

unread,
May 30, 2008, 11:48:22 PM5/30/08
to
Hi!

JimS 31.05.08 4:41 wrote:

>> Also, let count, what you get. In install_timer() you evaluate
>> 11931780/5=2386356=2469B4h. After converting this values to 16-bit short
>> value, you get 69B4h=27060 (or 11931780/27060=~441 Hz).
> The PIC frequency is 1193180 not 11931780.
> 1193180/65536 = 18.2Hz.

"11931780" is from Quakel source. The more precise, /theoretical/ PIT
frequency is 315000000/22/12=1193181.(81), where 315/22 MHz is mainboard
oscillator frequency (base frequency in NTSC), and PIT gets this source
divided by 12. 1193180 is a value, which used as approximation by BIOS
developers - it less precise, than 1193182, but contains interesting factors
(1193180=59659*5*4), although 1193182 also nice (14551*41*2). [But original
ratio 315*10^6/22/12=105*10^6/88 anyway more nice.]

JimS

unread,
May 31, 2008, 8:11:52 PM5/31/08
to
On Sat, 31 May 2008 07:48:22 +0400, "Arkady V.Belousov"
<arkady....@gmail.com> wrote:

>Hi!
>
>JimS 31.05.08 4:41 wrote:
>
>>> Also, let count, what you get. In install_timer() you evaluate
>>> 11931780/5=2386356=2469B4h. After converting this values to 16-bit short
>>> value, you get 69B4h=27060 (or 11931780/27060=~441 Hz).
>> The PIC frequency is 1193180 not 11931780.
>> 1193180/65536 = 18.2Hz.
>
> "11931780" is from Quakel source.

Where?

Arkady V.Belousov

unread,
May 31, 2008, 10:11:22 PM5/31/08
to
Hi!

JimS 01.06.08 4:11 wrote:

>> "11931780" is from Quakel source.
> Where?

Ops, sorry. Don't know how, but after copying expression from source
(or, may be, this was result of my mistype when I manually retype this?)
appear extraneous "7", original source contains valid value. My apologies.
Other my remarks remain in force.

0 new messages