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 #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 #include #include #include #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