100 kHz Timer Frequency in Windows XP [closed]
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this questionThere's a popular hobby level CNC machine tool control that operates in Windows XP and it has a timer that operates at a user-selectable rate ranging from 25 kHz up to 100 kHz.
It just so happens that I also build CNC machine tool controllers but I have been using a Galil Motion Control Inc. DMC1800 series DSP motion controller board which I control with my upper-level program. There are prospective buyers that cannot afford that configuration so I wrote another application which I plan to offer as software-based control package. The application is complete with the exception that I have no timer. (MS Multi-Media Timer is NOT sufficient.)
To avoid any confusion I'm referring to a periodic timer that is capable of operating at a frequency of 100 kHz and not a stopwatch 开发者_运维知识库timer.
Not possible. The fastest available timer on Windows is 1 ms (1 kHz). You'll need a real-time operating system or a dedicated controller. Even in a real-time OS, usually about 20 kHz is your max.
What exactly does this timer need to do? If it just needs to output a square wave between 25 kHz up to 100 kHz, then you will need extra hardware, but not outrageously expensive hardware. For example, look at this DT-340 from Data Translation. It can go even faster than you need, and I believe it can even trigger an interrupt. Or this PCI 8255/8254 48 I/O.
If you can afford USD 500 or so in your budget, there should be lots of hardware options. The actual programmable timer chip ought to be much cheaper than that, so if you are willing to roll your own circuit and interface it to the computer, you can probably do a lot better than USD 500.
I once build a circuit around the Intel 8253 Programmable Interval Timer chip, which was used inside the original IBM PC for generating the beeps out of the internal speaker. It was hooked up to a 1.193182 MHz crystal and has a 16 bit divider. This chip has been around for decades. If you need better, I'm sure there have been improvements since then.
When I say that the 8253 (or 8254) chip inside a PC is used for driving the internal speaker, I'm not being complete. There is a lot more about the Intel 8253 in Wikipedia. There it explains that output 0 is used to generate the clock interrupt, output 1 is used for DRAM refresh timing, and output 2 is used to drive the internal speaker.
The first two clock outputs generate interrupts, which is what you want, but the above descriptions of what these outputs currently do ought to give you some pause to reflect that changing their behavior might possibly cause Windows XP to notice. The third output to the speaker, is mostly harmless to mess around with, but you would need to figure out some way to redirect that signal to something that generates and interrupt, if that's what you need.
Probably Mach 3 is using the High Performance Event Timer (HPET), which according to here is part of recent Intel chipsets. Timer 0 and 1 are used for 8254 emulation.
"The ICH HPET Timer 2 interrupt may be routed to any one of the following IRQs: 11, 20, 21, 22, and 23, via the TIM2_CONF register. (Note: this register is called TIM3_CONF in Intel® ICH5.)"
You can get fairly close to 100 kHz polling using QueryPerformanceCounter in a loop on current CPUs.
For example:
typedef void ( *CallbackProc )();
void PollAtKhz( int khz, CallbackProc const &Callback )
{
int hz = khz * 1000;
LARGE_INTEGER li;
QueryPerformanceFrequency( &li );
if( li.QuadPart < hz )
return;
__int64 diff = li.QuadPart / hz;
LARGE_INTEGER NextStop;
LARGE_INTEGER CurStop;
QueryPerformanceCounter( &NextStop );
NextStop.QuadPart += diff;
while( true )
{
QueryPerformanceCounter( &CurStop );
if( CurStop.QuadPart >= NextStop.QuadPart )
{
Callback();
QueryPerformanceCounter( &NextStop );
NextStop.QuadPart += diff;
}
}
}
In my test, I got approximately 92-98 kHz frequency, using this code to test it:
void TestCallBack()
{
static int i = 0;
static time_t LastTime = time( NULL ) + 1;
++i;
if( time( NULL ) >= LastTime )
{
printf( "%d / sec\r\n", i );
LastTime = time( NULL ) + 1;
i = 0;
}
}
Obviously, this code requires maximum CPU usage, so to get these results, a SMP machine is a must. Additionally, bumping the process/thread priority to real-time helps as well.
The best you can do for timing in Windows is QueryPerformanceFrequency/QueryPerformanceCounter. The lowest frequency I've seen those produce is 1.1 MHz, so that would give sufficient frequency.
But even with that it as the other answers pointed out, it won't work. Window's isn't a real time operating system, it doesn't make any timing guarantees. There is no way to make sure that your code is running every 1 us (for 100 kHz), since Windows will swap away to other processes or kernel code.
You'll have to go with some sort of external hardware solution to get that kind of timing.
When you say periodic timer, I am supposing you meant a pulse generator?
Are you proposing a timer that would generate an event every 10 microsecond? I doubt you should do that.
You might try to program the audio output of the PC and interface that to the tool. You would have to silence/configure away PC sounds while your tool is operating to prevent frequencies that would be spurious to the pulse stream.
Have you considered a USB pulse generator? Or a cheap "USB sound card" dedicated to this operation?
Windows XP is not a realtime system, and I don't think there's a way to guarantee timers in the 10 microsecond range. You can look around in the Microsoft.Ccr.Core library, I think it's the closest you'll get.
Edit: I found more information from Microsoft. According to the How To Use QueryPerformanceCounter to Time Code knowledge-base article,
Function Units Resolution
---------------------------------------------------------------------------
Now, Time, Timer seconds 1 second
GetTickCount milliseconds approx. 10 ms
TimeGetTime milliseconds approx. 10 ms
QueryPerformanceCounter QueryPerformanceFrequency same
and that's in the context of an article that starts with the statement:
When timing code to identify performance bottlenecks, you want to use the highest resolution timer the system has to offer.
Robert Harvey is right, the QueryPerformanceFrequency is in the tens of microseconds range, but I don't think there is a way to use it to precisely trigger events. I think that makes it a complete bust for a software only solution. Have you looked at any chips like the Arduino that are fairly cheap? From the Arduino forums, it looks like 10 microsecond precision is possible.
Maybe you could use some of this:
http://www.geisswerks.com/ryan/FAQS/timing.html
Look for QueryPerformanceFrequency, but maybe the other solutions might be useful.
While I suspect meomaxy's solution is the best...
If you need high resolution differential timing, intel has some code here that claims accuracy down to the nanosecond. (There's also a good discussion of general differential timing possibilities).
Alright, after reading the Mach 3 documentation (which is well-written, informative, and even funny), I think I see what is going on. First, realize that there is a difference between having a user-space event trigger at a high frequency and having a kernel interrupt routine. The kernel interrupt routine must be fast, and thus not contain very much logic, so normally we say that it's impossible to have a generalized call-back in your program that can respond to events at frequencies > 1 kHz. Furthermore, operating systems use the local timers for the schedule, which decides when user programs can run, and typically the scheduler speed is not more than 1 kHz, therefore it's impossible to write a user-space program that responds faster than this.
However, in this case, you don't need to have complex user-space logic responding at that speed, since the goal is only to modulate an output pin at a high frequency in order to produce a PWM signal. It might be feasible to create a kernel interrupt handler for the APIC which has high priority and is triggered at high frequency, if it only does very simple things such as toggling an output pin on the parallel port.
So, if you wish to do this, I suggest you read up on kernel programming and using the APIC, and you might be achieve something useful to you. However, some words of advice:
- Distributing a driver with your software is a pain in the ass both for you as a developer and for your users who must install a driver which may or may not work. (Hardware is finicky and if your solution depends on very specific computer configurations your mileage may vary.)
- Having such a high-frequency interrupt running will bog down the computer and make things very hot. You may get stalls or blue screens. Be prepared to deal with this kind of annoyances.
- If you succeed in toggling an LPT pin in response to an APIC timer, I suggest hooking up an acquisition card or digital oscilloscope to measure not only the frequency, but also the jitter. Any software-timed signal tends to have more jitter, so watch out for this. Jitter effectively increases the noise in your signal. Additionally, jitter tends to remain constant, so at low frequencies it may not be a problem but at high frequencies the jitter may become a large percentage of your total period, significantly decreasing the signal-to-noise ratio.
- If your goal is really to just produce a PWM or pulse signal to control stepper motors, having a bit of out-board hardware is really the best way. I'll back this up with a few sub-points:
- Firstly, if you read the Mach 3 docs, they contain a section on how to electrically isolate your computer's parallel port in case of electrical issues. In other words, even if you use the built-in LPT port, some external hardware is recommended anyways just for safety. If you're going to do this, you may as well include a $2 timer chip.
- Since you are generating a high-frequency signal but only controlling this signal at a lower rate, there is no need to bog down the computer with the task of actually producing the signal itself---this is what timer chips are for.
- A $5 low-cast AVR microcontroller can talk to the computer over the USB port and generate a PWM signal. This is a far less expensive solution than buying a $100 board, but it depends on your needs. (Like how many signals, etc.) For example, buy a Teensy and just plug it into your computer's USB port, and write a 5-line program to control the 7 provided PWM outputs. Done, and done!
- If you search online for "PWM parallel", you'll find lots of tutorials on how to generate PWM signals using the parallel port, but notice that 99% of them are actually tutorials on how to control an external timer chip attached to the parallel port, not how to generate the actual PWM signal directly.
Finally, here are some documents you might find useful:
- µ-second precision timer support for the Linux kernel
- Soft timers
Windows Multimedia Timers may be able to give you 1 ms.
I would say that this is impossible without writing your own driver.
If you wrote your own driver however, you could grab ahold of HPET timers (aren't available on all machines, but come with most newer ones) and possibly the APIC timer (not sure if this can give you 100 kHz) and get 100 kHz from there.. This is pretty complex though so you'll have to do a lot more research.
Also, setting your application to real-time should help even though it'll devour your CPU usage.
To all Repondents,
I tried to make it clear that I was not interested in measuring an elapsed time yet most of the responses pertained to exactly that.
Apparently I did not adequately convey my point so I'll give it another try. I want to create an events that occurs 100,000 times in a time period of 1 second with a CPU cost of approximately 12%.
The program that I referenced, Mach 3, generates a frequency of 108,000 when the user had selected 100,000, but the frequency is very stable. I mention that to illustrate that the accuracy of the actually time interval is not critical just as long as the error in the interval time is consistent.
I will mention again that Mach 3 operates with a CPU cost of around 12%. The 108,000 frequency is emitted on a parallel port pin where it can be verified with a scope, which I have done.
Other respondents somewhat understood what I wanted to accomplish but their example was to measure the number of Loops that could occur in a time period of 1 Second while admitting that the CPU cost would be unacceptable.
The general consensus was that what I'm wanting to do is not possible. For those that align with that opinion I would encourage you to Google Mach 3 CNC, download a free copy of the program and then install it. Run the program, use the tabs to navigate to the diagnostics page you will be able to see for yourself that it is in fact possible. The program will initially open operating at the default frequency of 25kHz. The frequency can be changed by opening the menu selection 'Config' / 'Ports and Pins' / followed by selecting the new frequency and reopening the program.
Forums like this have a large number of post pertaining to this subject matter and the responses are, for the better part, the same as what I received. I have provided an example that clearly shows that it is POSSIBLE so let's figure out how Mach 3 is accomplishing this task.
C4C
I've been working with a CNC router myself lately using a realtime linux kernel, the issue you're seeing is the lack of realtime preemption in windows xp. I can't view the Mach3 stuff from here, but the only way it should be able to work is by using a "kernel level" driver in windows. (sorry, I'm not really a windows person, so I don't really know specifics). Writing some sort of driver to bypass windows default preemption model is your answer though, i would start by learning a bit about windows drivers and maybe looking at the realtime patches for the linux kernel for reference.
http://www.kernel.org/pub/linux/kernel/projects/rt/
A basic problem with using a PC for motion control, without dedicated hardware, is the data rate of the various outputs built in to most PC's. If your customers don't have the budget for the high end motion controller you mention, then they simply aren't going to have access to 100 kHz signals.
The I/O controllers for every port provides some kind of buffering so that you will get smooth results out of them. This largely serves the purpose of alleviating software from the need to 'bit-bang' those signals, and also makes I/O frequency much more stable.
The downside is the buffering will probably introduce some latency in the system, which may impact the performance closed loop control circuit with the control in software. Another downside is this limits your frequency options. One of the fastest I/O options on a PC that doesn't provide high end flow control like USB or SATA is actually the audio port, but that is limited to 64 kHz or 44 kHz on most systems.
If the audio port is an option for you, then you don't need to worry about timing at all, Just make sure you set the frequency properly, and produce your signal as you would otherwise.
If you need to use a digital signal, the parallel and serial ports work in a similar fashion , but at a lower maximum speed.
EDIT Hmm... It seems parallel ports are a bit faster than they used to be. An enhanced parallel Port (EPP) capable machine can give you up to 2mbits of of binary bandwidth, which should be well within the reach of your goal. However, due to the way the parallel interface works, data speed is dependent on the peripheral, rather than some predefined buffer speed. Essentially, the peripheral acknowledges that it has recieved data, or that it is ready to send data, for each byte transferred.
This isn't too bad, though, because a simple, clock driven peripheral is easy to set up.
Additionally, data cannot flow in both directions at the same time, data coming from the peripheral will cause the stream of data from the host PC to block. A possible way to circumvent that is to just arrange to have two parallel ports available, or arrange for the peripheral to limit its own data transmissions to every other cycle.
I/O on a such a port is normally interrupt driven. Besides a few error states, the most useful interrupts are generated when the input or output FIFO's reach a certain level. You can use this interrupt to write (or read) new data to the port. The threshold can be set to anywhere from 1 to 16 bytes. You should carefully test (with a logic analyzer/oscilloscope) that data is actually flowing at the expected speed, with the expected rate. You could do this almost as well in software using a QueryPerformanceCounter.
Could you try using something like IntervalZero's RTX. It's not free, it's a commercial product.It's written to introduce realtime into Windows (XP etc) It has some very fast timers. according to this paper RTX has timers with a value of 1 microsecond (whereas Windows is 1000 microseconds)
Not sure what pricing\licensing is like. I have dabbled with the eval version.
Sounds like you need a 555 timer (or a crystal), an AND gate and a parallel port (or a digital I/O USB device). You might be able to fake a soundcard DSP into doing something like this, but I wouldn't bet on it.
Any timer you can build on windows that will run at the required speed is going to be CPU bound. It's not that the compute CPU can't handle it, but you have to think about the rest of the moving parts on your computer. To get a reliable 100 kHz signal from software emulation to a hardware I/O signaling on standard hardware is quite a task. You will I/O bound a core just to get the right signal pattern.
A few options may be to create a loop back plug for a serial port and then play with bit patterns and signaling types to get a fairly stable signal. But you will be much better served to either build or buy a digital control board that is made to control a CNC mill. If you look, most of the gear related to that Mach 3 CNC is referring to control boards that take USB, RS-232, or LPT ports.
(Oh, and telling people they are wrong instead of having a constructive comment... doesn't win you any fans either)
I consider that the only way that currently good speeds can be achieved is through USB-type connections to the computer. You would have to make a USB Pnp device to achieve it !
精彩评论