Merge remote-tracking branch 'upstream/edge' into upstream-master
[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;
3b1e82d2
AW
66}
67
3eadcfee 68StepTicker::~StepTicker() {
3eadcfee
JM
69}
70
dc3542cf
JM
71//called when everythinf is setup and interrupts can start
72void StepTicker::start() {
73 NVIC_EnableIRQ(TIMER0_IRQn); // Enable interrupt handler
74 NVIC_EnableIRQ(TIMER1_IRQn); // Enable interrupt handler
75 NVIC_EnableIRQ(RIT_IRQn);
76}
77
921bdb42 78// Set the base stepping frequency
1ad23cd3 79void StepTicker::set_frequency( float frequency ){
3b1e82d2 80 this->frequency = frequency;
9e089978 81 this->period = floorf((SystemCoreClock/4.0F)/frequency); // SystemCoreClock/4 = Timer increments in a second
feb204be 82 LPC_TIM0->MR0 = this->period;
3b1e82d2
AW
83 if( LPC_TIM0->TC > LPC_TIM0->MR0 ){
84 LPC_TIM0->TCR = 3; // Reset
85 LPC_TIM0->TCR = 1; // Reset
86 }
87}
88
921bdb42 89// Set the reset delay
aed1f6ca
JM
90void StepTicker::set_reset_delay( float microseconds ){
91 uint32_t delay = floorf((SystemCoreClock/4.0F)*(microseconds/1000000.0F)); // SystemCoreClock/4 = Timer increments in a second
92 LPC_TIM1->MR0 = delay;
3b1e82d2
AW
93}
94
dc3542cf 95// this is the number of acceleration ticks per second
a157d099 96void StepTicker::set_acceleration_ticks_per_second(uint32_t acceleration_ticks_per_second) {
dc3542cf
JM
97 uint32_t us= roundf(1000000.0F/acceleration_ticks_per_second); // period in microseconds
98 LPC_RIT->RICOMPVAL = (uint32_t)(((SystemCoreClock / 1000000L) * us)-1); // us
99 LPC_RIT->RICOUNTER = 0;
100 LPC_RIT->RICTRL |= (8L); // Enable rit
3b1e82d2
AW
101}
102
544a5de3 103// Synchronize the acceleration timer, and optionally schedule it to fire now
398e9edc 104void StepTicker::synchronize_acceleration(bool fire_now) {
13256955 105 LPC_RIT->RICOUNTER = 0;
398e9edc
JM
106 if(fire_now){
107 NVIC_SetPendingIRQ(RIT_IRQn);
544a5de3
JM
108 }else{
109 if(NVIC_GetPendingIRQ(RIT_IRQn)) {
110 // clear pending interrupt so it does not interrupt immediately
111 LPC_RIT->RICTRL |= 1L; // also clear the interrupt in case it fired
112 NVIC_ClearPendingIRQ(RIT_IRQn);
113 }
398e9edc 114 }
13256955
JM
115}
116
117
acf766a4 118// Call signal_move_finished() on each active motor that asked to be signaled. We do this instead of inside of tick() so that
6b080aff 119// all tick()s are called before we do the move finishing
acf766a4 120void StepTicker::signal_a_move_finished(){
001c4b26 121 for (int motor = 0; motor < num_motors; motor++){
1fce036c
JM
122 if (this->active_motor[motor] && this->motor[motor]->is_move_finished){
123 this->motor[motor]->signal_move_finished();
9e089978 124 // Theoretically this does nothing and the reason for it is currently unknown and/or forgotten
1fce036c 125 // if(this->motor[motor]->moving == false){
9e089978
JM
126 // if (motor > 0){
127 // motor--;
128 // bitmask >>= 1;
129 // }
130 // }
bd0f7508 131 }
bd0f7508 132 }
bd0f7508
AW
133}
134
aed1f6ca
JM
135// Reset step pins on any motor that was stepped
136inline void StepTicker::unstep_tick(){
1fce036c 137 for (int i = 0; i < num_motors; i++) {
aed1f6ca 138 if(this->unstep[i]){
1fce036c 139 this->motor[i]->unstep();
aed1f6ca 140 }
3b1e82d2 141 }
13256955 142 this->unstep.reset();
3b1e82d2
AW
143}
144
813727fb 145extern "C" void TIMER1_IRQHandler (void){
7b49793d 146 LPC_TIM1->IR |= 1 << 0;
aed1f6ca 147 StepTicker::global_step_ticker->unstep_tick();
813727fb
AW
148}
149
921bdb42 150// The actual interrupt handler where we do all the work
3b1e82d2 151extern "C" void TIMER0_IRQHandler (void){
2fa50ca0
JM
152 StepTicker::global_step_ticker->TIMER0_IRQHandler();
153}
b2b0b56d 154
dc3542cf
JM
155extern "C" void RIT_IRQHandler (void){
156 LPC_RIT->RICTRL |= 1L;
157 StepTicker::global_step_ticker->acceleration_tick();
158}
159
16220afe
JM
160extern "C" void PendSV_Handler(void) {
161 StepTicker::global_step_ticker->PendSV_IRQHandler();
162}
163
164// slightly lower priority than TIMER0, the whole end of block/start of block is done here allowing the timer to continue ticking
3b1acdaa
JM
165void StepTicker::PendSV_IRQHandler (void) {
166
001c4b26
JM
167 if(this->do_move_finished.load() > 0) {
168 this->do_move_finished--;
a157d099 169 #ifdef STEPTICKER_DEBUG_PIN
36307133 170 stepticker_debug_pin= 1;
a157d099 171 #endif
16220afe 172
a157d099
JM
173 this->signal_a_move_finished();
174
175 #ifdef STEPTICKER_DEBUG_PIN
36307133 176 stepticker_debug_pin= 0;
a157d099
JM
177 #endif
178 }
cb2e6bc6
JM
179}
180
c6796a29 181// run in RIT lower priority than PendSV
dc3542cf 182void StepTicker::acceleration_tick() {
dc3542cf
JM
183 // call registered acceleration handlers
184 for (size_t i = 0; i < acceleration_tick_handlers.size(); ++i) {
185 acceleration_tick_handlers[i]();
3b1acdaa 186 }
16220afe
JM
187}
188
2fa50ca0 189void StepTicker::TIMER0_IRQHandler (void){
8aea2a35 190 // Reset interrupt register
813727fb 191 LPC_TIM0->IR |= 1 << 0;
c6796a29 192 tick_cnt++; // count number of ticks
4464301d 193
cb2e6bc6 194 // 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
1fce036c 195 for (uint32_t motor = 0; motor < num_motors; motor++){
c6796a29 196 // send tick to all active motors
aed1f6ca
JM
197 if(this->active_motor[motor] && this->motor[motor]->tick()){
198 // we stepped so schedule an unstep
199 this->unstep[motor]= 1;
200 }
12800c08 201 }
4464301d 202
aed1f6ca
JM
203 // We may have set a pin on in this tick, now we reset the timer to set it off
204 // Note there could be a race here if we run another tick before the unsteps have happened,
205 // right now it takes about 3-4us but if the unstep were near 10uS or greater it would be an issue
206 // also it takes at least 2us to get here so even when set to 1us pulse width it will still be about 3us
207 if( this->unstep.any()){
bd0f7508
AW
208 LPC_TIM1->TCR = 3;
209 LPC_TIM1->TCR = 1;
a157d099 210 }
aed1f6ca
JM
211 // just let it run it will fire every 143 seconds
212 // else{
213 // LPC_TIM1->TCR = 0; // disable interrupt, no point in it running if nothing to do
214 // }
a157d099 215
3b1acdaa 216 if(this->a_move_finished) {
cb2e6bc6
JM
217 this->a_move_finished= false;
218 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
219 }
220
bd0f7508 221 // If a move finished in this tick, we have to tell the actuator to act accordingly
cb2e6bc6 222 if(this->do_move_finished.load() > 0){
f095cddd 223 // we delegate the slow stuff to the pendsv handler which will run as soon as this interrupt exits
16220afe
JM
224 //NVIC_SetPendingIRQ(PendSV_IRQn); this doesn't work
225 SCB->ICSR = 0x10000000; // SCB_ICSR_PENDSVSET_Msk;
bd0f7508 226 }
3b1e82d2
AW
227}
228
1fce036c
JM
229// returns index of the stepper motor in the array and bitset
230int StepTicker::register_motor(StepperMotor* motor)
231{
232 this->motor.push_back(motor);
233 this->num_motors= this->motor.size();
234 return this->num_motors-1;
235}
bd0f7508 236
1fce036c 237// activate the specified motor, must have been registered
670fa10b 238void StepTicker::add_motor_to_active_list(StepperMotor* motor)
6e0063ab 239{
1fce036c
JM
240 bool enabled= active_motor.any(); // see if interrupt was previously enabled
241 active_motor[motor->index]= 1;
242 if(!enabled) {
243 LPC_TIM0->TCR = 1; // Enable interrupt
796c9f32 244 }
796c9f32
AW
245}
246
6b080aff 247// Remove a stepper from the list of active motors
670fa10b 248void StepTicker::remove_motor_from_active_list(StepperMotor* motor)
6e0063ab 249{
1fce036c
JM
250 active_motor[motor->index]= 0;
251 // If we have no motor to work on, disable the whole interrupt
252 if(this->active_motor.none()){
253 LPC_TIM0->TCR = 0; // Disable interrupt
13256955 254 tick_cnt= 0;
796c9f32 255 }
796c9f32 256}