Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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
Generated on Tue Jul 12 2022 20:45:31 by
1.7.2