Ejemplo n.º 1
0
void spindle_run(int8_t direction) //, uint16_t rpm) 
{
  if (direction != current_direction) {
    plan_synchronize();
    if (direction) {
      if(direction > 0) {
#ifdef RASPBERRYPI
#else
        SPINDLE_DIRECTION_PORT &= ~(1<<SPINDLE_DIRECTION_BIT);
#endif
      } else {
#ifdef RASPBERRYPI
#else
        SPINDLE_DIRECTION_PORT |= 1<<SPINDLE_DIRECTION_BIT;
#endif
      }
#ifdef RASPBERRYPI
#else
      SPINDLE_ENABLE_PORT |= 1<<SPINDLE_ENABLE_BIT;
#endif
    } else {
      spindle_stop();     
    }
    current_direction = direction;
  }
}
void spindle_init()
{
    current_direction = 0;
    SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT);
    SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT);
    spindle_stop();
}
Ejemplo n.º 3
0
void spindle_run(uint8_t direction, float rpm) 
{
  if (sys.state == STATE_CHECK_MODE) { return; }
  
  // Empty planner buffer to ensure spindle is set when programmed.
  protocol_auto_cycle_start();  //temp fix for M3 lockup
  protocol_buffer_synchronize(); 
  
  if (direction == SPINDLE_DISABLE) {

    spindle_stop();

  } else {
	#ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN

    if (direction == SPINDLE_ENABLE_CW) {
      SPINDLE_DIRECTION_PORT &= ~(1<<SPINDLE_DIRECTION_BIT);
    } else {
      SPINDLE_DIRECTION_PORT |= (1<<SPINDLE_DIRECTION_BIT);
    }
	#endif
	
	#ifdef VARIABLE_SPINDLE
   
      // TODO: Install the optional capability for frequency-based output for servos.
      #define SPINDLE_RPM_RANGE (SPINDLE_MAX_RPM-SPINDLE_MIN_RPM)
      #define RC_SERVO_RANGE (RC_SERVO_LONG-RC_SERVO_SHORT)
	  
	  #ifdef CPU_MAP_ATMEGA2560
      	TCCRA_REGISTER = (1<<COMB_BIT) | (1<<WAVE1_REGISTER) | (1<<WAVE0_REGISTER);
        TCCRB_REGISTER = (TCCRB_REGISTER & 0b11111000) | 0x07 | (1<<WAVE2_REGISTER) | (1<<WAVE3_REGISTER); // set to 1/1024 Prescaler
        OCR4A = 0xFFFF; // set the top 16bit value
        uint16_t current_pwm;
	  #else
        TCCRA_REGISTER = (1<<COMB_BIT) | (1<<WAVE1_REGISTER) | (1<<WAVE0_REGISTER);
        TCCRB_REGISTER = (TCCRB_REGISTER & 0b11111000) | 0x07; // set to 1/1024 Prescaler
	    uint8_t current_pwm;
	  #endif

	   if ( rpm < SPINDLE_MIN_RPM ) { rpm = 0; } 
      else { 
        rpm -= SPINDLE_MIN_RPM; 
        if ( rpm > SPINDLE_RPM_RANGE ) { rpm = SPINDLE_RPM_RANGE; } // Prevent integer overflow
      }
	  
      #ifdef RC_SERVO_INVERT 
          current_pwm = floor( RC_SERVO_LONG - rpm*(RC_SERVO_RANGE/SPINDLE_RPM_RANGE));
          OCR_REGISTER = current_pwm;
      #else
         current_pwm = floor( rpm*(RC_SERVO_RANGE/SPINDLE_RPM_RANGE) + RC_SERVO_SHORT);
          OCR_REGISTER = current_pwm;
      #endif    
	  #ifdef MINIMUM_SPINDLE_PWM
        if (current_pwm < MINIMUM_SPINDLE_PWM) { current_pwm = MINIMUM_SPINDLE_PWM; }
	     OCR_REGISTER = current_pwm;
      #endif 
    #endif  
  }
}
Ejemplo n.º 4
0
void spindle_init(void) {
  current_direction = SPINDLE_STOP;
  host_gpio_direction(SPINDLE_ENABLE, HOST_GPIO_DIRECTION_OUTPUT, HOST_GPIO_MODE_BIT);
  #ifdef SPINDLE_DIRECTION
    host_gpio_direction(SPINDLE_DIRECTION, HOST_GPIO_DIRECTION_OUTPUT, HOST_GPIO_MODE_BIT);
  #endif
  spindle_stop();
}
Ejemplo n.º 5
0
// Executes run-time commands, when required. This is called from various check points in the main
// program, primarily where there may be a while loop waiting for a buffer to clear space or any
// point where the execution time from the last check point may be more than a fraction of a second.
// This is a way to execute runtime commands asynchronously (aka multitasking) with grbl's g-code
// parsing and planning functions. This function also serves as an interface for the interrupts to
// set the system runtime flags, where only the main program to handles them, removing the need to
// define more computationally-expensive volatile variables.
// NOTE: The sys.execute variable flags are set by the serial read subprogram, except where noted.
void protocol_execute_runtime()
{
// evaluate emergency stop -cm
  if (!(AUX_PIN & (1<<AUX_STOP_BIT)))
    {
      if (!(sys.execute & EXEC_RESET)) { // Force stop only first time.
        st_go_idle();
        spindle_stop();
        sys.execute |= EXEC_RESET; // Set as true
      }
    }


  if (sys.execute) { // Enter only if any bit flag is true
    uint8_t rt_exec = sys.execute; // Avoid calling volatile multiple times

    // System abort. Steppers have already been force stopped.
    if (rt_exec & EXEC_RESET) {
      sys.abort = true;
      return; // Nothing else to do but exit.
    }

    // Execute and serial print status
    if (rt_exec & EXEC_STATUS_REPORT) {
      protocol_status_report();
      bit_false(sys.execute,EXEC_STATUS_REPORT);
    }

    // Execute and serial print switches
    if (rt_exec & EXEC_SWITCH_REPORT) {
      protocol_switch_report();
      bit_false(sys.execute,EXEC_SWITCH_REPORT);
    }

    // Initiate stepper feed hold
    if (rt_exec & EXEC_FEED_HOLD) {
      st_feed_hold(); // Initiate feed hold.
      bit_false(sys.execute,EXEC_FEED_HOLD);
    }

    // Reinitializes the stepper module running flags and re-plans the buffer after a feed hold.
    // NOTE: EXEC_CYCLE_STOP is set by the stepper subsystem when a cycle or feed hold completes.
    if (rt_exec & EXEC_CYCLE_STOP) {
      st_cycle_reinitialize();
      bit_false(sys.execute,EXEC_CYCLE_STOP);
    }

    if (rt_exec & EXEC_CYCLE_START) {
      st_cycle_start(); // Issue cycle start command to stepper subsystem
      #ifdef CYCLE_AUTO_START
        sys.auto_start = true; // Re-enable auto start after feed hold.
      #endif
      bit_false(sys.execute,EXEC_CYCLE_START);
    }
  }
}
Ejemplo n.º 6
0
void spindle_init()
{
  current_direction = 0;
#ifdef RASPBERRYPI
#else
  SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT);
  SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT);  
#endif
  spindle_stop();
}
void spindle_init()
{
    // On the Uno, spindle enable and PWM are shared. Other CPUs have seperate enable pin.
#ifdef VARIABLE_SPINDLE
    SPINDLE_PWM_DDR |= (1<<SPINDLE_PWM_BIT); // Configure as PWM output pin.
#ifndef CPU_MAP_ATMEGA328P
    SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT); // Configure as output pin.
#endif
#else
    SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT); // Configure as output pin.
#endif
    SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT); // Configure as output pin.
    spindle_stop();
}
Ejemplo n.º 8
0
void spindle_run(int8_t direction) {
  /* If we need to change state, we must wait for all moves to complete before
   * doing so. */
  if(direction != current_direction) {
    plan_synchronize();
    if(direction != SPINDLE_STOP) {
      #ifdef SPINDLE_DIRECTION
        if(direction == SPINDLE_CW)
          host_gpio_write(SPINDLE_DIRECTION, false, HOST_GPIO_MODE_BIT);
        else host_gpio_write(SPINDLE_DIRECTION, true, HOST_GPIO_MODE_BIT);
      #endif
      host_gpio_write(SPINDLE_ENABLE, true, HOST_GPIO_MODE_BIT);
    } else spindle_stop();
    current_direction = direction;
  }
}
void spindle_run(int8_t direction) //, uint16_t rpm)
{
    if (direction != current_direction) {
        plan_synchronize();
        if (direction) {
            if(direction > 0) {
                SPINDLE_DIRECTION_PORT &= ~(1<<SPINDLE_DIRECTION_BIT);
            } else {
                SPINDLE_DIRECTION_PORT |= 1<<SPINDLE_DIRECTION_BIT;
            }
            SPINDLE_ENABLE_PORT |= 1<<SPINDLE_ENABLE_BIT;
        } else {
            spindle_stop();
        }
        current_direction = direction;
    }
}
void spindle_run(uint8_t direction, float rpm)
{
    if (sys.state == STATE_CHECK_MODE) {
        return;
    }

    // Empty planner buffer to ensure spindle is set when programmed.
    protocol_auto_cycle_start();  //temp fix for M3 lockup
    protocol_buffer_synchronize();

    // Halt or set spindle direction and rpm.
    if (direction == SPINDLE_DISABLE) {

        spindle_stop();

    } else {

        if (direction == SPINDLE_ENABLE_CW) {
            SPINDLE_DIRECTION_PORT &= ~(1<<SPINDLE_DIRECTION_BIT);
        } else {
            SPINDLE_DIRECTION_PORT |= (1<<SPINDLE_DIRECTION_BIT);
        }

#ifdef VARIABLE_SPINDLE
#define SPINDLE_RPM_RANGE (SPINDLE_MAX_RPM-SPINDLE_MIN_RPM)
        TCCRA_REGISTER = (1<<COMB_BIT) | (1<<WAVE1_REGISTER) | (1<<WAVE0_REGISTER);
        TCCRB_REGISTER = (TCCRB_REGISTER & 0b11111000) | 0x02; // set to 1/8 Prescaler
        rpm -= SPINDLE_MIN_RPM;
        if ( rpm > SPINDLE_RPM_RANGE ) {
            rpm = SPINDLE_RPM_RANGE;    // Prevent uint8 overflow
        }
        uint8_t current_pwm = floor( rpm*(255.0/SPINDLE_RPM_RANGE) + 0.5);
        OCR_REGISTER = current_pwm;

#ifndef CPU_MAP_ATMEGA328P // On the Uno, spindle enable and PWM are shared.
        SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT);
#endif
#else
        SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT);
#endif

    }
}
Ejemplo n.º 11
0
void spindle_init()
{    
  // Configure variable spindle PWM and enable pin, if requried. On the Uno, PWM and enable are
  // combined unless configured otherwise.
  #ifdef VARIABLE_SPINDLE
    SPINDLE_PWM_DDR |= (1<<SPINDLE_PWM_BIT); // Configure as PWM output pin.
    #if defined(CPU_MAP_ATMEGA2560) || defined(USE_SPINDLE_DIR_AS_ENABLE_PIN)
      SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT); // Configure as output pin.
    #endif     
  // Configure no variable spindle and only enable pin.
  #else  
    SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT); // Configure as output pin.
  #endif
  
  #ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN
    SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT); // Configure as output pin.
  #endif
  spindle_stop();
}
Ejemplo n.º 12
0
// Method to ready the system to reset by setting the runtime reset command and killing any
// active processes in the system. This also checks if a system reset is issued while Grbl
// is in a motion state. If so, kills the steppers and sets the system alarm to flag position
// lost, since there was an abrupt uncontrolled deceleration. Called at an interrupt level by
// runtime abort command and hard limits. So, keep to a minimum.
void mc_reset()
{
  // Only this function can set the system reset. Helps prevent multiple kill calls.
  if (bit_isfalse(sys.execute, EXEC_RESET)) {
    bit_true_atomic(sys.execute, EXEC_RESET);

    // Kill spindle and coolant.
    spindle_stop();
    coolant_stop();

    // Kill steppers only if in any motion state, i.e. cycle, feed hold, homing, or jogging
    // NOTE: If steppers are kept enabled via the step idle delay setting, this also keeps
    // the steppers enabled by avoiding the go_idle call altogether, unless the motion state is
    // violated, by which, all bets are off.
    if (sys.state & (STATE_CYCLE | STATE_HOLD | STATE_HOMING)) {
      bit_true_atomic(sys.execute, EXEC_ALARM); // Flag main program to execute alarm state.
      st_go_idle(); // Force kill steppers. Position has likely been lost.
    }
  }
}
Ejemplo n.º 13
0
// Method to ready the system to reset by setting the runtime reset command and killing any
// active processes in the system. This also checks if a system reset is issued while Grbl
// is in a motion state. If so, kills the steppers and sets the system alarm to flag position
// lost, since there was an abrupt uncontrolled deceleration. Called at an interrupt level by
// runtime abort command and hard limits. So, keep to a minimum.
void mc_reset()
{
  // Only this function can set the system reset. Helps prevent multiple kill calls.
  if (bit_isfalse(sys.execute, EXEC_RESET)) {
    sys.execute |= EXEC_RESET;

    // Kill spindle and coolant.   
    spindle_stop();
    coolant_stop();

    // Kill steppers only if in any motion state, i.e. cycle, feed hold, homing, or jogging
    // NOTE: If steppers are kept enabled via the step idle delay setting, this also keeps
    // the steppers enabled by avoiding the go_idle call altogether, unless the motion state is
    // violated, by which, all bets are off.
    switch (sys.state) {
      case STATE_CYCLE: case STATE_HOLD: case STATE_HOMING: // case STATE_JOG:
        sys.execute |= EXEC_ALARM; // Execute alarm state.
        st_go_idle(); // Execute alarm force kills steppers. Position likely lost.
    }
  }
}
Ejemplo n.º 14
0
// Method to ready the system to reset by setting the realtime reset command and killing any
// active processes in the system. This also checks if a system reset is issued while Grbl
// is in a motion state. If so, kills the steppers and sets the system alarm to flag position
// lost, since there was an abrupt uncontrolled deceleration. Called at an interrupt level by
// realtime abort command and hard limits. So, keep to a minimum.
void mc_reset()
{
  // Only this function can set the system reset. Helps prevent multiple kill calls.
  if (bit_isfalse(sys_rt_exec_state, EXEC_RESET)) {
    bit_true_atomic(sys_rt_exec_state, EXEC_RESET);

    // Kill spindle and coolant.   
    spindle_stop();
    coolant_stop();

    // Kill steppers only if in any motion state, i.e. cycle, actively holding, or homing.
    // NOTE: If steppers are kept enabled via the step idle delay setting, this also keeps
    // the steppers enabled by avoiding the go_idle call altogether, unless the motion state is
    // violated, by which, all bets are off.
    if ((sys.state & (STATE_CYCLE | STATE_HOMING)) || (sys.suspend == SUSPEND_ENABLE_HOLD)) {
      if (sys.state == STATE_HOMING) { bit_true_atomic(sys_rt_exec_alarm, EXEC_ALARM_HOMING_FAIL); }
      else { bit_true_atomic(sys_rt_exec_alarm, EXEC_ALARM_ABORT_CYCLE); }
      st_go_idle(); // Force kill steppers. Position has likely been lost.
    }
  }
}
Ejemplo n.º 15
0
// Method to ready the system to reset by setting the realtime reset command and killing any
// active processes in the system. This also checks if a system reset is issued while Grbl
// is in a motion state. If so, kills the steppers and sets the system alarm to flag position
// lost, since there was an abrupt uncontrolled deceleration. Called at an interrupt level by
// realtime abort command and hard limits. So, keep to a minimum.
void mc_reset()
{
  // Only this function can set the system reset. Helps prevent multiple kill calls.
  if (bit_isfalse(sys_rt_exec_state, EXEC_RESET)) {
    system_set_exec_state_flag(EXEC_RESET);

    // Kill spindle and coolant.
    spindle_stop();
    coolant_stop();

    // Kill steppers only if in any motion state, i.e. cycle, actively holding, or homing.
    // NOTE: If steppers are kept enabled via the step idle delay setting, this also keeps
    // the steppers enabled by avoiding the go_idle call altogether, unless the motion state is
    // violated, by which, all bets are off.
    if ((sys.state & (STATE_CYCLE | STATE_HOMING | STATE_JOG)) ||
    		(sys.step_control & (STEP_CONTROL_EXECUTE_HOLD | STEP_CONTROL_EXECUTE_SYS_MOTION))) {
      if (sys.state == STATE_HOMING) { 
        if (!sys_rt_exec_alarm) {system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_RESET); }
      } else { system_set_exec_alarm(EXEC_ALARM_ABORT_CYCLE); }
      st_go_idle(); // Force kill steppers. Position has likely been lost.
    }
  }
}
Ejemplo n.º 16
0
// Executes one line of 0-terminated G-Code. The line is assumed to contain only uppercase
// characters and signed floating point values (no whitespace).
uint8_t gc_execute_line(char *line)
{
    int char_counter = 0;
    char letter;
    double value;
    double unit_converted_value;
    double inverse_feed_rate = -1;	// negative inverse_feed_rate means no inverse_feed_rate specified
    int radius_mode = FALSE;

    uint8_t absolute_override = FALSE;	/* 1 = absolute motion for this block only {G53} */
    uint8_t next_action = NEXT_ACTION_DEFAULT;	/* The action that will be taken by the parsed line */

    double target[3], offset[3];

    double p = 0, r = 0;
    int int_value;

    clear_vector(target);
    clear_vector(offset);

    gc.status_code = GCSTATUS_OK;

    // Disregard comments and block delete
    if (line[0] == '(') {
	return (gc.status_code);
    }
    if (line[0] == '/') {
	char_counter++;
    }				// ignore block delete  

    // If the line starts with an '$' it is a configuration-command
    if (line[0] == '$') {
	// Parameter lines are on the form '$4=374.3' or '$' to dump current settings
	char_counter = 1;
	if (line[char_counter] == 0) {
	    settings_dump();
	    return (GCSTATUS_OK);
	}
	read_double(line, &char_counter, &p);
	if (line[char_counter++] != '=') {
	    return (GCSTATUS_UNSUPPORTED_STATEMENT);
	}
	read_double(line, &char_counter, &value);
	if (line[char_counter] != 0) {
	    return (GCSTATUS_UNSUPPORTED_STATEMENT);
	}
	settings_store_setting(p, value);
	return (gc.status_code);
    }

    /* We'll handle this as g-code. First: parse all statements */

    // Pass 1: Commands
    while (next_statement(&letter, &value, line, &char_counter)) {
	int_value = trunc(value);
	switch (letter) {
	case 'G':
	    switch (int_value) {
	    case 0:
		gc.motion_mode = MOTION_MODE_SEEK;
		break;
	    case 1:
		gc.motion_mode = MOTION_MODE_LINEAR;
		break;
#ifndef CFG_TINY
	    case 2:
		gc.motion_mode = MOTION_MODE_CW_ARC;
		break;
	    case 3:
		gc.motion_mode = MOTION_MODE_CCW_ARC;
		break;
#endif
	    case 4:
		next_action = NEXT_ACTION_DWELL;
		break;
	    case 17:
		select_plane(X_AXIS, Y_AXIS, Z_AXIS);
		break;
	    case 18:
		select_plane(X_AXIS, Z_AXIS, Y_AXIS);
		break;
	    case 19:
		select_plane(Y_AXIS, Z_AXIS, X_AXIS);
		break;
	    case 20:
		gc.inches_mode = TRUE;
		break;
	    case 21:
		gc.inches_mode = FALSE;
		break;
	    case 28:
	    case 30:
		next_action = NEXT_ACTION_GO_HOME;
		break;
	    case 53:
		absolute_override = TRUE;
		break;
	    case 80:
		gc.motion_mode = MOTION_MODE_CANCEL;
		break;
	    case 90:
		gc.absolute_mode = TRUE;
		break;
	    case 91:
		gc.absolute_mode = FALSE;
		break;
	    case 93:
		gc.inverse_feed_rate_mode = TRUE;
		break;
	    case 94:
		gc.inverse_feed_rate_mode = FALSE;
		break;
	    default:
		FAIL(GCSTATUS_UNSUPPORTED_STATEMENT);
	    }
	    break;

	case 'M':
	    switch (int_value) {
	    case 0:
	    case 1:
		gc.program_flow = PROGRAM_FLOW_PAUSED;
		break;
	    case 2:
	    case 30:
	    case 60:
		gc.program_flow = PROGRAM_FLOW_COMPLETED;
		break;
	    case 3:
		gc.spindle_direction = 1;
		break;
	    case 4:
		gc.spindle_direction = -1;
		break;
	    case 5:
		gc.spindle_direction = 0;
		break;
	    default:
		FAIL(GCSTATUS_UNSUPPORTED_STATEMENT);
	    }
	    break;
	case 'T':
	    gc.tool = trunc(value);
	    break;
	}
	if (gc.status_code) {
	    break;
	}
    }

    // If there were any errors parsing this line, we will return right away with the bad news
    if (gc.status_code) {
	return (gc.status_code);
    }

    char_counter = 0;
    clear_vector(offset);
    memcpy(target, gc.position, sizeof(target));	// i.e. target = gc.position

    // Pass 2: Parameters
    while (next_statement(&letter, &value, line, &char_counter)) {
	int_value = trunc(value);
	unit_converted_value = to_millimeters(value);
	switch (letter) {
	case 'F':
	    if (gc.inverse_feed_rate_mode) {
		inverse_feed_rate = unit_converted_value;	// seconds per motion for this motion only
	    } else {
		if (gc.motion_mode == MOTION_MODE_SEEK) {
		    gc.seek_rate = unit_converted_value / 60;
		} else {
		    gc.feed_rate = unit_converted_value / 60;	// millimeters pr second
		}
	    }
	    break;
	case 'I':
	case 'J':
	case 'K':
	    offset[letter - 'I'] = unit_converted_value;
	    break;
	case 'P':
	    p = value;
	    break;
	case 'R':
	    r = unit_converted_value;
	    radius_mode = TRUE;
	    break;
	case 'S':
	    gc.spindle_speed = value;
	    break;
	case 'X':
	case 'Y':
	case 'Z':
	    if (gc.absolute_mode || absolute_override) {
		target[letter - 'X'] = unit_converted_value;
	    } else {
		target[letter - 'X'] += unit_converted_value;
	    }
	    break;
	}
    }

    // If there were any errors parsing this line, we will return right away with the bad news
    if (gc.status_code) {
	return (gc.status_code);
    }
    // Update spindle state
    if (gc.spindle_direction) {
	spindle_run(gc.spindle_direction, gc.spindle_speed);
    } else {
	spindle_stop();
    }

    // Perform any physical actions
    switch (next_action) {
    case NEXT_ACTION_GO_HOME:
	mc_go_home();
	break;
    case NEXT_ACTION_DWELL:
	mc_dwell(trunc(p * 1000));
	break;
    case NEXT_ACTION_DEFAULT:
	switch (gc.motion_mode) {
	case MOTION_MODE_CANCEL:
	    break;
	case MOTION_MODE_SEEK:
	    mc_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS],
		    gc.seek_rate, FALSE);
	    break;
	case MOTION_MODE_LINEAR:
	    mc_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS],
		    (gc.inverse_feed_rate_mode) ? inverse_feed_rate : gc.
		    feed_rate, gc.inverse_feed_rate_mode);
	    break;
#ifndef CFG_TINY
	case MOTION_MODE_CW_ARC:
	case MOTION_MODE_CCW_ARC:
	    if (radius_mode) {
		/* 
		   We need to calculate the center of the circle that has the designated radius and passes
		   through both the current position and the target position. This method calculates the following
		   set of equations where [x,y] is the vector from current to target position, d == magnitude of 
		   that vector, h == hypotenuse of the triangle formed by the radius of the circle, the distance to
		   the center of the travel vector. A vector perpendicular to the travel vector [-y,x] is scaled to the 
		   length of h [-y/d*h, x/d*h] and added to the center of the travel vector [x/2,y/2] to form the new point 
		   [i,j] at [x/2-y/d*h, y/2+x/d*h] which will be the center of our arc.

		   d^2 == x^2 + y^2
		   h^2 == r^2 - (d/2)^2
		   i == x/2 - y/d*h
		   j == y/2 + x/d*h

		   O <- [i,j]
		   -  |
		   r      -     |
		   -        |
		   -           | h
		   -              |
		   [0,0] ->  C -----------------+--------------- T  <- [x,y]
		   | <------ d/2 ---->|

		   C - Current position
		   T - Target position
		   O - center of circle that pass through both C and T
		   d - distance from C to T
		   r - designated radius
		   h - distance from center of CT to O

		   Expanding the equations:

		   d -> sqrt(x^2 + y^2)
		   h -> sqrt(4 * r^2 - x^2 - y^2)/2
		   i -> (x - (y * sqrt(4 * r^2 - x^2 - y^2)) / sqrt(x^2 + y^2)) / 2 
		   j -> (y + (x * sqrt(4 * r^2 - x^2 - y^2)) / sqrt(x^2 + y^2)) / 2

		   Which can be written:

		   i -> (x - (y * sqrt(4 * r^2 - x^2 - y^2))/sqrt(x^2 + y^2))/2
		   j -> (y + (x * sqrt(4 * r^2 - x^2 - y^2))/sqrt(x^2 + y^2))/2

		   Which we for size and speed reasons optimize to:

		   h_x2_div_d = sqrt(4 * r^2 - x^2 - y^2)/sqrt(x^2 + y^2)
		   i = (x - (y * h_x2_div_d))/2
		   j = (y + (x * h_x2_div_d))/2

		 */

		// Calculate the change in position along each selected axis
		double x =
		    target[gc.plane_axis_0] - gc.position[gc.plane_axis_0];
		double y =
		    target[gc.plane_axis_1] - gc.position[gc.plane_axis_1];

		clear_vector(offset);
		double h_x2_div_d = -sqrt(4 * r * r - x * x - y * y) / hypot(x, y);	// == -(h * 2 / d)
		// If r is smaller than d, the arc is now traversing the complex plane beyond the reach of any
		// real CNC, and thus - for practical reasons - we will terminate promptly:
		if (isnan(h_x2_div_d)) {
		    FAIL(GCSTATUS_FLOATING_POINT_ERROR);
		    return (gc.status_code);
		}
		// Invert the sign of h_x2_div_d if the circle is counter clockwise (see sketch below)
		if (gc.motion_mode == MOTION_MODE_CCW_ARC) {
		    h_x2_div_d = -h_x2_div_d;
		}

		/* The counter clockwise circle lies to the left of the target direction. When offset is positive,
		   the left hand circle will be generated - when it is negative the right hand circle is generated.


		   T  <-- Target position

		   ^ 
		   Clockwise circles with this center         |          Clockwise circles with this center will have
		   will have > 180 deg of angular travel      |          < 180 deg of angular travel, which is a good thing!
		   \         |          /   
		   center of arc when h_x2_div_d is positive ->  x <----- | -----> x <- center of arc when h_x2_div_d is negative
		   |
		   |

		   C  <-- Current position                                 */


		// Negative R is g-code-alese for "I want a circle with more than 180 degrees of travel" (go figure!), 
		// even though it is advised against ever generating such circles in a single line of g-code. By 
		// inverting the sign of h_x2_div_d the center of the circles is placed on the opposite side of the line of
		// travel and thus we get the unadvisably long arcs as prescribed.
		if (r < 0) {
		    h_x2_div_d = -h_x2_div_d;
		}
		// Complete the operation by calculating the actual center of the arc
		offset[gc.plane_axis_0] = (x - (y * h_x2_div_d)) / 2;
		offset[gc.plane_axis_1] = (y + (x * h_x2_div_d)) / 2;
	    }

	    /*
	       This segment sets up an clockwise or counterclockwise arc from the current position to the target position around 
	       the center designated by the offset vector. All theta-values measured in radians of deviance from the positive 
	       y-axis. 

	       | <- theta == 0
	       * * *                
	       *       *                                               
	       *           *                                             
	       *     O ----T   <- theta_end (e.g. 90 degrees: theta_end == PI/2)                                          
	       *   /                                                     
	       C   <- theta_start (e.g. -145 degrees: theta_start == -PI*(3/4))

	     */

	    // calculate the theta (angle) of the current point
	    double theta_start =
		theta(-offset[gc.plane_axis_0], -offset[gc.plane_axis_1]);
	    // calculate the theta (angle) of the target point
	    double theta_end =
		theta(target[gc.plane_axis_0] - offset[gc.plane_axis_0] -
		      gc.position[gc.plane_axis_0],
		      target[gc.plane_axis_1] - offset[gc.plane_axis_1] -
		      gc.position[gc.plane_axis_1]);
	    // ensure that the difference is positive so that we have clockwise travel
	    if (theta_end < theta_start) {
		theta_end += 2 * M_PI;
	    }
	    double angular_travel = theta_end - theta_start;
	    // Invert angular motion if the g-code wanted a counterclockwise arc
	    if (gc.motion_mode == MOTION_MODE_CCW_ARC) {
		angular_travel = angular_travel - 2 * M_PI;
	    }
	    // Find the radius
	    double radius =
		hypot(offset[gc.plane_axis_0], offset[gc.plane_axis_1]);
	    // Calculate the motion along the depth axis of the helix
	    double depth =
		target[gc.plane_axis_2] - gc.position[gc.plane_axis_2];
	    // Trace the arc
	    mc_arc(theta_start, angular_travel, radius, depth,
		   gc.plane_axis_0, gc.plane_axis_1, gc.plane_axis_2,
		   (gc.inverse_feed_rate_mode) ? inverse_feed_rate : gc.
		   feed_rate, gc.inverse_feed_rate_mode, gc.position);
	    // Finish off with a line to make sure we arrive exactly where we think we are
	    mc_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS],
		    (gc.inverse_feed_rate_mode) ? inverse_feed_rate : gc.
		    feed_rate, gc.inverse_feed_rate_mode);
	    break;
#endif
	}
    }

    // As far as the parser is concerned, the position is now == target. In reality the
    // motion control system might still be processing the action and the real tool position
    // in any intermediate location.
    memcpy(gc.position, target, sizeof(double) * 3);	// gc.position[] = target[];
    return (gc.status_code);
}
Ejemplo n.º 17
0
void spindle_set_state(uint8_t state, float rpm)
{
  // Halt or set spindle direction and rpm.
  spindle_status = state; // for jog controller
  if (state == SPINDLE_DISABLE) {

    spindle_stop();

  } else {

    #ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN
      if (state == SPINDLE_ENABLE_CW) {
        SPINDLE_DIRECTION_PORT &= ~(1<<SPINDLE_DIRECTION_BIT);
      } else {
        SPINDLE_DIRECTION_PORT |= (1<<SPINDLE_DIRECTION_BIT);
      }
    #endif

    #ifdef VARIABLE_SPINDLE
      // TODO: Install the optional capability for frequency-based output for servos.
      #ifdef CPU_MAP_ATMEGA2560
      	TCCRA_REGISTER = (1<<COMB_BIT) | (1<<WAVE1_REGISTER) | (1<<WAVE0_REGISTER);
        TCCRB_REGISTER = (TCCRB_REGISTER & 0b11111000) | 0x02 | (1<<WAVE2_REGISTER) | (1<<WAVE3_REGISTER); // set to 1/8 Prescaler
        OCR4A = 0xFFFF; // set the top 16bit value
        uint16_t current_pwm;
      #else
        TCCRA_REGISTER = (1<<COMB_BIT) | (1<<WAVE1_REGISTER) | (1<<WAVE0_REGISTER);
        TCCRB_REGISTER = (TCCRB_REGISTER & 0b11111000) | 0x02; // set to 1/8 Prescaler
        uint8_t current_pwm;
      #endif

      #define SPINDLE_RPM_RANGE (SPINDLE_MAX_RPM-SPINDLE_MIN_RPM)
      if ( rpm < SPINDLE_MIN_RPM ) { rpm = 0; } 
      else { 
        rpm -= SPINDLE_MIN_RPM; 
        if ( rpm > SPINDLE_RPM_RANGE ) { rpm = SPINDLE_RPM_RANGE; } // Prevent integer overflow
      }
      current_pwm = floor( rpm*(PWM_MAX_VALUE/SPINDLE_RPM_RANGE) + 0.5);
      #ifdef MINIMUM_SPINDLE_PWM
        if (current_pwm < MINIMUM_SPINDLE_PWM) { current_pwm = MINIMUM_SPINDLE_PWM; }
      #endif
      OCR_REGISTER = current_pwm; // Set PWM pin output
    
      // On the Uno, spindle enable and PWM are shared, unless otherwise specified.
      #if defined(CPU_MAP_ATMEGA2560) || defined(USE_SPINDLE_DIR_AS_ENABLE_PIN) 
        #ifdef INVERT_SPINDLE_ENABLE_PIN
          SPINDLE_ENABLE_PORT &= ~(1<<SPINDLE_ENABLE_BIT);
        #else
          SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT);
        #endif
      #endif
      
    #else   
      #ifdef INVERT_SPINDLE_ENABLE_PIN
		SPINDLE_ENABLE_PORT &= ~(1<<SPINDLE_ENABLE_BIT);
	  #else
		SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT);
	  #endif
    #endif

  }
}
Ejemplo n.º 18
0
// A helper method to set settings from command line
void settings_store_setting(int parameter, double value) {
  switch(parameter) {
	case 0: case 1: case 2:   // X, Y, Z
        if (value <= 0.0) {
          printPgmString(PSTR("Steps/mm must be > 0.0\r\n"));
          return;
        }
        settings.steps_per_mm[parameter] = value;
        break;
    case 3 :   // axe T : linear -> U or V or W,  rotary -> A or B or C
		if (value <= 0.0) {
	#if AXIS_T_TYPE == LINEAR
			printPgmString(PSTR("Steps/mm must be > 0.0\r\n"));
    #else
			printPgmString(PSTR("Steps/degree must be > 0.0\r\n"));
    #endif
          return;
        }
    #if AXIS_T_TYPE == LINEAR
        settings.steps_per_mm[parameter] = value;
    #else
		settings.steps_per_degree[parameter] = value;
    #endif

		break;
    case 4:
        if (value < 3) {
            printPgmString(PSTR("Step pulse must be >= 3 microseconds\r\n"));
            return;
        }
        settings.pulse_microseconds = round(value);
        break;
    case 5:
        settings.default_feed_rate = value;
        break;
    case 6:
        settings.default_seek_rate = value;
        break;
    case 7:
        settings.mm_per_arc_segment = value;
        break;
    case 8:
        settings.invert_mask_stepdir = trunc(value);
        break;
    case 9:
        settings.invert_mask_limit = trunc(value);
        break;
    case 10:
        settings.acceleration = value*60*60;
        break; // Convert to mm/min^2 for grbl internal use.
    case 11:
        settings.junction_deviation = fabs(value);
        break;
    case 12:
        settings.spindle_pwm = value;
        break;
    case 13:
        settings.default_spindle = value;
        break;
    case 14:
        settings.max_spindle = value;
        break;
    case 1000:
    	value ? st_enable(): st_disable();
    	if (!value) {
    		coolant_stop();
    		spindle_stop();
    	}
    	return;
        break;
    default:
      printPgmString(PSTR("Unknown parameter\r\n"));
      return;
  }
  write_settings();
  printPgmString(PSTR("Stored new setting\r\n"));
}
Ejemplo n.º 19
0
// Executes run-time commands, when required. This is called from various check points in the main
// program, primarily where there may be a while loop waiting for a buffer to clear space or any
// point where the execution time from the last check point may be more than a fraction of a second.
// This is a way to execute realtime commands asynchronously (aka multitasking) with grbl's g-code
// parsing and planning functions. This function also serves as an interface for the interrupts to 
// set the system realtime flags, where only the main program handles them, removing the need to
// define more computationally-expensive volatile variables. This also provides a controlled way to 
// execute certain tasks without having two or more instances of the same task, such as the planner
// recalculating the buffer upon a feedhold or override.
// NOTE: The sys_rt_exec_state variable flags are set by any process, step or serial interrupts, pinouts,
// limit switches, or the main program.
void protocol_execute_realtime()
{
  uint8_t rt_exec; // Temp variable to avoid calling volatile multiple times.

  do { // If system is suspended, suspend loop restarts here.
    
  // Check and execute alarms. 
  rt_exec = sys_rt_exec_alarm; // Copy volatile sys_rt_exec_alarm.
  if (rt_exec) { // Enter only if any bit flag is true
    // System alarm. Everything has shutdown by something that has gone severely wrong. Report
    // the source of the error to the user. If critical, Grbl disables by entering an infinite
    // loop until system reset/abort.
    sys.state = STATE_ALARM; // Set system alarm state
    if (rt_exec & EXEC_ALARM_HARD_LIMIT) {
      report_alarm_message(ALARM_HARD_LIMIT_ERROR); 
    } else if (rt_exec & EXEC_ALARM_SOFT_LIMIT) {
      report_alarm_message(ALARM_SOFT_LIMIT_ERROR);
    } else if (rt_exec & EXEC_ALARM_ABORT_CYCLE) {      
      report_alarm_message(ALARM_ABORT_CYCLE);
    } else if (rt_exec & EXEC_ALARM_PROBE_FAIL) {
      report_alarm_message(ALARM_PROBE_FAIL);
    } else if (rt_exec & EXEC_ALARM_HOMING_FAIL) {
      report_alarm_message(ALARM_HOMING_FAIL);
    }
    // Halt everything upon a critical event flag. Currently hard and soft limits flag this.
    if (rt_exec & EXEC_CRITICAL_EVENT) {
      report_feedback_message(MESSAGE_CRITICAL_EVENT);
      bit_false_atomic(sys_rt_exec_state,EXEC_RESET); // Disable any existing reset
      do { 
        // Nothing. Block EVERYTHING until user issues reset or power cycles. Hard limits
        // typically occur while unattended or not paying attention. Gives the user time
        // to do what is needed before resetting, like killing the incoming stream. The 
        // same could be said about soft limits. While the position is not lost, the incoming
        // stream could be still engaged and cause a serious crash if it continues afterwards.
        
        // TODO: Allow status reports during a critical alarm. Still need to think about implications of this.
//         if (sys_rt_exec_state & EXEC_STATUS_REPORT) { 
//           report_realtime_status();
//           bit_false_atomic(sys_rt_exec_state,EXEC_STATUS_REPORT); 
//         }
      } while (bit_isfalse(sys_rt_exec_state,EXEC_RESET));
    }
    bit_false_atomic(sys_rt_exec_alarm,0xFF); // Clear all alarm flags
  }
  
  // Check amd execute realtime commands
  rt_exec = sys_rt_exec_state; // Copy volatile sys_rt_exec_state.
  if (rt_exec) { // Enter only if any bit flag is true
  
    // Execute system abort. 
    if (rt_exec & EXEC_RESET) {
      sys.abort = true;  // Only place this is set true.
      return; // Nothing else to do but exit.
    }
    
    // Execute and serial print status
    if (rt_exec & EXEC_STATUS_REPORT) { 
      report_realtime_status();
      bit_false_atomic(sys_rt_exec_state,EXEC_STATUS_REPORT);
    }
  
    // Execute hold states.
    // NOTE: The math involved to calculate the hold should be low enough for most, if not all, 
    // operational scenarios. Once hold is initiated, the system enters a suspend state to block
    // all main program processes until either reset or resumed.
    if (rt_exec & (EXEC_MOTION_CANCEL | EXEC_FEED_HOLD | EXEC_SAFETY_DOOR)) {
      
      // TODO: CHECK MODE? How to handle this? Likely nothing, since it only works when IDLE and then resets Grbl.
                
      // State check for allowable states for hold methods.
      if ((sys.state == STATE_IDLE) || (sys.state & (STATE_CYCLE | STATE_HOMING | STATE_MOTION_CANCEL | STATE_HOLD | STATE_SAFETY_DOOR))) {

        // If in CYCLE state, all hold states immediately initiate a motion HOLD.
        if (sys.state == STATE_CYCLE) {
          st_update_plan_block_parameters(); // Notify stepper module to recompute for hold deceleration.
          sys.suspend = SUSPEND_ENABLE_HOLD; // Initiate holding cycle with flag.
        }
        // If IDLE, Grbl is not in motion. Simply indicate suspend ready state.
        if (sys.state == STATE_IDLE) { sys.suspend = SUSPEND_ENABLE_READY; }
        
        // Execute and flag a motion cancel with deceleration and return to idle. Used primarily by probing cycle
        // to halt and cancel the remainder of the motion.
        if (rt_exec & EXEC_MOTION_CANCEL) {
          // MOTION_CANCEL only occurs during a CYCLE, but a HOLD and SAFETY_DOOR may been initiated beforehand
          // to hold the CYCLE. If so, only flag that motion cancel is complete.
          if (sys.state == STATE_CYCLE) { sys.state = STATE_MOTION_CANCEL; }
          sys.suspend |= SUSPEND_MOTION_CANCEL; // Indicate motion cancel when resuming. Special motion complete.
        }
    
        // Execute a feed hold with deceleration, only during cycle.
        if (rt_exec & EXEC_FEED_HOLD) {
          // Block SAFETY_DOOR state from prematurely changing back to HOLD.
          if (bit_isfalse(sys.state,STATE_SAFETY_DOOR)) { sys.state = STATE_HOLD; }
        }
  
        // Execute a safety door stop with a feed hold, only during a cycle, and disable spindle/coolant.
        // NOTE: Safety door differs from feed holds by stopping everything no matter state, disables powered
        // devices (spindle/coolant), and blocks resuming until switch is re-engaged. The power-down is 
        // executed here, if IDLE, or when the CYCLE completes via the EXEC_CYCLE_STOP flag.
        if (rt_exec & EXEC_SAFETY_DOOR) {
          report_feedback_message(MESSAGE_SAFETY_DOOR_AJAR); 
          // If already in active, ready-to-resume HOLD, set CYCLE_STOP flag to force de-energize.
          // NOTE: Only temporarily sets the 'rt_exec' variable, not the volatile 'rt_exec_state' variable.
          if (sys.suspend & SUSPEND_ENABLE_READY) { bit_true(rt_exec,EXEC_CYCLE_STOP); }
          sys.suspend |= SUSPEND_ENERGIZE;
          sys.state = STATE_SAFETY_DOOR;
        }
         
      }
      bit_false_atomic(sys_rt_exec_state,(EXEC_MOTION_CANCEL | EXEC_FEED_HOLD | EXEC_SAFETY_DOOR));      
    }
          
    // Execute a cycle start by starting the stepper interrupt to begin executing the blocks in queue.
    if (rt_exec & EXEC_CYCLE_START) {
      // Block if called at same time as the hold commands: feed hold, motion cancel, and safety door.
      // Ensures auto-cycle-start doesn't resume a hold without an explicit user-input.
      if (!(rt_exec & (EXEC_FEED_HOLD | EXEC_MOTION_CANCEL | EXEC_SAFETY_DOOR))) { 
        // Cycle start only when IDLE or when a hold is complete and ready to resume.
        // NOTE: SAFETY_DOOR is implicitly blocked. It reverts to HOLD when the door is closed.
        if ((sys.state == STATE_IDLE) || ((sys.state & (STATE_HOLD | STATE_MOTION_CANCEL)) && (sys.suspend & SUSPEND_ENABLE_READY))) {
          // Re-energize powered components, if disabled by SAFETY_DOOR.
          if (sys.suspend & SUSPEND_ENERGIZE) { 
            // Delayed Tasks: Restart spindle and coolant, delay to power-up, then resume cycle.
            if (gc_state.modal.spindle != SPINDLE_DISABLE) { 
              spindle_set_state(gc_state.modal.spindle, gc_state.spindle_speed); 
              delay_ms(SAFETY_DOOR_SPINDLE_DELAY); // TODO: Blocking function call. Need a non-blocking one eventually.
            }
            if (gc_state.modal.coolant != COOLANT_DISABLE) { 
              coolant_set_state(gc_state.modal.coolant); 
              delay_ms(SAFETY_DOOR_COOLANT_DELAY); // TODO: Blocking function call. Need a non-blocking one eventually.
            }
            // TODO: Install return to pre-park position.
          }
          // Start cycle only if queued motions exist in planner buffer and the motion is not canceled.
          if (plan_get_current_block() && bit_isfalse(sys.suspend,SUSPEND_MOTION_CANCEL)) {
            sys.state = STATE_CYCLE;
            st_prep_buffer(); // Initialize step segment buffer before beginning cycle.
            st_wake_up();
          } else { // Otherwise, do nothing. Set and resume IDLE state.
            sys.state = STATE_IDLE;
          }
          sys.suspend = SUSPEND_DISABLE; // Break suspend state.
        }
      }    
      bit_false_atomic(sys_rt_exec_state,EXEC_CYCLE_START);
    }
    
    // Reinitializes the cycle plan and stepper system after a feed hold for a resume. Called by 
    // realtime command execution in the main program, ensuring that the planner re-plans safely.
    // NOTE: Bresenham algorithm variables are still maintained through both the planner and stepper
    // cycle reinitializations. The stepper path should continue exactly as if nothing has happened.   
    // NOTE: EXEC_CYCLE_STOP is set by the stepper subsystem when a cycle or feed hold completes.
    if (rt_exec & EXEC_CYCLE_STOP) {
      if (sys.state & (STATE_HOLD | STATE_SAFETY_DOOR)) {
        // Hold complete. Set to indicate ready to resume.  Remain in HOLD or DOOR states until user
        // has issued a resume command or reset.
        if (sys.suspend & SUSPEND_ENERGIZE) { // De-energize system if safety door has been opened.
          spindle_stop();
          coolant_stop();
          // TODO: Install parking motion here.
        }
        bit_true(sys.suspend,SUSPEND_ENABLE_READY);
      } else { // Motion is complete. Includes CYCLE, HOMING, and MOTION_CANCEL states.
        sys.suspend = SUSPEND_DISABLE;
        sys.state = STATE_IDLE;
      }
      bit_false_atomic(sys_rt_exec_state,EXEC_CYCLE_STOP);
    }
    
  }

  // Overrides flag byte (sys.override) and execution should be installed here, since they 
  // are realtime and require a direct and controlled interface to the main stepper program.

  // Reload step segment buffer
  if (sys.state & (STATE_CYCLE | STATE_HOLD | STATE_MOTION_CANCEL | STATE_SAFETY_DOOR | STATE_HOMING)) { st_prep_buffer(); }  
  
  // If safety door was opened, actively check when safety door is closed and ready to resume.
  // NOTE: This unlocks the SAFETY_DOOR state to a HOLD state, such that CYCLE_START can activate a resume.
  if (sys.state == STATE_SAFETY_DOOR) { 
    if (bit_istrue(sys.suspend,SUSPEND_ENABLE_READY)) { 
      #ifndef DEFAULTS_TRINAMIC
      if (!(system_check_safety_door_ajar())) {
        sys.state = STATE_HOLD; // Update to HOLD state to indicate door is closed and ready to resume.
      }
      #endif
    }
  }

  } while(sys.suspend); // Check for system suspend state before exiting.
  
}  
Ejemplo n.º 20
0
void spindle_set_state(uint8_t state, float rpm)
{
  if (sys.abort) { return; } // Block during abort.
  
//  // Halt or set spindle direction and rpm.
//  if (state == SPINDLE_DISABLE) {
//
//    spindle_stop();
//
//  } else {
//
//    #ifndef USE_SPINDLE_DIR_AS_ENABLE_PIN
//      if (state == SPINDLE_ENABLE_CW) {
//        SPINDLE_DIRECTION_PORT &= ~(1<<SPINDLE_DIRECTION_BIT);
//      } else {
//        SPINDLE_DIRECTION_PORT |= (1<<SPINDLE_DIRECTION_BIT);
//      }
//    #endif
//
//    #ifdef VARIABLE_SPINDLE
//
//      // TODO: Install the optional capability for frequency-based output for servos.
//      #ifdef CPU_MAP_ATMEGA2560
//        uint16_t current_pwm; // 2560 PWM register is 16-bit.
//      #else
//        uint8_t current_pwm;  // 328p PWM register is 8-bit.
//      #endif
//
//      // Calculate PWM register value based on rpm max/min settings and programmed rpm.
//      if (settings.rpm_max <= settings.rpm_min) {
//        // No PWM range possible. Set simple on/off spindle control pin state.
//        current_pwm = PWM_MAX_VALUE;
//      } else {
//        if (rpm > settings.rpm_max) { rpm = settings.rpm_max; }
//        if (rpm < settings.rpm_min) { rpm = settings.rpm_min; }
//        #ifdef SPINDLE_MINIMUM_PWM
//          float pwm_gradient = (PWM_MAX_VALUE-SPINDLE_MINIMUM_PWM)/(settings.rpm_max-settings.rpm_min);
//          current_pwm = floor( (rpm-settings.rpm_min)*pwm_gradient + (SPINDLE_MINIMUM_PWM+0.5));
//        #else
//          float pwm_gradient = (PWM_MAX_VALUE)/(settings.rpm_max-settings.rpm_min);
//          current_pwm = floor( (rpm-settings.rpm_min)*pwm_gradient + 0.5);
//        #endif
//      }
//
//      OCR_REGISTER = current_pwm; // Set PWM output level.
//      TCCRA_REGISTER |= (1<<COMB_BIT); // Ensure PWM output is enabled.
//
//      // On the Uno, spindle enable and PWM are shared, unless otherwise specified.
//      #if defined(CPU_MAP_ATMEGA2560) || defined(USE_SPINDLE_DIR_AS_ENABLE_PIN)
//        #ifdef INVERT_SPINDLE_ENABLE_PIN
//          SPINDLE_ENABLE_PORT &= ~(1<<SPINDLE_ENABLE_BIT);
//        #else
//          SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT);
//        #endif
//      #endif
//
//    #else
//
//      #ifdef INVERT_SPINDLE_ENABLE_PIN
//        SPINDLE_ENABLE_PORT &= ~(1<<SPINDLE_ENABLE_BIT);
//      #else
//        SPINDLE_ENABLE_PORT |= (1<<SPINDLE_ENABLE_BIT);
//      #endif
//
//    #endif
//
//  }

  if (state == SPINDLE_DISABLE)
  {
    spindle_stop();
  }
  else
  {
#ifdef VARIABLE_SPINDLE

	  int i;
	  for(i=500;i<=1500;i+=20)  // this is a bad hack, my ESC/MOTOR combo needs ramping to start
	  {
#ifdef STANDARD_GRBL
		  TIM_SetCompare1(TIM3,i);
#else
		  TIM_SetCompare3(TIM3,i);
#endif
		  delay_ms(20);
	  }

#else
	  if (state == SPINDLE_ENABLE_CW)
		  GPIO_ResetBits(SPINDLE_DIR);
	  else
		  GPIO_SetBits(SPINDLE_DIR);

	  GPIO_SetBits(SPINDLE_EN);
#endif
  }


}
Ejemplo n.º 21
0
void spindle_init()
{    
//  #ifdef VARIABLE_SPINDLE
//
//    // Configure variable spindle PWM and enable pin, if requried. On the Uno, PWM and enable are
//    // combined unless configured otherwise.
//    SPINDLE_PWM_DDR |= (1<<SPINDLE_PWM_BIT); // Configure as PWM output pin.
//    TCCRA_REGISTER = TCCRA_INIT_MASK; // Configure PWM output compare timer
//    TCCRB_REGISTER = TCCRB_INIT_MASK;
//    #ifdef CPU_MAP_ATMEGA2560
//      OCRA_REGISTER = OCRA_TOP_VALUE; // Set the top value for 16-bit fast PWM mode
//      SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT); // Configure as output pin.
//      SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT); // Configure as output pin.
//    #else // Otherwise 328p
//      #ifdef USE_SPINDLE_DIR_AS_ENABLE_PIN
//        SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT); // Configure as output pin.
//      #else
//        SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT); // Configure as output pin.
//      #endif
//    #endif
//
//  #else
//
//    // Configure no variable spindle and only enable pin.
//    SPINDLE_ENABLE_DDR |= (1<<SPINDLE_ENABLE_BIT); // Configure as output pin.
//    SPINDLE_DIRECTION_DDR |= (1<<SPINDLE_DIRECTION_BIT); // Configure as output pin.
//
//  #endif


#ifdef VARIABLE_SPINDLE

  //setup to control RC ESC, 20ms period, 0.5-1.5ms pulsewidth

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

#ifdef STANDARD_GRBL
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_StructInit(&GPIO_InitStructure); //Reset init structure
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_TIM3);

  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  TIM_TimeBaseStructInit( &TIM_TimeBaseStructure ); // Reset init structure

  TIM_TimeBaseStructure.TIM_Prescaler = 100 - 1;  // 100 MHz / 100 = 1 MHz
  TIM_TimeBaseStructure.TIM_Period = 20000 - 1;  // 1 MHz / 20000 = 50 Hz (20 ms)
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);


  TIM_OCInitTypeDef TIM_OCInitStructure;
  TIM_OCStructInit( &TIM_OCInitStructure );


  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_Pulse = 1000;
  TIM_OC1Init(TIM3, &TIM_OCInitStructure);
#else
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_StructInit(&GPIO_InitStructure); //Reset init structure
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  GPIO_PinAFConfig(GPIOB, GPIO_PinSource0, GPIO_AF_TIM3);

  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  TIM_TimeBaseStructInit( &TIM_TimeBaseStructure ); // Reset init structure

  TIM_TimeBaseStructure.TIM_Prescaler = 100 - 1;  // 100 MHz / 100 = 1 MHz
  TIM_TimeBaseStructure.TIM_Period = 20000 - 1;  // 1 MHz / 20000 = 50 Hz (20 ms)
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);


  TIM_OCInitTypeDef TIM_OCInitStructure;
  TIM_OCStructInit( &TIM_OCInitStructure );


  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_Pulse = 1000;
  TIM_OC3Init(TIM3, &TIM_OCInitStructure);
#endif

  TIM_Cmd( TIM3, ENABLE );
#else
  set_as_output(SPINDLE_DIR);
  set_as_output(SPINDLE_EN);
#endif

  spindle_stop();
}
Ejemplo n.º 22
-1
void protocol_execute_runtime()
{
  	uint8_t aux_bits;
  	
  	aux_bits = AUX_PIN ^ AUX_INVMASK; // apply invert mask
  	if (!(aux_bits & (1<<AUX_STOP_BIT)))
    	{
  			if (!(emerg_stop)) {
          st_go_idle();
          spindle_stop();
          sys.abort = true;
          emerg_stop = true;
        }
  	  }
    else {
      emerg_stop = false;
    }

  AUX_PORT ^= (1<<AUX_WDOG_BIT);	// Chargepump-Bit invertieren

  
  if (sys.execute) { // Enter only if any bit flag is true
    uint8_t rt_exec = sys.execute; // Avoid calling volatile multiple times    
 
    // System abort. Steppers have already been force stopped.
    if (rt_exec & EXEC_RESET) {
      sys.abort = true;
      return; // Nothing else to do but exit.
    }

    // Execute and serial print status
    if (rt_exec & EXEC_STATUS_REPORT) {
      protocol_status_report();
      bit_false(sys.execute,EXEC_STATUS_REPORT);
    }

    // Execute and serial print switches
    if (rt_exec & EXEC_SWITCH_REPORT) {
      protocol_switch_report();
      bit_false(sys.execute,EXEC_SWITCH_REPORT);
    }

    // Initiate stepper feed hold
    if (rt_exec & EXEC_FEED_HOLD) {
      st_feed_hold(); // Initiate feed hold.
      bit_false(sys.execute,EXEC_FEED_HOLD);
    }

    // Reinitializes the stepper module running flags and re-plans the buffer after a feed hold.
    // NOTE: EXEC_CYCLE_STOP is set by the stepper subsystem when a cycle or feed hold completes.
    if (rt_exec & EXEC_CYCLE_STOP) {
      st_cycle_reinitialize();
      bit_false(sys.execute,EXEC_CYCLE_STOP);
    }

    if (rt_exec & EXEC_CYCLE_START) {
      st_cycle_start(); // Issue cycle start command to stepper subsystem
      #ifdef CYCLE_AUTO_START
        sys.auto_start = true; // Re-enable auto start after feed hold.
      #endif
      bit_false(sys.execute,EXEC_CYCLE_START);
    }
  }
}