enabled specifying numeric config values using all strtof capabilities
[clinton/Smoothieware.git] / src / libs / StepTicker.cpp
CommitLineData
7b49793d 1/*
cd011f58
AW
2 This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
3 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.
4 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.
7b49793d 5 You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>.
cd011f58
AW
6*/
7
8
5673fe39 9#include "StepTicker.h"
cd011f58 10
3b1e82d2
AW
11using namespace std;
12#include <vector>
5673fe39 13
3b1e82d2
AW
14#include "libs/nuts_bolts.h"
15#include "libs/Module.h"
16#include "libs/Kernel.h"
5673fe39
MM
17#include "StepperMotor.h"
18
da3a10b9 19#include "system_LPC17xx.h" // mbed.h lib
3b1e82d2 20
bd0f7508
AW
21#include <mri.h>
22
921bdb42
AW
23// StepTicker handles the base frequency ticking for the Stepper Motors / Actuators
24// It has a list of those, and calls their tick() functions at regular intervals
25// They then do Bresenham stuff themselves
3b1e82d2
AW
26
27StepTicker* global_step_ticker;
28
29StepTicker::StepTicker(){
30 global_step_ticker = this;
93694d6b
AW
31
32 // Configure the timer
8aea2a35 33 LPC_TIM0->MR0 = 10000000; // Initial dummy value for Match Register
813727fb 34 LPC_TIM0->MCR = 3; // Match on MR0, reset on MR0, match on MR1
8aea2a35 35 LPC_TIM0->TCR = 0; // Disable interrupt
796c9f32 36
8aea2a35 37 LPC_SC->PCONP |= (1 << 2); // Power Ticker ON
813727fb
AW
38 LPC_TIM1->MR0 = 1000000;
39 LPC_TIM1->MCR = 1;
8aea2a35 40 LPC_TIM1->TCR = 1; // Enable interrupt
813727fb 41
7b49793d 42 // Default start values
bd0f7508
AW
43 this->moves_finished = false;
44 this->reset_step_pins = false;
feb204be 45 this->debug = 0;
650ed0a8
AW
46 this->has_axes = 0;
47 this->set_frequency(0.001);
48 this->set_reset_delay(100);
feb204be 49 this->last_duration = 0;
19f961f6 50 for (int i = 0; i < 12; i++){
6e0063ab 51 this->active_motors[i] = NULL;
19f961f6 52 }
6e0063ab 53 this->active_motor_bm = 0;
796c9f32 54
921bdb42 55 NVIC_EnableIRQ(TIMER0_IRQn); // Enable interrupt handler
813727fb 56 NVIC_EnableIRQ(TIMER1_IRQn); // Enable interrupt handler
3b1e82d2
AW
57}
58
921bdb42 59// Set the base stepping frequency
1ad23cd3 60void StepTicker::set_frequency( float frequency ){
3b1e82d2 61 this->frequency = frequency;
7b49793d 62 this->period = int(floor((SystemCoreClock/4)/frequency)); // SystemCoreClock/4 = Timer increments in a second
feb204be 63 LPC_TIM0->MR0 = this->period;
3b1e82d2
AW
64 if( LPC_TIM0->TC > LPC_TIM0->MR0 ){
65 LPC_TIM0->TCR = 3; // Reset
66 LPC_TIM0->TCR = 1; // Reset
67 }
68}
69
921bdb42 70// Set the reset delay
1ad23cd3
MM
71void StepTicker::set_reset_delay( float seconds ){
72 this->delay = int(floor(float(SystemCoreClock/4)*( seconds ))); // SystemCoreClock/4 = Timer increments in a second
813727fb 73 LPC_TIM1->MR0 = this->delay;
3b1e82d2
AW
74}
75
feb204be 76// Add a stepper motor object to our list of steppers we must take care of
670fa10b 77StepperMotor* StepTicker::add_stepper_motor(StepperMotor* stepper_motor){
feb204be 78 this->stepper_motors.push_back(stepper_motor);
7b49793d 79 stepper_motor->step_ticker = this;
650ed0a8 80 this->has_axes = true;
feb204be
AW
81 return stepper_motor;
82}
83
6b080aff 84// Call tick() on each active motor
7b49793d 85inline void StepTicker::tick(){
4df07f88 86 _isr_context = true;
6e0063ab 87 int i;
12aad2a0
AW
88 uint32_t bm = 1;
89 // We iterate over each active motor
90 for (i = 0; i < 12; i++, bm <<= 1){
91 if (this->active_motor_bm & bm){
6e0063ab
MM
92 this->active_motors[i]->tick();
93 }
3b1e82d2 94 }
4df07f88 95 _isr_context = false;
3b1e82d2
AW
96}
97
7b49793d 98// Call signal_mode_finished() on each active motor that asked to be signaled. We do this instead of inside of tick() so that
6b080aff 99// all tick()s are called before we do the move finishing
bd0f7508 100void StepTicker::signal_moves_finished(){
4df07f88
MM
101 _isr_context = true;
102
39a14e08
AG
103 uint16_t bitmask = 1;
104 for ( uint8_t motor = 0; motor < 12; motor++, bitmask <<= 1){
12800c08
AW
105 if (this->active_motor_bm & bitmask){
106 if(this->active_motors[motor]->is_move_finished){
107 this->active_motors[motor]->signal_move_finished();
108 if(this->active_motors[motor]->moving == false){
109 if (motor > 0){
110 motor--;
111 bitmask >>= 1;
6e0063ab
MM
112 }
113 }
114 }
bd0f7508 115 }
bd0f7508
AW
116 }
117 this->moves_finished = false;
4df07f88
MM
118
119 _isr_context = false;
bd0f7508
AW
120}
121
6b080aff 122// Reset step pins on all active motors
feb204be 123inline void StepTicker::reset_tick(){
4df07f88
MM
124 _isr_context = true;
125
6e0063ab
MM
126 int i;
127 uint32_t bm;
128 for (i = 0, bm = 1; i < 12; i++, bm <<= 1)
129 {
130 if (this->active_motor_bm & bm)
9c5fa39a 131 this->active_motors[i]->unstep();
3b1e82d2 132 }
4df07f88
MM
133
134 _isr_context = false;
3b1e82d2
AW
135}
136
813727fb 137extern "C" void TIMER1_IRQHandler (void){
7b49793d 138 LPC_TIM1->IR |= 1 << 0;
813727fb
AW
139 global_step_ticker->reset_tick();
140}
141
921bdb42 142// The actual interrupt handler where we do all the work
3b1e82d2 143extern "C" void TIMER0_IRQHandler (void){
b2b0b56d 144
8aea2a35 145 // Reset interrupt register
813727fb 146 LPC_TIM0->IR |= 1 << 0;
4464301d 147
7b49793d 148 // Step pins
39a14e08
AG
149 uint16_t bitmask = 1;
150 for (uint8_t motor = 0; motor < 12; motor++, bitmask <<= 1){
12800c08
AW
151 if (global_step_ticker->active_motor_bm & bitmask){
152 global_step_ticker->active_motors[motor]->tick();
153 }
154 }
4464301d 155
bd0f7508
AW
156 // We may have set a pin on in this tick, now we start the timer to set it off
157 if( global_step_ticker->reset_step_pins ){
158 LPC_TIM1->TCR = 3;
159 LPC_TIM1->TCR = 1;
160 global_step_ticker->reset_step_pins = false;
12aad2a0
AW
161 }else{
162 // Nothing happened, nothing after this really matters
d337942a 163 // TODO : This could be a problem when we use Actuators instead of StepperMotors, because this flag is specific to step generation
8aea2a35 164 LPC_TIM0->MR0 = global_step_ticker->period;
12aad2a0 165 return;
bd0f7508 166 }
19f961f6 167
bd0f7508 168 // If a move finished in this tick, we have to tell the actuator to act accordingly
19f961f6
AW
169 if( global_step_ticker->moves_finished ){
170
171 // Do not get out of here before everything is nice and tidy
f550bd20 172 LPC_TIM0->MR0 = 20000000;
19f961f6
AW
173
174 global_step_ticker->signal_moves_finished();
175
176 // If we went over the duration an interrupt is supposed to last, we have a problem
177 // That can happen tipically when we change blocks, where more than usual computation is done
178 // This can be OK, if we take notice of it, which we do now
179 if( LPC_TIM0->TC > global_step_ticker->period ){ // TODO: remove the size condition
180
19f961f6 181 uint32_t start_tc = LPC_TIM0->TC;
19f961f6
AW
182
183 // 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 )
184 uint32_t ticks_to_skip = ( ( LPC_TIM0->TC + global_step_ticker->last_duration ) / global_step_ticker->period );
185
186 // Next step is now to reduce this to how many steps we can *actually* skip
187 uint32_t ticks_we_actually_can_skip = ticks_to_skip;
188
189 int i;
190 uint32_t bm;
191 for (i = 0, bm = 1; i < 12; i++, bm <<= 1)
192 {
193 if (global_step_ticker->active_motor_bm & bm)
194 ticks_we_actually_can_skip =
195 min(ticks_we_actually_can_skip,
196 (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)
197 );
198 }
7b49793d 199
19f961f6
AW
200 // Adding to MR0 for this time is not enough, we must also increment the counters ourself artificially
201 for (i = 0, bm = 1; i < 12; i++, bm <<= 1)
202 {
203 if (global_step_ticker->active_motor_bm & bm)
204 global_step_ticker->active_motors[i]->fx_counter += (uint64_t)((uint64_t)(ticks_we_actually_can_skip)<<32);
205 }
650ed0a8 206
19f961f6
AW
207 // 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 )
208 LPC_TIM0->MR0 = ( ticks_to_skip + 1 ) * global_step_ticker->period;
650ed0a8 209
19f961f6
AW
210 // This is so that we know how long this computation takes, and we can take it into account next time
211 int difference = (int)(LPC_TIM0->TC) - (int)(start_tc);
212 if( difference > 0 ){ global_step_ticker->last_duration = (uint32_t)difference; }
6e0063ab 213
19f961f6
AW
214 }else{
215 LPC_TIM0->MR0 = global_step_ticker->period;
813727fb 216 }
650ed0a8 217
19f961f6
AW
218 while( LPC_TIM0->TC > LPC_TIM0->MR0 ){
219 LPC_TIM0->MR0 += global_step_ticker->period;
feb204be
AW
220 }
221
bd0f7508 222 }
813727fb 223
3b1e82d2
AW
224}
225
bd0f7508 226
796c9f32 227// We make a list of steppers that want to be called so that we don't call them for nothing
670fa10b 228void StepTicker::add_motor_to_active_list(StepperMotor* motor)
6e0063ab
MM
229{
230 uint32_t bm;
231 int i;
232 for (i = 0, bm = 1; i < 12; i++, bm <<= 1)
233 {
234 if (this->active_motors[i] == motor)
235 {
236 this->active_motor_bm |= bm;
f550bd20 237 if( this->active_motor_bm != 0 ){
8aea2a35
AW
238 LPC_TIM0->TCR = 1; // Enable interrupt
239 }
6e0063ab
MM
240 return;
241 }
242 if (this->active_motors[i] == NULL)
243 {
244 this->active_motors[i] = motor;
245 this->active_motor_bm |= bm;
f550bd20 246 if( this->active_motor_bm != 0 ){
8aea2a35
AW
247 LPC_TIM0->TCR = 1; // Enable interrupt
248 }
6e0063ab 249 return;
796c9f32 250 }
796c9f32 251 }
6e0063ab 252 return;
796c9f32
AW
253}
254
6b080aff 255// Remove a stepper from the list of active motors
670fa10b 256void StepTicker::remove_motor_from_active_list(StepperMotor* motor)
6e0063ab
MM
257{
258 uint32_t bm; int i;
259 for (i = 0, bm = 1; i < 12; i++, bm <<= 1)
260 {
261 if (this->active_motors[i] == motor)
262 {
263 this->active_motor_bm &= ~bm;
8aea2a35
AW
264 // If we have no motor to work on, disable the whole interrupt
265 if( this->active_motor_bm == 0 ){
dc4ca298 266 LPC_TIM0->TCR = 0; // Disable interrupt
8aea2a35 267 }
6e0063ab
MM
268 return;
269 }
796c9f32 270 }
796c9f32 271}