# Writing to parallel port with minimum latency

I want to use a parallel port to control some stepper motors (many of them). So far I've got it connected to a little test board with LEDs and I've written a C program in Linux to set the pins using outb or outl calls. Because I want to use all 12 output pins I'm setting both the data byte and the control byte. (Actually, more than 12 pins would be nice, but 12 will have to do.)

This all works and the LEDs light up as expected, but it's a bit too slow for my needs. A loop with 1,000,000 iterations that call outb twice (data and control byte) takes ~3.9 seconds. If I replace that with a single outl call that takes ~3.6 seconds, so it looks like each outl takes about 3.6 us. From what I read it should work in about 1 us or even less. The question is: how do I make it faster?

The machine is an AMD Sempron with an on-board parallel port. There are 3 settings for the port in BIOS: "Bi-directional", "ECP" and "EPP". ECP gives the numbers above. Bi-directional is slightly slower and EPP is much slower (running exactly the same code). Is there something special I need to do in code to take advantage of the faster modes? Is it a limitation of the hardware so maybe a dedicated PCI IO card would be faster? Do I need to use DMA (which I think requires a kernel-mode driver)?

Alternatively, is there some add-on device out there like a parallel port, but with more pins and/or lower latency for setting all the pins? (I don't need to change one pin at a time.)

Edit (more details):

I want to control 1,000 stepper motors in total. The original design was to have 5 Arduinos controlling 200 motors each using logic gates to address each motor in sequence. A 6th Arduino would be the "master" controller, sending data to the other 5. However, an Arduino doesn't have enough memory to store all the data I want to send, so that's where a PC came in. Once a PC was involved it seemed much simpler if I could cut out the Arduinos entirely and use 2 (maybe 4) parallel ports to control the motors directly, probably under RTLinux (though the test above was done on regular Linux). I don't think I'd need a 1 us timer resolution as such. I was thinking of a timer firing every 1500-2000 uS and each time sending signals to all 1000 motors, one by one (500 or 250 per parallel port). The parallel port speed seems to be the limitation here.

I understand that there are dedicated stepper motor controllers, but buying 1000 of them gets expensive. Is there something that can control many of them? Ideally I'd like to keep as much of the work as possible on the PC, because it's just so much easier to program and debug.

• Do you realize that Windows, Linux and other desktop systems can take control at unpredictable moments and stall your application for let's say half a second? There is a good reason some people use what is called a RealTimeOperatingSystems, which those desktop OSes definitely are NOT! – Wouter van Ooijen Oct 15 '12 at 6:23
• Apparently I do realise that, since I mentioned RTLinux. The initial test was not done under RTLinux, but are you suggesting that that was the limiting factor in this particular case? – EM0 Oct 15 '12 at 6:51
• I would say that any measurement on Linux should be distrusted. I am not sure about RTLinux. I also agree with the others that this is probably not a good architecture for what you want. I would consider a CAN or DIY RS485 network with microcontrollers, each controlling a bunch of steppers, commanded by high-level commands (not step-level commands ). – Wouter van Ooijen Oct 15 '12 at 7:49
• Why do you say measurements under Linux cannot be trusted? The machine was not doing anything else at the time and the time was consistently 3.60 or 3.59 seconds. If the OS was interfering I would expect much more variation from test to test than 0.3%. Could you post any more details or links on CAN or RS485 network? I'm new to this stuff. – EM0 Oct 15 '12 at 8:24
• Right now, you're just running a single simple test loop on the PC. If that's all this box will ever be doing, then the Linux-based PC is way overkill for this task. But we're presuming (because you haven't told us) that this PC will eventually be running additional code to define the overall behavior of the 1000 motors, and this other code will interfere with the timing of the parallel port. – Dave Tweed Oct 15 '12 at 10:35

For simple pulse generation for 1000 stepper motors, what you want is an FPGA where you can build many copies of a simple sequencer engine, and connect each copy to its own output pin.

However, the vast majority of the cost a stepper motor driver system is in the power switching transistors, FETs, (or for smaller motors, IC) - and the motors themselves, not the step pulse generator.

Once you are making a module with the switching electronics per motor (or per small number of motors), the cost of putting a microcontroller on there which can accept high-level commands over some sort of addressable serial bus is minor.

The whole project sounds rather implausible to begin with. Before you do anything with 1000 motors, you should gain some practical experience in systems with a half dozen or so.

Have a look at www.LinuxCNC.org. The purpose of this linux distribution it to drive step motors for DIY CNC machines. The linux kernel was patched to add kind of limited real time behaviors. One way they use to control the motors is... the parallel port. The kernel has dedicated real time routines that run every xxx us with reduced jitters in order to drive the motor drivers. The kernel also embed all the logic needed in case that you want to add some kind of PID controls to your motors. But.. I don't know how well it scales if you have to control 1000 motors...

• Thanks, didn't know LinuxCNC patched the kernel. They should provide these patches upstream so domains other than CNC could make use of them if needed. – Sabuncu Mar 16 '15 at 20:26

This is the sort of application in which you really don't want to be doing the low-level control of individual bits by writing software on a high-end computer. You should add some external hardware to handle those low-level details while the main system deals with higher-level behavior. Communication between the two then has fewer real-time constraints and can be implemented using USB, serial port, Ethernet, or embedded serial busses like SPI or I2C.

You can get dedicated stepper motor controller chips, or you can program a general-purpose microcontroller (many of which have dedicated hardware for driving motors and reading position encoders, for example) to do the job.

• Thanks, I know there are stepper motor controllers and microcontrollers, but was hoping for a simpler solution than the PC communicating with several microcontrollers, each of which then controls many stepper motors (see question edit). – EM0 Oct 15 '12 at 3:36

I think @DaveTweed's answer is fairly spot on, but I'd like to add a few more things to this.

You say that a single outb call should take 1 uS or less. Why do you think that? There is nothing (hardware or software) that will guarantee that level of performance.

For starters, is outb being implemented as a inline macro, or is is generating an actual function call? Even if it is an inline macro, what else is that macro doing? Could be be managing various logical to physical address mappings? All of these things will require time and could push out the execution time of outb or outl.

Then there is the hardware things that could cause this speed. PCIe, for example, is notorious for making single byte/word accesses slow. Writes are typically much faster than reads, but I can see how writes to the parallel port could go to >1us each. Other bus standards might have different effects on the speed, as well as the bus topology (location and type of bus bridges). It doesn't help that PC chip and motherboard makers are in no way motivated to make parallel port interfaces run fast.

Even if you got this working fast on this system, it doesn't mean that it'll run fast on the next system. To make matters worse, Linux is not a real-time operating system. There is no guarantee that you will get the performance that you want every time. You could have it running just fine for a while and then Linux does something that pauses your stepper motor pulses for 100 mS or longer. There are "real time" versions of Linux that improve things, but they don't improve things to the 1 uS level.

If I were doing this, I would get a nice ARM Cortex M0/M3/M4 with a USB interface and make the ARM do all of the stepper motor controlling. And then just interface it to your PC via USB. Do it right and the ARM could do all sorts of motor control stuff that would be too difficult to do in Linux.

• Thanks. I added more detail to my original post. The outl call is a macro. – EM0 Oct 15 '12 at 3:34

** 2nd edit* Now having read your details added, you need to consider a bottoms up and top-down approach for controlling 1024 motors from a single port. Bottom's up.. you want minimal duplication of hardware and top-down you want fault isolation and addressable control for device ( 10 bits), direction (1 bit) and distance, velocity for the remaining bits with CRC error detection on I/O. This type of communication was originally developed using ADLC and SDLC serial protocols with standard chips.

This question attempts to ask "How would you design a control system for 1000 stepper motors, that perhaps cost $500 for 1000 miniature motors. This will not be easy, and even harder with fault detection, isolation. Without it, imagine what your MTBF is going to be and debug time ?? I read symposiums that tried to answer, what would do with it, if you had such a system? e.g. a fluid Animanemone flower. http://www.taomc.com/stepperarray/stepperarray.htm **I would consult Microchip for an inexpensive array solution. Start with a block diagram and a list of requirements before any design. Then see what communication suits your application best. A custom serial synchronous channel may be better than an addressable channel by saving on the overhead with addressing using synchronous serial channels similar to LCD serial drivers using Display Serial Interface (DSI). You need to think more at the higher level requirements rather than the low level hardware interface on the OSI model and define all the requirements before choosing a reliable, inexpensive, maintainable design. An LCD pixel mapping approach may be all you need until you have a dead pixel. j/k. ** last edit ended* ** Added* The parallel port is limited in speed by the BIOS setting, your LPT driver and the LPT external buffer. The card linked below uses an 8 bit x 512 FIFO to buffer the output to achieve 2 to 1 uS data rates. Being that it is not cheap nor designed for stepper motors. I don't recommend it. • Step pulse and direction. • Step in and Step out This is how you should design your system. Microstepping, slew rate speed control for optimum seek speed can all be better (cheaply and more precisely) handled by discrete hardware as was done by some Japanese ST506 disk drives, 30 years ago. Although learning curve and design experience is required on this method. If desired, I can look for examples I know exist. If you reduce your clock speed requirements, these tools may be useful. http://www.fapo.com/1284tkit.htm *end edit * There is a 1uS Parallel Port solution but the card costs around$500. http://www.fapo.com/files/fportman.pdf The card uses a FIFO to buffer parallel port transfers.

The most cost effective solution is one that is in high volume demand. Your budget and I/O requirements need to be defined better for latency variations. Otherwise go back to the drawing-board and delegate the bandwidth of control to a dedicated hardware solution and use the PC for high level controls.

Normally 100~150KB/s is the maximum rate on Parallel port. You have done well to get more without a FIFO. But what latency variation can you tolerate?

Have a look at the Armadeus project boards: http://www.armadeus.com They provide small open source ARM based board with an embedded linux. Some of them have a FPGA connected to the ARM. They also provide examples on how to access the FPGA from the embedded linux. It could be interesting to implement the control and interface to your 1000 motors into the FPGA and use a user space linux application to drive the FPGA.

If the only reason you couldn't use an Arduino was it's limited memory, perhaps you could work around that by adding some external memory to the Arduino. I suspect the simplest way to add external memory involves the SD/MMC card protocol.

There's an Arduino library that makes reading (and writing) such cards pretty simple. For more details, I recommend the Micro SD card Tutorial from Lady Ada. You might also find useful the questions tagged or here at Electronics Design stackexchange, or a web search for arduino SD card.

Ignoring all the issues of suitability or choices of hardware and software for the purpose, I will take your original question at face value. Is it possible that the overhead for the loop is about 3 us? Recode your loop to execute 10 out instructions in a row, and make the loop go 100,000 times. See if the execution time is drops appreciably. This will tell you at least one thing about the execution of those instructions.