[Ed. Note. Originally written and published by Jesse Off, May 25, 2012]
A common task in embedded systems is control of DC motor speed and direction. These DC motors or servos can be brushed or brushless types with or without internal torque amplifying gears and transmissions. Some have built-in optical position encoders (also called quadrature encoders) that output waveforms that an embedded system can use to determine precise position and speed through the use of quadrature decoder logic. When money is no object, often times dedicated motor controller IC boards are used that have built in micro controllers that handle the H-Bridge PWM and quadrature functions and talk MODBUS to either another system controller or PLC (Programmable Logic Controller).
The typical circuit arrangement for a DC motor is a H-Bridge. With an H-bridge and simple software based GPIO bit-banging either Linux or a micro controller can turn on and off a motor in either forward or reverse direction. If, however, you want to modulate motor speed and power, you need to do PWM (pulse width modulation) on those GPIOs. Doing high-speed PWM bit banging in software is relatively straightforward on a micro controller, but on a SBC running Linux there are several limitations. On Linux, kernel drivers can interrupt the precise timing needed for accurate PWM such that the PWM waveform experiences high jitter or stutters at 100% or 0% duty for tens of milliseconds at a time as other processes take over the CPU.
Technologic Systems prefers to handle this sort of thing in FPGAs and has created a simple FPGA core to make RTOS's and dedicated microcontrollers unnecessary. The FPGA core attached below creates 8 PWM channels running at a DC motor appropriate PWM frequency of 1.5Khz with 8 bits of duty cycle precision (0-0% 255-100%). It also includes support for 4 16-bit quadrature counters and 4 16-bit edge/frequency counters. The core takes 19 16-bit registers of WISHBONE address space and 133 LUTS and 68 flip-flops on a Lattice XP2 such as whats found on the TS-75xx SBC series. For comparison, the Lattice XP2 on the $84 TS-7500 has 5000 LUTs capacity.
Note that this core is only appropriate for DC motors and not stepper motors (unipolar or bipolar). Nor is it appropriate for RC style servo motors as those have built in analog controller circuits that expect a 50Hz PWM control signal and not PWM modulated power. This core has been used in several custom projects at TS and usually involved with software PID loop control systems. (PID stands for Proportional Integral Derivation controller) Having an Linux OS for these higher level software functions is a lot nicer than programming micros and such is the benefit of the paired FPGA on most TS boards.
The source code of this core is attached below. Customers of TS using a TS supplied FPGA or CPU base board can freely use, modify, and otherwise instantiate this core in their custom FPGAs however they see fit. It is NOT licensed with the GPL or other such open source license that requires modifications to be re-submitted openly. TS doesn't care what you do with the source as long as its used only with our products and the GPL or LGPL license is frankly too restrictive.
Documentation is included in the source comments, but also listed here:
/* PWM motor controller core with quadrature inputs. * * Register map: * base + 0x0: PWM channel #0 (0-256 for 0%-100% duty) * base + 0x2: PWM channel #1 * base + 0x4: PWM channel #2 * base + 0x6: PWM channel #3 * base + 0x8: PWM channel #4 * base + 0xa: PWM channel #5 * base + 0xc: PWM channel #6 * base + 0xe: PWM channel #7 * base + 0x10: quadrature count #0 (16-bits, read-only) * base + 0x12: quadrature count #1 * base + 0x14: quadrature count #2 * base + 0x16: quadrature count #3 * base + 0x18: index pulse count #0 (16-bits, read-only) * base + 0x1a: index pulse count #1 * base + 0x1c: index pulse count #2 * base + 0x1e: index pulse count #3 * base + 0x20: configuration register (read-write) * bit 3-0: Hbridge enable chan#3 to chan#0 (LSB is chan#0) * bit 7-4: index pulse enable chan#3 to chan#0 (LSB is chan #0) * bit 11-8: index pulse polarity chan#3 to chan#0 (LSB is chan #0) * bit 15-12: quadrature enable chan#3 to chan#0 (LSB is chan #0) * base + 0x22: GPIO inputs (read-only) * bit 15-8: quadrature input pins 7-0 * bit 7-0: general input pins 7-0 * base + 0x24: overcurrent status * bit 15-4: reserved * bit 3-0: overcurrent status chan#3 to chan#0 * * * If quadrature channels are disabled, quadrature counts become * free-running upcounters and index pulse counts become edge * counters. * * * If overcurrent is tripped, H-bridge enable is automatically * temporarily deasserted. This effects as negative feedback * keeping current maxed out at approximately the trip point. */
The code file can be found on the Technologic Systems FTP site here.