www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1996/04/01/21:06:19

Xref: news2.mv.net comp.os.msdos.djgpp:2333
From: gfedor AT lerc DOT nasa DOT gov (Gregory Fedor)
Newsgroups: comp.os.msdos.djgpp
Subject: Help: My timer interrupt isn't keeping up.
Date: 1 Apr 1996 19:12:56 GMT
Organization: ADF Inc. / NASA Lewis Research Center
Lines: 241
Message-ID: <4jp9ro$e1q@sulawesi.lerc.nasa.gov>
NNTP-Posting-Host: gfedor.lerc.nasa.gov
To: djgpp AT delorie DOT com
DJ-Gateway: from newsgroup comp.os.msdos.djgpp

Included below is the code I've been working on.  I want to establish 
a 1 millisecond interrupt that simply increments a counter.  Then, the 
main program, based on that counter will collect data at various rates 
(ie. one timer, multiple rates).  To test this setup, the dummy main 
routine simply increments another counter each time the rate trigger 
occurs.  I then compare this count with the predicted rate calculated 
beforehand.

I ultimately will need to have accurate 1000 Hz and 10 Hz rates 
available (with others possible later).  When I run the test program 
with the following cases, these are my results:

Interval     Predicted Hz    Real Hz
--------     ------------    -------
  500ms           2             2
  100ms           10            10
  55ms            18.18         18
  25ms            40            40
  15ms            66.66         66
  10ms            100.00        98
  5ms             200.00        197
  2ms             500.00        491
  1ms             1000.00       981

As you can see I loose something at the end.  I ported this logic from 
 a Borland/Pharlap implementation.  The only difference being is that 
there there was also a real-mode interrupt for incrementing the tick 
counter.  I don't know how to do that with DJGPP.

Ultimately more processing than just incrementing real_hz will need to 
take place at these triggers, so I can't afford to loose any time just 
do the timer.

I would appreciate any advice.  I need to get this working like 
yesterday, so *anything* is appreciated.  I have looked in the FAQ 
(section 18.9-10) and it says that if the interrupts are happening too 
rapidly try writing the interrupt handler in assembly (which I don't 
know how to) or install a real-mode handler.  How do you do that in 
conjuction with the protected mode one?  (that would at least be 
closer to what has been working with Borland/Pharlap)

Thanks in advance
Gregory

//--------------------------------------------------------------------
// FILENAME: main.c
// PURPOSE:  
// AUTHOR:   Gregory Fedor
// VERSION INFO:
// $Log$
//--------------------------------------------------------------------

#include <stdio.h>
#include "timer.h"
#include "types.h"

extern long timer_count;

UINT highres[600000];

int main()
{
   int real_hz, interval;
   long trigger, end;
   float predict_hz;

   startTimer();
   
   trigger = 0;
   real_hz = 0;
   
   printf("Enter the interval (ms) ");
   scanf("%d", &interval);

   end = timer_count + 1000l;
   predict_hz = 1000.0 / interval;  // calculate the predicted hz

   printf("timer_count=%ld  ", timer_count);
   printf("end=%ld  ", end);
   printf("predict_hz=%f\n", predict_hz);

   // run for 1 second;
   while(timer_count < end)
   {
      // each millisecond increment a counter
      if(timer_count >= trigger)
      {
         real_hz++;
         trigger = timer_count + interval;
      }
   }

   printf("timer_count=%d  ", timer_count);
   printf("real_hz=%d\n", real_hz);
   
   stopTimer();
   
   return 0;
}

//--------------------------------------------------------------------
// FILENAME: timer.c
// PURPOSE:  functions for setting up the 8254 counter timer to
//           provide a 1 ms interrupt.
// AUTHOR:   Gregory Fedor
// VERSION INFO:
// $Log$
//--------------------------------------------------------------------

#include <stdio.h>
#include <ctype.h>
#include <dpmi.h>
#include <sys\segments.h>
#include "timer.h"
#include "types.h"

long timer_count;
// PIC mask variable storage locations
static unsigned char save_mask1, save_mask2;  
static _go32_dpmi_seginfo wrapper;
static __dpmi_paddr old_pm_isr, new_pm_isr;

void tick()
{
   timer_count++;

   outportb(PIC1_A, EOI);  // Send EOI to the master PIC
   outportb(PIC2_A, EOI);  // Send EOI to the slave PIC
}

void startTimer()
{  
   disable();

   // Setup the 8254 counter/timer to produce a 1ms
   // interrupt on timer #2.

   save_mask1 = inportb(PIC1_B);                // Read the PIC 1 Mask
   outportb(PIC1_B, (save_mask1 & IR2_UNMASK)); // Unmask IR2 in PIC 1
   outportb(TMD, TMD2_INIT);                    // Initialize mode 2
   outportb(TCT2, (TCT2_INIT & 0xff));          // Send count lo byte
   outportb(TCT2, ((TCT2_INIT & 0xff00) >> 8)); // Send count hi byte
   outportb(PORT_B, (inportb(PORT_B) | 0x01));  // Set the Gate Enable
   save_mask2 = inportb(PIC2_B);                // Read the PIC 2 Mask
   outportb(PIC2_B, (save_mask2 & IR9_UNMASK)); // Unmask IR9 in PIC 2
   
   // Okay now setup the new interrupt vector

   __dpmi_get_protected_mode_interrupt_vector (INTR_VEC, &old_pm_isr);
   
   wrapper.pm_offset = (ULONG) tick;
   wrapper.pm_selector = _my_cs();

   _go32_dpmi_allocate_iret_wrapper(&wrapper);

   new_pm_isr.offset32 = wrapper.pm_offset;
   new_pm_isr.selector = wrapper.pm_selector;

   __dpmi_set_protected_mode_interrupt_vector (INTR_VEC, &new_pm_isr);
   
   enable();   
}

void stopTimer()
{
   disable();
   
   outportb(TMD, TMD2_INIT);      // Stop timer by starting init
   outportb(PIC1_B, save_mask1);  // Restore original mask in PIC 1
   outportb(PIC2_B, save_mask2);  // Restore original mask in PIC 2
   
   // Restore the original interrupt vector

   __dpmi_set_protected_mode_interrupt_vector (INTR_VEC, &old_pm_isr);
   _go32_dpmi_free_iret_wrapper(&wrapper);
   
   enable();
}   


//--------------------------------------------------------------------
// FILENAME: types.h
// PURPOSE:  
// AUTHOR:   Gregory Fedor
// VERSION INFO:
// $Log$
//--------------------------------------------------------------------
#ifndef __types_h
#define __types_h

#define ULONG unsigned long
#define UINT unsigned int
#define UCHAR unsigned char

#endif


//--------------------------------------------------------------------
// FILENAME: timer.h
// PURPOSE:  
// AUTHOR:   Gregory Fedor
// VERSION INFO:
// $Log$
//--------------------------------------------------------------------
#ifndef __timer_h
#define __timer_h

// Timer/Counter #2 Registers
#define TCT2      0x42     // TCT2 Count/Status Register
#define TMD       0x43     // Timer Mode Register
#define TMD2_INIT 0xb4     // TCT2, lo-hi byte, mode 2
//#define TCT2_INIT 0xffff   // 55 msec (max) count
#define TCT2_INIT 0x04a9   // 1 msec count

// PIC #1 Registers
#define PIC1_A     0x20  // PIC #1 register A
#define PIC1_B     0x21  // PIC #1 register B
#define IR2_UNMASK 0xfb  // Enable IR2 interrupt for slave

// PIC #2 Registers
#define PIC2_A     0xA0  // PIC #2 register A
#define PIC2_B     0xA1  // PIC #2 register B
#define IR9_UNMASK 0xfd  // Enable IR1 (IR9) interrupt for TCT2

// Miscellaneous I/O Addresses
#define PORT_B   0x61  // I/O port B
#define EOI      0x20  // Non-specific End-Of-Interrupt byte
#define INTR_VEC 0x71
#define lOSC_FREQ 1193

void tick();
void startTimer();
void stopTimer();

#endif

-------------------------------------------------------------------------------
Gregory A. Fedor                          ADF Inc. / NASA Lewis Research Center
Computer Engineer                               Microgravity Experiments
    work: gfedor AT lerc DOT nasa DOT gov  http://sven.lerc.nasa.gov/~gfedor (216)977-1247
personal: gfedor AT en DOT com         http://www.en.com/users/gfedor

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019