int startGrbl(void) { // Initialize system serial_init(); // Setup serial baud rate and interrupts settings_init(); // Load grbl settings from EEPROM st_init(); // Setup stepper pins and interrupt timers sei(); // Enable interrupts memset(&sys, 0, sizeof(sys)); // Clear all system variables sys.abort = true; // Set abort to complete initialization sys.state = STATE_INIT; // Set alarm state to indicate unknown initial position // Wire.begin(); for(;;) { // Execute system reset upon a system abort, where the main program will return to this loop. // Once here, it is safe to re-initialize the system. At startup, the system will automatically // reset to finish the initialization process. if (sys.abort) { // Reset system. serial_reset_read_buffer(); // Clear serial read buffer plan_init(); // Clear block buffer and planner variables gc_init(); // Set g-code parser to default state protocol_init(); // Clear incoming line data and execute startup lines spindle_init(); coolant_init(); limits_init(); st_reset(); // Clear stepper subsystem variables. syspos(&encdr_x,&encdr_y,&encdr_z); ofst_x=encdr_x; ofst_y=encdr_y; ofst_z=encdr_z; // Sync cleared gcode and planner positions to current system position, which is only // cleared upon startup, not a reset/abort. sys_sync_current_position(); // Reset system variables. sys.abort = false; sys.execute = 0; if (bit_istrue(settings.flags,BITFLAG_AUTO_START)) { sys.auto_start = true; } // Check for power-up and set system alarm if homing is enabled to force homing cycle // by setting Grbl's alarm state. Alarm locks out all g-code commands, including the // startup scripts, but allows access to settings and internal commands. Only a homing // cycle '$H' or kill alarm locks '$X' will disable the alarm. // NOTE: The startup script will run after successful completion of the homing cycle, but // not after disabling the alarm locks. Prevents motion startup blocks from crashing into // things uncontrollably. Very bad. #ifdef HOMING_INIT_LOCK if (sys.state == STATE_INIT && bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { sys.state = STATE_ALARM; } #endif // Check for and report alarm state after a reset, error, or an initial power up. if (sys.state == STATE_ALARM) { report_feedback_message(MESSAGE_ALARM_LOCK); } else { // All systems go. Set system to ready and execute startup script. sys.state = STATE_IDLE; protocol_execute_startup(); } } protocol_execute_runtime(); // syspos(&encdr_x,&encdr_y); protocol_process(); // ... process the serial protocol } return 0; /* never reached */ }
// Directs and executes one line of formatted input from protocol_process. While mostly // incoming streaming g-code blocks, this also executes Grbl internal commands, such as // settings, initiating the homing cycle, and toggling switch states. This differs from // the runtime command module by being susceptible to when Grbl is ready to execute the // next line during a cycle, so for switches like block delete, the switch only effects // the lines that are processed afterward, not necessarily real-time during a cycle, // since there are motions already stored in the buffer. However, this 'lag' should not // be an issue, since these commands are not typically used during a cycle. uint8_t protocol_execute_line(char *line) { // Grbl internal command and parameter lines are of the form '$4=374.3' or '$' for help if(line[0] == '$') { uint8_t char_counter = 1; uint8_t helper_var = 0; // Helper variable float parameter, value; switch( line[char_counter] ) { case 0 : report_grbl_help(); break; case '$' : // Prints Grbl settings if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } else { report_grbl_settings(); } break; case '#' : // Print gcode parameters if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } else { report_gcode_parameters(); } break; case 'G' : // Prints gcode parser state if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } else { report_gcode_modes(); } break; case 'C' : // Set check g-code mode if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } // Perform reset when toggling off. Check g-code mode should only work if Grbl // is idle and ready, regardless of alarm locks. This is mainly to keep things // simple and consistent. if ( sys.state == STATE_CHECK_MODE ) { mc_reset(); report_feedback_message(MESSAGE_DISABLED); } else { if (sys.state) { return(STATUS_IDLE_ERROR); } sys.state = STATE_CHECK_MODE; report_feedback_message(MESSAGE_ENABLED); } break; case 'X' : // Disable alarm lock if ( line[++char_counter] != 0 ) { return(STATUS_UNSUPPORTED_STATEMENT); } if (sys.state == STATE_ALARM) { report_feedback_message(MESSAGE_ALARM_UNLOCK); sys.state = STATE_IDLE; // Don't run startup script. Prevents stored moves in startup from causing accidents. } break; case 'H' : // Perform homing cycle if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { // Only perform homing if Grbl is idle or lost. if ( sys.state==STATE_IDLE || sys.state==STATE_ALARM ) { mc_go_home(); if (!sys.abort) { protocol_execute_startup(); } // Execute startup scripts after successful homing. } else { return(STATUS_IDLE_ERROR); } } else { return(STATUS_SETTING_DISABLED); } break; // case 'J' : break; // Jogging methods // TODO: Here jogging can be placed for execution as a seperate subprogram. It does not need to be // susceptible to other runtime commands except for e-stop. The jogging function is intended to // be a basic toggle on/off with controlled acceleration and deceleration to prevent skipped // steps. The user would supply the desired feedrate, axis to move, and direction. Toggle on would // start motion and toggle off would initiate a deceleration to stop. One could 'feather' the // motion by repeatedly toggling to slow the motion to the desired location. Location data would // need to be updated real-time and supplied to the user through status queries. // More controlled exact motions can be taken care of by inputting G0 or G1 commands, which are // handled by the planner. It would be possible for the jog subprogram to insert blocks into the // block buffer without having the planner plan them. It would need to manage de/ac-celerations // on its own carefully. This approach could be effective and possibly size/memory efficient. case 'N' : // Startup lines. if ( line[++char_counter] == 0 ) { // Print startup lines for (helper_var=0; helper_var < N_STARTUP_LINE; helper_var++) { if (!(settings_read_startup_line(helper_var, line))) { report_status_message(STATUS_SETTING_READ_FAIL); } else { report_startup_line(helper_var,line); } } break; } else { // Store startup line helper_var = true; // Set helper_var to flag storing method. // No break. Continues into default: to read remaining command characters. } default : // Storing setting methods if(!read_float(line, &char_counter, ¶meter)) { return(STATUS_BAD_NUMBER_FORMAT); } if(line[char_counter++] != '=') { return(STATUS_UNSUPPORTED_STATEMENT); } if (helper_var) { // Store startup line // Prepare sending gcode block to gcode parser by shifting all characters helper_var = char_counter; // Set helper variable as counter to start of gcode block do { line[char_counter-helper_var] = line[char_counter]; } while (line[char_counter++] != 0); // Execute gcode block to ensure block is valid. helper_var = gc_execute_line(line); // Set helper_var to returned status code. if (helper_var) { return(helper_var); } else { helper_var = trunc(parameter); // Set helper_var to int value of parameter settings_store_startup_line(helper_var,line); } } else { // Store global setting. if(!read_float(line, &char_counter, &value)) { return(STATUS_BAD_NUMBER_FORMAT); } if(line[char_counter] != 0) { return(STATUS_UNSUPPORTED_STATEMENT); } return(settings_store_global_setting(parameter, value)); } } return(STATUS_OK); // If '$' command makes it to here, then everything's ok. } else { return(gc_execute_line(line)); // Everything else is gcode } }
void jogging() // Tests jog port pins and moves steppers { uint8_t jog_bits, jog_bits_old, out_bits0, jog_exit, last_sys_state; uint8_t i, limit_state, spindle_bits; uint32_t dest_step_rate, step_rate, step_delay; // Step delay after pulse switch (sys.state) { case STATE_CYCLE: case STATE_HOMING: case STATE_INIT: LED_PORT |= (1<<LED_ERROR_BIT); return; case STATE_ALARM: case STATE_QUEUED: LED_PORT &= ~(1<<LED_ERROR_BIT); break; default: LED_PORT |= (1<<LED_ERROR_BIT); } last_sys_state = sys.state; spindle_bits = (~PINOUT_PIN) & (1<<PIN_SPIN_TOGGLE); // active low if (spindle_bits) { if (spindle_status) { // gc.spindle_direction = 0; spindle_run(0); } else { // gc.spindle_direction = 1; // also update gcode spindle status spindle_run(1); } spindle_btn_release(); delay_ms(20); } jog_bits = (~JOGSW_PIN) & JOGSW_MASK; // active low if (!jog_bits) { return; } // nothing pressed // At least one jog/joystick switch is active if (jog_bits & (1<<JOG_ZERO)) { // Zero-Button gedrückt jog_btn_release(); sys.state = last_sys_state; if (bit_isfalse(PINOUT_PIN,bit(PIN_RESET))) { // RESET und zusätzlich ZERO gedrückt: Homing if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { // Only perform homing if Grbl is idle or lost. if ( sys.state==STATE_IDLE || sys.state==STATE_ALARM ) { mc_go_home(); if (!sys.abort) { protocol_execute_startup(); } // Execute startup scripts after successful homing. } } } else { // Zero current work position sys_sync_current_position(); // gc.coord_system[i] Current work coordinate system (G54+). Stores offset from absolute machine // position in mm. Loaded from EEPROM when called. // gc.coord_offset[i] Retains the G92 coordinate offset (work coordinates) relative to // machine zero in mm. Non-persistent. Cleared upon reset and boot. for (i=0; i<=2; i++) { // Axes indices are consistent, so loop may be used. gc.coord_offset[i] = gc.position[i] - gc.coord_system[i]; } // Z-Achse um bestimmten Betrag zurückziehen mc_line(gc.position[X_AXIS], gc.position[Y_AXIS], gc.position[Z_AXIS] + (settings.z_zero_pulloff * settings.z_scale), settings.default_seek_rate, false); plan_synchronize(); // Make sure the motion completes gc.position[Z_AXIS] = gc.position[Z_AXIS] - (settings.z_zero_gauge * settings.z_scale); gc.coord_offset[Z_AXIS] = gc.position[Z_AXIS] - gc.coord_system[Z_AXIS]; // The gcode parser position circumvented by the pull-off maneuver, so sync position vectors. // Sets the planner position vector to current steps. Called by the system abort routine. // Sets g-code parser position in mm. Input in steps. Called by the system abort and hard sys_sync_current_position(); // Syncs all internal position vectors to the current system position. } return; } ADCSRA = ADCSRA_init | (1<<ADIF); //0x93, clear ADIF uint8_t reverse_flag = 0; uint8_t out_bits = 0; uint8_t jog_select = 0; out_bits0 = (0) ^ (settings.invert_mask); ADCSRA = ADCSRA_init | (1<<ADIF); //0x93, clear ADIF ADCSRA = ADCSRA_init | (1<<ADSC); //0xC3; start conversion sys.state = STATE_JOG; // check for reverse switches if (jog_bits & (1<<JOGREV_X_BIT)) { // X reverse switch on out_bits0 ^= (1<<X_DIRECTION_BIT); out_bits = out_bits0 ^ (1<<X_STEP_BIT); reverse_flag = 1; } if (jog_bits & (1<<JOGREV_Y_BIT)) { // Y reverse switch on out_bits0 ^= (1<<Y_DIRECTION_BIT); out_bits = out_bits0 ^ (1<<Y_STEP_BIT); reverse_flag = 1; jog_select = 1; } if (jog_bits & (1<<JOGREV_Z_BIT)) { // Z reverse switch on out_bits0 ^= (1<<Z_DIRECTION_BIT); out_bits = out_bits0 ^ (1<<Z_STEP_BIT); reverse_flag = 1; jog_select = 2; } // check for forward switches if (jog_bits & (1<<JOGFWD_X_BIT)) { // X forward switch on out_bits = out_bits0 ^ (1<<X_STEP_BIT); } if (jog_bits & (1<<JOGFWD_Y_BIT)) { // Y forward switch on out_bits = out_bits0 ^ (1<<Y_STEP_BIT); jog_select = 1; } if (jog_bits & (1<<JOGFWD_Z_BIT)) { // Z forward switch on out_bits = out_bits0 ^ (1<<Z_STEP_BIT); jog_select = 2; } dest_step_rate = ADCH; // set initial dest_step_rate according to analog input dest_step_rate = (dest_step_rate * JOG_SPEED_FAC) + JOG_MIN_SPEED; step_rate = JOG_MIN_SPEED; // set initial step rate jog_exit = 0; while (!(ADCSRA && (1<<ADIF))) {} // warte bis ADIF-Bit gesetzt ADCSRA = ADCSRA_init; // exit conversion st_wake_up(); // prepare direction with small delay, direction settle time STEPPING_PORT = (STEPPING_PORT & ~STEPPING_MASK) | (out_bits0 & STEPPING_MASK); delay_us(10); jog_bits_old = jog_bits; i = 0; // now index for sending position data for(;;) { // repeat until button/joystick released // report_realtime_status(); // benötigt viel Zeit! ADCSRA = ADCSRA_init | (1<<ADIF); //0x93, clear ADIF // Get limit pin state #ifdef LIMIT_SWITCHES_ACTIVE_HIGH // When in an active-high switch configuration limit_state = LIMIT_PIN; #else limit_state = LIMIT_PIN ^ LIMIT_MASK; #endif if ((limit_state & LIMIT_MASK) && reverse_flag) { jog_exit = 1; } // immediate stop jog_bits = (~JOGSW_PIN) & JOGSW_MASK; // active low if (jog_bits == jog_bits_old) { // nothing changed if (step_rate < (dest_step_rate - 5)) { // Hysterese für A/D-Wandlung step_rate += JOG_RAMP; // accellerate } if (step_rate > (dest_step_rate + 5)) { // Hysterese für A/D-Wandlung step_rate -= JOG_RAMP; // brake } } else { if (step_rate > (JOG_MIN_SPEED*2)) { // switch change happened, fast brake to complete stop step_rate = ((step_rate * 99) / 100) - 10; } else { jog_exit = 1; } // finished to stop and exit } // stop and exit if done if (jog_exit || (sys.execute & EXEC_RESET)) { st_go_idle(); sys.state = last_sys_state; sys_sync_current_position(); return; } // update position registers if (reverse_flag) { sys.position[jog_select]--; } else { sys.position[jog_select]++; } ADCSRA = ADCSRA_init | (1<<ADSC); //0xC3; start ADC conversion // Both direction and step pins appropriately inverted and set. Perform one step STEPPING_PORT = (STEPPING_PORT & ~STEPPING_MASK) | (out_bits & STEPPING_MASK); delay_us(settings.pulse_microseconds); STEPPING_PORT = (STEPPING_PORT & ~STEPPING_MASK) | (out_bits0 & STEPPING_MASK); step_delay = (1000000/step_rate) - settings.pulse_microseconds - 100; // 100 = fester Wert für Schleifenzeit if (sys.execute & EXEC_STATUS_REPORT) { // status report requested, print short msg only printPgmString(PSTR("Jog\r\n")); sys.execute = 0; } delay_us(step_delay); #ifdef JOG_SPI_PRESENT send_spi_position(i); // bei jedem Durchlauf nur eine Achse übertragen i++; if (i>2) {i=0;} #endif while (!(ADCSRA && (1<<ADIF))) {} // warte ggf. bis ADIF-Bit gesetzt ADCSRA = ADCSRA_init; // exit conversion dest_step_rate = ADCH; // set next dest_step_rate according to analog input dest_step_rate = (dest_step_rate * JOG_SPEED_FAC) + JOG_MIN_SPEED; } }
int main(void) { #ifdef PART_LM4F120H5QR // ARM code SysCtlClockSet( SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN ); //set system clock to 80 MHz FPUEnable(); //enable the Floating Point Unit // FPULazyStackingEnable(); // Enable stacking for interrupt handlers #endif // Initialize system serial_init(); // Setup serial baud rate and interrupts settings_init(); // Load grbl settings from EEPROM st_init(); // Setup stepper pins and interrupt timers #ifdef PART_LM4F120H5QR // ARM code IntMasterEnable(); #else // AVR code sei(); // Enable interrupts #endif memset(&sys, 0, sizeof(sys)); // Clear all system variables sys.abort = true; // Set abort to complete initialization sys.state = STATE_INIT; // Set alarm state to indicate unknown initial position for(;;) { // Execute system reset upon a system abort, where the main program will return to this loop. // Once here, it is safe to re-initialize the system. At startup, the system will automatically // reset to finish the initialization process. if (sys.abort) { // Reset system. serial_reset_read_buffer(); // Clear serial read buffer plan_init(); // Clear block buffer and planner variables gc_init(); // Set g-code parser to default state protocol_init(); // Clear incoming line data and execute startup lines spindle_init(); coolant_init(); limits_init(); st_reset(); // Clear stepper subsystem variables. // Sync cleared gcode and planner positions to current system position, which is only // cleared upon startup, not a reset/abort. sys_sync_current_position(); // Reset system variables. sys.abort = false; sys.execute = 0; if (bit_istrue(settings.flags,BITFLAG_AUTO_START)) { sys.auto_start = true; } // Check for power-up and set system alarm if homing is enabled to force homing cycle // by setting Grbl's alarm state. Alarm locks out all g-code commands, including the // startup scripts, but allows access to settings and internal commands. Only a homing // cycle '$H' or kill alarm locks '$X' will disable the alarm. // NOTE: The startup script will run after successful completion of the homing cycle, but // not after disabling the alarm locks. Prevents motion startup blocks from crashing into // things uncontrollably. Very bad. #ifdef HOMING_INIT_LOCK if (sys.state == STATE_INIT && bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { sys.state = STATE_ALARM; } #endif // Check for and report alarm state after a reset, error, or an initial power up. if (sys.state == STATE_ALARM) { report_feedback_message(MESSAGE_ALARM_LOCK); } else { // All systems go. Set system to ready and execute startup script. sys.state = STATE_IDLE; protocol_execute_startup(); } } protocol_execute_runtime(); protocol_process(); // ... process the serial protocol // When the serial protocol returns, there are no more characters in the serial read buffer to // be processed and executed. This indicates that individual commands are being issued or // streaming is finished. In either case, auto-cycle start, if enabled, any queued moves. if (sys.auto_start) { st_cycle_start(); } } // return 0; /* never reached */ }