diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..6553990d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +root = true + +[*] +insert_final_newline = true \ No newline at end of file diff --git a/Grbl_Esp32/src/Motors/Motor.cpp b/Grbl_Esp32/src/Motors/Motor.cpp new file mode 100644 index 00000000..e3ba33fe --- /dev/null +++ b/Grbl_Esp32/src/Motors/Motor.cpp @@ -0,0 +1,53 @@ +/* + MotorClass.cpp + Part of Grbl_ESP32 + 2020 - Bart Dring + 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 . + TODO + Make sure public/private/protected is cleaned up. + Only a few Unipolar axes have been setup in init() + Get rid of Z_SERVO, just reply on Z_SERVO_PIN + Deal with custom machine ... machine_trinamic_setup(); + Class is ready to deal with non SPI pins, but they have not been needed yet. + It would be nice in the config message though + Testing + Done (success) + 3 Axis (3 Standard Steppers) + MPCNC (ganged with shared direction pin) + TMC2130 Pen Laser (trinamics, stallguard tuning) + Unipolar + TODO + 4 Axis SPI (Daisy Chain, Ganged with unique direction pins) + Reference + TMC2130 Datasheet https://www.trinamic.com/fileadmin/assets/Products/ICs_Documents/TMC2130_datasheet.pdf +*/ + +#include "Motor.h" + +namespace Motors { + Motor::Motor() { type_id = MOTOR; } + + void Motor::init() { _homing_mask = 0; } + + void Motor::config_message() {} + void Motor::debug_message() {} + void Motor::read_settings() {} + void Motor::set_disable(bool disable) {} + void Motor::set_direction_pins(uint8_t onMask) {} + void Motor::step(uint8_t step_mask, uint8_t dir_mask) {} + bool Motor::test() { return true; }; // true = OK + void Motor::update() {} + + void Motor::set_axis_name() { sprintf(_axis_name, "%c%s", report_get_axis_letter(axis_index), dual_axis_index ? "2" : ""); } + + void Motor::set_homing_mode(uint8_t homing_mask, bool isHoming) { _homing_mask = homing_mask; } +} diff --git a/Grbl_Esp32/src/Motors/Motor.h b/Grbl_Esp32/src/Motors/Motor.h new file mode 100644 index 00000000..f3bf3629 --- /dev/null +++ b/Grbl_Esp32/src/Motors/Motor.h @@ -0,0 +1,65 @@ +#pragma once + +/* + Motor.h + Header file for Motor Classes + Here is the hierarchy + Motor + Nullmotor + StandardStepper + TrinamicDriver + Unipolar + RC Servo + + These are for motors coordinated by Grbl_ESP32 + See motorClass.cpp for more details + + Part of Grbl_ESP32 + 2020 - Bart Dring + + 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 . +*/ + +#include "Motors.h" + +#include + +namespace Motors { + class Motor { + public: + Motor(); + + virtual void init(); // not in constructor because this also gets called when $$ settings change + virtual void config_message(); + virtual void debug_message(); + virtual void read_settings(); + virtual void set_homing_mode(uint8_t homing_mask, bool isHoming); + virtual void set_disable(bool disable); + virtual void set_direction_pins(uint8_t onMask); + virtual void step(uint8_t step_mask, uint8_t dir_mask); // only used on Unipolar right now + virtual bool test(); + virtual void set_axis_name(); + virtual void update(); + + motor_class_id_t type_id; + uint8_t is_active = false; + + protected: + uint8_t axis_index; // X_AXIS, etc + uint8_t dual_axis_index; // 0 = primary 1=ganged + + bool _showError; + bool _use_mpos = true; + uint8_t _homing_mask; + char _axis_name[10]; // this the name to use when reporting like "X" or "X2" + }; +} diff --git a/Grbl_Esp32/src/Motors/MotorClass.h b/Grbl_Esp32/src/Motors/MotorClass.h deleted file mode 100644 index a7d93b63..00000000 --- a/Grbl_Esp32/src/Motors/MotorClass.h +++ /dev/null @@ -1,205 +0,0 @@ -#pragma once - -/* - MotorClass.h - Header file for Motor Classes - Here is the hierarchy - Motor - Nullmotor - StandardStepper - TrinamicDriver - Unipolar - RC Servo - - These are for motors coordinated by Grbl_ESP32 - See motorClass.cpp for more details - - Part of Grbl_ESP32 - 2020 - Bart Dring - - 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 . -*/ - -#include "../grbl.h" -#include // https://github.com/teemuatlut/TMCStepper -#include "TrinamicDriverClass.h" -#include "RcServoClass.h" -//#include "SolenoidClass.h" - -extern uint8_t rmt_chan_num[MAX_AXES][2]; -extern rmt_item32_t rmtItem[2]; -extern rmt_config_t rmtConfig; - -typedef enum { MOTOR, NULL_MOTOR, STANDARD_MOTOR, TRINAMIC_SPI_MOTOR, UNIPOLAR_MOTOR, RC_SERVO_MOTOR, SOLENOID } motor_class_id_t; - -// These are used for setup and to talk to the motors as a group. -void init_motors(); -uint8_t get_next_trinamic_driver_index(); -bool motors_have_type_id(motor_class_id_t id); -void readSgTask(void* pvParameters); -void motors_read_settings(); -void motors_set_homing_mode(uint8_t homing_mask, bool isHoming); -void motors_set_disable(bool disable); -void motors_set_direction_pins(uint8_t onMask); -void motors_step(uint8_t step_mask, uint8_t dir_mask); -void servoUpdateTask(void* pvParameters); - -extern bool motor_class_steps; // true if at least one motor class is handling steps - -// ==================== Motor Classes ==================== - -class Motor { -public: - Motor(); - - virtual void init(); // not in constructor because this also gets called when $$ settings change - virtual void config_message(); - virtual void debug_message(); - virtual void read_settings(); - virtual void set_homing_mode(uint8_t homing_mask, bool isHoming); - virtual void set_disable(bool disable); - virtual void set_direction_pins(uint8_t onMask); - virtual void step(uint8_t step_mask, uint8_t dir_mask); // only used on Unipolar right now - virtual bool test(); - virtual void set_axis_name(); - virtual void update(); - - motor_class_id_t type_id; - uint8_t is_active = false; - -protected: - uint8_t axis_index; // X_AXIS, etc - uint8_t dual_axis_index; // 0 = primary 1=ganged - - bool _showError; - bool _use_mpos = true; - uint8_t _homing_mask; - char _axis_name[10]; // this the name to use when reporting like "X" or "X2" -}; - -class Nullmotor : public Motor {}; - -class StandardStepper : public Motor { -public: - StandardStepper(); - StandardStepper(uint8_t axis_index, uint8_t step_pin, uint8_t dir_pin, uint8_t disable_pin); - - virtual void config_message(); - virtual void init(); - virtual void set_direction_pins(uint8_t onMask); - void init_step_dir_pins(); - virtual void set_disable(bool disable); - uint8_t step_pin; - -protected: - bool _invert_step_pin; - uint8_t dir_pin; - uint8_t disable_pin; -}; - -class TrinamicDriver : public StandardStepper { -public: - TrinamicDriver(uint8_t axis_index, - uint8_t step_pin, - uint8_t dir_pin, - uint8_t disable_pin, - uint8_t cs_pin, - uint16_t driver_part_number, - float r_sense, - int8_t spi_index); - - void config_message(); - void init(); - void set_mode(bool isHoming); - void read_settings(); - void trinamic_test_response(); - void trinamic_stepper_enable(bool enable); - void debug_message(); - void set_homing_mode(uint8_t homing_mask, bool ishoming); - void set_disable(bool disable); - bool test(); - -private: - uint32_t calc_tstep(float speed, float percent); - - TMC2130Stepper* tmcstepper; // all other driver types are subclasses of this one - uint8_t _homing_mode; - uint8_t cs_pin = UNDEFINED_PIN; // The chip select pin (can be the same for daisy chain) - uint16_t _driver_part_number; // example: use 2130 for TMC2130 - float _r_sense; - int8_t spi_index; - -protected: - uint8_t _mode; - uint8_t _lastMode = 255; -}; - -class UnipolarMotor : public Motor { -public: - UnipolarMotor(); - UnipolarMotor(uint8_t axis_index, uint8_t pin_phase0, uint8_t pin_phase1, uint8_t pin_phase2, uint8_t pin_phase3); - void init(); - void config_message(); - void set_disable(bool disable); - void step(uint8_t step_mask, uint8_t dir_mask); // only used on Unipolar right now - -private: - uint8_t _pin_phase0; - uint8_t _pin_phase1; - uint8_t _pin_phase2; - uint8_t _pin_phase3; - uint8_t _current_phase; - bool _half_step; - bool _enabled; -}; - -class RcServo : public Motor { -public: - RcServo(); - RcServo(uint8_t axis_index, uint8_t pwm_pin, float min, float max); - virtual void config_message(); - virtual void init(); - void _write_pwm(uint32_t duty); - virtual void set_disable(bool disable); - virtual void update(); - void read_settings(); - void set_homing_mode(bool is_homing, bool isHoming); - -protected: - void set_location(); - void _get_calibration(); - - uint8_t _pwm_pin; - uint8_t _channel_num; - uint32_t _current_pwm_duty; - bool _disabled; - - float _position_min; - float _position_max; // position in millimeters - float _homing_position; - - float _pwm_pulse_min; - float _pwm_pulse_max; -}; - -class Solenoid : public RcServo { -public: - Solenoid(); - Solenoid(uint8_t axis_index, gpio_num_t pwm_pin, float transition_poiont); - void config_message(); - void set_location(); - void update(); - void init(); - void set_disable(bool disable); - - float _transition_poiont; -}; diff --git a/Grbl_Esp32/src/Motors/MotorClass.cpp b/Grbl_Esp32/src/Motors/Motors.cpp similarity index 87% rename from Grbl_Esp32/src/Motors/MotorClass.cpp rename to Grbl_Esp32/src/Motors/Motors.cpp index b5d1dfe6..2a54e455 100644 --- a/Grbl_Esp32/src/Motors/MotorClass.cpp +++ b/Grbl_Esp32/src/Motors/Motors.cpp @@ -1,40 +1,48 @@ /* - MotorClass.cpp - Part of Grbl_ESP32 - 2020 - Bart Dring - 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 . - TODO - Make sure public/private/protected is cleaned up. - Only a few Unipolar axes have been setup in init() - Get rid of Z_SERVO, just reply on Z_SERVO_PIN - Deal with custom machine ... machine_trinamic_setup(); - Class is ready to deal with non SPI pins, but they have not been needed yet. - It would be nice in the config message though - Testing - Done (success) - 3 Axis (3 Standard Steppers) - MPCNC (ganged with shared direction pin) - TMC2130 Pen Laser (trinamics, stallguard tuning) - Unipolar - TODO - 4 Axis SPI (Daisy Chain, Ganged with unique direction pins) - Reference - TMC2130 Datasheet https://www.trinamic.com/fileadmin/assets/Products/ICs_Documents/TMC2130_datasheet.pdf + MotorClass.cpp + Part of Grbl_ESP32 + 2020 - Bart Dring + 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 . + TODO + Make sure public/private/protected is cleaned up. + Only a few Unipolar axes have been setup in init() + Get rid of Z_SERVO, just reply on Z_SERVO_PIN + Deal with custom machine ... machine_trinamic_setup(); + Class is ready to deal with non SPI pins, but they have not been needed yet. + It would be nice in the config message though + Testing + Done (success) + 3 Axis (3 Standard Steppers) + MPCNC (ganged with shared direction pin) + TMC2130 Pen Laser (trinamics, stallguard tuning) + Unipolar + TODO + 4 Axis SPI (Daisy Chain, Ganged with unique direction pins) + Reference + TMC2130 Datasheet https://www.trinamic.com/fileadmin/assets/Products/ICs_Documents/TMC2130_datasheet.pdf */ -#include "../grbl.h" -#include "MotorClass.h" +#include "Motors.h" -Motor* myMotor[MAX_AXES][MAX_GANGED]; // number of axes (normal and ganged) +#include "Motor.h" +#include "../grbl.h" + +#include "NullMotor.h" +#include "StandardStepper.h" +#include "UnipolarMotor.h" +#include "RcServo.h" +#include "TrinamicDriver.h" + +Motors::Motor* myMotor[MAX_AXES][MAX_GANGED]; // number of axes (normal and ganged) static TaskHandle_t readSgTaskHandle = 0; // for realtime stallguard data diaplay static TaskHandle_t servoUpdateTaskHandle = 0; @@ -45,6 +53,8 @@ rmt_config_t rmtConfig; bool motor_class_steps; // true if at least one motor class is handling steps void init_motors() { + using namespace Motors; + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Init Motors"); #ifdef X_TRINAMIC_DRIVER @@ -402,7 +412,7 @@ void motors_step(uint8_t step_mask, uint8_t dir_mask) { } /* - This will print StallGuard data that is useful for tuning. + This will print StallGuard data that is useful for tuning. */ void readSgTask(void* pvParameters) { TickType_t xLastWakeTime; @@ -439,32 +449,3 @@ void TMC2130Stepper::switchCSpin(bool state) { i2s_out_delay(); } #endif - -// ============================== Class Methods ================================================ - -Motor ::Motor() { - type_id = MOTOR; -} - -void Motor ::init() { - _homing_mask = 0; -} - -void Motor ::config_message() {} -void Motor ::debug_message() {} -void Motor ::read_settings() {} -void Motor ::set_disable(bool disable) {} -void Motor ::set_direction_pins(uint8_t onMask) {} -void Motor ::step(uint8_t step_mask, uint8_t dir_mask) {} -bool Motor ::test() { - return true; -}; // true = OK -void Motor ::update() {} - -void Motor ::set_axis_name() { - sprintf(_axis_name, "%c%s", report_get_axis_letter(axis_index), dual_axis_index ? "2" : ""); -} - -void Motor ::set_homing_mode(uint8_t homing_mask, bool isHoming) { - _homing_mask = homing_mask; -} diff --git a/Grbl_Esp32/src/Motors/Motors.h b/Grbl_Esp32/src/Motors/Motors.h new file mode 100644 index 00000000..dafcf6a1 --- /dev/null +++ b/Grbl_Esp32/src/Motors/Motors.h @@ -0,0 +1,53 @@ +#pragma once + +/* + Motor.h + Header file for Motor Classes + Here is the hierarchy + Motor + Nullmotor + StandardStepper + TrinamicDriver + Unipolar + RC Servo + + These are for motors coordinated by Grbl_ESP32 + See motorClass.cpp for more details + + Part of Grbl_ESP32 + 2020 - Bart Dring + + 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 . +*/ + +#include "../grbl.h" +#include // https://github.com/teemuatlut/TMCStepper + +extern uint8_t rmt_chan_num[MAX_AXES][2]; +extern rmt_item32_t rmtItem[2]; +extern rmt_config_t rmtConfig; + +typedef enum { MOTOR, NULL_MOTOR, STANDARD_MOTOR, TRINAMIC_SPI_MOTOR, UNIPOLAR_MOTOR, RC_SERVO_MOTOR, SOLENOID } motor_class_id_t; + +// These are used for setup and to talk to the motors as a group. +void init_motors(); +uint8_t get_next_trinamic_driver_index(); +bool motors_have_type_id(motor_class_id_t id); +void readSgTask(void* pvParameters); +void motors_read_settings(); +void motors_set_homing_mode(uint8_t homing_mask, bool isHoming); +void motors_set_disable(bool disable); +void motors_set_direction_pins(uint8_t onMask); +void motors_step(uint8_t step_mask, uint8_t dir_mask); +void servoUpdateTask(void* pvParameters); + +extern bool motor_class_steps; // true if at least one motor class is handling steps diff --git a/Grbl_Esp32/src/Motors/NullMotor.h b/Grbl_Esp32/src/Motors/NullMotor.h new file mode 100644 index 00000000..e360392d --- /dev/null +++ b/Grbl_Esp32/src/Motors/NullMotor.h @@ -0,0 +1,7 @@ +#pragma once + +#include "Motor.h" + +namespace Motors { + class Nullmotor : public Motor {}; +} diff --git a/Grbl_Esp32/src/Motors/RcServo.cpp b/Grbl_Esp32/src/Motors/RcServo.cpp new file mode 100644 index 00000000..719eaf1b --- /dev/null +++ b/Grbl_Esp32/src/Motors/RcServo.cpp @@ -0,0 +1,189 @@ +/* + RcServoServoClass.cpp + + This allows an RcServo to be used like any other motor. Serrvos + do have limitation in travel and speed, so you do need to respect that. + + Part of Grbl_ESP32 + + 2020 - Bart Dring + + Servos have a limited travel, so they map the travel across a range in + the current work coordinatee system. The servo can only travel as far + as the range, but the internal axis value can keep going. + + Range: The range is specified in the machine definition file with... + #define X_SERVO_RANGE_MIN 0.0 + #define X_SERVO_RANGE_MAX 5.0 + + Direction: The direction can be changed using the $3 setting for the axis + + Homing: During homing, the servo will move to one of the endpoints. The + endpoint is determined by the $23 or $HomingDirInvertMask setting for the axis. + Do not define a homing cycle for the axis with the servo. + You do need at least 1 homing cycle. TODO: Fix this + + Calibration. You can tweak the endpoints using the $10n or nStepsPerMm and + $13n or $xMaxTravel setting, where n is the axis. + The value is a percent. If you secify a percent outside the + the range specified by the values below, it will be reset to 100.0 (100% ... no change) + The calibration adjusts in direction of positive momement, so a value above 100% moves + towards the higher axis value. + + #define SERVO_CAL_MIN + #define SERVO_CAL_MAX + + Grbl_ESP32 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 . +*/ + +#include "RcServo.h" + +namespace Motors { + RcServo::RcServo() {} + + RcServo::RcServo(uint8_t axis_index, uint8_t pwm_pin, float min, float max) { + type_id = RC_SERVO_MOTOR; + this->axis_index = axis_index % MAX_AXES; + this->dual_axis_index = axis_index < MAX_AXES ? 0 : 1; // 0 = primary 1 = ganged + this->_pwm_pin = pwm_pin; + _position_min = min; + _position_max = max; + init(); + } + + void RcServo::init() { + read_settings(); + _channel_num = sys_get_next_PWM_chan_num(); + ledcSetup(_channel_num, SERVO_PULSE_FREQ, SERVO_PULSE_RES_BITS); + ledcAttachPin(_pwm_pin, _channel_num); + _current_pwm_duty = 0; + is_active = true; // as opposed to NullMotors, this is a real motor + set_axis_name(); + config_message(); + } + + void RcServo::config_message() { + grbl_msg_sendf(CLIENT_SERIAL, + MSG_LEVEL_INFO, + "%s Axis RC Servo motor Output:%d Min:%5.3fmm Max:%5.3fmm", + _axis_name, + _pwm_pin, + _position_min, + _position_max); + } + + void RcServo::_write_pwm(uint32_t duty) { + // to prevent excessive calls to ledcWrite, make sure duty hass changed + if (duty == _current_pwm_duty) + return; + + _current_pwm_duty = duty; + + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Servo Pwm %d", _axis_name, duty); + ledcWrite(_channel_num, duty); + } + + // sets the PWM to zero. This allows most servos to be manually moved + void RcServo::set_disable(bool disable) { + return; + _disabled = disable; + if (_disabled) + _write_pwm(0); + } + + void RcServo::set_homing_mode(bool is_homing, bool isHoming) { + float home_pos = 0.0; + + if (!is_homing) + return; + + if (bit_istrue(homing_dir_mask->get(), bit(axis_index))) + home_pos = _position_min; + else + home_pos = _position_max; + + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Servo set home %d %3.2f", is_homing, home_pos); + sys_position[axis_index] = home_pos * axis_settings[axis_index]->steps_per_mm->get(); // convert to steps + } + + void RcServo::update() { set_location(); } + + void RcServo::set_location() { + uint32_t servo_pulse_len; + float servo_pos, mpos, offset; + // skip location if we are in alarm mode + + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "locate"); + _get_calibration(); + + if (sys.state == STATE_ALARM) { + set_disable(true); + return; + } + + mpos = system_convert_axis_steps_to_mpos(sys_position, axis_index); // get the axis machine position in mm + offset = gc_state.coord_system[axis_index] + gc_state.coord_offset[axis_index]; // get the current axis work offset + servo_pos = mpos - offset; // determine the current work position + + // determine the pulse length + servo_pulse_len = (uint32_t)mapConstrain(servo_pos, _position_min, _position_max, _pwm_pulse_min, _pwm_pulse_max); + + _write_pwm(servo_pulse_len); + } + + void RcServo::read_settings() { _get_calibration(); } + + // this should change to use its own settings. + void RcServo::_get_calibration() { + float _cal_min = 1.0; + float _cal_max = 1.0; + + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Read settings"); + + // make sure the min is in range + if ((axis_settings[axis_index]->steps_per_mm->get() < SERVO_CAL_MIN) || + (axis_settings[axis_index]->steps_per_mm->get() > SERVO_CAL_MAX)) { + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Servo calibration ($10%d) value error. Reset to 100", axis_index); + char reset_val[] = "100"; + axis_settings[axis_index]->steps_per_mm->setStringValue(reset_val); + } + + // make sure the max is in range + // Note: Max travel is set positive via $$, but stored as a negative number + if ((axis_settings[axis_index]->max_travel->get() < SERVO_CAL_MIN) || (axis_settings[axis_index]->max_travel->get() > SERVO_CAL_MAX)) { + grbl_msg_sendf(CLIENT_SERIAL, + MSG_LEVEL_INFO, + "Servo calibration ($13%d) value error. %3.2f Reset to 100", + axis_index, + axis_settings[axis_index]->max_travel->get()); + char reset_val[] = "100"; + axis_settings[axis_index]->max_travel->setStringValue(reset_val); + } + + _pwm_pulse_min = SERVO_MIN_PULSE; + _pwm_pulse_max = SERVO_MAX_PULSE; + + if (bit_istrue(dir_invert_mask->get(), bit(axis_index))) { // normal direction + _cal_min = 2.0 - (axis_settings[axis_index]->steps_per_mm->get() / 100.0); + _cal_max = 2.0 - (axis_settings[axis_index]->max_travel->get() / 100.0); + swap(_pwm_pulse_min, _pwm_pulse_max); + } else { // inverted direction + _cal_min = (axis_settings[axis_index]->steps_per_mm->get() / 100.0); + _cal_max = (axis_settings[axis_index]->max_travel->get() / 100.0); + } + + _pwm_pulse_min *= _cal_min; + _pwm_pulse_max *= _cal_max; + + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Servo calibration min:%1.2f max %1.2f", _pwm_pulse_min, _pwm_pulse_max); + } +} diff --git a/Grbl_Esp32/src/Motors/RcServo.h b/Grbl_Esp32/src/Motors/RcServo.h new file mode 100644 index 00000000..94b767d2 --- /dev/null +++ b/Grbl_Esp32/src/Motors/RcServo.h @@ -0,0 +1,55 @@ +#pragma once + +/* + RcServo.h + + Part of Grbl_ESP32 + + 2020 - Bart Dring + + 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 . +*/ + +#include "Motor.h" + +#include "RcServoSettings.h" + +namespace Motors { + class RcServo : public Motor { + public: + RcServo(); + RcServo(uint8_t axis_index, uint8_t pwm_pin, float min, float max); + virtual void config_message(); + virtual void init(); + void _write_pwm(uint32_t duty); + virtual void set_disable(bool disable); + virtual void update(); + void read_settings(); + void set_homing_mode(bool is_homing, bool isHoming); + + protected: + void set_location(); + void _get_calibration(); + + uint8_t _pwm_pin; + uint8_t _channel_num; + uint32_t _current_pwm_duty; + bool _disabled; + + float _position_min; + float _position_max; // position in millimeters + float _homing_position; + + float _pwm_pulse_min; + float _pwm_pulse_max; + }; +} diff --git a/Grbl_Esp32/src/Motors/RcServoClass.cpp b/Grbl_Esp32/src/Motors/RcServoClass.cpp deleted file mode 100644 index 49ae4341..00000000 --- a/Grbl_Esp32/src/Motors/RcServoClass.cpp +++ /dev/null @@ -1,190 +0,0 @@ -/* - RcServoServoClass.cpp - - This allows an RcServo to be used like any other motor. Serrvos - do have limitation in travel and speed, so you do need to respect that. - - Part of Grbl_ESP32 - - 2020 - Bart Dring - - Servos have a limited travel, so they map the travel across a range in - the current work coordinatee system. The servo can only travel as far - as the range, but the internal axis value can keep going. - - Range: The range is specified in the machine definition file with... - #define X_SERVO_RANGE_MIN 0.0 - #define X_SERVO_RANGE_MAX 5.0 - - Direction: The direction can be changed using the $3 setting for the axis - - Homing: During homing, the servo will move to one of the endpoints. The - endpoint is determined by the $23 or $HomingDirInvertMask setting for the axis. - Do not define a homing cycle for the axis with the servo. - You do need at least 1 homing cycle. TODO: Fix this - - Calibration. You can tweak the endpoints using the $10n or nStepsPerMm and - $13n or $xMaxTravel setting, where n is the axis. - The value is a percent. If you secify a percent outside the - the range specified by the values below, it will be reset to 100.0 (100% ... no change) - The calibration adjusts in direction of positive momement, so a value above 100% moves - towards the higher axis value. - - #define SERVO_CAL_MIN - #define SERVO_CAL_MAX - - Grbl_ESP32 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 . -*/ - -#include "MotorClass.h" - -RcServo ::RcServo() {} - -RcServo ::RcServo(uint8_t axis_index, uint8_t pwm_pin, float min, float max) { - type_id = RC_SERVO_MOTOR; - this->axis_index = axis_index % MAX_AXES; - this->dual_axis_index = axis_index < MAX_AXES ? 0 : 1; // 0 = primary 1 = ganged - this->_pwm_pin = pwm_pin; - _position_min = min; - _position_max = max; - init(); -} - -void RcServo ::init() { - read_settings(); - _channel_num = sys_get_next_PWM_chan_num(); - ledcSetup(_channel_num, SERVO_PULSE_FREQ, SERVO_PULSE_RES_BITS); - ledcAttachPin(_pwm_pin, _channel_num); - _current_pwm_duty = 0; - is_active = true; // as opposed to NullMotors, this is a real motor - set_axis_name(); - config_message(); -} - -void RcServo ::config_message() { - grbl_msg_sendf(CLIENT_SERIAL, - MSG_LEVEL_INFO, - "%s Axis RC Servo motor Output:%d Min:%5.3fmm Max:%5.3fmm", - _axis_name, - _pwm_pin, - _position_min, - _position_max); -} - -void RcServo::_write_pwm(uint32_t duty) { - // to prevent excessive calls to ledcWrite, make sure duty hass changed - if (duty == _current_pwm_duty) - return; - - _current_pwm_duty = duty; - - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Servo Pwm %d", _axis_name, duty); - ledcWrite(_channel_num, duty); -} - -// sets the PWM to zero. This allows most servos to be manually moved -void RcServo::set_disable(bool disable) { - return; - _disabled = disable; - if (_disabled) - _write_pwm(0); -} - -void RcServo::set_homing_mode(bool is_homing, bool isHoming) { - float home_pos = 0.0; - - if (!is_homing) - return; - - if (bit_istrue(homing_dir_mask->get(), bit(axis_index))) - home_pos = _position_min; - else - home_pos = _position_max; - - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Servo set home %d %3.2f", is_homing, home_pos); - sys_position[axis_index] = home_pos * axis_settings[axis_index]->steps_per_mm->get(); // convert to steps -} - -void RcServo::update() { - set_location(); -} - -void RcServo::set_location() { - uint32_t servo_pulse_len; - float servo_pos, mpos, offset; - // skip location if we are in alarm mode - - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "locate"); - _get_calibration(); - - if (sys.state == STATE_ALARM) { - set_disable(true); - return; - } - - mpos = system_convert_axis_steps_to_mpos(sys_position, axis_index); // get the axis machine position in mm - offset = gc_state.coord_system[axis_index] + gc_state.coord_offset[axis_index]; // get the current axis work offset - servo_pos = mpos - offset; // determine the current work position - - // determine the pulse length - servo_pulse_len = (uint32_t)mapConstrain(servo_pos, _position_min, _position_max, _pwm_pulse_min, _pwm_pulse_max); - - _write_pwm(servo_pulse_len); -} - -void RcServo::read_settings() { - _get_calibration(); -} - -// this should change to use its own settings. -void RcServo::_get_calibration() { - float _cal_min = 1.0; - float _cal_max = 1.0; - - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Read settings"); - - // make sure the min is in range - if ((axis_settings[axis_index]->steps_per_mm->get() < SERVO_CAL_MIN) || (axis_settings[axis_index]->steps_per_mm->get() > SERVO_CAL_MAX)) { - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Servo calibration ($10%d) value error. Reset to 100", axis_index); - char reset_val[] = "100"; - axis_settings[axis_index]->steps_per_mm->setStringValue(reset_val); - } - - // make sure the max is in range - // Note: Max travel is set positive via $$, but stored as a negative number - if ((axis_settings[axis_index]->max_travel->get() < SERVO_CAL_MIN) || (axis_settings[axis_index]->max_travel->get() > SERVO_CAL_MAX)) { - grbl_msg_sendf(CLIENT_SERIAL, - MSG_LEVEL_INFO, - "Servo calibration ($13%d) value error. %3.2f Reset to 100", - axis_index, - axis_settings[axis_index]->max_travel->get()); - char reset_val[] = "100"; - axis_settings[axis_index]->max_travel->setStringValue(reset_val); - } - - _pwm_pulse_min = SERVO_MIN_PULSE; - _pwm_pulse_max = SERVO_MAX_PULSE; - - if (bit_istrue(dir_invert_mask->get(), bit(axis_index))) { // normal direction - _cal_min = 2.0 - (axis_settings[axis_index]->steps_per_mm->get() / 100.0); - _cal_max = 2.0 - (axis_settings[axis_index]->max_travel->get() / 100.0); - swap(_pwm_pulse_min, _pwm_pulse_max); - } else { // inverted direction - _cal_min = (axis_settings[axis_index]->steps_per_mm->get() / 100.0); - _cal_max = (axis_settings[axis_index]->max_travel->get() / 100.0); - } - - _pwm_pulse_min *= _cal_min; - _pwm_pulse_max *= _cal_max; - - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Servo calibration min:%1.2f max %1.2f", _pwm_pulse_min, _pwm_pulse_max); -} \ No newline at end of file diff --git a/Grbl_Esp32/src/Motors/RcServoClass.h b/Grbl_Esp32/src/Motors/RcServoSettings.h similarity index 64% rename from Grbl_Esp32/src/Motors/RcServoClass.h rename to Grbl_Esp32/src/Motors/RcServoSettings.h index 84dafbc5..c07655ce 100644 --- a/Grbl_Esp32/src/Motors/RcServoClass.h +++ b/Grbl_Esp32/src/Motors/RcServoSettings.h @@ -1,24 +1,5 @@ #pragma once -/* - RcServoClass.h - - Part of Grbl_ESP32 - - 2020 - Bart Dring - - 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 is the pulse range of a the servo. Typical servos are 0.001 to 0.002 seconds // some servos have a wider range. You can adjust this here or in the calibration feature #define SERVO_MIN_PULSE_SEC 0.001 // min pulse in seconds diff --git a/Grbl_Esp32/src/Motors/Solenoid.h b/Grbl_Esp32/src/Motors/Solenoid.h new file mode 100644 index 00000000..fb973083 --- /dev/null +++ b/Grbl_Esp32/src/Motors/Solenoid.h @@ -0,0 +1,18 @@ +#pragma once + +#include "RcServo.h" + +namespace Motors { + class Solenoid : public RcServo { + public: + Solenoid(); + Solenoid(uint8_t axis_index, gpio_num_t pwm_pin, float transition_poiont); + void config_message(); + void set_location(); + void update(); + void init(); + void set_disable(bool disable); + + float _transition_poiont; + }; +} diff --git a/Grbl_Esp32/src/Motors/StandardStepper.cpp b/Grbl_Esp32/src/Motors/StandardStepper.cpp new file mode 100644 index 00000000..e181fa56 --- /dev/null +++ b/Grbl_Esp32/src/Motors/StandardStepper.cpp @@ -0,0 +1,103 @@ +/* + StandardStepperClass.cpp + + This is used for a stepper motor that just requires step and direction + pins. + TODO: Add an enable pin + + Part of Grbl_ESP32 + + 2020 - Bart Dring + + 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 . +*/ + +#include "StandardStepper.h" + +namespace Motors { + StandardStepper::StandardStepper() {} + + StandardStepper::StandardStepper(uint8_t axis_index, uint8_t step_pin, uint8_t dir_pin, uint8_t disable_pin) { + type_id = STANDARD_MOTOR; + this->axis_index = axis_index % MAX_AXES; + this->dual_axis_index = axis_index < MAX_AXES ? 0 : 1; // 0 = primary 1 = ganged + this->step_pin = step_pin; + this->dir_pin = dir_pin; + this->disable_pin = disable_pin; + init(); + } + + void StandardStepper::init() { + _homing_mask = 0; + is_active = true; // as opposed to NullMotors, this is a real motor + set_axis_name(); + init_step_dir_pins(); + config_message(); + } + + void StandardStepper::init_step_dir_pins() { + // TODO Step pin, but RMT complicates things + _invert_step_pin = bit_istrue(step_invert_mask->get(), bit(axis_index)); + pinMode(dir_pin, OUTPUT); + +#ifdef USE_RMT_STEPS + rmtConfig.rmt_mode = RMT_MODE_TX; + rmtConfig.clk_div = 20; + rmtConfig.mem_block_num = 2; + rmtConfig.tx_config.loop_en = false; + rmtConfig.tx_config.carrier_en = false; + rmtConfig.tx_config.carrier_freq_hz = 0; + rmtConfig.tx_config.carrier_duty_percent = 50; + rmtConfig.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW; + rmtConfig.tx_config.idle_output_en = true; + +# ifdef STEP_PULSE_DELAY + rmtItem[0].duration0 = STEP_PULSE_DELAY * 4; +# else + rmtItem[0].duration0 = 1; +# endif + + rmtItem[0].duration1 = 4 * pulse_microseconds->get(); + rmtItem[1].duration0 = 0; + rmtItem[1].duration1 = 0; + + rmt_chan_num[axis_index][dual_axis_index] = sys_get_next_RMT_chan_num(); + rmt_set_source_clk((rmt_channel_t)rmt_chan_num[axis_index][dual_axis_index], RMT_BASECLK_APB); + rmtConfig.channel = (rmt_channel_t)rmt_chan_num[axis_index][dual_axis_index]; + rmtConfig.tx_config.idle_level = _invert_step_pin ? RMT_IDLE_LEVEL_HIGH : RMT_IDLE_LEVEL_LOW; + rmtConfig.gpio_num = gpio_num_t(step_pin); // c is a wacky lang + rmtItem[0].level0 = rmtConfig.tx_config.idle_level; + rmtItem[0].level1 = !rmtConfig.tx_config.idle_level; + rmt_config(&rmtConfig); + rmt_fill_tx_items(rmtConfig.channel, &rmtItem[0], rmtConfig.mem_block_num, 0); + +#else + pinMode(step_pin, OUTPUT); + +#endif // USE_RMT_STEPS + pinMode(disable_pin, OUTPUT); + } + + void StandardStepper::config_message() { + grbl_msg_sendf(CLIENT_SERIAL, + MSG_LEVEL_INFO, + "%s Axis standard stepper motor Step:%s Dir:%s Disable:%s", + _axis_name, + pinName(step_pin).c_str(), + pinName(dir_pin).c_str(), + pinName(disable_pin).c_str()); + } + + void StandardStepper::set_direction_pins(uint8_t onMask) { digitalWrite(dir_pin, (onMask & bit(axis_index))); } + + void StandardStepper::set_disable(bool disable) { digitalWrite(disable_pin, disable); } +} diff --git a/Grbl_Esp32/src/Motors/StandardStepper.h b/Grbl_Esp32/src/Motors/StandardStepper.h new file mode 100644 index 00000000..8a4d7e8c --- /dev/null +++ b/Grbl_Esp32/src/Motors/StandardStepper.h @@ -0,0 +1,23 @@ +#pragma once + +#include "Motor.h" + +namespace Motors { + class StandardStepper : public Motor { + public: + StandardStepper(); + StandardStepper(uint8_t axis_index, uint8_t step_pin, uint8_t dir_pin, uint8_t disable_pin); + + virtual void config_message(); + virtual void init(); + virtual void set_direction_pins(uint8_t onMask); + void init_step_dir_pins(); + virtual void set_disable(bool disable); + uint8_t step_pin; + + protected: + bool _invert_step_pin; + uint8_t dir_pin; + uint8_t disable_pin; + }; +} diff --git a/Grbl_Esp32/src/Motors/StandardStepperClass.cpp b/Grbl_Esp32/src/Motors/StandardStepperClass.cpp deleted file mode 100644 index 2374d094..00000000 --- a/Grbl_Esp32/src/Motors/StandardStepperClass.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - StandardStepperClass.cpp - - This is used for a stepper motor that just requires step and direction - pins. - TODO: Add an enable pin - - Part of Grbl_ESP32 - - 2020 - Bart Dring - - 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 . -*/ - -#include "MotorClass.h" - -StandardStepper ::StandardStepper() {} - -StandardStepper ::StandardStepper(uint8_t axis_index, uint8_t step_pin, uint8_t dir_pin, uint8_t disable_pin) { - type_id = STANDARD_MOTOR; - this->axis_index = axis_index % MAX_AXES; - this->dual_axis_index = axis_index < MAX_AXES ? 0 : 1; // 0 = primary 1 = ganged - this->step_pin = step_pin; - this->dir_pin = dir_pin; - this->disable_pin = disable_pin; - init(); -} - -void StandardStepper ::init() { - _homing_mask = 0; - is_active = true; // as opposed to NullMotors, this is a real motor - set_axis_name(); - init_step_dir_pins(); - config_message(); -} - -void StandardStepper ::init_step_dir_pins() { - // TODO Step pin, but RMT complicates things - _invert_step_pin = bit_istrue(step_invert_mask->get(), bit(axis_index)); - pinMode(dir_pin, OUTPUT); - -#ifdef USE_RMT_STEPS - rmtConfig.rmt_mode = RMT_MODE_TX; - rmtConfig.clk_div = 20; - rmtConfig.mem_block_num = 2; - rmtConfig.tx_config.loop_en = false; - rmtConfig.tx_config.carrier_en = false; - rmtConfig.tx_config.carrier_freq_hz = 0; - rmtConfig.tx_config.carrier_duty_percent = 50; - rmtConfig.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW; - rmtConfig.tx_config.idle_output_en = true; - -# ifdef STEP_PULSE_DELAY - rmtItem[0].duration0 = STEP_PULSE_DELAY * 4; -# else - rmtItem[0].duration0 = 1; -# endif - - rmtItem[0].duration1 = 4 * pulse_microseconds->get(); - rmtItem[1].duration0 = 0; - rmtItem[1].duration1 = 0; - - rmt_chan_num[axis_index][dual_axis_index] = sys_get_next_RMT_chan_num(); - rmt_set_source_clk((rmt_channel_t)rmt_chan_num[axis_index][dual_axis_index], RMT_BASECLK_APB); - rmtConfig.channel = (rmt_channel_t)rmt_chan_num[axis_index][dual_axis_index]; - rmtConfig.tx_config.idle_level = _invert_step_pin ? RMT_IDLE_LEVEL_HIGH : RMT_IDLE_LEVEL_LOW; - rmtConfig.gpio_num = gpio_num_t(step_pin); // c is a wacky lang - rmtItem[0].level0 = rmtConfig.tx_config.idle_level; - rmtItem[0].level1 = !rmtConfig.tx_config.idle_level; - rmt_config(&rmtConfig); - rmt_fill_tx_items(rmtConfig.channel, &rmtItem[0], rmtConfig.mem_block_num, 0); - -#else - pinMode(step_pin, OUTPUT); - -#endif // USE_RMT_STEPS - pinMode(disable_pin, OUTPUT); -} - -void StandardStepper ::config_message() { - grbl_msg_sendf(CLIENT_SERIAL, - MSG_LEVEL_INFO, - "%s Axis standard stepper motor Step:%s Dir:%s Disable:%s", - _axis_name, - pinName(step_pin).c_str(), - pinName(dir_pin).c_str(), - pinName(disable_pin).c_str()); -} - -void StandardStepper ::set_direction_pins(uint8_t onMask) { - digitalWrite(dir_pin, (onMask & bit(axis_index))); -} - -void StandardStepper ::set_disable(bool disable) { - digitalWrite(disable_pin, disable); -} diff --git a/Grbl_Esp32/src/Motors/TrinamicDriver.cpp b/Grbl_Esp32/src/Motors/TrinamicDriver.cpp new file mode 100644 index 00000000..3e3613d9 --- /dev/null +++ b/Grbl_Esp32/src/Motors/TrinamicDriver.cpp @@ -0,0 +1,235 @@ +/* + TrinamicDriverClass.cpp + This is used for Trinamic SPI controlled stepper motor drivers. + + Part of Grbl_ESP32 + 2020 - Bart Dring + + 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 . + +*/ +#include "TrinamicDriver.h" + +#include + +namespace Motors { + TrinamicDriver::TrinamicDriver(uint8_t axis_index, + uint8_t step_pin, + uint8_t dir_pin, + uint8_t disable_pin, + uint8_t cs_pin, + uint16_t driver_part_number, + float r_sense, + int8_t spi_index) { + type_id = TRINAMIC_SPI_MOTOR; + this->axis_index = axis_index % MAX_AXES; + this->dual_axis_index = axis_index < 6 ? 0 : 1; // 0 = primary 1 = ganged + _driver_part_number = driver_part_number; + _r_sense = r_sense; + this->step_pin = step_pin; + this->dir_pin = dir_pin; + this->disable_pin = disable_pin; + this->cs_pin = cs_pin; + this->spi_index = spi_index; + + _homing_mode = TRINAMIC_HOMING_MODE; + _homing_mask = 0; // no axes homing + + if (_driver_part_number == 2130) + tmcstepper = new TMC2130Stepper(cs_pin, _r_sense, spi_index); + else if (_driver_part_number == 5160) + tmcstepper = new TMC5160Stepper(cs_pin, _r_sense, spi_index); + else { + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Trinamic unsupported p/n:%d", _driver_part_number); + return; + } + + set_axis_name(); + + init_step_dir_pins(); // from StandardStepper + + digitalWrite(cs_pin, HIGH); + pinMode(cs_pin, OUTPUT); + + // use slower speed if I2S + if (cs_pin >= I2S_OUT_PIN_BASE) + tmcstepper->setSPISpeed(TRINAMIC_SPI_FREQ); + + config_message(); + + // init() must be called later, after all TMC drivers have CS pins setup. + } + + void TrinamicDriver::init() { + SPI.begin(); // this will get called for each motor, but does not seem to hurt anything + + tmcstepper->begin(); + test(); // Try communicating with motor. Prints an error if there is a problem. + read_settings(); // pull info from settings + set_mode(false); + + _homing_mask = 0; + is_active = true; // as opposed to NullMotors, this is a real motor + } + + /* + This is the startup message showing the basic definition +*/ + void TrinamicDriver::config_message() { + grbl_msg_sendf(CLIENT_SERIAL, + MSG_LEVEL_INFO, + "%s Axis Trinamic TMC%d Step:%s Dir:%s CS:%s Disable:%s Index:%d", + _axis_name, + _driver_part_number, + pinName(step_pin).c_str(), + pinName(dir_pin).c_str(), + pinName(cs_pin).c_str(), + pinName(disable_pin).c_str(), + spi_index); + } + + bool TrinamicDriver::test() { + switch (tmcstepper->test_connection()) { + case 1: + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Trinamic driver test failed. Check connection", _axis_name); + return false; + case 2: + grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Trinamic driver test failed. Check motor power", _axis_name); + return false; + default: grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Trinamic driver test passed", _axis_name); return true; + } + } + + /* + Read setting and send them to the driver. Called at init() and whenever related settings change + both are stored as float Amps, but TMCStepper library expects... + uint16_t run (mA) + float hold (as a percentage of run) +*/ + void TrinamicDriver::read_settings() { + uint16_t run_i_ma = (uint16_t)(axis_settings[axis_index]->run_current->get() * 1000.0); + float hold_i_percent; + + if (axis_settings[axis_index]->run_current->get() == 0) + hold_i_percent = 0; + else { + hold_i_percent = axis_settings[axis_index]->hold_current->get() / axis_settings[axis_index]->run_current->get(); + if (hold_i_percent > 1.0) + hold_i_percent = 1.0; + } + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Current run %d hold %f", _axis_name, run_i_ma, hold_i_percent); + + tmcstepper->microsteps(axis_settings[axis_index]->microsteps->get()); + tmcstepper->rms_current(run_i_ma, hold_i_percent); + } + + void TrinamicDriver::set_homing_mode(uint8_t homing_mask, bool isHoming) { + _homing_mask = homing_mask; + set_mode(isHoming); + } + + /* + There are ton of settings. I'll start by grouping then into modes for now. + Many people will want quiet and stallgaurd homing. Stallguard only run in + Coolstep mode, so it will need to switch to Coolstep when homing +*/ + void TrinamicDriver::set_mode(bool isHoming) { + if (isHoming) + _mode = TRINAMIC_HOMING_MODE; + else + _mode = TRINAMIC_RUN_MODE; + + if (_lastMode == _mode) + return; + _lastMode = _mode; + + switch (_mode) { + case TRINAMIC_MODE_STEALTHCHOP: + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "TRINAMIC_MODE_STEALTHCHOP"); + tmcstepper->en_pwm_mode(true); + tmcstepper->pwm_autoscale(true); + tmcstepper->diag1_stall(false); + break; + case TRINAMIC_MODE_COOLSTEP: + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "TRINAMIC_MODE_COOLSTEP"); + tmcstepper->en_pwm_mode(false); + tmcstepper->pwm_autoscale(false); + tmcstepper->TCOOLTHRS(NORMAL_TCOOLTHRS); // when to turn on coolstep + tmcstepper->THIGH(NORMAL_THIGH); + break; + case TRINAMIC_MODE_STALLGUARD: + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "TRINAMIC_MODE_STALLGUARD"); + tmcstepper->en_pwm_mode(false); + tmcstepper->pwm_autoscale(false); + tmcstepper->TCOOLTHRS(calc_tstep(homing_feed_rate->get(), 150.0)); + tmcstepper->THIGH(calc_tstep(homing_feed_rate->get(), 60.0)); + tmcstepper->sfilt(1); + tmcstepper->diag1_stall(true); // stallguard i/o is on diag1 + tmcstepper->sgt(axis_settings[axis_index]->stallguard->get()); + break; + default: grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "TRINAMIC_MODE_UNDEFINED"); + } + } + + /* + This is the stallguard tuning info. It is call debug, so it could be generic across all classes. +*/ + void TrinamicDriver::debug_message() { + uint32_t tstep = tmcstepper->TSTEP(); + + if (tstep == 0xFFFFF || tstep < 1) // if axis is not moving return + return; + float feedrate = st_get_realtime_rate(); //* settings.microsteps[axis_index] / 60.0 ; // convert mm/min to Hz + + grbl_msg_sendf(CLIENT_SERIAL, + MSG_LEVEL_INFO, + "%s Stallguard %d SG_Val: %04d Rate: %05.0f mm/min SG_Setting:%d", + _axis_name, + tmcstepper->stallguard(), + tmcstepper->sg_result(), + feedrate, + axis_settings[axis_index]->stallguard->get()); + } + + // calculate a tstep from a rate + // tstep = TRINAMIC_FCLK / (time between 1/256 steps) + // This is used to set the stallguard window from the homing speed. + // The percent is the offset on the window + uint32_t TrinamicDriver::calc_tstep(float speed, float percent) { + float tstep = + speed / 60.0 * axis_settings[axis_index]->steps_per_mm->get() * (float)(256 / axis_settings[axis_index]->microsteps->get()); + tstep = TRINAMIC_FCLK / tstep * percent / 100.0; + + return (uint32_t)tstep; + } + + // this can use the enable feature over SPI. The dedicated pin must be in the enable mode, + // but that can be hardwired that way. + void TrinamicDriver::set_disable(bool disable) { + //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Axis disable %d", _axis_name, disable); + + digitalWrite(disable_pin, disable); + +#ifdef USE_TRINAMIC_ENABLE + if (disable) + tmcstepper->toff(TRINAMIC_TOFF_DISABLE); + else { + if (_mode == TRINAMIC_MODE_STEALTHCHOP) + tmcstepper->toff(TRINAMIC_TOFF_STEALTHCHOP); + else + tmcstepper->toff(TRINAMIC_TOFF_COOLSTEP); + } +#endif + // the pin based enable could be added here. + // This would be for individual motors, not the single pin for all motors. + } +} diff --git a/Grbl_Esp32/src/Motors/TrinamicDriverClass.h b/Grbl_Esp32/src/Motors/TrinamicDriver.h similarity index 55% rename from Grbl_Esp32/src/Motors/TrinamicDriverClass.h rename to Grbl_Esp32/src/Motors/TrinamicDriver.h index b1ab8040..d6aa863b 100644 --- a/Grbl_Esp32/src/Motors/TrinamicDriverClass.h +++ b/Grbl_Esp32/src/Motors/TrinamicDriver.h @@ -1,7 +1,7 @@ #pragma once /* - TrinamicDriverClass.h + TrinamicDriver.h Part of Grbl_ESP32 @@ -19,6 +19,10 @@ along with Grbl. If not, see . */ +#include "Motor.h" +#include "StandardStepper.h" +#include // https://github.com/teemuatlut/TMCStepper + #define TRINAMIC_MODE_STEALTHCHOP 0 // very quiet #define TRINAMIC_MODE_COOLSTEP 1 // everything runs cooler so higher current possible #define TRINAMIC_MODE_STALLGUARD 2 // coolstep plus generates stall indication @@ -54,5 +58,41 @@ # define TRINAMIC_TOFF_COOLSTEP 3 #endif -#include "MotorClass.h" -#include // https://github.com/teemuatlut/TMCStepper +namespace Motors { + class TrinamicDriver : public StandardStepper { + public: + TrinamicDriver(uint8_t axis_index, + uint8_t step_pin, + uint8_t dir_pin, + uint8_t disable_pin, + uint8_t cs_pin, + uint16_t driver_part_number, + float r_sense, + int8_t spi_index); + + void config_message(); + void init(); + void set_mode(bool isHoming); + void read_settings(); + void trinamic_test_response(); + void trinamic_stepper_enable(bool enable); + void debug_message(); + void set_homing_mode(uint8_t homing_mask, bool ishoming); + void set_disable(bool disable); + bool test(); + + private: + uint32_t calc_tstep(float speed, float percent); + + TMC2130Stepper* tmcstepper; // all other driver types are subclasses of this one + uint8_t _homing_mode; + uint8_t cs_pin = UNDEFINED_PIN; // The chip select pin (can be the same for daisy chain) + uint16_t _driver_part_number; // example: use 2130 for TMC2130 + float _r_sense; + int8_t spi_index; + + protected: + uint8_t _mode; + uint8_t _lastMode = 255; + }; +} diff --git a/Grbl_Esp32/src/Motors/TrinamicDriverClass.cpp b/Grbl_Esp32/src/Motors/TrinamicDriverClass.cpp deleted file mode 100644 index f36a4abf..00000000 --- a/Grbl_Esp32/src/Motors/TrinamicDriverClass.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/* - TrinamicDriverClass.cpp - This is used for Trinamic SPI controlled stepper motor drivers. - - Part of Grbl_ESP32 - 2020 - Bart Dring - - 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 . - -*/ -#include "MotorClass.h" -#include -#include "TrinamicDriverClass.h" - -TrinamicDriver ::TrinamicDriver(uint8_t axis_index, - uint8_t step_pin, - uint8_t dir_pin, - uint8_t disable_pin, - uint8_t cs_pin, - uint16_t driver_part_number, - float r_sense, - int8_t spi_index) { - type_id = TRINAMIC_SPI_MOTOR; - this->axis_index = axis_index % MAX_AXES; - this->dual_axis_index = axis_index < 6 ? 0 : 1; // 0 = primary 1 = ganged - _driver_part_number = driver_part_number; - _r_sense = r_sense; - this->step_pin = step_pin; - this->dir_pin = dir_pin; - this->disable_pin = disable_pin; - this->cs_pin = cs_pin; - this->spi_index = spi_index; - - _homing_mode = TRINAMIC_HOMING_MODE; - _homing_mask = 0; // no axes homing - - if (_driver_part_number == 2130) - tmcstepper = new TMC2130Stepper(cs_pin, _r_sense, spi_index); - else if (_driver_part_number == 5160) - tmcstepper = new TMC5160Stepper(cs_pin, _r_sense, spi_index); - else { - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Trinamic unsupported p/n:%d", _driver_part_number); - return; - } - - set_axis_name(); - - init_step_dir_pins(); // from StandardStepper - - digitalWrite(cs_pin, HIGH); - pinMode(cs_pin, OUTPUT); - - // use slower speed if I2S - if (cs_pin >= I2S_OUT_PIN_BASE) - tmcstepper->setSPISpeed(TRINAMIC_SPI_FREQ); - - config_message(); - - // init() must be called later, after all TMC drivers have CS pins setup. -} - -void TrinamicDriver ::init() { - SPI.begin(); // this will get called for each motor, but does not seem to hurt anything - - tmcstepper->begin(); - test(); // Try communicating with motor. Prints an error if there is a problem. - read_settings(); // pull info from settings - set_mode(false); - - _homing_mask = 0; - is_active = true; // as opposed to NullMotors, this is a real motor -} - -/* - This is the startup message showing the basic definition -*/ -void TrinamicDriver ::config_message() { - grbl_msg_sendf(CLIENT_SERIAL, - MSG_LEVEL_INFO, - "%s Axis Trinamic TMC%d Step:%s Dir:%s CS:%s Disable:%s Index:%d", - _axis_name, - _driver_part_number, - pinName(step_pin).c_str(), - pinName(dir_pin).c_str(), - pinName(cs_pin).c_str(), - pinName(disable_pin).c_str(), - spi_index); -} - -bool TrinamicDriver ::test() { - switch (tmcstepper->test_connection()) { - case 1: grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Trinamic driver test failed. Check connection", _axis_name); return false; - case 2: - grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Trinamic driver test failed. Check motor power", _axis_name); - return false; - default: grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Trinamic driver test passed", _axis_name); return true; - } -} - -/* - Read setting and send them to the driver. Called at init() and whenever related settings change - both are stored as float Amps, but TMCStepper library expects... - uint16_t run (mA) - float hold (as a percentage of run) -*/ -void TrinamicDriver ::read_settings() { - uint16_t run_i_ma = (uint16_t)(axis_settings[axis_index]->run_current->get() * 1000.0); - float hold_i_percent; - - if (axis_settings[axis_index]->run_current->get() == 0) - hold_i_percent = 0; - else { - hold_i_percent = axis_settings[axis_index]->hold_current->get() / axis_settings[axis_index]->run_current->get(); - if (hold_i_percent > 1.0) - hold_i_percent = 1.0; - } - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Current run %d hold %f", _axis_name, run_i_ma, hold_i_percent); - - tmcstepper->microsteps(axis_settings[axis_index]->microsteps->get()); - tmcstepper->rms_current(run_i_ma, hold_i_percent); -} - -void TrinamicDriver ::set_homing_mode(uint8_t homing_mask, bool isHoming) { - _homing_mask = homing_mask; - set_mode(isHoming); -} - -/* - There are ton of settings. I'll start by grouping then into modes for now. - Many people will want quiet and stallgaurd homing. Stallguard only run in - Coolstep mode, so it will need to switch to Coolstep when homing -*/ -void TrinamicDriver ::set_mode(bool isHoming) { - if (isHoming) - _mode = TRINAMIC_HOMING_MODE; - else - _mode = TRINAMIC_RUN_MODE; - - if (_lastMode == _mode) - return; - _lastMode = _mode; - - switch (_mode) { - case TRINAMIC_MODE_STEALTHCHOP: - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "TRINAMIC_MODE_STEALTHCHOP"); - tmcstepper->en_pwm_mode(true); - tmcstepper->pwm_autoscale(true); - tmcstepper->diag1_stall(false); - break; - case TRINAMIC_MODE_COOLSTEP: - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "TRINAMIC_MODE_COOLSTEP"); - tmcstepper->en_pwm_mode(false); - tmcstepper->pwm_autoscale(false); - tmcstepper->TCOOLTHRS(NORMAL_TCOOLTHRS); // when to turn on coolstep - tmcstepper->THIGH(NORMAL_THIGH); - break; - case TRINAMIC_MODE_STALLGUARD: - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "TRINAMIC_MODE_STALLGUARD"); - tmcstepper->en_pwm_mode(false); - tmcstepper->pwm_autoscale(false); - tmcstepper->TCOOLTHRS(calc_tstep(homing_feed_rate->get(), 150.0)); - tmcstepper->THIGH(calc_tstep(homing_feed_rate->get(), 60.0)); - tmcstepper->sfilt(1); - tmcstepper->diag1_stall(true); // stallguard i/o is on diag1 - tmcstepper->sgt(axis_settings[axis_index]->stallguard->get()); - break; - default: grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "TRINAMIC_MODE_UNDEFINED"); - } -} - -/* - This is the stallguard tuning info. It is call debug, so it could be generic across all classes. -*/ -void TrinamicDriver ::debug_message() { - uint32_t tstep = tmcstepper->TSTEP(); - - if (tstep == 0xFFFFF || tstep < 1) // if axis is not moving return - return; - float feedrate = st_get_realtime_rate(); //* settings.microsteps[axis_index] / 60.0 ; // convert mm/min to Hz - - grbl_msg_sendf(CLIENT_SERIAL, - MSG_LEVEL_INFO, - "%s Stallguard %d SG_Val: %04d Rate: %05.0f mm/min SG_Setting:%d", - _axis_name, - tmcstepper->stallguard(), - tmcstepper->sg_result(), - feedrate, - axis_settings[axis_index]->stallguard->get()); -} - -// calculate a tstep from a rate -// tstep = TRINAMIC_FCLK / (time between 1/256 steps) -// This is used to set the stallguard window from the homing speed. -// The percent is the offset on the window -uint32_t TrinamicDriver ::calc_tstep(float speed, float percent) { - float tstep = speed / 60.0 * axis_settings[axis_index]->steps_per_mm->get() * (float)(256 / axis_settings[axis_index]->microsteps->get()); - tstep = TRINAMIC_FCLK / tstep * percent / 100.0; - - return (uint32_t)tstep; -} - -// this can use the enable feature over SPI. The dedicated pin must be in the enable mode, -// but that can be hardwired that way. -void TrinamicDriver ::set_disable(bool disable) { - //grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "%s Axis disable %d", _axis_name, disable); - - digitalWrite(disable_pin, disable); - -#ifdef USE_TRINAMIC_ENABLE - if (disable) - tmcstepper->toff(TRINAMIC_TOFF_DISABLE); - else { - if (_mode == TRINAMIC_MODE_STEALTHCHOP) - tmcstepper->toff(TRINAMIC_TOFF_STEALTHCHOP); - else - tmcstepper->toff(TRINAMIC_TOFF_COOLSTEP); - } -#endif - // the pin based enable could be added here. - // This would be for individual motors, not the single pin for all motors. -} diff --git a/Grbl_Esp32/src/Motors/UnipolarMotor.cpp b/Grbl_Esp32/src/Motors/UnipolarMotor.cpp new file mode 100644 index 00000000..a2918ee1 --- /dev/null +++ b/Grbl_Esp32/src/Motors/UnipolarMotor.cpp @@ -0,0 +1,139 @@ +#include "UnipolarMotor.h" + +namespace Motors { + UnipolarMotor::UnipolarMotor() {} + + UnipolarMotor::UnipolarMotor(uint8_t axis_index, uint8_t pin_phase0, uint8_t pin_phase1, uint8_t pin_phase2, uint8_t pin_phase3) { + type_id = UNIPOLAR_MOTOR; + this->axis_index = axis_index % MAX_AXES; + this->dual_axis_index = axis_index < MAX_AXES ? 0 : 1; // 0 = primary 1 = ganged + _pin_phase0 = pin_phase0; + _pin_phase1 = pin_phase1; + _pin_phase2 = pin_phase2; + _pin_phase3 = pin_phase3; + + _half_step = true; // TODO read from settings ... microstep > 1 = half step + + set_axis_name(); + init(); + config_message(); + } + + void UnipolarMotor::init() { + pinMode(_pin_phase0, OUTPUT); + pinMode(_pin_phase1, OUTPUT); + pinMode(_pin_phase2, OUTPUT); + pinMode(_pin_phase3, OUTPUT); + _current_phase = 0; + } + + void UnipolarMotor::config_message() { + grbl_msg_sendf(CLIENT_SERIAL, + MSG_LEVEL_INFO, + "%s Axis unipolar stepper motor Ph0:%s Ph1:%s Ph2:%s Ph3:%s", + _axis_name, + pinName(_pin_phase0).c_str(), + pinName(_pin_phase1).c_str(), + pinName(_pin_phase2).c_str(), + pinName(_pin_phase3).c_str()); + } + + void UnipolarMotor::set_disable(bool disable) { + if (disable) { + digitalWrite(_pin_phase0, 0); + digitalWrite(_pin_phase1, 0); + digitalWrite(_pin_phase2, 0); + digitalWrite(_pin_phase3, 0); + } + _enabled = !disable; + } + + void UnipolarMotor::step(uint8_t step_mask, uint8_t dir_mask) { + uint8_t _phase[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; // temporary phase values...all start as off + uint8_t phase_max; + + if (!(step_mask & bit(axis_index))) + return; // a step is not required on this interrupt + + if (!_enabled) + return; // don't do anything, phase is not changed or lost + + if (_half_step) + phase_max = 7; + else + phase_max = 3; + + if (dir_mask & bit(axis_index)) { // count up + if (_current_phase == phase_max) + _current_phase = 0; + else + _current_phase++; + } else { // count down + if (_current_phase == 0) + _current_phase = phase_max; + else + _current_phase--; + } + /* + 8 Step : A – AB – B – BC – C – CD – D – DA + 4 Step : AB – BC – CD – DA + + Step IN4 IN3 IN2 IN1 + A 0 0 0 1 + AB 0 0 1 1 + B 0 0 1 0 + BC 0 1 1 0 + C 0 1 0 0 + CD 1 1 0 0 + D 1 0 0 0 + DA 1 0 0 1 + */ + if (_half_step) { + switch (_current_phase) { + case 0: _phase[0] = 1; break; + case 1: + _phase[0] = 1; + _phase[1] = 1; + break; + case 2: _phase[1] = 1; break; + case 3: + _phase[1] = 1; + _phase[2] = 1; + break; + case 4: _phase[2] = 1; break; + case 5: + _phase[2] = 1; + _phase[3] = 1; + break; + case 6: _phase[3] = 1; break; + case 7: + _phase[3] = 1; + _phase[0] = 1; + break; + } + } else { + switch (_current_phase) { + case 0: + _phase[0] = 1; + _phase[1] = 1; + break; + case 1: + _phase[1] = 1; + _phase[2] = 1; + break; + case 2: + _phase[2] = 1; + _phase[3] = 1; + break; + case 3: + _phase[3] = 1; + _phase[0] = 1; + break; + } + } + digitalWrite(_pin_phase0, _phase[0]); + digitalWrite(_pin_phase1, _phase[1]); + digitalWrite(_pin_phase2, _phase[2]); + digitalWrite(_pin_phase3, _phase[3]); + } +} diff --git a/Grbl_Esp32/src/Motors/UnipolarMotor.h b/Grbl_Esp32/src/Motors/UnipolarMotor.h new file mode 100644 index 00000000..d9594815 --- /dev/null +++ b/Grbl_Esp32/src/Motors/UnipolarMotor.h @@ -0,0 +1,24 @@ +#pragma once + +#include "Motor.h" + +namespace Motors { + class UnipolarMotor : public Motor { + public: + UnipolarMotor(); + UnipolarMotor(uint8_t axis_index, uint8_t pin_phase0, uint8_t pin_phase1, uint8_t pin_phase2, uint8_t pin_phase3); + void init(); + void config_message(); + void set_disable(bool disable); + void step(uint8_t step_mask, uint8_t dir_mask); // only used on Unipolar right now + + private: + uint8_t _pin_phase0; + uint8_t _pin_phase1; + uint8_t _pin_phase2; + uint8_t _pin_phase3; + uint8_t _current_phase; + bool _half_step; + bool _enabled; + }; +} diff --git a/Grbl_Esp32/src/Motors/UnipolarMotorClass.cpp b/Grbl_Esp32/src/Motors/UnipolarMotorClass.cpp deleted file mode 100644 index 3c8aed36..00000000 --- a/Grbl_Esp32/src/Motors/UnipolarMotorClass.cpp +++ /dev/null @@ -1,137 +0,0 @@ -#include "MotorClass.h" - -UnipolarMotor ::UnipolarMotor() {} - -UnipolarMotor ::UnipolarMotor(uint8_t axis_index, uint8_t pin_phase0, uint8_t pin_phase1, uint8_t pin_phase2, uint8_t pin_phase3) { - type_id = UNIPOLAR_MOTOR; - this->axis_index = axis_index % MAX_AXES; - this->dual_axis_index = axis_index < MAX_AXES ? 0 : 1; // 0 = primary 1 = ganged - _pin_phase0 = pin_phase0; - _pin_phase1 = pin_phase1; - _pin_phase2 = pin_phase2; - _pin_phase3 = pin_phase3; - - _half_step = true; // TODO read from settings ... microstep > 1 = half step - - set_axis_name(); - init(); - config_message(); -} - -void UnipolarMotor ::init() { - pinMode(_pin_phase0, OUTPUT); - pinMode(_pin_phase1, OUTPUT); - pinMode(_pin_phase2, OUTPUT); - pinMode(_pin_phase3, OUTPUT); - _current_phase = 0; -} - -void UnipolarMotor ::config_message() { - grbl_msg_sendf(CLIENT_SERIAL, - MSG_LEVEL_INFO, - "%s Axis unipolar stepper motor Ph0:%s Ph1:%s Ph2:%s Ph3:%s", - _axis_name, - pinName(_pin_phase0).c_str(), - pinName(_pin_phase1).c_str(), - pinName(_pin_phase2).c_str(), - pinName(_pin_phase3).c_str()); -} - -void UnipolarMotor ::set_disable(bool disable) { - if (disable) { - digitalWrite(_pin_phase0, 0); - digitalWrite(_pin_phase1, 0); - digitalWrite(_pin_phase2, 0); - digitalWrite(_pin_phase3, 0); - } - _enabled = !disable; -} - -void UnipolarMotor::step(uint8_t step_mask, uint8_t dir_mask) { - uint8_t _phase[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; // temporary phase values...all start as off - uint8_t phase_max; - - if (!(step_mask & bit(axis_index))) - return; // a step is not required on this interrupt - - if (!_enabled) - return; // don't do anything, phase is not changed or lost - - if (_half_step) - phase_max = 7; - else - phase_max = 3; - - if (dir_mask & bit(axis_index)) { // count up - if (_current_phase == phase_max) - _current_phase = 0; - else - _current_phase++; - } else { // count down - if (_current_phase == 0) - _current_phase = phase_max; - else - _current_phase--; - } - /* - 8 Step : A – AB – B – BC – C – CD – D – DA - 4 Step : AB – BC – CD – DA - - Step IN4 IN3 IN2 IN1 - A 0 0 0 1 - AB 0 0 1 1 - B 0 0 1 0 - BC 0 1 1 0 - C 0 1 0 0 - CD 1 1 0 0 - D 1 0 0 0 - DA 1 0 0 1 - */ - if (_half_step) { - switch (_current_phase) { - case 0: _phase[0] = 1; break; - case 1: - _phase[0] = 1; - _phase[1] = 1; - break; - case 2: _phase[1] = 1; break; - case 3: - _phase[1] = 1; - _phase[2] = 1; - break; - case 4: _phase[2] = 1; break; - case 5: - _phase[2] = 1; - _phase[3] = 1; - break; - case 6: _phase[3] = 1; break; - case 7: - _phase[3] = 1; - _phase[0] = 1; - break; - } - } else { - switch (_current_phase) { - case 0: - _phase[0] = 1; - _phase[1] = 1; - break; - case 1: - _phase[1] = 1; - _phase[2] = 1; - break; - case 2: - _phase[2] = 1; - _phase[3] = 1; - break; - case 3: - _phase[3] = 1; - _phase[0] = 1; - break; - } - } - digitalWrite(_pin_phase0, _phase[0]); - digitalWrite(_pin_phase1, _phase[1]); - digitalWrite(_pin_phase2, _phase[2]); - digitalWrite(_pin_phase3, _phase[3]); -} diff --git a/Grbl_Esp32/src/grbl.h b/Grbl_Esp32/src/grbl.h index 56bdd0b4..42965b95 100644 --- a/Grbl_Esp32/src/grbl.h +++ b/Grbl_Esp32/src/grbl.h @@ -57,7 +57,7 @@ #include "serial.h" #include "Pins.h" #include "Spindles/SpindleClass.h" -#include "Motors/MotorClass.h" +#include "Motors/Motors.h" #include "stepper.h" #include "jog.h" #include "inputbuffer.h" diff --git a/Grbl_Esp32/src/servo_axis.cpp b/Grbl_Esp32/src/servo_axis.cpp index fec865c4..85589e35 100644 --- a/Grbl_Esp32/src/servo_axis.cpp +++ b/Grbl_Esp32/src/servo_axis.cpp @@ -24,6 +24,8 @@ #include "grbl.h" +#include "servo_axis.h" + #ifdef USE_SERVO_AXES static TaskHandle_t servosSyncTaskHandle = 0; diff --git a/Grbl_Esp32/src/servo_axis.h b/Grbl_Esp32/src/servo_axis.h index fe9399ac..031ea15c 100644 --- a/Grbl_Esp32/src/servo_axis.h +++ b/Grbl_Esp32/src/servo_axis.h @@ -53,7 +53,7 @@ */ -#include "Motors/RcServoClass.h" +#include "Motors/RcServoSettings.h" #define SERVO_HOMING_OFF 0 // servo is off during homing #define SERVO_HOMING_TARGET 1 // servo is send to a location during homing