diff --git a/README.md b/README.md index 69b60340f..c629b1e29 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,23 @@ -# Horus 3D Scanner Firmware - -This firmware is written in C. Version 0.2. +# Horus 3D Scanner Firmware for WAVGAT + ZUMSCAN boards +This firmware is derived from Horus firmware v 2.0 Derived from Grbl v0.9 by Jesús Arroyo (Mundo Reader S.L.) - Grbl's lead developer is Simen Svale Skogsrud. Sonney Jeon (Chamnit) improved some parts of grbl. +Firmware adds extra initialization code to setup WAVGAT boards. +It also should be compatible with generic arduino boards. + +This firmware get back some grbl features stripped out by Horus/Ciclop: +- multiple axis support (X,Y,Z) +- limit switches and homing +- G0, G4 G Codes support + +So you can use this firmware with your experimental hardware. + +To use second stepper on ZUMSCAN shield with this firmware it is needed to rewire two pins on the shield board: +- desolder or cut pins 6,7 on ZUMSCAN shield so they not connected to arduino +- wire 6->9, 7->10 + ## Features @@ -14,13 +26,16 @@ Grbl's lead developer is Simen Svale Skogsrud. Sonney Jeon (Chamnit) improved so * Laser modules control * Analog sensor read * Configuration interface with $ commands +* Up to 3 steppers +* Use limit switches The default baudrate is 115200. ## Implemented G Codes -* G1 - Angular movement +* G0,G1- Angular movement +* G4 - Dwell (delay) * G50 - Reset all positions to zero * M0 - Program pause * M2 - Program end and reset @@ -34,7 +49,20 @@ The default baudrate is 115200. ### Arduino -Open *horus-fw.ino*, select your board and upload. +Open *horus-fw.ino*, select your board + +Adjust configuration for your hardware: + + - axis resolution (defaults.h, section DEFAULTS_HORUS) + For Ciclop hardware with Nema-17 stepper and x16 microstepping driver + DEFAULT_X_STEPS_PER_DEG 16\*200/360 // step/deg + + - limit switches + cpu_map.h, section CPU_MAP_ATMEGA328P_ZUMSCAN: adjust limit switches pins. More detailed info in cpu_map.h + config.h: homing probe order and params HOMING_INIT_LOCK, HOMING_CYCLE_\*, N_HOMING_LOCATE_CYCLE + + +Build and upload. ### Make diff --git a/config.h b/config.h index 5eb8898e0..e217ea907 100644 --- a/config.h +++ b/config.h @@ -51,7 +51,8 @@ // Default cpu mappings. Grbl officially supports the Arduino Uno only. Other processor types // may exist from user-supplied templates or directly user-defined in cpu_map.h -#define CPU_MAP_ATMEGA328P_HORUS // Arduino Uno CPU for Horus Project +//#define CPU_MAP_ATMEGA328P_HORUS // Arduino Uno CPU for Horus Project +#define CPU_MAP_ATMEGA328P_ZUMSCAN // Define runtime command special characters. These characters are 'picked-off' directly from the // serial read data stream and are not passed to the grbl line execution parser. Select characters @@ -84,9 +85,10 @@ // on separate pin, but homed in one cycle. Also, it should be noted that the function of hard limits // will not be affected by pin sharing. // NOTE: Defaults are set for a traditional 3-axis CNC machine. Z-axis first to clear, followed by X & Y. -#define HOMING_CYCLE_0 (1< 0) { FAIL(STATUS_GCODE_COMMAND_VALUE_NOT_INTEGER); } // [Unsupported or invalid Gxx.x command] // Check for more than one command per modal group violations in the current block @@ -203,10 +211,16 @@ uint8_t gc_execute_line(char *line) words (I,J,K,L,P,R) have multiple connotations and/or depend on the issued commands. */ switch(letter){ case 'F': word_bit = WORD_F; gc_block.values.f = value; break; + case 'P': word_bit = WORD_P; gc_block.values.p = value; break; + case 'S': word_bit = WORD_S; gc_block.values.s = value; break; case 'T': word_bit = WORD_T; gc_block.values.t = int_value; break; // gc.values.t = int_value; case 'X': word_bit = WORD_X; gc_block.values.xyz[X_AXIS] = value; axis_words |= (1<. +*/ +/* + This file is based on work from Grbl v0.8, distributed under the + terms of the MIT-license. See COPYING for more details. + Copyright (c) 2009-2011 Simen Svale Skogsrud + Copyright (c) 2012 Sungeun K. Jeon +*/ + +#include "system.h" +#include "settings.h" +#include "protocol.h" +#include "planner.h" +#include "stepper.h" +#include "motion_control.h" +#include "limits.h" +#include "report.h" + +// Homing axis search distance multiplier. Computed by this value times the axis max travel. +#define HOMING_AXIS_SEARCH_SCALAR 1.5 // Must be > 1 to ensure limit switch will be engaged. + + +void limits_init() +{ + LIMIT_DDR &= ~(LIMIT_MASK); // Set as input pins + + if (bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) { + LIMIT_PORT &= ~(LIMIT_MASK); // Normal low operation. Requires external pull-down. + } else { + LIMIT_PORT |= (LIMIT_MASK); // Enable internal pull-up resistors. Normal high operation. + } + + if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) { + LIMIT_PCMSK |= LIMIT_MASK; // Enable specific pins of the Pin Change Interrupt + PCICR |= (1 << LIMIT_INT); // Enable Pin Change Interrupt + } else { + limits_disable(); + } + + #ifdef ENABLE_SOFTWARE_DEBOUNCE + MCUSR &= ~(1< settings.max_travel[idx]) { max_travel = settings.max_travel[idx]; } + } + max_travel *= -HOMING_AXIS_SEARCH_SCALAR; // Ensure homing switches engaged by over-estimating max travel. + + plan_reset(); // Reset planner buffer to zero planner current position and to clear previous motions. + + do { + // Initialize invert_pin boolean based on approach and invert pin user setting. + if (bit_isfalse(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) { invert_pin = approach; } + else { invert_pin = !approach; } + + // Initialize and declare variables needed for homing routine. + uint8_t n_active_axis = 0; + uint8_t axislock = 0; + + for (idx=0; idx 0); + + // The active cycle axes should now be homed and machine limits have been located. By + // default, grbl defines machine space as all negative, as do most CNCs. Since limit switches + // can be on either side of an axes, check and set axes machine zero appropriately. Also, + // set up pull-off maneuver from axes limit switches that have been homed. This provides + // some initial clearance off the switches and should also help prevent them from falsely + // triggering when hard limits are enabled or when more than one axes shares a limit pin. + for (idx=0; idx -settings.max_travel[idx]) { soft_limit_error = true; } + } else { + if (target[idx] > 0 || target[idx] < settings.max_travel[idx]) { soft_limit_error = true; } + } + #else + // NOTE: max_travel is stored as negative + if (target[idx] > 0 || target[idx] < settings.max_travel[idx]) { soft_limit_error = true; } + #endif + + if (soft_limit_error) { + // Force feed hold if cycle is active. All buffered blocks are guaranteed to be within + // workspace volume so just come to a controlled stop so position is not lost. When complete + // enter alarm mode. + if (sys.state == STATE_CYCLE) { + bit_true_atomic(sys.execute, EXEC_FEED_HOLD); + do { + protocol_execute_runtime(); + if (sys.abort) { return; } + } while ( sys.state != STATE_IDLE || sys.state != STATE_QUEUED); + } + + mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown. + bit_true_atomic(sys.execute, (EXEC_ALARM | EXEC_CRIT_EVENT)); // Indicate soft limit critical event + protocol_execute_runtime(); // Execute to enter critical event loop and system abort + return; + } + } +} diff --git a/limits.h b/limits.h new file mode 100644 index 000000000..6ccd70f20 --- /dev/null +++ b/limits.h @@ -0,0 +1,41 @@ +/* + limits.h - code pertaining to limit-switches and performing the homing cycle + Part of Grbl v0.9 + + Copyright (c) 2012-2014 Sungeun K. Jeon + + Grbl 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. + + Grbl 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. + + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . +*/ +/* + This file is based on work from Grbl v0.8, distributed under the + terms of the MIT-license. See COPYING for more details. + Copyright (c) 2009-2011 Simen Svale Skogsrud +*/ + +#ifndef limits_h +#define limits_h + + +// Initialize the limits module +void limits_init(); + +void limits_disable(); + +// Perform one portion of the homing cycle based on the input settings. +void limits_go_home(uint8_t cycle_mask); + +// Check for soft limit violations +void limits_soft_check(float *target); + +#endif \ No newline at end of file diff --git a/main.c b/main.c index 354258e15..7254f824b 100644 --- a/main.c +++ b/main.c @@ -35,7 +35,105 @@ #include "probe.h" #include "report.h" #include "ldr.h" +#include "limits.h" +// ----------- WAVGAT boards support --------- +/* For WAVGAT boards the manufacturer/seller provide the URL to download board specific files + * after installing this files you can select the right board in Arduino IDE (WAVGAT UNO R3) and use it normally + * + * But to compile Horus-FW you should edit + * hardware\wavgat\WAV8F\cores\lgt8f\wiring.c + * and comment out (disable) following functions: + * ISR(TIMER0_OVF_vect) + * unsigned long millis() + * unsigned long micros() + * void delay(unsigned long ms) + */ + +#if defined(ARDUINO_AVR_LARDU_328E) + +#include "lgtx8p.h" +#define NO_TIM0 + +#define INT_OSC 0 +#define EXT_OSC 1 + + + +void sysClock(uint8_t mode) +{ + if(mode == EXT_OSC) { + // enable external crystal + GPIOR0 = PMCR | 0x04; + PMCR = 0x80; + PMCR = GPIOR0; + + // waiting for crystal stable + delay(20); + + // switch to external crystal + GPIOR0 = (PMCR & 0x9f) | 0x20; + PMCR = 0x80; + PMCR = GPIOR0; + + // set to right prescale + CLKPR = 0x80; + CLKPR = 0x00; + } else if(mode == INT_OSC) { + // prescaler settings + CLKPR = 0x80; + CLKPR = 0x01; + + // switch to internal crystal + GPIOR0 = PMCR & 0x9f; + PMCR = 0x80; + PMCR = GPIOR0; + + // disable external crystal + GPIOR0 = PMCR & 0xfb; + PMCR = 0x80; + PMCR = GPIOR0; + } +} + +void lgt8fx8x_init() +{ +#if defined(__LGT8FX8E__) +// store ivref calibration + GPIOR1 = VCAL1; + GPIOR2 = VCAL2; + +#if defined(__LGT8F_SSOP20__) + GPIOR0 = PMXCR | 0x07; + PMXCR = 0x80; + PMXCR = GPIOR0; +#endif + +// enable 1KB E2PROM + ECCR = 0x80; + ECCR = 0x40; + +// clock source settings + if((VDTCR & 0x0C) == 0x0C) { + // switch to external crystal + sysClock(EXT_OSC); + } else { + CLKPR = 0x80; + CLKPR = 0x01; + } +#else + // enable 32KRC for WDT + GPIOR0 = PMCR | 0x10; + PMCR = 0x80; + PMCR = GPIOR0; + + // clock scalar to 16MHz + CLKPR = 0x80; + CLKPR = 0x01; +#endif +} + +#endif // Declare system global variable structure system_t sys; @@ -43,6 +141,10 @@ system_t sys; int main(void) { +#if defined(ARDUINO_AVR_LARDU_328E) + lgt8fx8x_init(); +#endif + // Initialize system upon power-up. serial_init(); // Setup serial baud rate and interrupts settings_init(); // Load grbl settings from EEPROM @@ -76,6 +178,7 @@ int main(void) serial_reset_read_buffer(); // Clear serial read buffer gc_init(); // Set g-code parser to default state laser_init(); + limits_init(); probe_init(); plan_reset(); // Clear block buffer and planner variables st_reset(); // Clear stepper subsystem variables. @@ -89,6 +192,7 @@ int main(void) sys.execute = 0; if (bit_istrue(settings.flags,BITFLAG_AUTO_START)) { sys.auto_start = true; } else { sys.auto_start = false; } +// sys.soft_limit = false; // Start Grbl main loop. Processes program inputs and executes them. protocol_main_loop(); diff --git a/motion_control.c b/motion_control.c index 8767bde70..83d7d550e 100644 --- a/motion_control.c +++ b/motion_control.c @@ -232,7 +232,7 @@ void mc_dwell(float seconds) } -/*// Perform homing cycle to locate and set machine zero. Only '$H' executes this command. +// Perform homing cycle to locate and set machine zero. Only '$H' executes this command. // NOTE: There should be no motions in the buffer and Grbl must be in an idle state before // executing the homing cycle. This prevents incorrect buffered plans after homing. void mc_homing_cycle() @@ -267,7 +267,7 @@ void mc_homing_cycle() // If hard limits feature enabled, re-enable hard limits pin change register after homing cycle. limits_init(); -}*/ +} // Perform tool length probe cycle. Requires probe switch. diff --git a/settings.c b/settings.c index 0a9c39899..8991d88ba 100644 --- a/settings.c +++ b/settings.c @@ -257,11 +257,11 @@ uint8_t settings_store_global_setting(uint8_t parameter, float value) { settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE; } else { settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; } break; - /*case 21: + case 21: if (int_value) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; } else { settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE; } limits_init(); // Re-init to immediately change. NOTE: Nice to have but could be problematic later. - break;*/ + break; case 22: if (int_value) { settings.flags |= BITFLAG_HOMING_ENABLE; } else { @@ -314,9 +314,12 @@ void settings_init() { // Returns step pin mask according to Grbl internal axis indexing. uint8_t get_step_pin_mask(uint8_t axis_idx) { - /*if ( axis_idx == X_AXIS ) { return((1<direction_bits & (1<steps[Y_AXIS]; #endif if (st.counter_y > st.exec_block->step_event_count) { - /*st.step_outbits |= (1<step_event_count; if (st.exec_block->direction_bits & (1<steps[Z_AXIS]; #endif if (st.counter_z > st.exec_block->step_event_count) { - /*st.step_outbits |= (1<step_event_count; if (st.exec_block->direction_bits & (1<