fix deadlock/race condition
[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
11#include "libs/nuts_bolts.h"
12#include "libs/Module.h"
13#include "libs/Kernel.h"
5673fe39 14#include "StepperMotor.h"
c9cc5e06 15#include "StreamOutputPool.h"
da3a10b9 16#include "system_LPC17xx.h" // mbed.h lib
61134a65 17#include <math.h>
bd0f7508
AW
18#include <mri.h>
19
9e089978
JM
20#ifdef STEPTICKER_DEBUG_PIN
21#include "gpio.h"
22extern GPIO stepticker_debug_pin;
23#endif
24
61134a65
JM
25extern bool _isr_context;
26
921bdb42
AW
27// StepTicker handles the base frequency ticking for the Stepper Motors / Actuators
28// It has a list of those, and calls their tick() functions at regular intervals
29// They then do Bresenham stuff themselves
3b1e82d2 30
2fa50ca0 31StepTicker* StepTicker::global_step_ticker;
3b1e82d2 32
1fce036c 33StepTicker::StepTicker(){
2fa50ca0 34 StepTicker::global_step_ticker = this;
93694d6b
AW
35
36 // Configure the timer
8aea2a35 37 LPC_TIM0->MR0 = 10000000; // Initial dummy value for Match Register
813727fb 38 LPC_TIM0->MCR = 3; // Match on MR0, reset on MR0, match on MR1
8aea2a35 39 LPC_TIM0->TCR = 0; // Disable interrupt
796c9f32 40
8aea2a35 41 LPC_SC->PCONP |= (1 << 2); // Power Ticker ON
813727fb
AW
42 LPC_TIM1->MR0 = 1000000;
43 LPC_TIM1->MCR = 1;
8aea2a35 44 LPC_TIM1->TCR = 1; // Enable interrupt
813727fb 45
7b49793d 46 // Default start values
acf766a4 47 this->a_move_finished = false;
3b1acdaa 48 this->do_move_finished = false;
bd0f7508 49 this->reset_step_pins = false;
3b1acdaa 50 this->set_frequency(100000);
650ed0a8 51 this->set_reset_delay(100);
a157d099 52 this->set_acceleration_ticks_per_second(1000);
feb204be 53 this->last_duration = 0;
1fce036c
JM
54 this->num_motors= 0;
55 this->active_motor.reset();
a157d099 56 this->acceleration_tick_cnt= 0;
3b1acdaa 57 this->do_acceleration_tick= false;
796c9f32 58
921bdb42 59 NVIC_EnableIRQ(TIMER0_IRQn); // Enable interrupt handler
813727fb 60 NVIC_EnableIRQ(TIMER1_IRQn); // Enable interrupt handler
3b1e82d2
AW
61}
62
3eadcfee 63StepTicker::~StepTicker() {
3eadcfee
JM
64}
65
921bdb42 66// Set the base stepping frequency
1ad23cd3 67void StepTicker::set_frequency( float frequency ){
3b1e82d2 68 this->frequency = frequency;
9e089978 69 this->period = floorf((SystemCoreClock/4.0F)/frequency); // SystemCoreClock/4 = Timer increments in a second
feb204be 70 LPC_TIM0->MR0 = this->period;
3b1e82d2
AW
71 if( LPC_TIM0->TC > LPC_TIM0->MR0 ){
72 LPC_TIM0->TCR = 3; // Reset
73 LPC_TIM0->TCR = 1; // Reset
74 }
75}
76
921bdb42 77// Set the reset delay
1ad23cd3 78void StepTicker::set_reset_delay( float seconds ){
9e089978 79 this->delay = floorf((SystemCoreClock/4.0F)*seconds); // SystemCoreClock/4 = Timer increments in a second
813727fb 80 LPC_TIM1->MR0 = this->delay;
3b1e82d2
AW
81}
82
a157d099
JM
83// this is the number of stepper ticks (100,000/sec) per acceleration tick
84void StepTicker::set_acceleration_ticks_per_second(uint32_t acceleration_ticks_per_second) {
85 this->acceleration_tick_period= floorf(this->frequency/acceleration_ticks_per_second);
3b1e82d2
AW
86}
87
acf766a4 88// Call signal_move_finished() on each active motor that asked to be signaled. We do this instead of inside of tick() so that
6b080aff 89// all tick()s are called before we do the move finishing
acf766a4 90void StepTicker::signal_a_move_finished(){
4df07f88
MM
91 _isr_context = true;
92
1fce036c
JM
93 for (int motor = 0; motor < num_motors; motor++){
94 if (this->active_motor[motor] && this->motor[motor]->is_move_finished){
95 this->motor[motor]->signal_move_finished();
9e089978 96 // Theoretically this does nothing and the reason for it is currently unknown and/or forgotten
1fce036c 97 // if(this->motor[motor]->moving == false){
9e089978
JM
98 // if (motor > 0){
99 // motor--;
100 // bitmask >>= 1;
101 // }
102 // }
bd0f7508 103 }
bd0f7508 104 }
4df07f88
MM
105
106 _isr_context = false;
bd0f7508
AW
107}
108
6b080aff 109// Reset step pins on all active motors
feb204be 110inline void StepTicker::reset_tick(){
4df07f88
MM
111 _isr_context = true;
112
1fce036c
JM
113 for (int i = 0; i < num_motors; i++) {
114 if(this->active_motor[i])
115 this->motor[i]->unstep();
3b1e82d2 116 }
4df07f88
MM
117
118 _isr_context = false;
3b1e82d2
AW
119}
120
813727fb 121extern "C" void TIMER1_IRQHandler (void){
7b49793d 122 LPC_TIM1->IR |= 1 << 0;
2fa50ca0 123 StepTicker::global_step_ticker->reset_tick();
813727fb
AW
124}
125
921bdb42 126// The actual interrupt handler where we do all the work
3b1e82d2 127extern "C" void TIMER0_IRQHandler (void){
2fa50ca0
JM
128 StepTicker::global_step_ticker->TIMER0_IRQHandler();
129}
b2b0b56d 130
16220afe
JM
131extern "C" void PendSV_Handler(void) {
132 StepTicker::global_step_ticker->PendSV_IRQHandler();
133}
134
135// slightly lower priority than TIMER0, the whole end of block/start of block is done here allowing the timer to continue ticking
a157d099 136// also handles the acceleration tick
3b1acdaa
JM
137void StepTicker::PendSV_IRQHandler (void) {
138
139 if(this->do_move_finished) {
140 this->do_move_finished= false;
16220afe 141
a157d099
JM
142 #ifdef STEPTICKER_DEBUG_PIN
143 stepticker_debug_pin= 1;
144 #endif
16220afe 145
a157d099
JM
146 this->signal_a_move_finished();
147
148 #ifdef STEPTICKER_DEBUG_PIN
149 stepticker_debug_pin= 0;
150 #endif
151 }
f095cddd 152
3b1acdaa
JM
153 if(this->do_acceleration_tick) {
154 this->do_acceleration_tick= false;
155 // call registered acceleration handlers
156 for (size_t i = 0; i < acceleration_tick_handlers.size(); ++i) {
157 acceleration_tick_handlers[i]();
158 }
159 }
16220afe
JM
160}
161
2fa50ca0 162void StepTicker::TIMER0_IRQHandler (void){
8aea2a35 163 // Reset interrupt register
813727fb 164 LPC_TIM0->IR |= 1 << 0;
16220afe 165 LPC_TIM0->MR0 = this->period;
4464301d 166
7b49793d 167 // Step pins
1fce036c
JM
168 for (uint32_t motor = 0; motor < num_motors; motor++){
169 if (this->active_motor[motor]){
170 this->motor[motor]->tick();
12800c08
AW
171 }
172 }
4464301d 173
bd0f7508 174 // We may have set a pin on in this tick, now we start the timer to set it off
2fa50ca0 175 if( this->reset_step_pins ){
bd0f7508
AW
176 LPC_TIM1->TCR = 3;
177 LPC_TIM1->TCR = 1;
2fa50ca0 178 this->reset_step_pins = false;
a157d099
JM
179 }
180
181 // do an acceleration tick, after we have done everything else
182 if(++this->acceleration_tick_cnt >= this->acceleration_tick_period) {
183 this->acceleration_tick_cnt= 0;
184 this->do_acceleration_tick= true;
bd0f7508 185 }
61134a65 186
3b1acdaa
JM
187 if(this->a_move_finished) {
188 this->a_move_finished = false;
189 this->do_move_finished= 1;
190 }
191
bd0f7508 192 // If a move finished in this tick, we have to tell the actuator to act accordingly
3b1acdaa 193 if(this->do_move_finished || this->do_acceleration_tick){
f095cddd 194 // we delegate the slow stuff to the pendsv handler which will run as soon as this interrupt exits
16220afe
JM
195 //NVIC_SetPendingIRQ(PendSV_IRQn); this doesn't work
196 SCB->ICSR = 0x10000000; // SCB_ICSR_PENDSVSET_Msk;
bd0f7508 197 }
3b1e82d2
AW
198}
199
1fce036c
JM
200// returns index of the stepper motor in the array and bitset
201int StepTicker::register_motor(StepperMotor* motor)
202{
203 this->motor.push_back(motor);
204 this->num_motors= this->motor.size();
205 return this->num_motors-1;
206}
bd0f7508 207
1fce036c 208// activate the specified motor, must have been registered
670fa10b 209void StepTicker::add_motor_to_active_list(StepperMotor* motor)
6e0063ab 210{
1fce036c
JM
211 bool enabled= active_motor.any(); // see if interrupt was previously enabled
212 active_motor[motor->index]= 1;
213 if(!enabled) {
214 LPC_TIM0->TCR = 1; // Enable interrupt
796c9f32 215 }
796c9f32
AW
216}
217
6b080aff 218// Remove a stepper from the list of active motors
670fa10b 219void StepTicker::remove_motor_from_active_list(StepperMotor* motor)
6e0063ab 220{
1fce036c
JM
221 active_motor[motor->index]= 0;
222 // If we have no motor to work on, disable the whole interrupt
223 if(this->active_motor.none()){
224 LPC_TIM0->TCR = 0; // Disable interrupt
796c9f32 225 }
796c9f32 226}