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

High Speed IRQ Timer/Clock in C

3 views
Skip to first unread message

Andrew Wan

unread,
Dec 27, 2007, 7:01:30 AM12/27/07
to
I found this excellent High Speed Timer (in Pascal). I compiled it
(using Turbo Pascal 7 and it runs fine):

http://www.sorucevap.com/bilisimteknolojisi/programcilik/pascal/ders.asp?207995
and same High Speed Timer here too:
http://groups.google.com/group/comp.lang.pascal/browse_thread/thread/92e9398f16c10ba4/e67ff3cf587648ef?lnk=st&q=inline(%24CD)+inline(%241C)+inline(%249C)&rnum=1&hl=en#e67ff3cf587648ef

I converted it to C (using p2c), compiled it using Borland C++ 4.5 and
it runs. But it crashes when it gets to setvect(...) in TimerOn().

Does anyone know how IRQ programming works in C? If you know IRQ timer/
clock please contact me. I need urgent help in understanding why it's
not working.

Andrew Wan

unread,
Dec 27, 2007, 7:04:56 AM12/27/07
to
On Dec 27, 12:01 pm, Andrew Wan <andw...@googlemail.com> wrote:
> I found this excellent High Speed Timer (in Pascal). I compiled it
> (using Turbo Pascal 7 and it runs fine):
>
> http://www.sorucevap.com/bilisimteknolojisi/programcilik/pascal/ders....
> and same High Speed Timer here too:http://groups.google.com/group/comp.lang.pascal/browse_thread/thread/...

>
> I converted it to C (using p2c), compiled it using Borland C++ 4.5 and
> it runs. But it crashes when it gets to setvect(...) in TimerOn().
>
> Does anyone know how IRQ programming works in C? If you know IRQ timer/
> clock please contact me. I need urgent help in understanding why it's
> not working.

Here it is in C:
#include "p2c.h"
#include "extra.h"

#define TIMER_G
#include "timer.h"

#define MaxRate 1193180L


void interrupt(__far *OldInt08)();//Static _PROCEDURE OldInt08,
OldInt1C;
void interrupt(__far *OldInt1C)();
Static unsigned short IntCount08, Trigger;
Static boolean TimerAlreadySet;
Static unsigned short Frequency;


Static Void IrqOn()
{
/* p2c: timer1.pas, line 37:
* Note: Inline assembly language encountered [254] */
asm{sti;}//asm(" inline $FB");
}


Static Void IrqOff()
{
/* p2c: timer1.pas, line 40:
* Note: Inline assembly language encountered [254] */
asm{sti;}//asm(" inline $FA");
}
/* p2c: timer1.pas, line 43: Note: Ignoring INTERRUPT keyword [258] */


/*$F+*/
void interrupt NewInt1C()//Static Void NewInt1C()
{
ClockTicks++;
}
/* p2c: timer1.pas, line 50: Note: Ignoring INTERRUPT keyword [258] */


/*$F-*/

/*$F+*/
void interrupt NewInt08()//Static Void NewInt08()
{
IrqOff();
/* p2c: timer1.pas, line 53:
* Note: Inline assembly language encountered [254] */
asm{int 1Ch;}//asm(" inline $CD");
//asm(" inline $1C"); /*Generate INT 1Ch instruction to call
interrupt 1Ch*/
if (IntCount08 == Trigger) {
IntCount08 = 0;
/* p2c: timer1.pas, line 57:
* Note: Inline assembly language encountered [254] */
asm{pushf;}//asm(" inline $9C");
/*if (OldInt08.link != NULL)
(*(Void(*) PP((Anyptr _link)))OldInt08.proc)(OldInt08.link);
else
(*(Void(*) PV())OldInt08.proc)();*/
} else
IntCount08++;
outp( 0x20, 0x20 );//PORT(0x20) = 0x20; /*Sends non-specific EOI
to the PIC*/
/* p2c: timer1.pas, line 64: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 64: Warning: Invalid assignment [168] */
IrqOn();
}


/*$F-*/

Void TimerOn(Freq)
long Freq;
{
LONGINT Temp = MaxRate;
unsigned short Count;
_PROCEDURE TEMP1;

if (TimerAlreadySet)
return;
ClockTicks = 0;
IntCount08 = 0;
Frequency = Freq;
Trigger = (long)(Freq / 18.2);
Temp = (long)((double)Temp / Freq);
Count = Temp;
GetIntVec(0x8, OldInt08);
TEMP1.proc = (Anyptr)NewInt08;
TEMP1.link = (Anyptr)NULL;
/* p2c: timer1.pas, line 83:
* Warning: Symbol 'GETINTVEC' is not defined [221] */
SetIntVec(0x8, NewInt08);//SetIntVec(0x8, TEMP1);
/* p2c: timer1.pas, line 84:
* Warning: Symbol 'SETINTVEC' is not defined [221] */
GetIntVec(0x1c, OldInt1C);
TEMP1.proc = (Anyptr)NewInt1C;
TEMP1.link = (Anyptr)NULL;
/* p2c: timer1.pas, line 85:
* Warning: Symbol 'GETINTVEC' is not defined [221] */
SetIntVec(0x1c, NewInt1C);//SetIntVec(0x1c, TEMP1);
/* p2c: timer1.pas, line 86:
* Warning: Symbol 'SETINTVEC' is not defined [221] */
outp( 0x43, 0xb6);
/* p2c: timer1.pas, line 87: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 87: Warning: Invalid assignment [168] */
outp( 0x40, Count & 255);
/* p2c: timer1.pas, line 88: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 88: Warning: Invalid assignment [168] */
outp( 0x40, Count >> 8);
/* p2c: timer1.pas, line 89: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 89: Warning: Invalid assignment [168] */
TimerAlreadySet = true;
}


Void TimerOff()
{
if (!TimerAlreadySet)
return;
outp( 0x43, 0xb6);
/* p2c: timer1.pas, line 98: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 98: Warning: Invalid assignment [168] */
outp( 0x40, 0xff);
/* p2c: timer1.pas, line 99: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 99: Warning: Invalid assignment [168] */
outp( 0x40, 0xff);
/* p2c: timer1.pas, line 100: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 100: Warning: Invalid assignment [168] */
SetIntVec(0x8, OldInt08);
/* p2c: timer1.pas, line 101:
* Warning: Symbol 'SETINTVEC' is not defined [221] */
SetIntVec(0x1c, OldInt1C);
/* p2c: timer1.pas, line 102:
* Warning: Symbol 'SETINTVEC' is not defined [221] */
TimerAlreadySet = false;
}


Void ResetTimer()
{
ClockTicks = 0;
}


double TimeElapsed()
{
return ((double)ClockTicks / Frequency);
}


void _Timer_init()
{
static int _was_initialized = 0;
if (_was_initialized++)
return;
TimerAlreadySet = false;
}
/* p2c: Note: Remember to call _Timer_init() in main program [215] */

/* End. */

void main()
{
_Timer_init();
}

Andrew Wan

unread,
Dec 28, 2007, 5:09:41 AM12/28/07
to
Here is the translated C code:
----------------------
#include "p2c.h"
#include "extra.h"

#define TIMER_G
#include "timer.h"

#define MaxRate 1193180L


void interrupt(__far *OldInt08)();//Static _PROCEDURE OldInt08,
OldInt1C;
void interrupt(__far *OldInt1C)();
Static unsigned short IntCount08, Trigger;
Static boolean TimerAlreadySet;
Static unsigned short Frequency;

void GetIntVec(int a, void interrupt(__far *b)())
{
b = getvect(a);
}

void SetIntVec(int a, void interrupt(__far *b)())
{
setvect(a, b);
}


Static Void IrqOn()
{
/* p2c: timer1.pas, line 37:
* Note: Inline assembly language encountered [254] */
asm{sti;}//asm(" inline $FB");
}


Static Void IrqOff()
{
/* p2c: timer1.pas, line 40:
* Note: Inline assembly language encountered [254] */

asm{cli;}//asm(" inline $FA");


}
/* p2c: timer1.pas, line 43: Note: Ignoring INTERRUPT keyword [258] */


/*$F+*/
void interrupt NewInt1C()//Static Void NewInt1C()

{printf("\nNewInt1C()");


ClockTicks++;
}
/* p2c: timer1.pas, line 50: Note: Ignoring INTERRUPT keyword [258] */


/*$F-*/

/*$F+*/
void interrupt NewInt08()//Static Void NewInt08()

{printf("\nNewInt08()");


IrqOff();
/* p2c: timer1.pas, line 53:
* Note: Inline assembly language encountered [254] */
asm{int 1Ch;}//asm(" inline $CD");
//asm(" inline $1C"); /*Generate INT 1Ch instruction to call
interrupt 1Ch*/
if (IntCount08 == Trigger) {
IntCount08 = 0;
/* p2c: timer1.pas, line 57:
* Note: Inline assembly language encountered [254] */
asm{pushf;}//asm(" inline $9C");

OldInt08();/*if (OldInt08.link != NULL)


(*(Void(*) PP((Anyptr _link)))OldInt08.proc)(OldInt08.link);
else
(*(Void(*) PV())OldInt08.proc)();*/
} else
IntCount08++;

outportb( 0x20, 0x20 );//PORT(0x20) = 0x20; /*Sends non-specific


EOI to the PIC*/
/* p2c: timer1.pas, line 64: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 64: Warning: Invalid assignment [168] */
IrqOn();
}


/*$F-*/

Void TimerOn(Freq)
long Freq;
{
LONGINT Temp = MaxRate;
unsigned short Count;
_PROCEDURE TEMP1;

printf("\nTimerOn()");


if (TimerAlreadySet)
return;
ClockTicks = 0;
IntCount08 = 0;
Frequency = Freq;
Trigger = (long)(Freq / 18.2);
Temp = (long)((double)Temp / Freq);
Count = Temp;
GetIntVec(0x8, OldInt08);
TEMP1.proc = (Anyptr)NewInt08;
TEMP1.link = (Anyptr)NULL;
/* p2c: timer1.pas, line 83:
* Warning: Symbol 'GETINTVEC' is not defined [221] */
SetIntVec(0x8, NewInt08);//SetIntVec(0x8, TEMP1);
/* p2c: timer1.pas, line 84:
* Warning: Symbol 'SETINTVEC' is not defined [221] */
GetIntVec(0x1c, OldInt1C);
TEMP1.proc = (Anyptr)NewInt1C;
TEMP1.link = (Anyptr)NULL;
/* p2c: timer1.pas, line 85:
* Warning: Symbol 'GETINTVEC' is not defined [221] */
SetIntVec(0x1c, NewInt1C);//SetIntVec(0x1c, TEMP1);
/* p2c: timer1.pas, line 86:
* Warning: Symbol 'SETINTVEC' is not defined [221] */

outportb( 0x43, 0xb6);


/* p2c: timer1.pas, line 87: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 87: Warning: Invalid assignment [168] */

outportb( 0x40, Count & 255);


/* p2c: timer1.pas, line 88: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 88: Warning: Invalid assignment [168] */

outportb( 0x40, Count >> 8);


/* p2c: timer1.pas, line 89: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 89: Warning: Invalid assignment [168] */
TimerAlreadySet = true;
}


Void TimerOff()
{printf("\nTimerOff()");
if (!TimerAlreadySet)
return;
outportb( 0x43, 0xb6);


/* p2c: timer1.pas, line 98: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 98: Warning: Invalid assignment [168] */

outportb( 0x40, 0xff);


/* p2c: timer1.pas, line 99: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 99: Warning: Invalid assignment [168] */

outportb( 0x40, 0xff);


/* p2c: timer1.pas, line 100: Note: Reference to PORT [191] */
/* p2c: timer1.pas, line 100: Warning: Invalid assignment [168] */
SetIntVec(0x8, OldInt08);
/* p2c: timer1.pas, line 101:
* Warning: Symbol 'SETINTVEC' is not defined [221] */
SetIntVec(0x1c, OldInt1C);
/* p2c: timer1.pas, line 102:
* Warning: Symbol 'SETINTVEC' is not defined [221] */
TimerAlreadySet = false;
}


Void ResetTimer()
{
ClockTicks = 0;
}


double TimeElapsed()
{
return ((double)ClockTicks / Frequency);
}


void _Timer_init()
{
static int _was_initialized = 0;
if (_was_initialized++)
return;
TimerAlreadySet = false;
}
/* p2c: Note: Remember to call _Timer_init() in main program [215] */

/* End. */

void main()
{
int i;
_Timer_init();

TimerOn(546);
for(i=0; i<100000; i++) {
if (i%10000==0)
printf("\n... %d", i);
}
TimerOff();

}

Andrew Wan

unread,
Jan 16, 2008, 6:30:09 AM1/16/08
to

I found the closest Turbo C DOS timer source code written by David
Oshinsky at:

[url]http://www.bookcase.com/library/software/msdos.devel.apps.turbo-
c.html[/url] (TIMERTST)

To get my own timer (original Pascal port) I had to comment out
asm{ int 1Ch;} & asm{pushf;} in NewInt08() function. Also I had to
omit all debugging printfs in the interrupt functions. Afterwards my
program doesn't crash anymore.

What am wondering is:

1. In Pascal version it uses inline($CD / $1C); & inline($9C); before
the OldInt08() call. I though I could call the equivalent asm{ int
1Ch;} & asm{pushf;} but I guess this was wrong since it crashed my
program. Is there an inline assembly call in C?

2. David's initializing the timer code uses
[code]
/* Set up 8259 PIC chip to allow INT0 interrupt. */
outportb(0x21, inportb(0x21) & 0xfe);

/* issue command to 8253: counter 0, binary counter, rate generator
*/
/* (mode 2), load least significant byte of counter followed by
*/
/* most significant byte */
outportb(0x43, 0x34);

/* Timer is set for 0x4cd * 813.8 ns = 1 ms (LSB followed by MSB). */
outportb(0x40, 0xcd); /* least significant byte of timer count */
outportb(0x40, 0x04); /* most significant byte of timer count */
[/code]
But mine uses
[code]
outportb( 0x43, 0xb6);


outportb( 0x40, Count & 255);

outportb( 0x40, Count >> 8);
[/code]
What is the difference? Even though both works.

3. Same goes for the clean up code:
His is:
[code]
/* restore 8253 to original state set during PC boot */
/* NOTE: this program leaves 8259 mask register with */
/* least significant bit clear (i.e., INT0 enabled). */
outportb(0x43, 0x34);
outportb(0x40, 0);
outportb(0x40, 0);
[/code]
Mine is:
[code]
outportb( 0x43, 0xb6);
outportb( 0x40, 0xff);
outportb( 0x40, 0xff);
[/code]
Again both works but I don't understand why different?

0 new messages