Sergey Pastor / grbl1
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers spindle_control.c Source File

spindle_control.c

00001 /*
00002   spindle_control.c - spindle control methods
00003   Part of Grbl
00004 
00005   Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
00006   Copyright (c) 2009-2011 Simen Svale Skogsrud
00007 
00008   Grbl is free software: you can redistribute it and/or modify
00009   it under the terms of the GNU General Public License as published by
00010   the Free Software Foundation, either version 3 of the License, or
00011   (at your option) any later version.
00012 
00013   Grbl is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016   GNU General Public License for more details.
00017 
00018   You should have received a copy of the GNU General Public License
00019   along with Grbl.  If not, see <http://www.gnu.org/licenses/>.
00020 */
00021 
00022 #include "grbl.h"
00023 
00024 
00025 #ifdef VARIABLE_SPINDLE
00026   static float pwm_gradient; // Precalulated value to speed up rpm to PWM conversions.
00027 #endif
00028 
00029 
00030 void spindle_init()
00031 {
00032 #ifdef VARIABLE_SPINDLE
00033   pwm_gradient = SPINDLE_PWM_RANGE / (settings.rpm_max - settings.rpm_min);
00034 #endif
00035 
00036 #ifdef AVRTARGET
00037   #ifdef VARIABLE_SPINDLE
00038 
00039     // Configure variable spindle PWM and enable pin, if requried. On the Uno, PWM and enable are
00040     // combined unless configured otherwise.
00041     SPINDLE_PWM_DDR |= (1<<SPINDLE_PWM_BIT); // Configure as PWM output pin.
00042     SPINDLE_TCCRA_REGISTER = SPINDLE_TCCRA_INIT_MASK; // Configure PWM output compare timer
00043     SPINDLE_TCCRB_REGISTER = SPINDLE_TCCRB_INIT_MASK;
00044     #ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
00045       SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT); // Configure as output pin.
00046     #else
00047       SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT); // Configure as output pin.
00048     #endif
00049 
00050   #else
00051 
00052     // Configure no variable spindle and only enable pin.
00053     SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT); // Configure as output pin.
00054     SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT); // Configure as output pin.
00055 
00056   #endif
00057 #endif
00058 #if defined (STM32F103C8)
00059     GPIO_InitTypeDef GPIO_InitStructure;
00060     RCC_APB2PeriphClockCmd(RCC_SPINDLE_ENABLE_PORT, ENABLE);
00061     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
00062     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
00063 #ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
00064   GPIO_InitStructure.GPIO_Pin = 1 << SPINDLE_ENABLE_BIT;
00065 #else
00066   GPIO_InitStructure.GPIO_Pin = 1 << SPINDLE_DIRECTION_BIT;
00067 #endif
00068   GPIO_Init(SPINDLE_ENABLE_PORT, &GPIO_InitStructure);
00069 
00070 
00071 #ifdef VARIABLE_SPINDLE
00072   RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
00073   TIM_TimeBaseInitTypeDef timerInitStructure;
00074   TIM_OCInitTypeDef outputChannelInit = { 0 };
00075   TIM_TimeBaseStructInit(&timerInitStructure);
00076 
00077   timerInitStructure.TIM_Prescaler = F_CPU / 1000000 - 1; // 1000
00078   timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
00079   timerInitStructure.TIM_Period = SPINDLE_PWM_MAX_VALUE - 1;
00080   timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
00081   timerInitStructure.TIM_RepetitionCounter = 0;
00082   TIM_TimeBaseInit(TIM1, &timerInitStructure);
00083 
00084   outputChannelInit.TIM_OCMode = TIM_OCMode_PWM1;
00085   outputChannelInit.TIM_Pulse = 0;     // initi speed is 0
00086   outputChannelInit.TIM_OutputState = TIM_OutputState_Enable;
00087   outputChannelInit.TIM_OCPolarity = TIM_OCPolarity_High;
00088 
00089   TIM_OC1Init(TIM1, &outputChannelInit);
00090   TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
00091   TIM_CtrlPWMOutputs(TIM1, DISABLE);
00092   TIM_Cmd(TIM1, ENABLE);
00093 
00094   RCC_APB2PeriphClockCmd(RCC_SPINDLE_PWM_PORT, ENABLE);
00095   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
00096   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
00097   GPIO_InitStructure.GPIO_Pin = 1 << SPINDLE_PWM_BIT;
00098   GPIO_Init(SPINDLE_PWM_PORT, &GPIO_InitStructure);
00099 
00100 
00101 #endif
00102 #endif
00103 
00104   spindle_stop();
00105 }
00106 
00107 
00108 uint8_t spindle_get_state()
00109 {
00110   uint8_t pin = 0;
00111     #ifdef VARIABLE_SPINDLE
00112     #ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
00113 #ifdef AVRTARGET
00114   pin = SPINDLE_ENABLE_PORT;
00115 #endif
00116 #if defined (STM32F103C8)
00117   pin = GPIO_ReadInputData(SPINDLE_ENABLE_PORT);
00118 #endif
00119           // No spindle direction output pin. 
00120             #ifdef INVERT_SPINDLE_ENABLE_PIN
00121               if (bit_isfalse(pin,(1<<SPINDLE_ENABLE_BIT))) { return(SPINDLE_STATE_CW); }
00122         #else
00123                 if (bit_istrue(pin,(1<<SPINDLE_ENABLE_BIT))) { return(SPINDLE_STATE_CW); }
00124         #endif
00125     #else
00126 #ifdef AVRTARGET
00127   pin = SPINDLE_DIRECTION_PORT;
00128     if (SPINDLE_TCCRA_REGISTER & (1<<SPINDLE_COMB_BIT)) 
00129 #endif
00130 #if defined (STM32F103C8)
00131       pin = GPIO_ReadInputData(SPINDLE_DIRECTION_PORT);
00132 #endif
00133      {
00134         if (pin & (1<<SPINDLE_DIRECTION_BIT)) { return(SPINDLE_STATE_CCW); }
00135         else { return(SPINDLE_STATE_CW); }
00136       }
00137     #endif
00138     #else
00139 #ifdef AVRTARGET
00140   pin = SPINDLE_ENABLE_PORT;
00141 #endif
00142 #if defined (STM32F103C8)
00143   pin = GPIO_ReadInputData(SPINDLE_ENABLE_PORT);
00144 #endif
00145         #ifdef INVERT_SPINDLE_ENABLE_PIN
00146           if (bit_isfalse(pin,(1<<SPINDLE_ENABLE_BIT))) {
00147         #else
00148           if (bit_istrue(pin,(1<<SPINDLE_ENABLE_BIT))) {
00149         #endif
00150           if (pin & (1 << SPINDLE_DIRECTION_BIT)) { return(SPINDLE_STATE_CCW); }
00151           else { return(SPINDLE_STATE_CW); }
00152         }
00153     #endif
00154     return(SPINDLE_STATE_DISABLE);
00155 }
00156 
00157 
00158 // Disables the spindle and sets PWM output to zero when PWM variable spindle speed is enabled.
00159 // Called by various main program and ISR routines. Keep routine small, fast, and efficient.
00160 // Called by spindle_init(), spindle_set_speed(), spindle_set_state(), and mc_reset().
00161 void spindle_stop()
00162 {
00163 #ifdef VARIABLE_SPINDLE
00164 #ifdef AVRTARGET
00165     SPINDLE_TCCRA_REGISTER &= ~(1<<SPINDLE_COMB_BIT); // Disable PWM. Output voltage is zero.
00166 #endif
00167 #if defined (STM32F103C8)
00168     TIM_CtrlPWMOutputs(TIM1, DISABLE);
00169 #endif
00170 
00171     #ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
00172       #ifdef INVERT_SPINDLE_ENABLE_PIN
00173         SetSpindleEnablebit();
00174       #else
00175         ResetSpindleEnablebit();
00176       #endif
00177     #endif
00178 #else
00179     #ifdef INVERT_SPINDLE_ENABLE_PIN
00180       SetSpindleEnablebit();
00181     #else
00182       ResetSpindleEnablebit();
00183     #endif
00184 #endif
00185 }
00186 
00187 
00188 #ifdef VARIABLE_SPINDLE
00189   // Sets spindle speed PWM output and enable pin, if configured. Called by spindle_set_state()
00190   // and stepper ISR. Keep routine small and efficient.
00191   void spindle_set_speed(SPINDLE_PWM_TYPE pwm_value)
00192   {
00193 #ifdef AVRTARGET
00194         SPINDLE_OCR_REGISTER = pwm_value; // Set PWM output level.
00195 #endif
00196 #if defined (STM32F103C8)
00197         TIM1->CCR1 = pwm_value;
00198 #endif
00199         #ifdef SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED
00200      if (pwm_value == SPINDLE_PWM_OFF_VALUE) {
00201         spindle_stop();
00202       } else {
00203                 #ifdef AVRTARGET
00204                     SPINDLE_TCCRA_REGISTER |= (1<<SPINDLE_COMB_BIT); // Ensure PWM output is enabled.
00205                 #endif
00206                 #if defined (STM32F103C8)
00207                         TIM_CtrlPWMOutputs(TIM1, ENABLE);
00208                 #endif
00209                 #ifdef INVERT_SPINDLE_ENABLE_PIN
00210                     ResetSpindleEnablebit();
00211                 #else
00212                     SetSpindleEnablebit();
00213                 #endif
00214          }
00215         #else
00216             if (pwm_value == SPINDLE_PWM_OFF_VALUE) {
00217             #ifdef AVRTARGET
00218                 SPINDLE_TCCRA_REGISTER &= ~(1 << SPINDLE_COMB_BIT); // Disable PWM. Output voltage is zero.
00219             #endif
00220             #if defined (STM32F103C8)
00221                 TIM_CtrlPWMOutputs(TIM1, DISABLE);
00222             #endif
00223             } else {
00224             #ifdef AVRTARGET
00225       SPINDLE_TCCRA_REGISTER |= (1<<SPINDLE_COMB_BIT); // Ensure PWM output is enabled.
00226             #endif
00227             #if defined (STM32F103C8)
00228       TIM_CtrlPWMOutputs(TIM1, ENABLE);
00229             #endif
00230             }
00231         #endif
00232     }
00233 
00234 
00235   // Called by spindle_set_state() and step segment generator. Keep routine small and efficient.
00236   SPINDLE_PWM_TYPE spindle_compute_pwm_value(float rpm) // 328p PWM register is 8-bit.
00237   {
00238     SPINDLE_PWM_TYPE pwm_value;
00239     rpm *= (0.010f*sys.spindle_speed_ovr); // Scale by spindle speed override value.
00240     // Calculate PWM register value based on rpm max/min settings and programmed rpm.
00241     if ((settings.rpm_min >= settings.rpm_max) || (rpm >= settings.rpm_max)) {
00242       // No PWM range possible. Set simple on/off spindle control pin state.
00243       sys.spindle_speed = settings.rpm_max;
00244       pwm_value = SPINDLE_PWM_MAX_VALUE;
00245     } else if (rpm <= settings.rpm_min) {
00246       if (rpm == 0.0f) { // S0 disables spindle
00247         sys.spindle_speed = 0.0f;
00248         pwm_value = SPINDLE_PWM_OFF_VALUE;
00249       } else { // Set minimum PWM output
00250         sys.spindle_speed = settings.rpm_min;
00251         pwm_value = SPINDLE_PWM_MIN_VALUE;
00252       }
00253     } else { 
00254       // Compute intermediate PWM value with linear spindle speed model.
00255       // NOTE: A nonlinear model could be installed here, if required, but keep it VERY light-weight.
00256       sys.spindle_speed = rpm;
00257         pwm_value = (SPINDLE_PWM_TYPE)floorf((rpm - settings.rpm_min)*pwm_gradient) + SPINDLE_PWM_MIN_VALUE;
00258     }
00259     return(pwm_value);
00260   }
00261 #endif
00262 
00263 
00264 // Immediately sets spindle running state with direction and spindle rpm via PWM, if enabled.
00265 // Called by g-code parser spindle_sync(), parking retract and restore, g-code program end,
00266 // sleep, and spindle stop override.
00267 #ifdef VARIABLE_SPINDLE
00268   void spindle_set_state(uint8_t state, float rpm)
00269 #else
00270   void _spindle_set_state(uint8_t state)
00271 #endif
00272 {
00273   if (sys.abort) { return; } // Block during abort.
00274   if (state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm.
00275   
00276     #ifdef VARIABLE_SPINDLE
00277       sys.spindle_speed = 0.0f;
00278     #endif
00279     spindle_stop();
00280   
00281   } else {
00282     #ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN
00283       if (state == SPINDLE_ENABLE_CW) {
00284         ResetSpindleDirectionBit();
00285       }
00286       else {
00287       SetSpindleDirectionBit();
00288       }
00289     #endif
00290   
00291     #ifdef VARIABLE_SPINDLE
00292       // NOTE: Assumes all calls to this function is when Grbl is not moving or must remain off.
00293       if (settings.flags & BITFLAG_LASER_MODE) {
00294         if (state == SPINDLE_ENABLE_CCW) { rpm = 0.0f; } // TODO: May need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE);
00295       }
00296     spindle_set_speed(spindle_compute_pwm_value(rpm));
00297         #endif
00298     #if (defined(USE_SPINDLE_DIR_AS_ENABLE_PIN) && \
00299         !defined(SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED)) || !defined(VARIABLE_SPINDLE)
00300       // NOTE: Without variable spindle, the enable bit should just turn on or off, regardless
00301       // if the spindle speed value is zero, as its ignored anyhow.
00302       #ifdef INVERT_SPINDLE_ENABLE_PIN
00303         ResetSpindleEnablebit();
00304       #else
00305         SetSpindleEnablebit();
00306       #endif    
00307     #endif
00308   }
00309   
00310   sys.report_ovr_counter = 0; // Set to report change immediately
00311 }
00312 
00313 
00314 // G-code parser entry-point for setting spindle state. Forces a planner buffer sync and bails 
00315 // if an abort or check-mode is active.
00316 #ifdef VARIABLE_SPINDLE
00317   void spindle_sync(uint8_t state, float rpm)
00318   {
00319     if (sys.state == STATE_CHECK_MODE) { return; }
00320     protocol_buffer_synchronize(); // Empty planner buffer to ensure spindle is set when programmed.
00321     spindle_set_state(state,rpm);
00322   }
00323 #else
00324   void _spindle_sync(uint8_t state)
00325   {
00326     if (sys.state == STATE_CHECK_MODE) { return; }
00327     protocol_buffer_synchronize(); // Empty planner buffer to ensure spindle is set when programmed.
00328     _spindle_set_state(state);
00329   }
00330 #endif