FM DDS: First Light Hardware

Some Barely Viable Prototype hardware for a frequency modulated DDS to replace Channel Elements requiring now-unobtainable crystals:

FM DDS - First Light layout
FM DDS – First Light layout

The heatsink (surely harvested from a PC, then salvaged from a box o’ goodies) runs about 25 °C above ambient while dropping a 12 V input to 5 V at 180 mA, so it’s good for maybe 2°C/W. It carries a KA278RA05C LDO regulator; you’d probably want something fancier in real life.

The AD9851 DDS requires a 5 V supply to run at 180 MHz from the 30 MHz oscillator on its PCB, with the side effect of putting its minimum Logic 1 Voltage threshold at 3.5 V. Because the Teensy 3.6 runs at 3.3 V from its own on-board linear regulator, the DIP 74AHCT125 level shifter between the two boosts the Teensy’s LVCMOS SPI signals to good old TTL.

The sticker on the CPU reminds me of the jumper cut between the USB +5 V line and the VIN pin, thus putting the Teensy on the better-regulated local supply for the benefit of its ADC reference:

Teensy 3.6 Back - VIN to VUSB jumper
Teensy 3.6 Back – VIN to VUSB jumper

The picture comes from PJRC’s exceedingly helpful Teensy 3.6 reference cards.

I ran header pins along both sides of the Teensy to simplify attaching scope probes and suchlike; the dangling gray wire brings the scope’s Arbitrary Function generator signal to the Teensy’s A9 input.

The FMDDS Mock 3 firmware lit right up, albeit with the faceplant of sending the SPI bytes in the wrong order and the wrong bit direction, which was easily fixed after a bit of puzzling:

FM DDS 10 MHz - SPI 16 MHz LSB
FM DDS 10 MHz – SPI 16 MHz LSB

Just a typo, could happen to anyone …

Teensy 3.6 USB Serial Startup

The Arduino Serial doc says the USB hardware on the (now obsolescent) Leonardo requires a test-for-open before using the serial port:

  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB

As it happens, you must also use that test on the ARM-based Teensy 3.6.

The gotcha happens when the USB port doesn’t become available, in which case the conditional remains true and the loop continues forever, which is precisely what happened when I powered the Teensy from a USB battery pack on the Squidwrench Operating Table.

After some flailing around, this startup snippet falls through after ahem awhile:

#define BUILTIN_LED 13

... snippage ...


int waited = 0;
while (!Serial && waited < 3000) {
  if (! (waited % 50))

... snippage ...

Serial.printf(" serial wait: %d ms\n\n",waited);

The serial startup delay seems to vary unpredictably between 800 and 1800 ms, so 3000 ms may be too short:

serial wait: 1033 ms
serial wait: 899 ms
serial wait: 907 ms

The ARM Teensy connects the board's built-in LED to the same SPI clock as on the AVR Arduinos, so it's only useful during startup, but having some hint will come in handy the next time it jams for another reason.

MPCNC: Epoxy-filled Connector

When I wired up the MPCNC’s tool length probe, I planned to reinforce the wiring with a dab of epoxy. What I didn’t notice in my enthusiasm, alas, was the opening from the rear to the front in each pin slot:

Epoxied connector - rear
Epoxied connector – rear

Which let the epoxy flow completely through the connector:

Epoxied connector - front
Epoxied connector – front

So I cut the mess off and applied heatstink tubing on each wire, just like I should have in the first place.

Now you know the rest of the story …

I really dislike pin headers as cable connectors, but that’s what the Protoneer CNC board uses:

MPCNC - Protoneer Wiring - SSR
MPCNC – Protoneer Wiring – SSR

It’ll be Good Enough if I don’t do anything else particularly stupid.

MPCNC: Tool Length Probe Station

Having a tool length probe station on the Sherline, I had to build one for the MPCNC:

MPCNC Tool Length Probe - plotter pen
MPCNC Tool Length Probe – plotter pen

It’s little more than a flange atop a wide base:

MPCNC Tool Length Probe - Slic3r preview
MPCNC Tool Length Probe – Slic3r preview

The flange offset puts the switch actuator on the midline of the base, not that that matters, and the base features rounded corners and a suitable legend, because I can.

I clipped the PCB’s through-hold leads nearly flush and stuck it to the flange with 3M permanent foam tape, which seems to work much better than screws & inserts for simple things that need never come apart.

The Protoneer CNC Shield includes a Probe input on the GRBL-compliant A5, although it took me a while to find the legend on the SCL pin in the I2C header. I moved the endstop power jumper to another header, then conjured a quick-and-dirty connector:

Protoneer CNC Shield - Tool Probe Wiring
Protoneer CNC Shield – Tool Probe Wiring

When I embed the endstop switch PCB in epoxy, I’ll add a drop to the connector while engaging in Magical Thinking. The whole Arduino + CNC Shield must go into an enclosure after I finish measuring the motor currents.

To forestall discussions about switch repeatability and accuracy, suffice it to say the MPCNC doesn’t claim to be much more than a woodworking router, so those switches seem Good Enough.

The OpenSCAD source code as a GitHub Gist:

// MPCNC Tool Length Probe Station
// Ed Nisley KE4ZNU - 2017-12-08
/* [Extrusion] */
ThreadThick = 0.25; // [0.20, 0.25]
ThreadWidth = 0.40; // [0.40]
function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
/* [Hidden] */
Protrusion = 0.1; // [0.01, 0.1]
HoleWindage = 0.2;
/* [Sizes] */
EndstopPCB = [40.0,16.5,1.6]; // endstop PCB
ComponentHeight = 6.0; // max component height above PCB
SwitchOffset = [35.0,21.0,4.75]; // touch point center from lower left PCB corner
SwitchTravel = 2.5; // first touch to switch actuation
TapeThick = 1.0; // foam mounting tape
WallThick = 4.0; // basic wall & floor thickness
BaseRadius = 5.0;
Base = [IntegerMultiple(EndstopPCB[0] + 2*BaseRadius,20),
IntegerMultiple(EndstopPCB[2] + TapeThick + WallThick + 2*BaseRadius,2*25),
NumSides = 8*4;
TextDepth = 2*ThreadThick;
//- Build it
union() {
difference() {
for (i=[-1,1], j=[-1,1])
translate([i*(Base[0]/2 - BaseRadius),j*(Base[1]/2 - BaseRadius),0])
intersection() {
translate([0,0,Base[2] - TextDepth])
linear_extrude(height=TextDepth + Protrusion) {
text(text="Tool Probe",size=6,spacing=1.05,font="Arial:style=Regular",halign="center");
WallThick/2 + TapeThick + SwitchOffset[2],
(EndstopPCB[1] - Protrusion)/2 + Base[2]])
cube([EndstopPCB[0],WallThick,EndstopPCB[1] + Protrusion],center=true);

The original doodles show a severely over-complexicated solution desperately searching for an actual problem:

MPCNC Tool Length Probe - doodles
MPCNC Tool Length Probe – doodles

Putting a large flat pan at the end of a relatively long lever arm, with the pivot arranged to put the pan level at the switch actuation point, made sense at the time. Give the relatively small tools I expect to use, directly ramming them into the switch lever should work just as well.

Putting all that complexity in harm’s way seemed like a Bad Idea when I sat down and looked at it in cold blood.

MPCNC: Epoxy-Coated Endstop Switches

Using 3D printer style endstop switches has the advantage of putting low-pass filters (i.e. caps) at the switches, plus adding LED blinkiness, but it does leave the +5 V and Gnd conductors hanging out in the breeze. After mulling over various enclosures, it occured to me I could just entomb the things in epoxy and be done with it.

The first step was to get rid of the PCB mounting screws and use 3M permanent foam tape:

MPCNC - Epoxy-coated Endstop - Adhesive Tape
MPCNC – Epoxy-coated Endstop – Adhesive Tape

Get all the switches set up and level, mix up 2.8 g of XTC-3D (because I have way too much), and dab it on the switches until all the exposed conductors have at least a thin coat:

MPCNC - Epoxy-coated Endstop - Installed
MPCNC – Epoxy-coated Endstop – Installed

You should use a bit more care than I: the epoxy can creep around the corner of the switch and immobilize the actuator in its relaxed position. Some deft X-Acto knife work solved the problem, but only after firmly smashing the X axis against the nonfunctional switch.

Epoxy isn’t a particularly good encapsulant, because it cures hard and tends to crack components off the board during temperature extremes. These boards live in the basement, cost under a buck, and I have plenty of spares, so let’s see what happens.

At least it’s now somewhat more difficult to apply a dead short across the Arduino’s power supply, which comes directly from a Raspberry Pi’s USB port.

MPCNC: Stepper Motor Power Control

GRBL responds to critical errors by disabling its outputs, which seems like a useful feature for a big-enough-to-hurt CNC machine like the MPCNC. Unlike the RAMPS 1.4 board, there’s no dedicated power-control pin, so I connected the Coolant output to the same DC-DC SSR I tried out with the RAMPS board:

MPCNC - CNC Shield - Power SSR
MPCNC – CNC Shield – Power SSR

With homing enabled, GRBL emerges from power-on resets and error conditions with the spindle and coolant turned off and the G-Code interpreter in a locked state requiring manual intervention, so turning the stepper power on fits right in:

  • $x – Unlock the controls
  • m8 – Coolant output on = enable stepper power
  • $h – Home all axes

The steppers go clunk as the power supply turns on, providing an audible confirmation. The dim red LED on the SSR isn’t particularly conspicuous.

Turning the stepper power off:

  • m9 – Coolant output off = disable stepper power

I think the A4988 drivers maintain their microstep position with the stepper power supply off, because their logic power remains on. In any event, you probably wouldn’t want to restart after an emergency stop without clearing the fault and re-homing the axes.

The board has Cycle Start, Feed Hold, and Abort inputs just crying out for big colorful pushbutton switches.

Unlike the RAMPS board, the Prontoneer CNC Shield does not feed stepper power to the underlying Arduino UNO, leaving it safely powered by USB or the coax jack.


MPCNC: 12 V Supply vs. Stepper Current vs. Axis Speed

The default MPCNC configuration wires the two stepper motors on each axis in series, doubling the total resistance and inductance of a single motor. The stock Automation Technology motor presents 2.8 Ω and 4.8 mH in each winding to the driver, for an L/R time constant of τ = 1.7 ms. Doubling both doesn’t change the ratio, but including the harness wiring resistance gives 1.6 ms = 9.6 mH / 6 Ω.

The default DRV8825 driver configuration uses 1:32 microstepping, which I thought was excessive. I replaced the stock RAMPS setup with a Protoneer / GRBL setup using A4988 drivers in 1:16 microstepping mode, got it configured, and made a few measurements:

MPCNC CNC Shield - Current Measurement Setup
MPCNC CNC Shield – Current Measurement Setup

The current probe measures the winding current in the red wire. The voltage probe at the bottom isn’t doing anything, because I ran out of hands.

Here’s a 10 mm X axis move at 3600 mm/min = 60 mm/s:

MPCNC X 10mm 60mm-s 500mA-div
MPCNC X 10mm 60mm-s 500mA-div

The top trace shows the winding current at 500 mA/div. The bottom trace shows the voltage applied to the winding at the A4988 driver pin.

Basically, the +12 V supply doesn’t provide enough headroom to let the driver force the required current into the winding at full speed, which is why the peak current decreases as the step rate increases and the sinusoid becomes a square(-ish) wave. The applied voltage switches rapidly to maintain the proper winding current when the axis is stationary or moving slowly (where the driver’s PWM current control works fine), but turns into a square (well, rectangular) wave as the pace picks up (and the driver loses control of the current).

The motor drives a 16 tooth pulley with a 2 mm belt pitch, so each revolution moves 32 mm of belt. With 1:16 microstepping, each revolution requires 3200 = 200 full step × 16 microstep/step pulses, which works out to 100 step/mm = (3200 step/rev) / (32 mm/rev). At the commanded speed near the middle of the trace, the driver must produce 6000 step/s = 60 mm/s × 100 step/mm, so each step lasts 167 μs, about τ/10.

In round numbers, the first full cycle on the left has a 20 ms period. Each full cycle = 4 full steps = 64 microsteps, so the belt moved (60 step) / (100 step/mm) = 0.6 mm, at an (average) speed of 30 mm/s = 1800 mm/min. The current begins to fall off by the third cycle with a 12 ms period, a pace of 50 mm/s = 3000 mm/s, and pretty much falls off a cliff by 60 mm/s in the middle.

To be fair, those are aggressive speeds for milling, but lasers and 3D printers tick along pretty quickly, so they’re not unreasonable.

More study is indicated, as the saying goes …