Fork of Smoothie to port to mbed non-LPC targets.
Fork of Smoothie by
StepTicker.cpp
00001 /* 00002 This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl). 00003 Smoothie is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 00004 Smoothie is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 00005 You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>. 00006 */ 00007 00008 00009 #include "StepTicker.h" 00010 00011 using namespace std; 00012 #include <vector> 00013 00014 #include "libs/nuts_bolts.h" 00015 #include "libs/Module.h" 00016 #include "libs/Kernel.h" 00017 #include "StepperMotor.h" 00018 00019 #include "system_LPC17xx.h" // mbed.h lib 00020 00021 #include <mri.h> 00022 00023 // StepTicker handles the base frequency ticking for the Stepper Motors / Actuators 00024 // It has a list of those, and calls their tick() functions at regular intervals 00025 // They then do Bresenham stuff themselves 00026 00027 StepTicker* global_step_ticker; 00028 00029 StepTicker::StepTicker(){ 00030 global_step_ticker = this; 00031 00032 // Configure the timer 00033 LPC_TIM0->MR0 = 10000000; // Initial dummy value for Match Register 00034 LPC_TIM0->MCR = 3; // Match on MR0, reset on MR0, match on MR1 00035 LPC_TIM0->TCR = 0; // Disable interrupt 00036 00037 LPC_SC->PCONP |= (1 << 2); // Power Ticker ON 00038 LPC_TIM1->MR0 = 1000000; 00039 LPC_TIM1->MCR = 1; 00040 LPC_TIM1->TCR = 1; // Enable interrupt 00041 00042 // Default start values 00043 this->moves_finished = false; 00044 this->reset_step_pins = false; 00045 this->debug = 0; 00046 this->has_axes = 0; 00047 this->set_frequency(0.001); 00048 this->set_reset_delay(100); 00049 this->last_duration = 0; 00050 for (int i = 0; i < 12; i++){ 00051 this->active_motors[i] = NULL; 00052 } 00053 this->active_motor_bm = 0; 00054 00055 NVIC_EnableIRQ(TIMER0_IRQn); // Enable interrupt handler 00056 NVIC_EnableIRQ(TIMER1_IRQn); // Enable interrupt handler 00057 } 00058 00059 // Set the base stepping frequency 00060 void StepTicker::set_frequency( float frequency ){ 00061 this->frequency = frequency; 00062 this->period = int(floor((SystemCoreClock/4)/frequency)); // SystemCoreClock/4 = Timer increments in a second 00063 LPC_TIM0->MR0 = this->period; 00064 if( LPC_TIM0->TC > LPC_TIM0->MR0 ){ 00065 LPC_TIM0->TCR = 3; // Reset 00066 LPC_TIM0->TCR = 1; // Reset 00067 } 00068 } 00069 00070 // Set the reset delay 00071 void StepTicker::set_reset_delay( float seconds ){ 00072 this->delay = int(floor(float(SystemCoreClock/4)*( seconds ))); // SystemCoreClock/4 = Timer increments in a second 00073 LPC_TIM1->MR0 = this->delay; 00074 } 00075 00076 // Add a stepper motor object to our list of steppers we must take care of 00077 StepperMotor* StepTicker::add_stepper_motor(StepperMotor* stepper_motor){ 00078 this->stepper_motors.push_back(stepper_motor); 00079 stepper_motor->step_ticker = this; 00080 this->has_axes = true; 00081 return stepper_motor; 00082 } 00083 00084 // Call tick() on each active motor 00085 inline void StepTicker::tick(){ 00086 _isr_context = true; 00087 int i; 00088 uint32_t bm = 1; 00089 // We iterate over each active motor 00090 for (i = 0; i < 12; i++, bm <<= 1){ 00091 if (this->active_motor_bm & bm){ 00092 this->active_motors[i]->tick(); 00093 } 00094 } 00095 _isr_context = false; 00096 } 00097 00098 // Call signal_mode_finished() on each active motor that asked to be signaled. We do this instead of inside of tick() so that 00099 // all tick()s are called before we do the move finishing 00100 void StepTicker::signal_moves_finished(){ 00101 _isr_context = true; 00102 00103 uint16_t bitmask = 1; 00104 for ( uint8_t motor = 0; motor < 12; motor++, bitmask <<= 1){ 00105 if (this->active_motor_bm & bitmask){ 00106 if(this->active_motors[motor]->is_move_finished){ 00107 this->active_motors[motor]->signal_move_finished(); 00108 if(this->active_motors[motor]->moving == false){ 00109 if (motor > 0){ 00110 motor--; 00111 bitmask >>= 1; 00112 } 00113 } 00114 } 00115 } 00116 } 00117 this->moves_finished = false; 00118 00119 _isr_context = false; 00120 } 00121 00122 // Reset step pins on all active motors 00123 inline void StepTicker::reset_tick(){ 00124 _isr_context = true; 00125 00126 int i; 00127 uint32_t bm; 00128 for (i = 0, bm = 1; i < 12; i++, bm <<= 1) 00129 { 00130 if (this->active_motor_bm & bm) 00131 this->active_motors[i]->unstep(); 00132 } 00133 00134 _isr_context = false; 00135 } 00136 00137 extern "C" void TIMER1_IRQHandler (void){ 00138 LPC_TIM1->IR |= 1 << 0; 00139 global_step_ticker->reset_tick(); 00140 } 00141 00142 // The actual interrupt handler where we do all the work 00143 extern "C" void TIMER0_IRQHandler (void){ 00144 00145 // Reset interrupt register 00146 LPC_TIM0->IR |= 1 << 0; 00147 00148 // Step pins 00149 uint16_t bitmask = 1; 00150 for (uint8_t motor = 0; motor < 12; motor++, bitmask <<= 1){ 00151 if (global_step_ticker->active_motor_bm & bitmask){ 00152 global_step_ticker->active_motors[motor]->tick(); 00153 } 00154 } 00155 00156 // We may have set a pin on in this tick, now we start the timer to set it off 00157 if( global_step_ticker->reset_step_pins ){ 00158 LPC_TIM1->TCR = 3; 00159 LPC_TIM1->TCR = 1; 00160 global_step_ticker->reset_step_pins = false; 00161 }else{ 00162 // Nothing happened, nothing after this really matters 00163 // TODO : This could be a problem when we use Actuators instead of StepperMotors, because this flag is specific to step generation 00164 LPC_TIM0->MR0 = global_step_ticker->period; 00165 return; 00166 } 00167 00168 // If a move finished in this tick, we have to tell the actuator to act accordingly 00169 if( global_step_ticker->moves_finished ){ 00170 00171 // Do not get out of here before everything is nice and tidy 00172 LPC_TIM0->MR0 = 20000000; 00173 00174 global_step_ticker->signal_moves_finished(); 00175 00176 // If we went over the duration an interrupt is supposed to last, we have a problem 00177 // That can happen tipically when we change blocks, where more than usual computation is done 00178 // This can be OK, if we take notice of it, which we do now 00179 if( LPC_TIM0->TC > global_step_ticker->period ){ // TODO: remove the size condition 00180 00181 uint32_t start_tc = LPC_TIM0->TC; 00182 00183 // How many ticks we want to skip ( this does not include the current tick, but we add the time we spent doing this computation last time ) 00184 uint32_t ticks_to_skip = ( ( LPC_TIM0->TC + global_step_ticker->last_duration ) / global_step_ticker->period ); 00185 00186 // Next step is now to reduce this to how many steps we can *actually* skip 00187 uint32_t ticks_we_actually_can_skip = ticks_to_skip; 00188 00189 int i; 00190 uint32_t bm; 00191 for (i = 0, bm = 1; i < 12; i++, bm <<= 1) 00192 { 00193 if (global_step_ticker->active_motor_bm & bm) 00194 ticks_we_actually_can_skip = 00195 min(ticks_we_actually_can_skip, 00196 (uint32_t)((uint64_t)( (uint64_t)global_step_ticker->active_motors[i]->fx_ticks_per_step - (uint64_t)global_step_ticker->active_motors[i]->fx_counter ) >> 32) 00197 ); 00198 } 00199 00200 // Adding to MR0 for this time is not enough, we must also increment the counters ourself artificially 00201 for (i = 0, bm = 1; i < 12; i++, bm <<= 1) 00202 { 00203 if (global_step_ticker->active_motor_bm & bm) 00204 global_step_ticker->active_motors[i]->fx_counter += (uint64_t)((uint64_t)(ticks_we_actually_can_skip)<<32); 00205 } 00206 00207 // When must we have our next MR0 ? ( +1 is here to account that we are actually doing a legit MR0 match here too, not only overtime ) 00208 LPC_TIM0->MR0 = ( ticks_to_skip + 1 ) * global_step_ticker->period; 00209 00210 // This is so that we know how long this computation takes, and we can take it into account next time 00211 int difference = (int)(LPC_TIM0->TC) - (int)(start_tc); 00212 if( difference > 0 ){ global_step_ticker->last_duration = (uint32_t)difference; } 00213 00214 }else{ 00215 LPC_TIM0->MR0 = global_step_ticker->period; 00216 } 00217 00218 while( LPC_TIM0->TC > LPC_TIM0->MR0 ){ 00219 LPC_TIM0->MR0 += global_step_ticker->period; 00220 } 00221 00222 } 00223 00224 } 00225 00226 00227 // We make a list of steppers that want to be called so that we don't call them for nothing 00228 void StepTicker::add_motor_to_active_list(StepperMotor* motor) 00229 { 00230 uint32_t bm; 00231 int i; 00232 for (i = 0, bm = 1; i < 12; i++, bm <<= 1) 00233 { 00234 if (this->active_motors[i] == motor) 00235 { 00236 this->active_motor_bm |= bm; 00237 if( this->active_motor_bm != 0 ){ 00238 LPC_TIM0->TCR = 1; // Enable interrupt 00239 } 00240 return; 00241 } 00242 if (this->active_motors[i] == NULL) 00243 { 00244 this->active_motors[i] = motor; 00245 this->active_motor_bm |= bm; 00246 if( this->active_motor_bm != 0 ){ 00247 LPC_TIM0->TCR = 1; // Enable interrupt 00248 } 00249 return; 00250 } 00251 } 00252 return; 00253 } 00254 00255 // Remove a stepper from the list of active motors 00256 void StepTicker::remove_motor_from_active_list(StepperMotor* motor) 00257 { 00258 uint32_t bm; int i; 00259 for (i = 0, bm = 1; i < 12; i++, bm <<= 1) 00260 { 00261 if (this->active_motors[i] == motor) 00262 { 00263 this->active_motor_bm &= ~bm; 00264 // If we have no motor to work on, disable the whole interrupt 00265 if( this->active_motor_bm == 0 ){ 00266 LPC_TIM0->TCR = 0; // Disable interrupt 00267 } 00268 return; 00269 } 00270 } 00271 }
Generated on Tue Jul 12 2022 20:09:02 by 1.7.2