fix when slow ticker gets started
[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 25
921bdb42
AW
26// StepTicker handles the base frequency ticking for the Stepper Motors / Actuators
27// It has a list of those, and calls their tick() functions at regular intervals
28// They then do Bresenham stuff themselves
3b1e82d2 29
2fa50ca0 30StepTicker* StepTicker::global_step_ticker;
3b1e82d2 31
1fce036c 32StepTicker::StepTicker(){
2fa50ca0 33 StepTicker::global_step_ticker = this;
93694d6b
AW
34
35 // Configure the timer
8aea2a35 36 LPC_TIM0->MR0 = 10000000; // Initial dummy value for Match Register
813727fb 37 LPC_TIM0->MCR = 3; // Match on MR0, reset on MR0, match on MR1
8aea2a35 38 LPC_TIM0->TCR = 0; // Disable interrupt
796c9f32 39
8aea2a35 40 LPC_SC->PCONP |= (1 << 2); // Power Ticker ON
813727fb
AW
41 LPC_TIM1->MR0 = 1000000;
42 LPC_TIM1->MCR = 1;
aed1f6ca 43 LPC_TIM1->TCR = 0; // Disable interrupt
813727fb 44
dc3542cf
JM
45 // Setup RIT timer
46 LPC_SC->PCONP |= (1L<<16); // RIT Power
47 LPC_SC->PCLKSEL1 &= ~(3L << 26); // Clear PCLK_RIT bits;
48 LPC_SC->PCLKSEL1 |= (1L << 26); // Set PCLK_RIT bits to 0x01;
49 LPC_RIT->RICOMPVAL = (uint32_t)(((SystemCoreClock / 1000000L) * 1000)-1); // 1ms period
50 LPC_RIT->RICOUNTER = 0;
51 // Set counter clear/reset after interrupt
52 LPC_RIT->RICTRL |= (2L); //RITENCLR
53 LPC_RIT->RICTRL &= ~(8L); // disable
54 //NVIC_SetVector(RIT_IRQn, (uint32_t)&_ritisr);
55
7b49793d 56 // Default start values
acf766a4 57 this->a_move_finished = false;
001c4b26 58 this->do_move_finished = 0;
aed1f6ca 59 this->unstep.reset();
3b1acdaa 60 this->set_frequency(100000);
650ed0a8 61 this->set_reset_delay(100);
a157d099 62 this->set_acceleration_ticks_per_second(1000);
1fce036c
JM
63 this->num_motors= 0;
64 this->active_motor.reset();
c6796a29 65 this->tick_cnt= 0;
37102904 66 probe_fnc= nullptr;
3b1e82d2
AW
67}
68
3eadcfee 69StepTicker::~StepTicker() {
3eadcfee
JM
70}
71
b772a11c 72//called when everything is setup and interrupts can start
dc3542cf
JM
73void StepTicker::start() {
74 NVIC_EnableIRQ(TIMER0_IRQn); // Enable interrupt handler
75 NVIC_EnableIRQ(TIMER1_IRQn); // Enable interrupt handler
76 NVIC_EnableIRQ(RIT_IRQn);
77}
78
921bdb42 79// Set the base stepping frequency
1ad23cd3 80void StepTicker::set_frequency( float frequency ){
3b1e82d2 81 this->frequency = frequency;
9e089978 82 this->period = floorf((SystemCoreClock/4.0F)/frequency); // SystemCoreClock/4 = Timer increments in a second
feb204be 83 LPC_TIM0->MR0 = this->period;
3b1e82d2
AW
84 if( LPC_TIM0->TC > LPC_TIM0->MR0 ){
85 LPC_TIM0->TCR = 3; // Reset
86 LPC_TIM0->TCR = 1; // Reset
87 }
88}
89
921bdb42 90// Set the reset delay
aed1f6ca
JM
91void StepTicker::set_reset_delay( float microseconds ){
92 uint32_t delay = floorf((SystemCoreClock/4.0F)*(microseconds/1000000.0F)); // SystemCoreClock/4 = Timer increments in a second
93 LPC_TIM1->MR0 = delay;
3b1e82d2
AW
94}
95
dc3542cf 96// this is the number of acceleration ticks per second
a157d099 97void StepTicker::set_acceleration_ticks_per_second(uint32_t acceleration_ticks_per_second) {
dc3542cf
JM
98 uint32_t us= roundf(1000000.0F/acceleration_ticks_per_second); // period in microseconds
99 LPC_RIT->RICOMPVAL = (uint32_t)(((SystemCoreClock / 1000000L) * us)-1); // us
100 LPC_RIT->RICOUNTER = 0;
101 LPC_RIT->RICTRL |= (8L); // Enable rit
3b1e82d2
AW
102}
103
544a5de3 104// Synchronize the acceleration timer, and optionally schedule it to fire now
398e9edc 105void StepTicker::synchronize_acceleration(bool fire_now) {
13256955 106 LPC_RIT->RICOUNTER = 0;
398e9edc
JM
107 if(fire_now){
108 NVIC_SetPendingIRQ(RIT_IRQn);
544a5de3
JM
109 }else{
110 if(NVIC_GetPendingIRQ(RIT_IRQn)) {
111 // clear pending interrupt so it does not interrupt immediately
112 LPC_RIT->RICTRL |= 1L; // also clear the interrupt in case it fired
113 NVIC_ClearPendingIRQ(RIT_IRQn);
114 }
398e9edc 115 }
13256955
JM
116}
117
118
acf766a4 119// Call signal_move_finished() on each active motor that asked to be signaled. We do this instead of inside of tick() so that
6b080aff 120// all tick()s are called before we do the move finishing
acf766a4 121void StepTicker::signal_a_move_finished(){
001c4b26 122 for (int motor = 0; motor < num_motors; motor++){
1fce036c
JM
123 if (this->active_motor[motor] && this->motor[motor]->is_move_finished){
124 this->motor[motor]->signal_move_finished();
9e089978 125 // Theoretically this does nothing and the reason for it is currently unknown and/or forgotten
1fce036c 126 // if(this->motor[motor]->moving == false){
9e089978
JM
127 // if (motor > 0){
128 // motor--;
129 // bitmask >>= 1;
130 // }
131 // }
bd0f7508 132 }
bd0f7508 133 }
bd0f7508
AW
134}
135
aed1f6ca
JM
136// Reset step pins on any motor that was stepped
137inline void StepTicker::unstep_tick(){
1fce036c 138 for (int i = 0; i < num_motors; i++) {
aed1f6ca 139 if(this->unstep[i]){
1fce036c 140 this->motor[i]->unstep();
aed1f6ca 141 }
3b1e82d2 142 }
13256955 143 this->unstep.reset();
3b1e82d2
AW
144}
145
813727fb 146extern "C" void TIMER1_IRQHandler (void){
7b49793d 147 LPC_TIM1->IR |= 1 << 0;
aed1f6ca 148 StepTicker::global_step_ticker->unstep_tick();
813727fb
AW
149}
150
921bdb42 151// The actual interrupt handler where we do all the work
3b1e82d2 152extern "C" void TIMER0_IRQHandler (void){
2fa50ca0
JM
153 StepTicker::global_step_ticker->TIMER0_IRQHandler();
154}
b2b0b56d 155
dc3542cf
JM
156extern "C" void RIT_IRQHandler (void){
157 LPC_RIT->RICTRL |= 1L;
158 StepTicker::global_step_ticker->acceleration_tick();
159}
160
16220afe
JM
161extern "C" void PendSV_Handler(void) {
162 StepTicker::global_step_ticker->PendSV_IRQHandler();
163}
164
165// slightly lower priority than TIMER0, the whole end of block/start of block is done here allowing the timer to continue ticking
3b1acdaa
JM
166void StepTicker::PendSV_IRQHandler (void) {
167
001c4b26
JM
168 if(this->do_move_finished.load() > 0) {
169 this->do_move_finished--;
a157d099 170 #ifdef STEPTICKER_DEBUG_PIN
36307133 171 stepticker_debug_pin= 1;
a157d099 172 #endif
16220afe 173
a157d099
JM
174 this->signal_a_move_finished();
175
176 #ifdef STEPTICKER_DEBUG_PIN
36307133 177 stepticker_debug_pin= 0;
a157d099
JM
178 #endif
179 }
cb2e6bc6
JM
180}
181
c6796a29 182// run in RIT lower priority than PendSV
dc3542cf 183void StepTicker::acceleration_tick() {
dc3542cf
JM
184 // call registered acceleration handlers
185 for (size_t i = 0; i < acceleration_tick_handlers.size(); ++i) {
186 acceleration_tick_handlers[i]();
3b1acdaa 187 }
16220afe
JM
188}
189
2fa50ca0 190void StepTicker::TIMER0_IRQHandler (void){
8aea2a35 191 // Reset interrupt register
813727fb 192 LPC_TIM0->IR |= 1 << 0;
c6796a29 193 tick_cnt++; // count number of ticks
4464301d 194
37102904
JM
195 // check if we are probing and if so check the probe status and force an end of move if it is triggered
196 if(probe_fnc && probe_fnc()) {
197 // we do exactly what we would do if stepping had finished
198 for (uint32_t motor = 0; motor < num_motors; motor++){
199 if(this->active_motor[motor]){
200 this->motor[motor]->force_finish_move();
201 }
202 }
203
204 }else{
205
206 // Step pins NOTE takes 1.2us when nothing to step, 1.8-2us for one motor stepped and 2.6us when two motors stepped, 3.167us when three motors stepped
207 for (uint32_t motor = 0; motor < num_motors; motor++){
208 // send tick to all active motors
209 if(this->active_motor[motor] && this->motor[motor]->tick()){
210 // we stepped so schedule an unstep
211 this->unstep[motor]= 1;
212 }
aed1f6ca 213 }
12800c08 214 }
4464301d 215
aed1f6ca
JM
216 // We may have set a pin on in this tick, now we reset the timer to set it off
217 // Note there could be a race here if we run another tick before the unsteps have happened,
218 // right now it takes about 3-4us but if the unstep were near 10uS or greater it would be an issue
219 // also it takes at least 2us to get here so even when set to 1us pulse width it will still be about 3us
220 if( this->unstep.any()){
bd0f7508
AW
221 LPC_TIM1->TCR = 3;
222 LPC_TIM1->TCR = 1;
a157d099 223 }
aed1f6ca
JM
224 // just let it run it will fire every 143 seconds
225 // else{
226 // LPC_TIM1->TCR = 0; // disable interrupt, no point in it running if nothing to do
227 // }
a157d099 228
3b1acdaa 229 if(this->a_move_finished) {
cb2e6bc6
JM
230 this->a_move_finished= false;
231 this->do_move_finished++; // Note this is an atomic variable because it is updated in two interrupts of different priorities so can be pre-empted
3b1acdaa
JM
232 }
233
bd0f7508 234 // If a move finished in this tick, we have to tell the actuator to act accordingly
cb2e6bc6 235 if(this->do_move_finished.load() > 0){
f095cddd 236 // we delegate the slow stuff to the pendsv handler which will run as soon as this interrupt exits
16220afe
JM
237 //NVIC_SetPendingIRQ(PendSV_IRQn); this doesn't work
238 SCB->ICSR = 0x10000000; // SCB_ICSR_PENDSVSET_Msk;
bd0f7508 239 }
3b1e82d2
AW
240}
241
1fce036c
JM
242// returns index of the stepper motor in the array and bitset
243int StepTicker::register_motor(StepperMotor* motor)
244{
245 this->motor.push_back(motor);
246 this->num_motors= this->motor.size();
247 return this->num_motors-1;
248}
bd0f7508 249
1fce036c 250// activate the specified motor, must have been registered
670fa10b 251void StepTicker::add_motor_to_active_list(StepperMotor* motor)
6e0063ab 252{
1fce036c
JM
253 bool enabled= active_motor.any(); // see if interrupt was previously enabled
254 active_motor[motor->index]= 1;
255 if(!enabled) {
256 LPC_TIM0->TCR = 1; // Enable interrupt
796c9f32 257 }
796c9f32
AW
258}
259
6b080aff 260// Remove a stepper from the list of active motors
670fa10b 261void StepTicker::remove_motor_from_active_list(StepperMotor* motor)
6e0063ab 262{
1fce036c
JM
263 active_motor[motor->index]= 0;
264 // If we have no motor to work on, disable the whole interrupt
265 if(this->active_motor.none()){
266 LPC_TIM0->TCR = 0; // Disable interrupt
13256955 267 tick_cnt= 0;
796c9f32 268 }
796c9f32 269}