XController Spindle Direction Pin Reassignment

I have an XController driving an XCarve 750.

The 0-5V spindle speed pin is routed to an IOT relay for controlling the spindle, and the PWM pin is routed to a JTech Photonics laser controller. This works fine.

However, I wanted direct router speed control, so I bought a VHipe SuperPID AC motor controller.

The SuperPID will take either a PWM or 0-5V speed control signal, so no worries there. However, it also wants a +5V SPINDLE ENABLE signal.

The ugly hack to get that working would be to connect the MIST COOLANT output to the SuperPID SPINDLE ENABLE, and then add the mist coolant on/off gcode to any spindle control lines via the postprocessor. That will work, but it’s a terrible, terrible idea because it’s non-obvious from the code how to actually turn the spindle on or off.

So what I want looks like a custom GRBL build that assigns the SPINDLE DIRECTION to the mist coolant pin.

Looking in the GRBL code, I see this:

// By default on a 328p(Uno), Grbl combines the variable spindle PWM and the enable into one pin to help
// preserve I/O pins. For certain setups, these may need to be separate pins. This configure option uses
// the spindle direction pin(D13) as a separate spindle enable pin along with spindle speed PWM on pin D11.
// NOTE: This configure option only works with VARIABLE_SPINDLE enabled and a 328p processor (Uno).
// NOTE: Without a direction pin, M4 will not have a pin output to indicate a difference with M3. 
// NOTE: BEWARE! The Arduino bootloader toggles the D13 pin when it powers up. If you flash Grbl with
// a programmer (you can use a spare Arduino as "Arduino as ISP". Search the web on how to wire this.),
// this D13 LED toggling should go away. We haven't tested this though. Please report how it goes!
// #define USE_SPINDLE_DIR_AS_ENABLE_PIN // Default disabled. Uncomment to enable.

OK, so if I define this, D13 will become the enable pin, with the caveat that it will flash high during bootup, potentially starting the spindle. If I ensure to always power cycle the XController with the SuperPID turned off, this won’t be a problem. I can live with that.

It isn’t clear to me though if the XController has D13 wired to anything.

So if I turn off M7 by commenting out the define:

// Enables a second coolant control pin via the mist coolant g-code command M7 on the Arduino Uno
// analog pin 4. Only use this option if you require a second coolant control pin.
// NOTE: The M8 flood coolant control pin on analog pin 3 will still be functional regardless.
 #define ENABLE_M7 // Disabled by default. Uncomment to enable.

That should free up analogue pin 4.

This bit of code in spindle_control.c

void spindle_init()
{
  #ifdef VARIABLE_SPINDLE

    // Configure variable spindle PWM and enable pin, if requried. On the Uno, PWM and enable are
    // combined unless configured otherwise.
    SPINDLE_PWM_DDR |= (1<<SPINDLE_PWM_BIT); // Configure as PWM output pin.
    SPINDLE_TCCRA_REGISTER = SPINDLE_TCCRA_INIT_MASK; // Configure PWM output compare timer
    SPINDLE_TCCRB_REGISTER = SPINDLE_TCCRB_INIT_MASK;
    #ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
      SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT); // Configure as output pin.
    #else
      SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT); // Configure as output pin.
    #endif

    pwm_gradient = SPINDLE_PWM_RANGE/(settings.rpm_max-settings.rpm_min);

  #else

    // Configure no variable spindle and only enable pin.
    SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT); // Configure as output pin.
    SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT); // Configure as output pin.

  #endif

  spindle_stop();
}

specifically, the line

SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT); // Configure as output pin.

sets the output pin

cpu_map.h has the following:

// Define spindle enable and spindle direction output pins.
  #define SPINDLE_ENABLE_DDR    DDRB
  #define SPINDLE_ENABLE_PORT   PORTB
  // Z Limit pin and spindle PWM/enable pin swapped to access hardware PWM on Pin 11.
  #ifdef VARIABLE_SPINDLE
    #ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
      // If enabled, spindle direction pin now used as spindle enable, while PWM remains on D11.
      #define SPINDLE_ENABLE_BIT    5  // Uno Digital Pin 13 (NOTE: D13 can't be pulled-high input due to LED.)
    #else
      #define SPINDLE_ENABLE_BIT    3  // Uno Digital Pin 11
    #endif
  #else
    #define SPINDLE_ENABLE_BIT    4  // Uno Digital Pin 12
  #endif
  #ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN
    #define SPINDLE_DIRECTION_DDR   DDRB
    #define SPINDLE_DIRECTION_PORT  PORTB
    #define SPINDLE_DIRECTION_BIT   5  // Uno Digital Pin 13 (NOTE: D13 can't be pulled-high input due to LED.)
  #endif

  // Define flood and mist coolant enable output pins.
  #define COOLANT_FLOOD_DDR   DDRC
  #define COOLANT_FLOOD_PORT  PORTC
  #define COOLANT_FLOOD_BIT   3  // Uno Analog Pin 3
  #define COOLANT_MIST_DDR   DDRC
  #define COOLANT_MIST_PORT  PORTC
  #define COOLANT_MIST_BIT   4  // Uno Analog Pin 4

So I feel like taking the DDR, port and bit for mist cooling and assigning it to spindle direction should work?

Like this:

#define SPINDLE_DIRECTION_DDR   DDRC // using mist coolant DDR for SuperPID
    #define SPINDLE_DIRECTION_PORT  PORTC // using mist coolant port for SuperPID
    #define SPINDLE_DIRECTION_BIT   4  // Uno Analog port 4 - was D13

The two big unknowns are:

  1. Does the XController use D13 for anything?
  2. Does the code that sets a digital output high also work for an analog output?

Is there anyone around who understands how the XController is physically wired? Or docs published somewhere?

Digging deeper… I don’t see any code that assigns a variable voltage to the supposed 0-5V analog output on the XController - and the port itself is labelled 0-10V.

Is that just an enable switch with no actual variable voltage?