Exploring the question of using a Raspberry Pi 3 to drive a 3D printer.
By this I do not mean something like OctoPrint, which chats with a 3D printer’s existing controller (usually Arduino-based). When a Pi 3 is ~$35, it is a bit silly to use anything less.
Heard this was attempted before, with limited success. The problem is that Linux is not really meant for hard/fast real-time usage. There are options to and variants of Linux that are bit better at real-time.
But I am not interested in the entire general domain of real-time applications. I am interested in updating the output pins (GPIO) on a Raspberry Pi 3 in an efficient, predictable manner.
(Keep in mind, the following is what I gathered while waiting on an eight-hour print. I might be badly wrong about any of this.)
First, seems two output pins are needed to provide the signals needed to control a stepper motor. Those control signals are in turn amplified in voltage and power by an external circuit, to the levels needed to directly drive a stepper motor. (I got a bit lost trying to sort through the various options. Will return to this topic, later.)
As a starting point, note this guy collected measures for various means of updating the GPIO pins on a Raspberry Pi.
http://codeandlife.com/2015/03/25/raspberry-pi-2-vs-1-gpio-benchmark/
He managed 185 kHz on a Pi B (which has a slower CPU than the Pi 3) using WiringPi. So we should be able to manage at least that.
Seems the GPIO pins are visible to the CPU as memory-mapped device registers. Libraries that offer functions to set the state of an individual pin follow the usual convention of reading the register, masking out the present value of the pin, OR-ing in the new state, and writing the updated word back to the register.
Yeh. I am not going to do that.
At any given point in time, I know the exact values to be output on all the GPIO pins. That means I can update all the GPIO pins with a single-word write to memory. Writes to memory are very, very fast - though the hardware may introduce wait-states for writes to device registers.
Well, now I need a regular event from which to perform those writes.
The Linux kernel gets regular interrupts from the hardware clock. The amount of processing I need to add is small. The rate at which kernel receives clock interrupts is configurable - though I do not know the practical limits on a Pi 3.
This does not quite work as other interrupts can mask the clock interrupt, introducing jitter. As a Pi 3 has a quad CPUs, I can set the CPU affinity for the clock to one CPU, and all other interrupts to other CPUs. That should eliminate the jitter. (Again, barring hardware oddities.)
The remainder of the problem is “soft” real-time.
There needs to be a task running to plan the updates to the GPIO pins. The “plan” is really just a buffer containing a list of delay/value pairs. Need to figure out how to pass this buffer from userspace to the kernel.
More reading to do…