Fork of Smoothie to port to mbed non-LPC targets.
Fork of Smoothie by
SlowTicker.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 using namespace std; 00009 #include <vector> 00010 #include "libs/nuts_bolts.h" 00011 #include "libs/Module.h" 00012 #include "libs/Kernel.h" 00013 #include "SlowTicker.h" 00014 #include "libs/Hook.h" 00015 #include "modules/robot/Conveyor.h" 00016 00017 // This module uses a Timer to periodically call hooks 00018 // Modules register with a function ( callback ) and a frequency, and we then call that function at the given frequency. 00019 00020 SlowTicker* global_slow_ticker; 00021 00022 SlowTicker::SlowTicker(){ 00023 max_frequency = 0; 00024 global_slow_ticker = this; 00025 00026 // TODO: What is this ?? 00027 flag_1s_flag = 0; 00028 flag_1s_count = SystemCoreClock>>2; 00029 00030 g4_ticks = 0; 00031 g4_pause = false; 00032 } 00033 00034 void SlowTicker::on_module_loaded(){ 00035 register_for_event(ON_IDLE); 00036 register_for_event(ON_GCODE_RECEIVED); 00037 register_for_event(ON_GCODE_EXECUTE); 00038 } 00039 00040 // Set the base frequency we use for all sub-frequencies 00041 void SlowTicker::set_frequency( int frequency ){ 00042 this->interval = (SystemCoreClock >> 2) / frequency; // SystemCoreClock/4 = Timer increments in a second 00043 flag_1s_count= SystemCoreClock>>2; 00044 } 00045 00046 // The actual interrupt being called by the timer, this is where work is done 00047 void SlowTicker::tick(){ 00048 00049 // Call all hooks that need to be called ( bresenham ) 00050 for (uint32_t i=0; i<this->hooks.size(); i++){ 00051 Hook* hook = this->hooks.at(i); 00052 hook->countdown -= this->interval; 00053 if (hook->countdown < 0) 00054 { 00055 hook->countdown += hook->interval; 00056 hook->call(); 00057 } 00058 } 00059 00060 // deduct tick time from secound counter 00061 flag_1s_count -= this->interval; 00062 // if a whole second has elapsed, 00063 if (flag_1s_count < 0) 00064 { 00065 // add a second to our counter 00066 flag_1s_count += SystemCoreClock >> 2; 00067 // and set a flag for idle event to pick up 00068 flag_1s_flag++; 00069 } 00070 00071 // if we're counting down a pause 00072 if (g4_ticks > 0) 00073 { 00074 // deduct tick time from timeout 00075 if (g4_ticks > interval) 00076 g4_ticks -= interval; 00077 else 00078 g4_ticks = 0; 00079 } 00080 } 00081 00082 bool SlowTicker::flag_1s(){ 00083 // atomic flag check routine 00084 // first disable interrupts 00085 __disable_irq(); 00086 // then check for a flag 00087 if (flag_1s_flag) 00088 { 00089 // if we have a flag, decrement the counter 00090 flag_1s_flag--; 00091 // re-enable interrupts 00092 __enable_irq(); 00093 // and tell caller that we consumed a flag 00094 return true; 00095 } 00096 // if no flag, re-enable interrupts and return false 00097 __enable_irq(); 00098 return false; 00099 } 00100 00101 #include "gpio.h" 00102 extern GPIO leds[]; 00103 void SlowTicker::on_idle(void*) 00104 { 00105 static uint16_t ledcnt= 0; 00106 if(THEKERNEL->use_leds) { 00107 // flash led 3 to show we are alive 00108 leds[2]= (ledcnt++ & 0x1000) ? 1 : 0; 00109 } 00110 00111 // if interrupt has set the 1 second flag 00112 if (flag_1s()) 00113 // fire the on_second_tick event 00114 THEKERNEL->call_event(ON_SECOND_TICK); 00115 00116 // if G4 has finished, release our pause 00117 if (g4_pause && (g4_ticks == 0)) 00118 { 00119 g4_pause = false; 00120 THEKERNEL->pauser->release(); 00121 } 00122 } 00123 00124 // When a G4-type gcode is received, add it to the queue so we can execute it in time 00125 void SlowTicker::on_gcode_received(void* argument){ 00126 Gcode* gcode = static_cast<Gcode*>(argument); 00127 // Add the gcode to the queue ourselves if we need it 00128 if( gcode->has_g && gcode->g == 4 ){ 00129 THEKERNEL->conveyor->append_gcode(gcode); 00130 // ensure that no subsequent gcodes get executed along with our G4 00131 THEKERNEL->conveyor->queue_head_block(); 00132 } 00133 } 00134 00135 // When a G4-type gcode is executed, start the pause 00136 void SlowTicker::on_gcode_execute(void* argument){ 00137 Gcode* gcode = static_cast<Gcode*>(argument); 00138 00139 if (gcode->has_g){ 00140 if (gcode->g == 4){ 00141 gcode->mark_as_taken(); 00142 bool updated = false; 00143 if (gcode->has_letter('P')) { 00144 updated = true; 00145 g4_ticks += gcode->get_int('P') * ((SystemCoreClock >> 2) / 1000UL); 00146 } 00147 if (gcode->has_letter('S')) { 00148 updated = true; 00149 g4_ticks += gcode->get_int('S') * (SystemCoreClock >> 2); 00150 } 00151 if (updated){ 00152 // G4 Smm Pnn should pause for mm seconds + nn milliseconds 00153 // at 120MHz core clock, the longest possible delay is (2^32 / (120MHz / 4)) = 143 seconds 00154 if (!g4_pause){ 00155 g4_pause = true; 00156 THEKERNEL->pauser->take(); 00157 } 00158 } 00159 } 00160 } 00161 } 00162 00163 extern "C" void TIMER2_IRQHandler (void){ 00164 global_slow_ticker->tick(); 00165 }
Generated on Tue Jul 12 2022 20:09:02 by 1.7.2