home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.lang.pascal
- Path: sparky!uunet!munnari.oz.au!newsroom.utas.edu.au!pc_100.psychol.utas.edu.au!peter
- From: peter@psychnet.psychol.utas.edu.au (Peter R. Tattam)
- Subject: Re: High speed clock
- Message-ID: <peter.430.724488284@psychnet.psychol.utas.edu.au>
- Keywords: clock
- Sender: news@newsroom.utas.edu.au
- Organization: Psychology Department, University of Tasmania
- References: <1992Nov20.091212.24871@lth.se> <peter.422.723796479@psychnet.psychol.utas.edu.au> <Bz47zL.5sH@news.cso.uiuc.edu>
- Date: Wed, 16 Dec 1992 06:44:44 GMT
- Lines: 149
-
- In article <Bz47zL.5sH@news.cso.uiuc.edu> amead@s.psych.uiuc.edu (Alan Mead) writes:
- >From: amead@s.psych.uiuc.edu (Alan Mead)
- >Subject: Re: High speed clock
- >Date: Fri, 11 Dec 1992 22:04:30 GMT
- >Keywords: clock
-
- >>In article <1992Nov20.091212.24871@lth.se> d92bo@efd.lth.se (Bengt Oehman) writes:
- >>From: d92bo@efd.lth.se (Bengt Oehman)
- >>Subject: High speed clock
- >>Keywords: clock
- >>Date: 20 Nov 92 09:12:12 GMT
-
-
- >>Does anyone out there know how to do high-speed timing?
- >>The internal clock ticks with 18.2 ticks per second, and
- >>sometimes this is too slow. I want a resolution of about
- >>one millisecond.
-
- >>Please reply via email.
-
- >I'll reply via email too...
-
- >First, a solution: there is a self-extracting zip file, TIMER.EXE,
- >that can be had by anon-ftp from my host, s.psych.uiuc.edu (in /pub I
- >think) that incudes a driver that will do this.
-
- >Now, can anyone EXPLAIN how this is done? I have always wanted to
- >know--it's really not the best situation to have very OS-specific code
- >that you cannot understand and thus maintain. And, unfortunately, the
- >standard in psych is to time events to the millisecond.
-
- >Thanks much.
-
- >-alan
-
- Ok. I posted something a while back to do it.
-
- Basically the idea is to reprogram the timer chip to tick at a different rate.
- You will need some data sheets on how to drive the timer chip... I think
- help-pc has some info in it. The clock normally divides down a 1.193 Mhz clock
- by 65536 (a divisor of 0 which wraps around in 16 bits) This is where the
- really wierd number of 18.2 comes from. When they designed the original PC,
- they skimped on the design a bit. That 1.193 Mhz is derived from the 4.77 Mhz
- master clock. Pity they didn't choose a more palatable clock frequency, it
- has made the PC an extremely poor timekeeper.
-
- What you have to do is change the divisor to some other number. To
- get 1000 Hz (1 millisecond) you will need a divisor of 1193. This is accurate
- to 0.1% which is good enough for most purposes, but the inaccuracy builds up
- over time.... for e.g. recording a night's eeg data.
-
- I have experimented with rates down to a divisor of 64 when using the clock to
- generate sound samples on the fly with a 386. Quite a fun little way to turn
- your pc into a primitive sound processor.
-
- Of course changing the default speed will muck up the time as recorded by DOS.
- To get around this, I use the following code to check when the clock *would*
- have normally ticked. I have a counter which has added to it the clock
- divisor every time the interrupt is called. This counter is a word value so
- every time the counter "wraps around", the carry bit is set. Now there is no
- mechanism for testing the carry bit in pascal after adding one variable to
- another so one has to resort to a little assembly code to make it happen.
- Here's the critical section. I have annotated it a little to hopefully
- explain what's going on.
-
- procedure tick_int; assembler;
- asm
-
- { save ax and ds }
-
- push ax
- push ds
-
- { set up our ds }
-
- mov ax,seg @data
- mov ds,ax
-
- { tell the interrupt controller we have finished...
- this allows next timer interrupt to proceed even when halfway through the
- timer tick }
-
- mov al,$20
- out $20,al
-
- { increment our millisecond timer }
-
- inc [timer]
-
- { here's the tricky bit.... update our count of 1.193Mhz clocks }
-
- add [clocks],one_msec { one_msec is a constant defined as 1193 }
- jnc @1
-
- { our counter overflowed... call the standard bios clock }
-
- pushf
- call [save_clock]
-
- @1:
- { we are done... usual return from interrupt }
-
- pop ds
- pop ax
- iret
- end;
-
-
-
- Now most of this needn't be done as assembly code (don't flame me even though
- it's in a pascal group, but someone did ask *how* it was done.) the only
- critical bits would be the "add [clock],one_msec" part and the following
- "pushf/call [save_clock]" pair. It's impossible to simulate the pushf without
- a lot of hard work. The check for carry could be simulated by using a longint
- and check for >= 65536 and taking appropriate actions, but the carry method
- will be much safer since the add operation is atomic and the carry is a
- side-effect of the operation.
-
- Reprogramming the timer is fairly simple.... just a few port assignments.
-
- port[$43] := $36;
- port[$40] := lo(one_msec);
- port[$40] := hi(one_msec);
-
- and when finished return it back to normal.
-
- port[$43] := $36;
- port[$40] := 0;
- port[$40] := 0;
-
- Don't bother trying to save the values of the ports.... reading and writing
- accesses different registers.
-
- All that remains to be done is to save the old interrupt vector, attach the
- routine to our routine, and away you go.
-
- I will post the full unit again in another posting.
-
- When you've figured all that out, I'll describe a technique I developed which
- allows you to send samples to the pc's speaker by twiddling a couple of timer
- registers.
-
- Peter
-
- ----------------------------------------------------------------------------
- P.Tattam International Phone 61-02-202346
- Programmer, Psychology Department Australia Phone 002-202346
- University of Tasmania, Hobart, Tasmania, Australia
- ----------------------------------------------------------------------------
-