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.
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
