spindle pwm

This commit is contained in:
Todd Fleming 2017-01-12 19:28:38 -05:00
parent 6f13d0d18b
commit 4e9d5f78b4
6 changed files with 91 additions and 80 deletions

View File

@ -209,7 +209,7 @@
// NOTE: If VARIABLE_SPINDLE is enabled(default), this option has no effect as the PWM output and
// spindle enable are combined to one pin. If you need both this option and spindle speed PWM,
// uncomment the config option USE_SPINDLE_DIR_AS_ENABLE_PIN below.
// #define INVERT_SPINDLE_ENABLE_PIN // Default disabled. Uncomment to enable.
// not ported #define INVERT_SPINDLE_ENABLE_PIN // Default disabled. Uncomment to enable.
// Inverts the selected coolant pin from low-disabled/high-enabled to low-enabled/high-disabled. Useful
// for some pre-built electronic boards.
@ -333,12 +333,37 @@
// tool length offset value is subtracted from the current location.
#define TOOL_LENGTH_OFFSET_AXIS Z_AXIS // Default z-axis. Valid values are X_AXIS, Y_AXIS, or Z_AXIS.
// Enables variable spindle output voltage for different RPM values. On the Arduino Uno, the spindle
// enable pin will output 5V for maximum RPM with 256 intermediate levels and 0V when disabled.
// NOTE: IMPORTANT for Arduino Unos! When enabled, the Z-limit pin D11 and spindle enable pin D12 switch!
// The hardware PWM output on pin D11 is required for variable spindle output voltages.
// Enables variable spindle output voltage for different RPM values.
#define VARIABLE_SPINDLE // Default enabled. Comment to disable.
// RPM Scaling on LPC17xx
//
// 0 SPINDLE_PWM_OFF_VALUE SPINDLE_PERIOD
// | | |
// |---|---|--------------------------|----|
// | |
// SPINDLE_PWM_MIN_VALUE SPINDLE_PWM_MAX_VALUE
//
// settings.rpm_min settings.rpm_max
// |--------------------------|
// ^
// gcode S value
//
// if(S <= 0)
// pwm = SPINDLE_PWM_OFF_VALUE;
// else if(S <= settings.rpm_min)
// pwm = SPINDLE_PWM_MIN_VALUE;
// else if(S >= settings.rpm_max)
// pwm = SPINDLE_PWM_MAX_VALUE;
// else
// pwm = scaled value. settings.rpm_min scales to SPINDLE_PWM_MIN_VALUE. settings.rpm_max
// scales to SPINDLE_PWM_MAX_VALUE.
#define SPINDLE_PWM_PERIOD (SystemCoreClock / 40000) // SystemCoreClock / frequency
#define SPINDLE_PWM_OFF_VALUE (SPINDLE_PWM_PERIOD * 0.0) // SPINDLE_PWM_PERIOD * fraction
#define SPINDLE_PWM_MIN_VALUE (SPINDLE_PWM_PERIOD * 0.0) // SPINDLE_PWM_PERIOD * fraction
#define SPINDLE_PWM_MAX_VALUE (SPINDLE_PWM_PERIOD * 1.0) // SPINDLE_PWM_PERIOD * fraction
// Used by variable spindle output only. This forces the PWM output to a minimum duty cycle when enabled.
// The PWM pin will still read 0V when the spindle is disabled. Most users will not need this option, but
// it may be useful in certain scenarios. This minimum PWM settings coincides with the spindle rpm minimum
@ -348,7 +373,7 @@
// in mind that you will begin to lose PWM resolution with increased minimum PWM values, since you have less
// and less range over the total 255 PWM levels to signal different spindle speeds.
// NOTE: Compute duty cycle at the minimum PWM by this equation: (% duty cycle)=(SPINDLE_PWM_MIN_VALUE/255)*100
// #define SPINDLE_PWM_MIN_VALUE 5 // Default disabled. Uncomment to enable. Must be greater than zero. Integer (1-255).
// define now lives above. #define SPINDLE_PWM_MIN_VALUE 5 // Default disabled. Uncomment to enable. Must be greater than zero. Integer (1-255).
// 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
@ -358,7 +383,7 @@
// 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.
// not ported #define USE_SPINDLE_DIR_AS_ENABLE_PIN // Default disabled. Uncomment to enable.
// With this enabled, Grbl sends back an echo of the line it has received, which has been pre-parsed (spaces
// removed, capitalized letters, no comments) and is to be immediately executed by Grbl. Echoes will not be
@ -626,6 +651,7 @@
// hard limits not ported #define LIMIT_PCMSK PCMSK0 // Pin change interrupt register
// Define spindle enable and spindle direction output pins.
/* not ported
#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.
@ -644,6 +670,7 @@
#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
@ -675,31 +702,16 @@
#define PROBE_BIT 5 // Uno Analog Pin 5
#define PROBE_MASK (1<<PROBE_BIT)
// Variable spindle configuration below. Do not change unless you know what you are doing.
// NOTE: Only used when variable spindle is enabled.
#define SPINDLE_PWM_MAX_VALUE 255 // Don't change. 328p fast PWM mode fixes top value as 255.
#ifndef SPINDLE_PWM_MIN_VALUE
#define SPINDLE_PWM_MIN_VALUE 1 // Must be greater than zero.
#endif
#define SPINDLE_PWM_OFF_VALUE 0
#define SPINDLE_PWM_RANGE (SPINDLE_PWM_MAX_VALUE-SPINDLE_PWM_MIN_VALUE)
#define SPINDLE_TCCRA_REGISTER TCCR2A
#define SPINDLE_TCCRB_REGISTER TCCR2B
#define SPINDLE_OCR_REGISTER OCR2A
#define SPINDLE_COMB_BIT COM2A1
// Prescaled, 8-bit Fast PWM mode.
#define SPINDLE_TCCRA_INIT_MASK ((1<<WGM20) | (1<<WGM21)) // Configures fast PWM mode.
// #define SPINDLE_TCCRB_INIT_MASK (1<<CS20) // Disable prescaler -> 62.5kHz
// #define SPINDLE_TCCRB_INIT_MASK (1<<CS21) // 1/8 prescaler -> 7.8kHz (Used in v0.9)
// #define SPINDLE_TCCRB_INIT_MASK ((1<<CS21) | (1<<CS20)) // 1/32 prescaler -> 1.96kHz
#define SPINDLE_TCCRB_INIT_MASK (1<<CS22) // 1/64 prescaler -> 0.98kHz (J-tech laser)
// NOTE: On the 328p, these must be the same as the SPINDLE_ENABLE settings.
#define SPINDLE_PWM_DDR DDRB
#define SPINDLE_PWM_PORT PORTB
#define SPINDLE_PWM_BIT 3 // Uno Digital Pin 11
// The LPC17xx has 6 PWM channels. Each channel has 2 pins. It can drive both pins simultaneously to the same value.
//
// PWM Channel PWM1_CH1 PWM1_CH2 PWM1_CH3 PWM1_CH4 PWM1_CH5 PWM1_CH6
// Primary pin P1.18 P1.20 P1.21 P1.23 P1.24 P1.26
// Secondary pin P2.0 P2.1 P2.2 P2.3 P2.4 P2.6
#define SPINDLE_PWM_CHANNEL PWM1_CH5
#define SPINDLE_PWM_USE_PRIMARY_PIN false
#define SPINDLE_PWM_USE_SECONDARY_PIN true
// Stepper current control
#define CURRENT_I2C Driver_I2C1 // I2C driver for current control. Comment out to disable.
#define CURRENT_MCP44XX_ADDR 0b0101100 // Address of MCP44XX
#define CURRENT_WIPERS {0, 1, 6, 7}; // Wiper registers (X, Y, Z, A)
@ -722,7 +734,7 @@
#define DEFAULT_X_MAX_TRAVEL 200.0 // mm
#define DEFAULT_Y_MAX_TRAVEL 200.0 // mm
#define DEFAULT_Z_MAX_TRAVEL 200.0 // mm
#define DEFAULT_SPINDLE_RPM_MAX 1000.0 // rpm
#define DEFAULT_SPINDLE_RPM_MAX 1.0 // rpm
#define DEFAULT_SPINDLE_RPM_MIN 0.0 // rpm
#define DEFAULT_STEP_PULSE_MICROSECONDS 1
#define DEFAULT_STEPPING_INVERT_MASK 0

View File

@ -84,11 +84,13 @@
#endif
#endif
/* restriction removed
#if defined(SPINDLE_PWM_MIN_VALUE)
#if !(SPINDLE_PWM_MIN_VALUE > 0)
#error "SPINDLE_PWM_MIN_VALUE must be greater than zero."
#endif
#endif
*/
#if (REPORT_WCO_REFRESH_BUSY_COUNT < REPORT_WCO_REFRESH_IDLE_COUNT)
#error "WCO busy refresh is less than idle refresh."

View File

@ -20,6 +20,7 @@
*/
#include "grbl.h"
#include "pwm_driver.h"
#ifdef VARIABLE_SPINDLE
@ -30,26 +31,27 @@
void spindle_init()
{
#ifdef VARIABLE_SPINDLE
pwm_init(&SPINDLE_PWM_CHANNEL, SPINDLE_PWM_USE_PRIMARY_PIN, SPINDLE_PWM_USE_SECONDARY_PIN, SPINDLE_PWM_PERIOD, 0);
pwm_enable(&SPINDLE_PWM_CHANNEL);
/* not ported
// 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);
pwm_gradient = (SPINDLE_PWM_MAX_VALUE-SPINDLE_PWM_MIN_VALUE)/(settings.rpm_max-settings.rpm_min);
#else
/* not ported
// 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();
@ -58,6 +60,7 @@ void spindle_init()
uint8_t spindle_get_state()
{
/* not ported
#ifdef VARIABLE_SPINDLE
#ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
// No spindle direction output pin.
@ -82,6 +85,7 @@ uint8_t spindle_get_state()
else { return(SPINDLE_STATE_CW); }
}
#endif
*/
return(SPINDLE_STATE_DISABLE);
}
@ -92,7 +96,8 @@ uint8_t spindle_get_state()
void spindle_stop()
{
#ifdef VARIABLE_SPINDLE
SPINDLE_TCCRA_REGISTER &= ~(1<<SPINDLE_COMB_BIT); // Disable PWM. Output voltage is zero.
pwm_set_width(&SPINDLE_PWM_CHANNEL, 0);
/* not ported
#ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
#ifdef INVERT_SPINDLE_ENABLE_PIN
SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT); // Set pin to high
@ -100,12 +105,15 @@ void spindle_stop()
SPINDLE_ENABLE_PORT &= ~(1<<SPINDLE_ENABLE_BIT); // Set pin to low
#endif
#endif
*/
#else
/* not ported
#ifdef INVERT_SPINDLE_ENABLE_PIN
SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT); // Set pin to high
#else
SPINDLE_ENABLE_PORT &= ~(1<<SPINDLE_ENABLE_BIT); // Set pin to low
#endif
*/
#endif
}
@ -113,48 +121,34 @@ void spindle_stop()
#ifdef VARIABLE_SPINDLE
// Sets spindle speed PWM output and enable pin, if configured. Called by spindle_set_state()
// and stepper ISR. Keep routine small and efficient.
void spindle_set_speed(uint8_t pwm_value)
void spindle_set_speed(uint32_t pwm_value)
{
if (pwm_value == SPINDLE_PWM_OFF_VALUE) {
spindle_stop();
} else {
SPINDLE_OCR_REGISTER = pwm_value; // Set PWM output level.
SPINDLE_TCCRA_REGISTER |= (1<<SPINDLE_COMB_BIT); // Ensure PWM output is enabled.
#if defined(USE_SPINDLE_DIR_AS_ENABLE_PIN)
#ifdef INVERT_SPINDLE_ENABLE_PIN
SPINDLE_ENABLE_PORT &= ~(1<<SPINDLE_ENABLE_BIT);
#else
SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT);
#endif
#endif
}
pwm_set_width(&SPINDLE_PWM_CHANNEL, pwm_value);
}
// Called by spindle_set_state() and step segment generator. Keep routine small and efficient.
uint8_t spindle_compute_pwm_value(float rpm) // 328p PWM register is 8-bit.
uint32_t spindle_compute_pwm_value(float rpm)
{
uint8_t pwm_value;
uint32_t pwm_value;
rpm *= (0.010*sys.spindle_speed_ovr); // Scale by spindle speed override value.
// Calculate PWM register value based on rpm max/min settings and programmed rpm.
if ((settings.rpm_min >= settings.rpm_max) || (rpm >= settings.rpm_max)) {
// No PWM range possible. Set simple on/off spindle control pin state.
if (rpm <= 0) {
sys.spindle_speed = 0;
pwm_value = SPINDLE_PWM_OFF_VALUE;
}
else if (rpm <= settings.rpm_min) {
sys.spindle_speed = settings.rpm_min;
pwm_value = SPINDLE_PWM_MIN_VALUE;
}
else if (rpm >= settings.rpm_max) {
sys.spindle_speed = settings.rpm_max;
pwm_value = SPINDLE_PWM_MAX_VALUE;
} else if (rpm <= settings.rpm_min) {
if (rpm == 0.0) { // S0 disables spindle
sys.spindle_speed = 0.0;
pwm_value = SPINDLE_PWM_OFF_VALUE;
} else { // Set minimum PWM output
sys.spindle_speed = settings.rpm_min;
pwm_value = SPINDLE_PWM_MIN_VALUE;
}
} else {
// Compute intermediate PWM value with linear spindle speed model.
// NOTE: A nonlinear model could be installed here, if required, but keep it VERY light-weight.
pwm_value = SPINDLE_PWM_MAX_VALUE - 1;
}
else {
sys.spindle_speed = rpm;
pwm_value = floor((rpm-settings.rpm_min)*pwm_gradient) + SPINDLE_PWM_MIN_VALUE;
pwm_value = floor((rpm - settings.rpm_min) * pwm_gradient) + SPINDLE_PWM_MIN_VALUE;
if(pwm_value >= SPINDLE_PWM_MAX_VALUE)
pwm_value = SPINDLE_PWM_MAX_VALUE - 1;
}
return(pwm_value);
}
@ -181,11 +175,13 @@ void spindle_stop()
} else {
#ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN
/* not ported
if (state == SPINDLE_ENABLE_CW) {
SPINDLE_DIRECTION_PORT &= ~(1<<SPINDLE_DIRECTION_BIT);
} else {
SPINDLE_DIRECTION_PORT |= (1<<SPINDLE_DIRECTION_BIT);
}
*/
#endif
#ifdef VARIABLE_SPINDLE
@ -197,11 +193,13 @@ void spindle_stop()
#else
// NOTE: Without variable spindle, the enable bit should just turn on or off, regardless
// if the spindle speed value is zero, as its ignored anyhow.
/* not ported
#ifdef INVERT_SPINDLE_ENABLE_PIN
SPINDLE_ENABLE_PORT &= ~(1<<SPINDLE_ENABLE_BIT);
#else
SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT);
#endif
#endif
*/
#endif
}

View File

@ -48,11 +48,10 @@ uint8_t spindle_get_state();
void spindle_set_state(uint8_t state, float rpm);
// Sets spindle PWM quickly for stepper ISR. Also called by spindle_set_state().
// NOTE: 328p PWM register is 8-bit.
void spindle_set_speed(uint8_t pwm_value);
void spindle_set_speed(uint32_t pwm_value);
// Computes 328p-specific PWM register value for the given RPM for quick updating.
uint8_t spindle_compute_pwm_value(float rpm);
// Computes PWM register value for the given RPM for quick updating.
uint32_t spindle_compute_pwm_value(float rpm);
#else

View File

@ -81,7 +81,7 @@ typedef struct {
uint8_t prescaler; // Without AMASS, a prescaler is required to adjust for slow timing.
#endif
#ifdef VARIABLE_SPINDLE
uint8_t spindle_pwm;
uint32_t spindle_pwm;
#endif
} segment_t;
static segment_t segment_buffer[SEGMENT_BUFFER_SIZE];
@ -158,7 +158,7 @@ typedef struct {
#ifdef VARIABLE_SPINDLE
float inv_rate; // Used by PWM laser mode to speed up segment calculations.
uint8_t current_spindle_pwm;
uint32_t current_spindle_pwm;
#endif
} st_prep_t;
static st_prep_t prep;

View File

@ -289,7 +289,7 @@
#define PLL1CFG_Val 0x00000023
#define CCLKCFG_Val 0x00000003
#define USBCLKCFG_Val 0x00000000
#define PCLKSEL0_Val 0x00000014
#define PCLKSEL0_Val 0x00001014
#define PCLKSEL1_Val 0x00005000
#define PCONP_Val 0x04E887DE
#define CLKOUTCFG_Val 0x00000000