spindle pwm
This commit is contained in:
		| @@ -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 | ||||
|   | ||||
| @@ -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." | ||||
|   | ||||
| @@ -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 | ||||
|    | ||||
|   } | ||||
|   | ||||
| @@ -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 | ||||
|    | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user