Mesa 5i25 Superport: Reflash and Step-Direction Pin Swap

For reasons lost in the mists of time, the DB-25 pinout used in the Sherline CNC Driver Box is kinda-sorta the same as everybody else’s DB-25 pinout, with minor difference of swapping the Step and Direction pins on each axis. This made no difference with the LinuxCNC parallel port driver, because (nearly) all pins are alike to it, but having recently found the Mesa 5i25 Everything I/O card and being desirous of upgrading to the latest & Greatest LinuxCNC, I figured why not throw all the balls in the air at once?

Although it’s theoretically possible to recompile the FPGA source code to swap the pins, the least horrible alternative was converting a null modem (remember null modems?) into a passthrough pinswapper:

DB-25 Parallel Adapter - Step-Direction pin swap
DB-25 Parallel Adapter – Step-Direction pin swap

Make sure you put jumper W2 in the DOWN position to route pins 22-25 to DC ground, rather than +5 V. W1 does the same for the internal header, herein unused, but it’s in the same position just for neatness.

Similarly, put both W3 and W4 in their UP position to enable +5 V tolerance, connect the pullups to +5 V, and enable the pullups, thereby keeping the Sherline logic happy.

Jumper W5 must be UP in order to have the thing work.

The relevant diagram:

Mesa 5i25 - jumper locations
Mesa 5i25 – jumper locations

Flashing the 5i25 with the Probotix PBX-RF firmware produced the best fit to a simple parallel port:

sudo mesaflash --verbose --device 5i25 --write 5i25/configs/hostmot2/5i25_prob_rfx2.bit
sudo mesaflash --verbose --device 5i25 --reload

The mesaflash utility and all the BIT files come from their 5i25.zip file with all the goodies.

The Gecko G540 pinout came in a close second and, should the Sherline box go toes-up, I’ll probably replace it with a G540 and (definitely) rewire the steppers from Sherline’s unipolar drive to bipolar drive mode.

The 5i25 pinout now looks like this:

halrun

halcmd: loadrt hostmot2
Note: Using POSIX realtime
hm2: loading Mesa HostMot2 driver version 0.15

halcmd: loadrt hm2_pci
hm2_pci: loading Mesa AnyIO HostMot2 driver version 0.7
hm2_pci: discovered 5i25 at 0000:04:02.0
hm2/hm2_5i25.0: Low Level init 0.15
hm2/hm2_5i25.0: 34 I/O Pins used:
hm2/hm2_5i25.0:     IO Pin 000 (P3-01): IOPort
hm2/hm2_5i25.0:     IO Pin 001 (P3-14): PWMGen #0, pin Out0 (PWM or Up) (Output)
hm2/hm2_5i25.0:     IO Pin 002 (P3-02): StepGen #0, pin Step (Output)
hm2/hm2_5i25.0:     IO Pin 003 (P3-15): IOPort
hm2/hm2_5i25.0:     IO Pin 004 (P3-03): StepGen #0, pin Direction (Output)
hm2/hm2_5i25.0:     IO Pin 005 (P3-16): PWMGen #0, pin Out1 (Dir or Down) (Output)
hm2/hm2_5i25.0:     IO Pin 006 (P3-04): StepGen #1, pin Step (Output)
hm2/hm2_5i25.0:     IO Pin 007 (P3-17): IOPort
hm2/hm2_5i25.0:     IO Pin 008 (P3-05): StepGen #1, pin Direction (Output)
hm2/hm2_5i25.0:     IO Pin 009 (P3-06): StepGen #2, pin Step (Output)
hm2/hm2_5i25.0:     IO Pin 010 (P3-07): StepGen #2, pin Direction (Output)
hm2/hm2_5i25.0:     IO Pin 011 (P3-08): StepGen #3, pin Step (Output)
hm2/hm2_5i25.0:     IO Pin 012 (P3-09): StepGen #3, pin Direction (Output)
hm2/hm2_5i25.0:     IO Pin 013 (P3-10): IOPort
hm2/hm2_5i25.0:     IO Pin 014 (P3-11): Encoder #0, pin A (Input)
hm2/hm2_5i25.0:     IO Pin 015 (P3-12): Encoder #0, pin B (Input)
hm2/hm2_5i25.0:     IO Pin 016 (P3-13): Encoder #0, pin Index (Input)
hm2/hm2_5i25.0:     IO Pin 017 (P2-01): IOPort
hm2/hm2_5i25.0:     IO Pin 018 (P2-14): PWMGen #1, pin Out0 (PWM or Up) (Output)
hm2/hm2_5i25.0:     IO Pin 019 (P2-02): StepGen #4, pin Step (Output)
hm2/hm2_5i25.0:     IO Pin 020 (P2-15): IOPort
hm2/hm2_5i25.0:     IO Pin 021 (P2-03): StepGen #4, pin Direction (Output)
hm2/hm2_5i25.0:     IO Pin 022 (P2-16): PWMGen #1, pin Out1 (Dir or Down) (Output)
hm2/hm2_5i25.0:     IO Pin 023 (P2-04): StepGen #5, pin Step (Output)
hm2/hm2_5i25.0:     IO Pin 024 (P2-17): IOPort
hm2/hm2_5i25.0:     IO Pin 025 (P2-05): StepGen #5, pin Direction (Output)
hm2/hm2_5i25.0:     IO Pin 026 (P2-06): StepGen #6, pin Step (Output)
hm2/hm2_5i25.0:     IO Pin 027 (P2-07): StepGen #6, pin Direction (Output)
hm2/hm2_5i25.0:     IO Pin 028 (P2-08): StepGen #7, pin Step (Output)
hm2/hm2_5i25.0:     IO Pin 029 (P2-09): StepGen #7, pin Direction (Output)
hm2/hm2_5i25.0:     IO Pin 030 (P2-10): IOPort
hm2/hm2_5i25.0:     IO Pin 031 (P2-11): Encoder #1, pin A (Input)
hm2/hm2_5i25.0:     IO Pin 032 (P2-12): Encoder #1, pin B (Input)
hm2/hm2_5i25.0:     IO Pin 033 (P2-13): Encoder #1, pin Index (Input)
hm2/hm2_5i25.0: registered
hm2_5i25.0: initialized AnyIO board at 0000:04:02.0

P3 is the DB-25 on the back panel and P2 is the internal IDC header.

123 Block Links: Sherline Tooling Plate

Because the 123 block hole spacing doesn’t match the Sherline tooling plate’s 1.16 inch screw hole grid, each block has only a single 10-32 SHCS holding it down through a cap screw head pin:

123 Block Links - Sherline table alignment
123 Block Links – Sherline table alignment

The spring clamp squashes a pair of reasonably straight steel bars against the blocks, whereupon gentle tightening can produce perfect Good Enough™ alignment.

You could remove the tooling plate and attach the blocks directly to the Sherline’s table with two (or more!) T-nuts and screws per block. I expect no standard SHCS length would be quite right for the distance between the head held in the block pin and the T-nut in the table slot, not to mention removing and reinstalling the tooling plate is enough of a nuisance I’d rather not do it without good reason.

Just to see how things looked, I attached the cursor milling fixture with threaded block pins:

123 Block Links - Sherline layout
123 Block Links – Sherline layout

Note that the remaining 10-32 clearance hole in the fixture (for the cursor hub) doesn’t align with the underlying hole in the block; the next fixture must take into account both the Sherline and the 123 block grids, as well as which block holes align with the tooling plate. Bleh!

123 Block Links: Threaded Pins

The pins capturing the SHCS heads will mount the 123 blocks to the Sherline’s table or tooling plate, but attaching things to the blocks or joining them requires threaded pins on the other end of the screws:

123 Block Links - trial assembly
123 Block Links – trial assembly

Optical illusion: those two pins are the same length.

I grabbed a length of 3/8 inch aluminum rod in the Sherline vise, center-drilled four holes spaced 7/8 inch apart, then drilled them with a #20 drill for E-Z tapping.

Space the holes with manual CNC command entry:

GO X[0*0.875*25.4]
GO X[1*0.875*25.4]
GO X[2*0.875*25.4]
GO X[3*0.875*25.4]

That’s LinuxCNC on a Sherline with hard-inch leadscrews and G21 active. I normally use millimeters, but inch dimensions make more sense for these pins.

Transfer the rod to the lathe for hand tapping:

123 Block Links - tapping
123 Block Links – tapping

Not shown here: stick a transfer punch in one of the holes and eyeballometrically align tap with punch to get straight threads.

Then, for each pin:

  • Chuck rod so the whole pin sticks out
  • Turn OD to 8.4 mm
  • Face to 3/8 inch rightward from hole center
  • Chamfer edge with file
  • Part off a little more than 3/8 inch leftward from hole center
  • Find pin in chip tray
  • Rechuck the other way around
  • Face to 3/8 inch rightward from hole center
  • Chamfer edge with file
  • Ease thread entries with a round file
  • Done!

Again, I can’t believe I’m the first person to think of these pins; aim me at the commercial offerings I can’t find anywhere.

Update: The keywords “cross dowel nut” and “furniture bolt” will turn up useful products intended for woodworkers. Thanks to blaz for the suggestion.

Tek Circuit Computer: Cursor Hairline

Given a machined cursor blank, clamp it into position:

Tek CC Cursor - cursor hairline fixture
Tek CC Cursor – cursor hairline fixture

You don’t want to clamp the cursor directly to the Sherline tooling plate, because the diamond drag bit would pass over two or three of those 10-32 screw holes which would, by the conservation of perversity, leave visible defects. In hindsight, I should have put a recess for an aluminum plate in there.

After a single pass at Z=-4.0 mm, add two strips of tape to protect the adjoining surface and scribble it with red lacquer crayon:

Tek CC Cursor - tape color fill
Tek CC Cursor – tape color fill

Peel the tape off:

Tek CC Cursor - tape removed
Tek CC Cursor – tape removed

Then wipe off the residue using a soft cloth wetted with denatured alcohol:

Tek CC Cursor - red cursor detail
Tek CC Cursor – red cursor detail

That looks much like the previous efforts. I’d like a more uniform trench, but I don’t know how to get there from here.

In any event, the hairline looks pretty good against laser-printed scales:

Tek CC Cursor - red cursor white laser decks - magnified
Tek CC Cursor – red cursor white laser decks – magnified

The new cursor is the lower one lying atop a laser-printed Pickett-style Circuit Computer:

Tek CC Cursor - red cursor yellow laser decks - overview
Tek CC Cursor – red cursor yellow laser decks – overview

Looks good enough to eat, as the saying goes …

Tek Circuit Computer: Cursor Milling Toolpath

Unlike the adhesive fixture, this setup requires a pause while milling the cursor outline to reclamp it from the front:

Tek CC Cursor Fixture - outline rear clamp
Tek CC Cursor Fixture – outline rear clamp

The trick is applying the front clamp before releasing the rear clamp:

Tek CC Cursor Fixture - outline both clamp
Tek CC Cursor Fixture – outline both clamp

Then continue the mission:

Tek CC Cursor Fixture - outline front clamp
Tek CC Cursor Fixture – outline front clamp

Because the tool path includes cutter compensation, GCMC adds entry and exit arcs to ensure a smooth transition:

Tek CC Cursor - Milling path
Tek CC Cursor – Milling path

The pix show a single cursor in the fixture while verifying the setup worked the way it should. Obviously, milling a stack of cursors eliminates a whole bunch of fiddling.

The tweaked MillCursor function from the mostly otherwise unchanged GCMC code:

    comment("Clamp on rear half of cursor!");

    local cp = {p0};                                             // enter at hub tangent point
    cp += varc_ccw([0mm,-2*p0.y,-],-hr,0,0.2mm,5deg) + p0;       // arc to tangent at hub bottom

    cp += {[p1.x,-p1.y,-]};                                      // lower tip entry point
    cp += varc_ccw([p2.x-p1.x,-(p2.y-p1.y),-],CursorTipRadius,0,0.2mm,5deg) + [p1.x,-p1.y,-];  // arc to tip exit at p2

    cp += varc_ccw([p1.x-p2.x,p1.y-p2.y,-],CursorTipRadius,0,0.2mm,5deg) + p2;  // arc to tip exit at p1

    goto([-,-,CursorSafeZ]);
    goto([0,0,-]);
    feedrate(MillSpeed);
    tracepath_comp(cp,CutterOD/2,TPC_OLDZ + TPC_RIGHT + TPC_ARCIN + TPC_ARCOUT);

    comment("Clamp on front half of cursor!");
    pause();                                      // wait for reclamping

    p1.z = MillZ;                                //  ... set milling depth
    cp = {p1};
    cp += {p0};
                                                 // exit at hub tangent
    tracepath_comp(cp,CutterOD/2,TPC_OLDZ + TPC_RIGHT + TPC_ARCIN + TPC_ARCOUT);

<<< snippage >>>

  goto([-,-,CursorSafeZ]);
  goto([0,0,-]);

Next, scribing a nice hairline with the new fixture.

Makergear M2: Initial PrusaSlicer Configuration

After replacing the nozzle and the filament drive body on the M2, I figured I might as well throw all the balls in the air and switch to PrusaSlicer for all my slicing needs. It’s built from the Slic3r project, gaining features used by Prusa’s printers / filaments and a considerably improved UI, with a full-time paid staff working on it:

PrusaSlicer screenshot
PrusaSlicer screenshot

Of course, I immediately turned on Expert mode.

CAUTION: My heavily customized start_gcode will crash your M2, because you haven’t relocated the Z-axis switch, haven’t calibrated Z=0 at the platform surface, and don’t put the XY=0 origin in the center of the platform.

You have been warned: consider this as a serving suggestion, not a finished product.

Because everything I design looks more-or-less like a bracket, I absolutely don’t care about surface finish, and I’m content to use only a few colors of PETG from a single supplier, a single Slic3r configuration has sufficed for nearly everything I print. A few manual tweaks for specific models, perhaps to change the number of perimeters or the infill percentage, handle the remaining cases.

With all that in mind, here’s the current result of File → Export → Export Config as a GitHub Gist:

# generated by PrusaSlicer 2.2.0+linux-x64 on 2021-01-01 at 13:33:03 UTC
avoid_crossing_perimeters = 0
bed_custom_model =
bed_custom_texture =
bed_shape = -100x-125,100x-125,100x125,-100x125
bed_temperature = 90
before_layer_gcode =
between_objects_gcode =
bottom_fill_pattern = hilbertcurve
bottom_solid_layers = 3
bottom_solid_min_thickness = 0
bridge_acceleration = 0
bridge_angle = 0
bridge_fan_speed = 100
bridge_flow_ratio = 1
bridge_speed = 50
brim_width = 0
clip_multipart_objects = 1
colorprint_heights =
complete_objects = 0
cooling = 1
cooling_tube_length = 5
cooling_tube_retraction = 91.5
default_acceleration = 0
default_filament_profile = ""
default_print_profile =
deretract_speed = 0
disable_fan_first_layers = 6
dont_support_bridges = 1
draft_shield = 0
duplicate_distance = 6
elefant_foot_compensation = 0
end_filament_gcode = "; Filament-specific end gcode \n;END gcode for filament\n"
end_gcode = ;-- PrusaSlicer End G-Code for M2 starts --\n; Ed Nisley KE4NZU - 15 November 2013\nG1 Z160 F2000 ; lower bed\nG1 X135 Y100 F30000 ; nozzle to right, bed front\nM104 S0 ; drop extruder temperature\nM140 S0 ; drop bed temperature\nM106 S0 ; bed fan off\nM84 ; disable motors\n;-- PrusaSlicer End G-Code ends --\n\n
ensure_vertical_shell_thickness = 1
external_perimeter_extrusion_width = 0
external_perimeter_speed = 50%
external_perimeters_first = 0
extra_loading_move = -2
extra_perimeters = 1
extruder_clearance_height = 20
extruder_clearance_radius = 20
extruder_colour = ""
extruder_offset = 0x0
extrusion_axis = E
extrusion_multiplier = 0.95
extrusion_width = 0.4
fan_always_on = 0
fan_below_layer_time = 15
filament_colour = #29B2B2
filament_cooling_final_speed = 3.4
filament_cooling_initial_speed = 2.2
filament_cooling_moves = 4
filament_cost = 25
filament_density = 0.95
filament_deretract_speed = nil
filament_diameter = 1.72
filament_load_time = 0
filament_loading_speed = 28
filament_loading_speed_start = 3
filament_max_volumetric_speed = 0
filament_minimal_purge_on_wipe_tower = 15
filament_notes = ""
filament_ramming_parameters = "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6"
filament_retract_before_travel = nil
filament_retract_before_wipe = nil
filament_retract_layer_change = nil
filament_retract_length = nil
filament_retract_lift = nil
filament_retract_lift_above = nil
filament_retract_lift_below = nil
filament_retract_restart_extra = nil
filament_retract_speed = nil
filament_settings_id = "M2 Esun PETG"
filament_soluble = 0
filament_toolchange_delay = 0
filament_type = PET
filament_unload_time = 0
filament_unloading_speed = 90
filament_unloading_speed_start = 100
filament_vendor = (Unknown)
filament_wipe = nil
fill_angle = 45
fill_density = 25%
fill_pattern = 3dhoneycomb
first_layer_acceleration = 0
first_layer_bed_temperature = 90
first_layer_extrusion_width = 0
first_layer_height = 0.25
first_layer_speed = 15
first_layer_temperature = 250
gap_fill_speed = 25
gcode_comments = 0
gcode_flavor = marlin
gcode_label_objects = 0
high_current_on_filament_swap = 0
host_type = octoprint
infill_acceleration = 0
infill_every_layers = 1
infill_extruder = 1
infill_extrusion_width = 0
infill_first = 1
infill_only_where_needed = 0
infill_overlap = 15%
infill_speed = 60
interface_shells = 0
layer_gcode =
layer_height = 0.25
machine_max_acceleration_e = 10000,5000
machine_max_acceleration_extruding = 10000,1250
machine_max_acceleration_retracting = 10000,1250
machine_max_acceleration_x = 2500,1000
machine_max_acceleration_y = 2500,1000
machine_max_acceleration_z = 2500,200
machine_max_feedrate_e = 10000,5000
machine_max_feedrate_x = 450,200
machine_max_feedrate_y = 450,200
machine_max_feedrate_z = 100,30
machine_max_jerk_e = 100,50
machine_max_jerk_x = 25,10
machine_max_jerk_y = 25,10
machine_max_jerk_z = 10,5
machine_min_extruding_rate = 0,0
machine_min_travel_rate = 0,0
max_fan_speed = 100
max_layer_height = 0
max_print_height = 200
max_print_speed = 80
max_volumetric_speed = 0
min_fan_speed = 100
min_layer_height = 0.1
min_print_speed = 10
min_skirt_length = 25
notes =
nozzle_diameter = 0.35
only_retract_when_crossing_perimeters = 1
ooze_prevention = 0
output_filename_format = [input_filename_base].gcode
overhangs = 1
parking_pos_retraction = 92
perimeter_acceleration = 0
perimeter_extruder = 1
perimeter_extrusion_width = 0
perimeter_speed = 50
perimeters = 3
post_process =
print_host =
print_settings_id = M2 Default
printer_model =
printer_notes =
printer_settings_id = M2 Default
printer_technology = FFF
printer_variant =
printer_vendor =
printhost_apikey =
printhost_cafile =
raft_layers = 0
remaining_times = 0
resolution = 0.01
retract_before_travel = 3
retract_before_wipe = 0%
retract_layer_change = 0
retract_length = 1
retract_length_toolchange = 10
retract_lift = 0
retract_lift_above = 0
retract_lift_below = 0
retract_restart_extra = 0
retract_restart_extra_toolchange = 0
retract_speed = 60
seam_position = nearest
serial_port =
serial_speed = 250000
silent_mode = 1
single_extruder_multi_material = 0
single_extruder_multi_material_priming = 1
skirt_distance = 3
skirt_height = 1
skirts = 3
slice_closing_radius = 0.049
slowdown_below_layer_time = 5
small_perimeter_speed = 25%
solid_infill_below_area = 70
solid_infill_every_layers = 0
solid_infill_extruder = 1
solid_infill_extrusion_width = 0
solid_infill_speed = 75%
spiral_vase = 0
standby_temperature_delta = -5
start_filament_gcode = "; Filament gcode\n"
start_gcode = ;-- PrusaSlicer Start G-Code for M2 starts --\n; Ed Nisley KE4NZU\n; Makergear V4 hot end\n; Origin at platform center, set by MANUAL_X_HOME_POS compiled constants\n; Z-min switch at platform, must move nozzle to X=135 to clear\nG90 ; absolute coordinates\nG21 ; millimeters\nM83 ; relative extrusion distance\nM104 S[first_layer_temperature] ; start extruder heating\nM140 S[first_layer_bed_temperature] ; start bed heating\nM17 ; enable steppers\nG4 P500 ; ... wait for power up\nG92 Z0 ; set Z to zero, wherever it might be now\nG0 Z10 F1000 ; move platform downward to clear nozzle; may crash at bottom\nG28 Y ; home Y to clear plate, offset from compiled constant\nG28 X ; home X, offset from M206 X, offset from compiled constant\nG0 X135 Y0 F15000 ; move off platform to right side, center Y\nG28 Z ; home Z to platform switch, offset from M206 Z measured\nG0 Z2.0 F1000 ; get air under switch\nG0 Y-126 F10000 ; set up for priming, zig around corner\nG0 X0 ; center X\nG0 Y-124.5 ; just over platform edge\nG0 Z0 F500 ; exactly at platform\nM190 S[first_layer_bed_temperature] ; wait for bed to finish heating\nM109 S[first_layer_temperature] ; set extruder temperature and wait\nG1 E20 F300 ; prime to get pressure, generate blob on edge\nG0 Y-123 F5000 ; shear off blob\nG0 X15 F15000 ; jerk away from blob, move over surface\nG4 P500 ; pause to attach\nG1 X45 F500 ; slowly smear snot to clear nozzle\nG1 Z1.0 F2000 ; clear bed for travel\n;-- PrusaSlicer Start G-Code ends --\n
support_material = 0
support_material_angle = 0
support_material_auto = 1
support_material_buildplate_only = 0
support_material_contact_distance = 0.2
support_material_enforce_layers = 0
support_material_extruder = 1
support_material_extrusion_width = 0.31
support_material_interface_contact_loops = 0
support_material_interface_extruder = 1
support_material_interface_layers = 3
support_material_interface_spacing = 0
support_material_interface_speed = 100%
support_material_pattern = rectilinear
support_material_spacing = 2.5
support_material_speed = 60
support_material_synchronize_layers = 0
support_material_threshold = 0
support_material_with_sheath = 1
support_material_xy_spacing = 50%
temperature = 250
thin_walls = 1
threads = 4
thumbnails =
toolchange_gcode =
top_fill_pattern = hilbertcurve
top_infill_extrusion_width = 0
top_solid_infill_speed = 50%
top_solid_layers = 3
top_solid_min_thickness = 0
travel_speed = 300
use_firmware_retraction = 0
use_relative_e_distances = 0
use_volumetric_e = 0
variable_layer_height = 1
wipe = 0
wipe_into_infill = 0
wipe_into_objects = 0
wipe_tower = 0
wipe_tower_bridging = 10
wipe_tower_no_sparse_layers = 0
wipe_tower_rotation_angle = 0
wipe_tower_width = 60
wipe_tower_x = 180
wipe_tower_y = 140
wiping_volumes_extruders = 70,70
wiping_volumes_matrix = 0
xy_size_compensation = 0
z_offset = 0

Shuttles Game: Tapered Pegs

As is all too common with 3D printed replacement parts done remotely, the first Shuttles game pegs didn’t quite fit into the game board’s holes. Fortunately, living in the future means rapid prototyping and quick turnaround:

Shuttles Game pegs - tapered - solid model
Shuttles Game pegs – tapered – solid model

They’re slightly smaller, tapered toward the bottom, and take slightly less time to print.

The OpenSCAD code in the GitHub Gist now has has the tweaks.