High Speed IRQ Timer/Clock in C

Discussion in 'C Programming' started by Andrew Wan, Dec 27, 2007.

  1. Andrew Wan

    Andrew Wan Guest

    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...1C) inline($9C)&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, Dec 27, 2007
    #1
    1. Advertising

  2. Andrew Wan

    Jason Burgon Guest

    "Andrew Wan" <> wrote in message
    news:...
    > 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

    That isn't particularly good code or particularly high speed either. It is
    not too diffucult with a standard PC to have timers with a resolution of
    836ns, and have as many of them as you want as well.

    --
    Jay

    Jason Burgon - author of Graphic Vision
    http://homepage.ntlworld.com/gvision
    Jason Burgon, Dec 27, 2007
    #2
    1. Advertising

  3. Andrew Wan

    Andrew Wan Guest

    And so we have a translated C code here:
    #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, Dec 28, 2007
    #3
  4. "Andrew Wan" <> wrote in message
    news:...

    Dropped comp.lang.c++, openwatcom.users.c_cpp NG's. Francis Glassborow
    posted to
    comp.lang.learn.c-c++,alt.lang.asm,alt.msdos.programmer,comp.os.msdos.progra
    mmer NG's, so you may get some responses on those too.

    The code is very close to compiling for OpenWatcom. Mostly some incorrect
    keywords, wrong location for keywords, and differently named environment
    specific functions... You should replace the "Static", "boolean", "Void"
    etc. with the correct text instead of using the #define's like I did below.
    Many of the functions have K&R style void arg's, e.g., the () in "Static
    Void IrqOn()". These should be reworked to "Static Void IrqOn(void)". You
    should replace the C++ comments // with C comments /* */ or #if 0 #endif.
    Once you get it compile, if it doesn't work as you expect, you can post to
    openwatcom.users.c_cpp, alt.os.development, comp.os.msdos.programmer, etc.
    for IRQ programming.


    Rod Pemberton

    > And so we have a translated C code here:
    > #include "p2c.h"
    > #include "extra.h"
    >


    //#include "p2c.h"
    //#include "extra.h"

    > #define TIMER_G
    > #include "timer.h"


    //#include "timer.h"

    >
    >
    >
    > #define MaxRate 1193180L
    >


    #if 1
    #define Static static
    #define boolean int
    #define Void void
    #define LONGINT long int
    #define getvect _dos_getvect
    #define setvect _dos_setvect
    #if 0
    #define asm _asm
    #endif
    #define outportb outp
    #include <dos.h>
    #include <stdio.h>
    #include <conio.h>
    #define true 1
    #define false 0
    unsigned long ClockTicks;
    #endif


    >
    > void interrupt(__far *OldInt08)();//Static _PROCEDURE OldInt08,
    > OldInt1C;


    //void interrupt(__far *OldInt08)();//Static _PROCEDURE OldInt08, OldInt1C;
    void (__interrupt __far *OldInt08)();

    > void interrupt(__far *OldInt1C)();


    //void interrupt(__far *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)())


    //void GetIntVec(int a, void interrupt(__far *b)())
    void GetIntVec(int a, void (__interrupt __far *b)())

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


    //void SetIntVec(int a, void interrupt(__far *b)())
    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");


    //asm{sti;}//asm(" inline $FB");
    _asm{sti}

    > }
    >
    >
    > Static Void IrqOff()
    > {
    > /* p2c: timer1.pas, line 40:
    > * Note: Inline assembly language encountered [254] */
    > asm{cli;}//asm(" inline $FA");


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

    > }
    > /* 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{int 1Ch;}//asm(" inline $CD");
    _asm{int 1Ch}

    > //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");


    //asm{pushf;}//asm(" inline $9C");
    _asm{pushf}

    > 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;


    // _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;


    //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;


    //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 main(void)

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


    return(0);

    > }
    Rod Pemberton, Dec 28, 2007
    #4
  5. Andrew Wan

    CBFalconer Guest

    Andrew Wan wrote:
    >
    > And so we have a translated C code here:
    > #include "p2c.h"
    > #include "extra.h"
    >
    > #define TIMER_G
    > #include "timer.h"

    .... snip ...

    And what does this have to do with the C language?

    --
    Merry Christmas, Happy Hanukah, Happy New Year
    Joyeux Noel, Bonne Annee, Frohe Weihnachten
    Chuck F (cbfalconer at maineline dot net)
    <http://cbfalconer.home.att.net>



    --
    Posted via a free Usenet account from http://www.teranews.com
    CBFalconer, Dec 28, 2007
    #5
  6. On 2007-12-28, CBFalconer <> wrote:
    > Andrew Wan wrote:
    >>
    >> And so we have a translated C code here:
    >> #include "p2c.h"
    >> #include "extra.h"
    >>
    >> #define TIMER_G
    >> #include "timer.h"

    > ... snip ...
    >
    > And what does this have to do with the C language?


    1. Dunno, but neither does it with Pascal language.
    2. The OP didn't suffix "-language". That's yours.
    Marco van de Voort, Dec 28, 2007
    #6
  7. Andrew Wan

    Andrew Wan Guest

    On Dec 28 2007, 11:30 pm, Marco van de Voort <> wrote:
    > On 2007-12-28, CBFalconer <> wrote:
    >
    > > Andrew Wan wrote:

    >
    > >> And so we have a translated C code here:
    > >> #include "p2c.h"
    > >> #include "extra.h"

    >
    > >> #define TIMER_G
    > >> #include "timer.h"

    > > ... snip ...

    >
    > > And what does this have to do with the C language?

    >
    > 1. Dunno, but neither does it with Pascal language.
    > 2. The OP didn't suffix "-language". That's yours.


    Rod, thanks for converting the code for OpenWatcom. It compiles fine
    under Borland C++ 4.5 and Turbo C 3.0. I posted it to both Pascal & C
    newsgroups for help in understanding both low level Pascal & C
    language.

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

    http://www.bookcase.com/library/software/msdos.devel.apps.turbo- c.html (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  */
    
    But mine uses
    Code:
    outportb( 0x43, 0xb6);
    outportb( 0x40, Count & 255);
    outportb( 0x40, Count >> 8);
    
    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);
    
    Mine is:
    Code:
    outportb( 0x43, 0xb6);
    outportb( 0x40, 0xff);
    outportb( 0x40, 0xff);
    
    Again both works but I don't understand why different?
    Andrew Wan, Jan 16, 2008
    #7
  8. On 2008-01-16, Andrew Wan <> wrote:
    >
    > 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?


    TP has support for interrupt routines, that end with "Retf" instead of
    "Ret". It could be that the C compiler did it differently, or somehow reacts
    more badly to the stack modification.
    Marco van de Voort, Jan 16, 2008
    #8
  9. Andrew Wan

    CBFalconer Guest

    Marco van de Voort wrote:
    > Andrew Wan <> wrote:
    >
    >> 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?

    >
    > TP has support for interrupt routines, that end with "Retf"
    > instead of "Ret". It could be that the C compiler did it
    > differently, or somehow reacts more badly to the stack
    > modification.


    In the x86 an interrupt 1) pushes the flags. 2) disables further
    interrupts 3) performs a call. 1 and 2 are not performed by an
    ordinary call. Therefore the return instruction has to be
    different, to reverse effects 1 and 2. That is done by the retf
    instruction.

    This has nothing to do with C, but handles the characteristics of
    the hardware. Thus it is OT here on c.l.c. It also has nothing to
    do with Pascal. Some group with 'asm' in its name is probably
    suitable.

    --
    [mail]: Chuck F (cbfalconer at maineline dot net)
    [page]: <http://cbfalconer.home.att.net>
    Try the download section.



    --
    Posted via a free Usenet account from http://www.teranews.com
    CBFalconer, Jan 16, 2008
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. whizkid
    Replies:
    3
    Views:
    3,045
  2. Javi
    Replies:
    2
    Views:
    1,441
  3. FyberOptic

    Hooking Parallel Port IRQ

    FyberOptic, Sep 8, 2006, in forum: C++
    Replies:
    1
    Views:
    412
    red floyd
    Sep 8, 2006
  4. Andrew Wan

    High Speed IRQ Timer/Clock in C

    Andrew Wan, Dec 27, 2007, in forum: C++
    Replies:
    7
    Views:
    419
    Marco van de Voort
    Jan 16, 2008
  5. tarek
    Replies:
    4
    Views:
    516
    JohnDuq
    Mar 31, 2009
Loading...

Share This Page