mirror of
https://github.com/bdring/Grbl_Esp32.git
synced 2025-08-24 23:16:09 +02:00
Updated style of Spindles according to style doc. Added namespace Spindles. (#529)
* Renamed spindleclass file. * Added (empty) header files; renamed SpindleClass.cpp * Moved spindle classes, introduced namespaces * Fixed forward declaration. * Removed obsolete commented out code * Fixed overrides and constructors * Applied clang-format * Fixed 10vspindle set_spindle_dir_pin and set_enable_pin. Co-authored-by: Stefan de Bruijn <stefan@nubilosoft.com>
This commit is contained in:
@@ -34,7 +34,7 @@ volatile uint8_t sys_rt_exec_accessory_override; // Global realtime executor bi
|
|||||||
volatile uint8_t sys_rt_exec_debug;
|
volatile uint8_t sys_rt_exec_debug;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Spindle* spindle;
|
Spindles::Spindle* spindle;
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
#ifdef USE_I2S_OUT
|
#ifdef USE_I2S_OUT
|
||||||
@@ -87,7 +87,7 @@ void setup() {
|
|||||||
if (homing_enable->get())
|
if (homing_enable->get())
|
||||||
sys.state = STATE_ALARM;
|
sys.state = STATE_ALARM;
|
||||||
#endif
|
#endif
|
||||||
spindle_select();
|
Spindles::Spindle::spindle_select();
|
||||||
#ifdef ENABLE_WIFI
|
#ifdef ENABLE_WIFI
|
||||||
wifi_config.begin();
|
wifi_config.begin();
|
||||||
#endif
|
#endif
|
||||||
|
@@ -23,143 +23,142 @@
|
|||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#include "SpindleClass.h"
|
#include "10vSpindle.h"
|
||||||
|
|
||||||
void _10vSpindle ::init() {
|
namespace Spindles {
|
||||||
get_pins_and_settings(); // these gets the standard PWM settings, but many need to be changed for BESC
|
void _10vSpindle::init() {
|
||||||
|
get_pins_and_settings(); // these gets the standard PWM settings, but many need to be changed for BESC
|
||||||
|
|
||||||
// a couple more pins not inherited from PWM Spindle
|
// a couple more pins not inherited from PWM Spindle
|
||||||
#ifdef SPINDLE_FORWARD_PIN
|
#ifdef SPINDLE_FORWARD_PIN
|
||||||
_forward_pin = SPINDLE_FORWARD_PIN;
|
_forward_pin = SPINDLE_FORWARD_PIN;
|
||||||
#else
|
#else
|
||||||
_forward_pin = UNDEFINED_PIN;
|
_forward_pin = UNDEFINED_PIN;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SPINDLE_REVERSE_PIN
|
#ifdef SPINDLE_REVERSE_PIN
|
||||||
_reverse_pin = SPINDLE_REVERSE_PIN;
|
_reverse_pin = SPINDLE_REVERSE_PIN;
|
||||||
#else
|
#else
|
||||||
_reverse_pin = UNDEFINED_PIN;
|
_reverse_pin = UNDEFINED_PIN;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (_output_pin == UNDEFINED_PIN) {
|
if (_output_pin == UNDEFINED_PIN) {
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: BESC output pin not defined");
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: BESC output pin not defined");
|
||||||
return; // We cannot continue without the output pin
|
return; // We cannot continue without the output pin
|
||||||
|
}
|
||||||
|
|
||||||
|
ledcSetup(_spindle_pwm_chan_num, (double)_pwm_freq, _pwm_precision); // setup the channel
|
||||||
|
ledcAttachPin(_output_pin, _spindle_pwm_chan_num); // attach the PWM to the pin
|
||||||
|
|
||||||
|
pinMode(_enable_pin, OUTPUT);
|
||||||
|
pinMode(_direction_pin, OUTPUT);
|
||||||
|
pinMode(_forward_pin, OUTPUT);
|
||||||
|
pinMode(_reverse_pin, OUTPUT);
|
||||||
|
|
||||||
|
set_rpm(0);
|
||||||
|
|
||||||
|
config_message();
|
||||||
|
|
||||||
|
is_reversable = true; // these VFDs are always reversable
|
||||||
|
use_delays = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ledcSetup(_spindle_pwm_chan_num, (double)_pwm_freq, _pwm_precision); // setup the channel
|
// prints the startup message of the spindle config
|
||||||
ledcAttachPin(_output_pin, _spindle_pwm_chan_num); // attach the PWM to the pin
|
void _10vSpindle::config_message() {
|
||||||
|
grbl_msg_sendf(CLIENT_SERIAL,
|
||||||
|
MSG_LEVEL_INFO,
|
||||||
|
"0-10V spindle Out:%s Enbl:%s, Dir:%s, Fwd:%s, Rev:%s, Freq:%dHz Res:%dbits",
|
||||||
|
pinName(_output_pin).c_str(),
|
||||||
|
pinName(_enable_pin).c_str(),
|
||||||
|
pinName(_direction_pin).c_str(),
|
||||||
|
pinName(_forward_pin).c_str(),
|
||||||
|
pinName(_reverse_pin).c_str(),
|
||||||
|
_pwm_freq,
|
||||||
|
_pwm_precision);
|
||||||
|
}
|
||||||
|
|
||||||
pinMode(_enable_pin, OUTPUT);
|
uint32_t _10vSpindle::set_rpm(uint32_t rpm) {
|
||||||
pinMode(_direction_pin, OUTPUT);
|
uint32_t pwm_value;
|
||||||
pinMode(_forward_pin, OUTPUT);
|
|
||||||
pinMode(_reverse_pin, OUTPUT);
|
|
||||||
|
|
||||||
set_rpm(0);
|
if (_output_pin == UNDEFINED_PIN)
|
||||||
|
return rpm;
|
||||||
|
|
||||||
config_message();
|
// apply speed overrides
|
||||||
|
rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (percent)
|
||||||
|
|
||||||
is_reversable = true; // these VFDs are always reversable
|
// apply limits limits
|
||||||
use_delays = true;
|
if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm))
|
||||||
}
|
rpm = _max_rpm;
|
||||||
|
else if (rpm != 0 && rpm <= _min_rpm)
|
||||||
|
rpm = _min_rpm;
|
||||||
|
sys.spindle_speed = rpm;
|
||||||
|
|
||||||
// prints the startup message of the spindle config
|
// determine the pwm value
|
||||||
void _10vSpindle ::config_message() {
|
if (rpm == 0)
|
||||||
grbl_msg_sendf(CLIENT_SERIAL,
|
pwm_value = _pwm_off_value;
|
||||||
MSG_LEVEL_INFO,
|
else
|
||||||
"0-10V spindle Out:%s Enbl:%s, Dir:%s, Fwd:%s, Rev:%s, Freq:%dHz Res:%dbits",
|
pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value);
|
||||||
pinName(_output_pin).c_str(),
|
|
||||||
pinName(_enable_pin).c_str(),
|
|
||||||
pinName(_direction_pin).c_str(),
|
|
||||||
pinName(_forward_pin).c_str(),
|
|
||||||
pinName(_reverse_pin).c_str(),
|
|
||||||
_pwm_freq,
|
|
||||||
_pwm_precision);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t _10vSpindle::set_rpm(uint32_t rpm) {
|
set_output(pwm_value);
|
||||||
uint32_t pwm_value;
|
|
||||||
|
|
||||||
if (_output_pin == UNDEFINED_PIN)
|
|
||||||
return rpm;
|
return rpm;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
void _10vSpindle::set_state(uint8_t state, uint32_t rpm) {
|
||||||
|
if (sys.abort)
|
||||||
|
return; // Block during abort.
|
||||||
|
|
||||||
// apply speed overrides
|
if (state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm.
|
||||||
rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (percent)
|
sys.spindle_speed = 0;
|
||||||
|
stop();
|
||||||
|
} else {
|
||||||
|
set_spindle_dir_pin(state == SPINDLE_ENABLE_CW);
|
||||||
|
set_rpm(rpm);
|
||||||
|
}
|
||||||
|
|
||||||
// apply limits limits
|
set_enable_pin(state != SPINDLE_DISABLE);
|
||||||
if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm))
|
|
||||||
rpm = _max_rpm;
|
|
||||||
else if (rpm != 0 && rpm <= _min_rpm)
|
|
||||||
rpm = _min_rpm;
|
|
||||||
sys.spindle_speed = rpm;
|
|
||||||
|
|
||||||
// determine the pwm value
|
sys.report_ovr_counter = 0; // Set to report change immediately
|
||||||
if (rpm == 0)
|
}
|
||||||
pwm_value = _pwm_off_value;
|
|
||||||
else
|
|
||||||
pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value);
|
|
||||||
|
|
||||||
set_output(pwm_value);
|
*/
|
||||||
return rpm;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
void _10vSpindle::set_state(uint8_t state, uint32_t rpm) {
|
|
||||||
if (sys.abort)
|
|
||||||
return; // Block during abort.
|
|
||||||
|
|
||||||
if (state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm.
|
uint8_t _10vSpindle::get_state() {
|
||||||
sys.spindle_speed = 0;
|
if (_current_pwm_duty == 0 || _output_pin == UNDEFINED_PIN)
|
||||||
stop();
|
return (SPINDLE_STATE_DISABLE);
|
||||||
} else {
|
if (_direction_pin != UNDEFINED_PIN)
|
||||||
set_spindle_dir_pin(state == SPINDLE_ENABLE_CW);
|
return digitalRead(_direction_pin) ? SPINDLE_STATE_CW : SPINDLE_STATE_CCW;
|
||||||
set_rpm(rpm);
|
return (SPINDLE_STATE_CW);
|
||||||
}
|
}
|
||||||
|
|
||||||
set_enable_pin(state != SPINDLE_DISABLE);
|
void _10vSpindle::stop() {
|
||||||
|
// inverts are delt with in methods
|
||||||
|
set_enable_pin(false);
|
||||||
|
set_output(_pwm_off_value);
|
||||||
|
}
|
||||||
|
|
||||||
sys.report_ovr_counter = 0; // Set to report change immediately
|
void _10vSpindle::set_enable_pin(bool enable) {
|
||||||
}
|
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "_10vSpindle::set_enable_pin");
|
||||||
|
if (_off_with_zero_speed && sys.spindle_speed == 0)
|
||||||
*/
|
enable = false;
|
||||||
|
|
||||||
uint8_t _10vSpindle::get_state() {
|
|
||||||
if (_current_pwm_duty == 0 || _output_pin == UNDEFINED_PIN)
|
|
||||||
return (SPINDLE_STATE_DISABLE);
|
|
||||||
if (_direction_pin != UNDEFINED_PIN)
|
|
||||||
return digitalRead(_direction_pin) ? SPINDLE_STATE_CW : SPINDLE_STATE_CCW;
|
|
||||||
return (SPINDLE_STATE_CW);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _10vSpindle::stop() {
|
|
||||||
// inverts are delt with in methods
|
|
||||||
set_enable_pin(false);
|
|
||||||
set_output(_pwm_off_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _10vSpindle::set_enable_pin(bool enable) {
|
|
||||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "_10vSpindle::set_enable_pin");
|
|
||||||
if (_off_with_zero_speed && sys.spindle_speed == 0)
|
|
||||||
enable = false;
|
|
||||||
|
|
||||||
#ifdef INVERT_SPINDLE_ENABLE_PIN
|
#ifdef INVERT_SPINDLE_ENABLE_PIN
|
||||||
enable = !enable;
|
enable = !enable;
|
||||||
#endif
|
#endif
|
||||||
digitalWrite(_enable_pin, enable);
|
digitalWrite(_enable_pin, enable);
|
||||||
|
|
||||||
// turn off anything that acts like an enable
|
// turn off anything that acts like an enable
|
||||||
if (!enable) {
|
if (!enable) {
|
||||||
digitalWrite(_direction_pin, enable);
|
digitalWrite(_direction_pin, enable);
|
||||||
digitalWrite(_forward_pin, enable);
|
digitalWrite(_forward_pin, enable);
|
||||||
digitalWrite(_reverse_pin, enable);
|
digitalWrite(_reverse_pin, enable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _10vSpindle::set_spindle_dir_pin(bool Clockwise) {
|
||||||
|
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "_10vSpindle::set_spindle_dir_pin");
|
||||||
|
digitalWrite(_direction_pin, Clockwise);
|
||||||
|
digitalWrite(_forward_pin, Clockwise);
|
||||||
|
digitalWrite(_reverse_pin, !Clockwise);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _10vSpindle::set_spindle_dir_pin(bool Clockwise) {
|
|
||||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "_10vSpindle::set_spindle_dir_pin");
|
|
||||||
digitalWrite(_direction_pin, Clockwise);
|
|
||||||
digitalWrite(_forward_pin, Clockwise);
|
|
||||||
digitalWrite(_reverse_pin, !Clockwise);
|
|
||||||
}
|
|
||||||
|
58
Grbl_Esp32/src/Spindles/10vSpindle.h
Normal file
58
Grbl_Esp32/src/Spindles/10vSpindle.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/*
|
||||||
|
10vSpindle.h
|
||||||
|
|
||||||
|
This is basically a PWM spindle with some changes, so a separate forward and
|
||||||
|
reverse signal can be sent.
|
||||||
|
|
||||||
|
The direction pins will act as enables for the 2 directions. There is usually
|
||||||
|
a min RPM with VFDs, that speed will remain even if speed is 0. You
|
||||||
|
must turn off both direction pins when enable is off.
|
||||||
|
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PWMSpindle.h"
|
||||||
|
|
||||||
|
namespace Spindles {
|
||||||
|
class _10vSpindle : public PWMSpindle {
|
||||||
|
public:
|
||||||
|
_10vSpindle() = default;
|
||||||
|
|
||||||
|
_10vSpindle(const _10vSpindle&) = delete;
|
||||||
|
_10vSpindle(_10vSpindle&&) = delete;
|
||||||
|
_10vSpindle& operator=(const _10vSpindle&) = delete;
|
||||||
|
_10vSpindle& operator=(_10vSpindle&&) = delete;
|
||||||
|
|
||||||
|
void init() override;
|
||||||
|
void config_message() override;
|
||||||
|
uint32_t set_rpm(uint32_t rpm) override;
|
||||||
|
//void set_state(uint8_t state, uint32_t rpm);
|
||||||
|
|
||||||
|
uint8_t get_state() override;
|
||||||
|
void stop() override;
|
||||||
|
|
||||||
|
virtual ~_10vSpindle() {}
|
||||||
|
|
||||||
|
uint8_t _forward_pin;
|
||||||
|
uint8_t _reverse_pin;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void set_enable_pin(bool enable_pin) override;
|
||||||
|
void set_spindle_dir_pin(bool Clockwise) override;
|
||||||
|
};
|
||||||
|
}
|
@@ -30,7 +30,7 @@
|
|||||||
BESC_MAX_PULSE_SECS is typically 2ms (0.002 sec) or more
|
BESC_MAX_PULSE_SECS is typically 2ms (0.002 sec) or more
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#include "SpindleClass.h"
|
#include "BESCSpindle.h"
|
||||||
|
|
||||||
// don't change these
|
// don't change these
|
||||||
#define BESC_PWM_FREQ 50.0f // Hz
|
#define BESC_PWM_FREQ 50.0f // Hz
|
||||||
@@ -51,70 +51,72 @@
|
|||||||
#define BESC_MIN_PULSE_CNT (uint16_t)(BESC_MIN_PULSE_SECS / BESC_PULSE_PERIOD * 65535.0)
|
#define BESC_MIN_PULSE_CNT (uint16_t)(BESC_MIN_PULSE_SECS / BESC_PULSE_PERIOD * 65535.0)
|
||||||
#define BESC_MAX_PULSE_CNT (uint16_t)(BESC_MAX_PULSE_SECS / BESC_PULSE_PERIOD * 65535.0)
|
#define BESC_MAX_PULSE_CNT (uint16_t)(BESC_MAX_PULSE_SECS / BESC_PULSE_PERIOD * 65535.0)
|
||||||
|
|
||||||
void BESCSpindle ::init() {
|
namespace Spindles {
|
||||||
get_pins_and_settings(); // these gets the standard PWM settings, but many need to be changed for BESC
|
void BESCSpindle::init() {
|
||||||
|
get_pins_and_settings(); // these gets the standard PWM settings, but many need to be changed for BESC
|
||||||
|
|
||||||
if (_output_pin == UNDEFINED_PIN) {
|
if (_output_pin == UNDEFINED_PIN) {
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: BESC output pin not defined");
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: BESC output pin not defined");
|
||||||
return; // We cannot continue without the output pin
|
return; // We cannot continue without the output pin
|
||||||
|
}
|
||||||
|
|
||||||
|
// override some settings to what is required for a BESC
|
||||||
|
_pwm_freq = (uint32_t)BESC_PWM_FREQ;
|
||||||
|
_pwm_precision = 16;
|
||||||
|
|
||||||
|
// override these settings
|
||||||
|
_pwm_off_value = BESC_MIN_PULSE_CNT;
|
||||||
|
_pwm_min_value = _pwm_off_value;
|
||||||
|
_pwm_max_value = BESC_MAX_PULSE_CNT;
|
||||||
|
|
||||||
|
ledcSetup(_spindle_pwm_chan_num, (double)_pwm_freq, _pwm_precision); // setup the channel
|
||||||
|
ledcAttachPin(_output_pin, _spindle_pwm_chan_num); // attach the PWM to the pin
|
||||||
|
|
||||||
|
pinMode(_enable_pin, OUTPUT);
|
||||||
|
|
||||||
|
set_rpm(0);
|
||||||
|
|
||||||
|
use_delays = true;
|
||||||
|
|
||||||
|
config_message();
|
||||||
}
|
}
|
||||||
|
|
||||||
// override some settings to what is required for a BESC
|
// prints the startup message of the spindle config
|
||||||
_pwm_freq = (uint32_t)BESC_PWM_FREQ;
|
void BESCSpindle::config_message() {
|
||||||
_pwm_precision = 16;
|
grbl_msg_sendf(CLIENT_SERIAL,
|
||||||
|
MSG_LEVEL_INFO,
|
||||||
|
"BESC spindle on Pin:%s Min:%0.2fms Max:%0.2fms Freq:%dHz Res:%dbits",
|
||||||
|
pinName(_output_pin).c_str(),
|
||||||
|
BESC_MIN_PULSE_SECS * 1000.0, // convert to milliseconds
|
||||||
|
BESC_MAX_PULSE_SECS * 1000.0, // convert to milliseconds
|
||||||
|
_pwm_freq,
|
||||||
|
_pwm_precision);
|
||||||
|
}
|
||||||
|
|
||||||
// override these settings
|
uint32_t BESCSpindle::set_rpm(uint32_t rpm) {
|
||||||
_pwm_off_value = BESC_MIN_PULSE_CNT;
|
uint32_t pwm_value;
|
||||||
_pwm_min_value = _pwm_off_value;
|
|
||||||
_pwm_max_value = BESC_MAX_PULSE_CNT;
|
|
||||||
|
|
||||||
ledcSetup(_spindle_pwm_chan_num, (double)_pwm_freq, _pwm_precision); // setup the channel
|
if (_output_pin == UNDEFINED_PIN)
|
||||||
ledcAttachPin(_output_pin, _spindle_pwm_chan_num); // attach the PWM to the pin
|
return rpm;
|
||||||
|
|
||||||
pinMode(_enable_pin, OUTPUT);
|
// apply speed overrides
|
||||||
|
rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (percent)
|
||||||
|
|
||||||
set_rpm(0);
|
// apply limits limits
|
||||||
|
if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm))
|
||||||
|
rpm = _max_rpm;
|
||||||
|
else if (rpm != 0 && rpm <= _min_rpm)
|
||||||
|
rpm = _min_rpm;
|
||||||
|
sys.spindle_speed = rpm;
|
||||||
|
|
||||||
use_delays = true;
|
// determine the pwm value
|
||||||
|
if (rpm == 0) {
|
||||||
|
pwm_value = _pwm_off_value;
|
||||||
|
} else {
|
||||||
|
pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value);
|
||||||
|
}
|
||||||
|
|
||||||
config_message();
|
set_output(pwm_value);
|
||||||
}
|
|
||||||
|
|
||||||
// prints the startup message of the spindle config
|
|
||||||
void BESCSpindle ::config_message() {
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL,
|
|
||||||
MSG_LEVEL_INFO,
|
|
||||||
"BESC spindle on Pin:%s Min:%0.2fms Max:%0.2fms Freq:%dHz Res:%dbits",
|
|
||||||
pinName(_output_pin).c_str(),
|
|
||||||
BESC_MIN_PULSE_SECS * 1000.0, // convert to milliseconds
|
|
||||||
BESC_MAX_PULSE_SECS * 1000.0, // convert to milliseconds
|
|
||||||
_pwm_freq,
|
|
||||||
_pwm_precision);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t BESCSpindle::set_rpm(uint32_t rpm) {
|
|
||||||
uint32_t pwm_value;
|
|
||||||
|
|
||||||
if (_output_pin == UNDEFINED_PIN)
|
|
||||||
return rpm;
|
return rpm;
|
||||||
|
|
||||||
// apply speed overrides
|
|
||||||
rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (percent)
|
|
||||||
|
|
||||||
// apply limits limits
|
|
||||||
if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm))
|
|
||||||
rpm = _max_rpm;
|
|
||||||
else if (rpm != 0 && rpm <= _min_rpm)
|
|
||||||
rpm = _min_rpm;
|
|
||||||
sys.spindle_speed = rpm;
|
|
||||||
|
|
||||||
// determine the pwm value
|
|
||||||
if (rpm == 0) {
|
|
||||||
pwm_value = _pwm_off_value;
|
|
||||||
} else {
|
|
||||||
pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set_output(pwm_value);
|
|
||||||
return rpm;
|
|
||||||
}
|
}
|
||||||
|
54
Grbl_Esp32/src/Spindles/BESCSpindle.h
Normal file
54
Grbl_Esp32/src/Spindles/BESCSpindle.h
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/*
|
||||||
|
BESCSpindle.cpp
|
||||||
|
|
||||||
|
This a special type of PWM spindle for RC type Brushless DC Speed
|
||||||
|
controllers. They use a short pulse for off and a longer pulse for
|
||||||
|
full on. The pulse is always a small portion of the full cycle.
|
||||||
|
Some BESCs have a special turn on procedure. This may be a one time
|
||||||
|
procedure or must be done every time. The user must do that via gcode.
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Important ESC Settings
|
||||||
|
50 Hz this is a typical frequency for an ESC
|
||||||
|
Some ESCs can handle higher frequencies, but there is no advantage to changing it.
|
||||||
|
|
||||||
|
Determine the typical min and max pulse length of your ESC
|
||||||
|
BESC_MIN_PULSE_SECS is typically 1ms (0.001 sec) or less
|
||||||
|
BESC_MAX_PULSE_SECS is typically 2ms (0.002 sec) or more
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PWMSpindle.h"
|
||||||
|
|
||||||
|
namespace Spindles {
|
||||||
|
class BESCSpindle : public PWMSpindle {
|
||||||
|
public:
|
||||||
|
BESCSpindle() = default;
|
||||||
|
|
||||||
|
BESCSpindle(const BESCSpindle&) = delete;
|
||||||
|
BESCSpindle(BESCSpindle&&) = delete;
|
||||||
|
BESCSpindle& operator=(const BESCSpindle&) = delete;
|
||||||
|
BESCSpindle& operator=(BESCSpindle&&) = delete;
|
||||||
|
|
||||||
|
void init() override;
|
||||||
|
void config_message() override;
|
||||||
|
uint32_t set_rpm(uint32_t rpm) override;
|
||||||
|
|
||||||
|
virtual ~BESCSpindle() {}
|
||||||
|
};
|
||||||
|
}
|
@@ -21,84 +21,86 @@
|
|||||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#include "SpindleClass.h"
|
#include "DacSpindle.h"
|
||||||
|
|
||||||
// ======================================== DacSpindle ======================================
|
namespace Spindles {
|
||||||
void DacSpindle ::init() {
|
// ======================================== DacSpindle ======================================
|
||||||
get_pins_and_settings();
|
void DacSpindle::init() {
|
||||||
|
get_pins_and_settings();
|
||||||
|
|
||||||
if (_output_pin == UNDEFINED_PIN)
|
if (_output_pin == UNDEFINED_PIN)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_min_rpm = rpm_min->get();
|
_min_rpm = rpm_min->get();
|
||||||
_max_rpm = rpm_max->get();
|
_max_rpm = rpm_max->get();
|
||||||
_pwm_min_value = 0; // not actually PWM...DAC counts
|
_pwm_min_value = 0; // not actually PWM...DAC counts
|
||||||
_pwm_max_value = 255; // not actually PWM...DAC counts
|
_pwm_max_value = 255; // not actually PWM...DAC counts
|
||||||
_gpio_ok = true;
|
_gpio_ok = true;
|
||||||
|
|
||||||
if (_output_pin != GPIO_NUM_25 && _output_pin != GPIO_NUM_26) { // DAC can only be used on these pins
|
if (_output_pin != GPIO_NUM_25 && _output_pin != GPIO_NUM_26) { // DAC can only be used on these pins
|
||||||
_gpio_ok = false;
|
_gpio_ok = false;
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "DAC spindle pin invalid GPIO_NUM_%d (pin 25 or 26 only)", _output_pin);
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "DAC spindle pin invalid GPIO_NUM_%d (pin 25 or 26 only)", _output_pin);
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
pinMode(_enable_pin, OUTPUT);
|
|
||||||
pinMode(_direction_pin, OUTPUT);
|
|
||||||
|
|
||||||
is_reversable = (_direction_pin != UNDEFINED_PIN);
|
|
||||||
use_delays = true;
|
|
||||||
|
|
||||||
config_message();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DacSpindle ::config_message() {
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL,
|
|
||||||
MSG_LEVEL_INFO,
|
|
||||||
"DAC spindle Output:%s, Enbl:%s, Dir:%s, Res:8bits",
|
|
||||||
pinName(_output_pin).c_str(),
|
|
||||||
pinName(_enable_pin).c_str(),
|
|
||||||
pinName(_direction_pin).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t DacSpindle::set_rpm(uint32_t rpm) {
|
|
||||||
if (_output_pin == UNDEFINED_PIN)
|
|
||||||
return rpm;
|
|
||||||
|
|
||||||
uint32_t pwm_value;
|
|
||||||
|
|
||||||
// apply overrides and limits
|
|
||||||
rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (percent)
|
|
||||||
|
|
||||||
// Calculate PWM register value based on rpm max/min settings and programmed rpm.
|
|
||||||
if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm)) {
|
|
||||||
// No PWM range possible. Set simple on/off spindle control pin state.
|
|
||||||
sys.spindle_speed = _max_rpm;
|
|
||||||
pwm_value = _pwm_max_value;
|
|
||||||
} else if (rpm <= _min_rpm) {
|
|
||||||
if (rpm == 0) { // S0 disables spindle
|
|
||||||
sys.spindle_speed = 0;
|
|
||||||
pwm_value = 0;
|
|
||||||
} else { // Set minimum PWM output
|
|
||||||
rpm = _min_rpm;
|
|
||||||
sys.spindle_speed = rpm;
|
|
||||||
pwm_value = 0;
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Spindle RPM less than min RPM:%5.2f %d", rpm, pwm_value);
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Compute intermediate PWM value with linear spindle speed model.
|
|
||||||
// NOTE: A nonlinear model could be installed here, if required, but keep it VERY light-weight.
|
|
||||||
sys.spindle_speed = rpm;
|
|
||||||
|
|
||||||
pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value);
|
pinMode(_enable_pin, OUTPUT);
|
||||||
|
pinMode(_direction_pin, OUTPUT);
|
||||||
|
|
||||||
|
is_reversable = (_direction_pin != UNDEFINED_PIN);
|
||||||
|
use_delays = true;
|
||||||
|
|
||||||
|
config_message();
|
||||||
}
|
}
|
||||||
|
|
||||||
set_output(pwm_value);
|
void DacSpindle::config_message() {
|
||||||
|
grbl_msg_sendf(CLIENT_SERIAL,
|
||||||
|
MSG_LEVEL_INFO,
|
||||||
|
"DAC spindle Output:%s, Enbl:%s, Dir:%s, Res:8bits",
|
||||||
|
pinName(_output_pin).c_str(),
|
||||||
|
pinName(_enable_pin).c_str(),
|
||||||
|
pinName(_direction_pin).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
return rpm;
|
uint32_t DacSpindle::set_rpm(uint32_t rpm) {
|
||||||
}
|
if (_output_pin == UNDEFINED_PIN)
|
||||||
|
return rpm;
|
||||||
|
|
||||||
void DacSpindle ::set_output(uint32_t duty) {
|
uint32_t pwm_value;
|
||||||
if (_gpio_ok) {
|
|
||||||
dacWrite(_output_pin, (uint8_t)duty);
|
// apply overrides and limits
|
||||||
|
rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (percent)
|
||||||
|
|
||||||
|
// Calculate PWM register value based on rpm max/min settings and programmed rpm.
|
||||||
|
if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm)) {
|
||||||
|
// No PWM range possible. Set simple on/off spindle control pin state.
|
||||||
|
sys.spindle_speed = _max_rpm;
|
||||||
|
pwm_value = _pwm_max_value;
|
||||||
|
} else if (rpm <= _min_rpm) {
|
||||||
|
if (rpm == 0) { // S0 disables spindle
|
||||||
|
sys.spindle_speed = 0;
|
||||||
|
pwm_value = 0;
|
||||||
|
} else { // Set minimum PWM output
|
||||||
|
rpm = _min_rpm;
|
||||||
|
sys.spindle_speed = rpm;
|
||||||
|
pwm_value = 0;
|
||||||
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Spindle RPM less than min RPM:%5.2f %d", rpm, pwm_value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Compute intermediate PWM value with linear spindle speed model.
|
||||||
|
// NOTE: A nonlinear model could be installed here, if required, but keep it VERY light-weight.
|
||||||
|
sys.spindle_speed = rpm;
|
||||||
|
|
||||||
|
pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_output(pwm_value);
|
||||||
|
|
||||||
|
return rpm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DacSpindle::set_output(uint32_t duty) {
|
||||||
|
if (_gpio_ok) {
|
||||||
|
dacWrite(_output_pin, (uint8_t)duty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
51
Grbl_Esp32/src/Spindles/DacSpindle.h
Normal file
51
Grbl_Esp32/src/Spindles/DacSpindle.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/*
|
||||||
|
DacSpindle.cpp
|
||||||
|
|
||||||
|
This uses the Analog DAC in the ESP32 to generate a voltage
|
||||||
|
proportional to the GCode S value desired. Some spindle uses
|
||||||
|
a 0-5V or 0-10V value to control the spindle. You would use
|
||||||
|
an Op Amp type circuit to get from the 0.3.3V of the ESP32 to that voltage.
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PWMSpindle.h"
|
||||||
|
|
||||||
|
namespace Spindles {
|
||||||
|
// This uses one of the (2) DAC pins on ESP32 to output a voltage
|
||||||
|
class DacSpindle : public PWMSpindle {
|
||||||
|
public:
|
||||||
|
DacSpindle() = default;
|
||||||
|
|
||||||
|
DacSpindle(const DacSpindle&) = delete;
|
||||||
|
DacSpindle(DacSpindle&&) = delete;
|
||||||
|
DacSpindle& operator=(const DacSpindle&) = delete;
|
||||||
|
DacSpindle& operator=(DacSpindle&&) = delete;
|
||||||
|
|
||||||
|
void init() override;
|
||||||
|
void config_message() override;
|
||||||
|
uint32_t set_rpm(uint32_t rpm) override;
|
||||||
|
|
||||||
|
virtual ~DacSpindle() {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _gpio_ok; // DAC is on a valid pin
|
||||||
|
protected:
|
||||||
|
void set_output(uint32_t duty); // sets DAC instead of PWM
|
||||||
|
};
|
||||||
|
}
|
@@ -109,9 +109,9 @@
|
|||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#include "SpindleClass.h"
|
#include "HuanyangSpindle.h"
|
||||||
|
|
||||||
#include "driver/uart.h"
|
#include <driver/uart.h>
|
||||||
|
|
||||||
#define HUANYANG_UART_PORT UART_NUM_2 // hard coded for this port right now
|
#define HUANYANG_UART_PORT UART_NUM_2 // hard coded for this port right now
|
||||||
#define ECHO_TEST_CTS UART_PIN_NO_CHANGE // CTS pin is not used
|
#define ECHO_TEST_CTS UART_PIN_NO_CHANGE // CTS pin is not used
|
||||||
@@ -131,337 +131,335 @@
|
|||||||
# define HUANYANG_BAUD_RATE 9600 // PD164 setting
|
# define HUANYANG_BAUD_RATE 9600 // PD164 setting
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// communication task and queue stuff
|
namespace Spindles {
|
||||||
typedef struct {
|
// communication task and queue stuff
|
||||||
uint8_t tx_length;
|
typedef struct {
|
||||||
uint8_t rx_length;
|
uint8_t tx_length;
|
||||||
bool critical;
|
uint8_t rx_length;
|
||||||
char msg[HUANYANG_MAX_MSG_SIZE];
|
bool critical;
|
||||||
} hy_command_t;
|
char msg[HUANYANG_MAX_MSG_SIZE];
|
||||||
|
} hy_command_t;
|
||||||
|
|
||||||
typedef enum : uint8_t {
|
typedef enum : uint8_t {
|
||||||
READ_SET_FREQ = 0, // The set frequency
|
READ_SET_FREQ = 0, // The set frequency
|
||||||
READ_OUTPUT_FREQ = 1, // The current operating frequency
|
READ_OUTPUT_FREQ = 1, // The current operating frequency
|
||||||
READ_OUTPUT_AMPS = 2, //
|
READ_OUTPUT_AMPS = 2, //
|
||||||
READ_SET_RPM = 3, // This is the last requested freq even in off mode
|
READ_SET_RPM = 3, // This is the last requested freq even in off mode
|
||||||
READ_DC_VOLTAGE = 4, //
|
READ_DC_VOLTAGE = 4, //
|
||||||
READ_AC_VOLTAGE = 5, //
|
READ_AC_VOLTAGE = 5, //
|
||||||
READ_CONT = 6, // counting value???
|
READ_CONT = 6, // counting value???
|
||||||
READ_TEMP = 7, //
|
READ_TEMP = 7, //
|
||||||
} read_register_t;
|
} read_register_t;
|
||||||
|
|
||||||
QueueHandle_t hy_cmd_queue;
|
QueueHandle_t hy_cmd_queue;
|
||||||
|
|
||||||
static TaskHandle_t vfd_cmdTaskHandle = 0;
|
static TaskHandle_t vfd_cmdTaskHandle = 0;
|
||||||
|
|
||||||
bool hy_spindle_ok = true;
|
bool hy_spindle_ok = true;
|
||||||
|
|
||||||
// The communications task
|
// The communications task
|
||||||
void vfd_cmd_task(void* pvParameters) {
|
void vfd_cmd_task(void* pvParameters) {
|
||||||
static bool unresponsive = false; // to pop off a message once each time it becomes unresponsive
|
static bool unresponsive = false; // to pop off a message once each time it becomes unresponsive
|
||||||
uint8_t reg_item = 0x00;
|
uint8_t reg_item = 0x00;
|
||||||
hy_command_t next_cmd;
|
hy_command_t next_cmd;
|
||||||
uint8_t rx_message[HUANYANG_MAX_MSG_SIZE];
|
uint8_t rx_message[HUANYANG_MAX_MSG_SIZE];
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (xQueueReceive(hy_cmd_queue, &next_cmd, 0) == pdTRUE) {
|
if (xQueueReceive(hy_cmd_queue, &next_cmd, 0) == pdTRUE) {
|
||||||
uart_flush(HUANYANG_UART_PORT);
|
uart_flush(HUANYANG_UART_PORT);
|
||||||
//report_hex_msg(next_cmd.msg, "Tx: ", next_cmd.tx_length);
|
//report_hex_msg(next_cmd.msg, "Tx: ", next_cmd.tx_length);
|
||||||
uart_write_bytes(HUANYANG_UART_PORT, next_cmd.msg, next_cmd.tx_length);
|
uart_write_bytes(HUANYANG_UART_PORT, next_cmd.msg, next_cmd.tx_length);
|
||||||
|
|
||||||
uint16_t read_length = uart_read_bytes(HUANYANG_UART_PORT, rx_message, next_cmd.rx_length, RESPONSE_WAIT_TICKS);
|
uint16_t read_length = uart_read_bytes(HUANYANG_UART_PORT, rx_message, next_cmd.rx_length, RESPONSE_WAIT_TICKS);
|
||||||
|
|
||||||
if (read_length < next_cmd.rx_length) {
|
if (read_length < next_cmd.rx_length) {
|
||||||
if (!unresponsive) {
|
if (!unresponsive) {
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Spindle RS485 Unresponsive %d", read_length);
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Spindle RS485 Unresponsive %d", read_length);
|
||||||
if (next_cmd.critical) {
|
if (next_cmd.critical) {
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Critical Spindle RS485 Unresponsive");
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Critical Spindle RS485 Unresponsive");
|
||||||
system_set_exec_alarm(EXEC_ALARM_SPINDLE_CONTROL);
|
system_set_exec_alarm(EXEC_ALARM_SPINDLE_CONTROL);
|
||||||
|
}
|
||||||
|
unresponsive = true;
|
||||||
}
|
}
|
||||||
unresponsive = true;
|
} else {
|
||||||
|
// success
|
||||||
|
unresponsive = false;
|
||||||
|
//report_hex_msg(rx_message, "Rx: ", read_length);
|
||||||
|
uint32_t ret_value = ((uint32_t)rx_message[4] << 8) + rx_message[5];
|
||||||
|
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Item:%d value:%05d ", rx_message[3], ret_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// success
|
HuanyangSpindle::read_value(reg_item); // only this appears to work all the time. Other registers are flakey.
|
||||||
unresponsive = false;
|
if (reg_item < 0x03)
|
||||||
//report_hex_msg(rx_message, "Rx: ", read_length);
|
reg_item++;
|
||||||
uint32_t ret_value = ((uint32_t)rx_message[4] << 8) + rx_message[5];
|
else {
|
||||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Item:%d value:%05d ", rx_message[3], ret_value);
|
reg_item = 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
HuanyangSpindle ::read_value(reg_item); // only this appears to work all the time. Other registers are flakey.
|
|
||||||
if (reg_item < 0x03)
|
|
||||||
reg_item++;
|
|
||||||
else {
|
|
||||||
reg_item = 0x00;
|
|
||||||
}
|
}
|
||||||
|
vTaskDelay(HUANYANG_POLL_RATE); // TODO: What is the best value here?
|
||||||
}
|
}
|
||||||
vTaskDelay(HUANYANG_POLL_RATE); // TODO: What is the best value here?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ================== Class methods ==================================
|
|
||||||
|
|
||||||
void HuanyangSpindle ::init() {
|
|
||||||
hy_spindle_ok = true; // initialize
|
|
||||||
|
|
||||||
// fail if required items are not defined
|
|
||||||
if (!get_pins_and_settings()) {
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Huanyang spindle errors");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_task_running) { // init can happen many times, we only want to start one task
|
// ================== Class methods ==================================
|
||||||
hy_cmd_queue = xQueueCreate(HUANYANG_QUEUE_SIZE, sizeof(hy_command_t));
|
|
||||||
xTaskCreatePinnedToCore(vfd_cmd_task, // task
|
void HuanyangSpindle::init() {
|
||||||
"vfd_cmdTaskHandle", // name for task
|
hy_spindle_ok = true; // initialize
|
||||||
2048, // size of task stack
|
|
||||||
NULL, // parameters
|
// fail if required items are not defined
|
||||||
1, // priority
|
if (!get_pins_and_settings()) {
|
||||||
&vfd_cmdTaskHandle,
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Huanyang spindle errors");
|
||||||
0 // core
|
return;
|
||||||
);
|
}
|
||||||
_task_running = true;
|
|
||||||
|
if (!_task_running) { // init can happen many times, we only want to start one task
|
||||||
|
hy_cmd_queue = xQueueCreate(HUANYANG_QUEUE_SIZE, sizeof(hy_command_t));
|
||||||
|
xTaskCreatePinnedToCore(vfd_cmd_task, // task
|
||||||
|
"vfd_cmdTaskHandle", // name for task
|
||||||
|
2048, // size of task stack
|
||||||
|
NULL, // parameters
|
||||||
|
1, // priority
|
||||||
|
&vfd_cmdTaskHandle,
|
||||||
|
0 // core
|
||||||
|
);
|
||||||
|
_task_running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this allows us to init() again later.
|
||||||
|
// If you change certain settings, init() gets called agian
|
||||||
|
uart_driver_delete(HUANYANG_UART_PORT);
|
||||||
|
|
||||||
|
uart_config_t uart_config = {
|
||||||
|
.baud_rate = HUANYANG_BAUD_RATE,
|
||||||
|
.data_bits = UART_DATA_8_BITS,
|
||||||
|
.parity = UART_PARITY_DISABLE,
|
||||||
|
.stop_bits = UART_STOP_BITS_1,
|
||||||
|
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||||
|
.rx_flow_ctrl_thresh = 122,
|
||||||
|
};
|
||||||
|
|
||||||
|
uart_param_config(HUANYANG_UART_PORT, &uart_config);
|
||||||
|
|
||||||
|
uart_set_pin(HUANYANG_UART_PORT, _txd_pin, _rxd_pin, _rts_pin, UART_PIN_NO_CHANGE);
|
||||||
|
|
||||||
|
uart_driver_install(HUANYANG_UART_PORT, HUANYANG_BUF_SIZE * 2, 0, 0, NULL, 0);
|
||||||
|
|
||||||
|
uart_set_mode(HUANYANG_UART_PORT, UART_MODE_RS485_HALF_DUPLEX);
|
||||||
|
|
||||||
|
is_reversable = true; // these VFDs are always reversable
|
||||||
|
use_delays = true;
|
||||||
|
|
||||||
|
//
|
||||||
|
_current_rpm = 0;
|
||||||
|
_state = SPINDLE_DISABLE;
|
||||||
|
|
||||||
|
config_message();
|
||||||
}
|
}
|
||||||
|
|
||||||
// this allows us to init() again later.
|
// Checks for all the required pin definitions
|
||||||
// If you change certain settings, init() gets called agian
|
// It returns a message for each missing pin
|
||||||
uart_driver_delete(HUANYANG_UART_PORT);
|
// Returns true if all pins are defined.
|
||||||
|
bool HuanyangSpindle::get_pins_and_settings() {
|
||||||
uart_config_t uart_config = {
|
|
||||||
.baud_rate = HUANYANG_BAUD_RATE,
|
|
||||||
.data_bits = UART_DATA_8_BITS,
|
|
||||||
.parity = UART_PARITY_DISABLE,
|
|
||||||
.stop_bits = UART_STOP_BITS_1,
|
|
||||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
|
||||||
.rx_flow_ctrl_thresh = 122,
|
|
||||||
};
|
|
||||||
|
|
||||||
uart_param_config(HUANYANG_UART_PORT, &uart_config);
|
|
||||||
|
|
||||||
uart_set_pin(HUANYANG_UART_PORT, _txd_pin, _rxd_pin, _rts_pin, UART_PIN_NO_CHANGE);
|
|
||||||
|
|
||||||
uart_driver_install(HUANYANG_UART_PORT, HUANYANG_BUF_SIZE * 2, 0, 0, NULL, 0);
|
|
||||||
|
|
||||||
uart_set_mode(HUANYANG_UART_PORT, UART_MODE_RS485_HALF_DUPLEX);
|
|
||||||
|
|
||||||
is_reversable = true; // these VFDs are always reversable
|
|
||||||
use_delays = true;
|
|
||||||
|
|
||||||
//
|
|
||||||
_current_rpm = 0;
|
|
||||||
_state = SPINDLE_DISABLE;
|
|
||||||
|
|
||||||
config_message();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks for all the required pin definitions
|
|
||||||
// It returns a message for each missing pin
|
|
||||||
// Returns true if all pins are defined.
|
|
||||||
bool HuanyangSpindle ::get_pins_and_settings() {
|
|
||||||
#ifdef HUANYANG_TXD_PIN
|
#ifdef HUANYANG_TXD_PIN
|
||||||
_txd_pin = HUANYANG_TXD_PIN;
|
_txd_pin = HUANYANG_TXD_PIN;
|
||||||
#else
|
#else
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Undefined HUANYANG_TXD_PIN");
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Undefined HUANYANG_TXD_PIN");
|
||||||
hy_spindle_ok = false;
|
hy_spindle_ok = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HUANYANG_RXD_PIN
|
#ifdef HUANYANG_RXD_PIN
|
||||||
_rxd_pin = HUANYANG_RXD_PIN;
|
_rxd_pin = HUANYANG_RXD_PIN;
|
||||||
#else
|
#else
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Undefined HUANYANG_RXD_PIN");
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Undefined HUANYANG_RXD_PIN");
|
||||||
hy_spindle_ok = false;
|
hy_spindle_ok = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HUANYANG_RTS_PIN
|
#ifdef HUANYANG_RTS_PIN
|
||||||
_rts_pin = HUANYANG_RTS_PIN;
|
_rts_pin = HUANYANG_RTS_PIN;
|
||||||
#else
|
#else
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Undefined HUANYANG_RTS_PIN");
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Undefined HUANYANG_RTS_PIN");
|
||||||
hy_spindle_ok = false;
|
hy_spindle_ok = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (laser_mode->get()) {
|
if (laser_mode->get()) {
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Huanyang spindle disabled in laser mode. Set $GCode/LaserMode=Off and restart");
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Huanyang spindle disabled in laser mode. Set $GCode/LaserMode=Off and restart");
|
||||||
hy_spindle_ok = false;
|
hy_spindle_ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_min_rpm = rpm_min->get();
|
||||||
|
_max_rpm = rpm_max->get();
|
||||||
|
|
||||||
|
return hy_spindle_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
_min_rpm = rpm_min->get();
|
void HuanyangSpindle::config_message() {
|
||||||
_max_rpm = rpm_max->get();
|
grbl_msg_sendf(CLIENT_SERIAL,
|
||||||
|
MSG_LEVEL_INFO,
|
||||||
|
"Huanyang Spindle Tx:%s Rx:%s RTS:%s",
|
||||||
|
pinName(_txd_pin).c_str(),
|
||||||
|
pinName(_rxd_pin).c_str(),
|
||||||
|
pinName(_rts_pin).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
return hy_spindle_ok;
|
void HuanyangSpindle::set_state(uint8_t state, uint32_t rpm) {
|
||||||
}
|
if (sys.abort)
|
||||||
|
return; // Block during abort.
|
||||||
|
|
||||||
void HuanyangSpindle ::config_message() {
|
bool critical = (sys.state == STATE_CYCLE || state != SPINDLE_DISABLE);
|
||||||
grbl_msg_sendf(CLIENT_SERIAL,
|
|
||||||
MSG_LEVEL_INFO,
|
|
||||||
"Huanyang Spindle Tx:%s Rx:%s RTS:%s",
|
|
||||||
pinName(_txd_pin).c_str(),
|
|
||||||
pinName(_rxd_pin).c_str(),
|
|
||||||
pinName(_rts_pin).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void HuanyangSpindle ::set_state(uint8_t state, uint32_t rpm) {
|
if (_current_state != state) { // already at the desired state. This function gets called a lot.
|
||||||
if (sys.abort)
|
set_mode(state, critical); // critical if we are in a job
|
||||||
return; // Block during abort.
|
|
||||||
|
|
||||||
bool critical = (sys.state == STATE_CYCLE || state != SPINDLE_DISABLE);
|
|
||||||
|
|
||||||
if (_current_state != state) { // already at the desired state. This function gets called a lot.
|
|
||||||
set_mode(state, critical); // critical if we are in a job
|
|
||||||
set_rpm(rpm);
|
|
||||||
if (state == SPINDLE_DISABLE) {
|
|
||||||
sys.spindle_speed = 0;
|
|
||||||
if (_current_state != state)
|
|
||||||
mc_dwell(spindle_delay_spindown->get());
|
|
||||||
} else {
|
|
||||||
if (_current_state != state)
|
|
||||||
mc_dwell(spindle_delay_spinup->get());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (_current_rpm != rpm)
|
|
||||||
set_rpm(rpm);
|
set_rpm(rpm);
|
||||||
}
|
if (state == SPINDLE_DISABLE) {
|
||||||
|
sys.spindle_speed = 0;
|
||||||
_current_state = state; // store locally for faster get_state()
|
if (_current_state != state)
|
||||||
|
mc_dwell(spindle_delay_spindown->get());
|
||||||
sys.report_ovr_counter = 0; // Set to report change immediately
|
} else {
|
||||||
|
if (_current_state != state)
|
||||||
return;
|
mc_dwell(spindle_delay_spinup->get());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
bool HuanyangSpindle ::set_mode(uint8_t mode, bool critical) {
|
if (_current_rpm != rpm)
|
||||||
if (!hy_spindle_ok)
|
set_rpm(rpm);
|
||||||
return false;
|
|
||||||
|
|
||||||
hy_command_t mode_cmd;
|
|
||||||
|
|
||||||
mode_cmd.tx_length = 6;
|
|
||||||
mode_cmd.rx_length = 6;
|
|
||||||
|
|
||||||
mode_cmd.msg[0] = HUANYANG_ADDR;
|
|
||||||
mode_cmd.msg[1] = 0x03;
|
|
||||||
mode_cmd.msg[2] = 0x01;
|
|
||||||
|
|
||||||
if (mode == SPINDLE_ENABLE_CW)
|
|
||||||
mode_cmd.msg[3] = 0x01;
|
|
||||||
else if (mode == SPINDLE_ENABLE_CCW)
|
|
||||||
mode_cmd.msg[3] = 0x11;
|
|
||||||
else { //SPINDLE_DISABLE
|
|
||||||
mode_cmd.msg[3] = 0x08;
|
|
||||||
|
|
||||||
if (!xQueueReset(hy_cmd_queue)) {
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD spindle off, queue could not be reset");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_current_state = state; // store locally for faster get_state()
|
||||||
|
|
||||||
|
sys.report_ovr_counter = 0; // Set to report change immediately
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
add_ModRTU_CRC(mode_cmd.msg, mode_cmd.rx_length);
|
bool HuanyangSpindle::set_mode(uint8_t mode, bool critical) {
|
||||||
|
if (!hy_spindle_ok)
|
||||||
|
return false;
|
||||||
|
|
||||||
mode_cmd.critical = critical;
|
hy_command_t mode_cmd;
|
||||||
|
|
||||||
if (xQueueSend(hy_cmd_queue, &mode_cmd, 0) != pdTRUE)
|
mode_cmd.tx_length = 6;
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD Queue Full");
|
mode_cmd.rx_length = 6;
|
||||||
|
|
||||||
return true;
|
mode_cmd.msg[0] = HUANYANG_ADDR;
|
||||||
}
|
mode_cmd.msg[1] = 0x03;
|
||||||
|
mode_cmd.msg[2] = 0x01;
|
||||||
|
|
||||||
uint32_t HuanyangSpindle ::set_rpm(uint32_t rpm) {
|
if (mode == SPINDLE_ENABLE_CW)
|
||||||
if (!hy_spindle_ok)
|
mode_cmd.msg[3] = 0x01;
|
||||||
return 0;
|
else if (mode == SPINDLE_ENABLE_CCW)
|
||||||
|
mode_cmd.msg[3] = 0x11;
|
||||||
|
else { //SPINDLE_DISABLE
|
||||||
|
mode_cmd.msg[3] = 0x08;
|
||||||
|
|
||||||
hy_command_t rpm_cmd;
|
if (!xQueueReset(hy_cmd_queue)) {
|
||||||
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD spindle off, queue could not be reset");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// apply override
|
add_ModRTU_CRC(mode_cmd.msg, mode_cmd.rx_length);
|
||||||
rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (uint8_t percent)
|
|
||||||
|
|
||||||
// apply limits
|
mode_cmd.critical = critical;
|
||||||
if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm))
|
|
||||||
rpm = _max_rpm;
|
|
||||||
else if (rpm != 0 && rpm <= _min_rpm)
|
|
||||||
rpm = _min_rpm;
|
|
||||||
|
|
||||||
sys.spindle_speed = rpm;
|
if (xQueueSend(hy_cmd_queue, &mode_cmd, 0) != pdTRUE)
|
||||||
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD Queue Full");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t HuanyangSpindle::set_rpm(uint32_t rpm) {
|
||||||
|
if (!hy_spindle_ok)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
hy_command_t rpm_cmd;
|
||||||
|
|
||||||
|
// apply override
|
||||||
|
rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (uint8_t percent)
|
||||||
|
|
||||||
|
// apply limits
|
||||||
|
if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm))
|
||||||
|
rpm = _max_rpm;
|
||||||
|
else if (rpm != 0 && rpm <= _min_rpm)
|
||||||
|
rpm = _min_rpm;
|
||||||
|
|
||||||
|
sys.spindle_speed = rpm;
|
||||||
|
|
||||||
|
if (rpm == _current_rpm) // prevent setting same RPM twice
|
||||||
|
return rpm;
|
||||||
|
|
||||||
|
_current_rpm = rpm;
|
||||||
|
|
||||||
|
// TODO add the speed modifiers override, linearization, etc.
|
||||||
|
|
||||||
|
rpm_cmd.tx_length = 7;
|
||||||
|
rpm_cmd.rx_length = 6;
|
||||||
|
|
||||||
|
rpm_cmd.msg[0] = HUANYANG_ADDR;
|
||||||
|
rpm_cmd.msg[1] = 0x05;
|
||||||
|
rpm_cmd.msg[2] = 0x02;
|
||||||
|
|
||||||
|
uint16_t data = (uint16_t)(rpm * 100 / 60); // send Hz * 10 (Ex:1500 RPM = 25Hz .... Send 2500)
|
||||||
|
|
||||||
|
rpm_cmd.msg[3] = (data & 0xFF00) >> 8;
|
||||||
|
rpm_cmd.msg[4] = (data & 0xFF);
|
||||||
|
|
||||||
|
add_ModRTU_CRC(rpm_cmd.msg, rpm_cmd.tx_length);
|
||||||
|
|
||||||
|
rpm_cmd.critical = false;
|
||||||
|
|
||||||
|
if (xQueueSend(hy_cmd_queue, &rpm_cmd, 0) != pdTRUE)
|
||||||
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD Queue Full");
|
||||||
|
|
||||||
if (rpm == _current_rpm) // prevent setting same RPM twice
|
|
||||||
return rpm;
|
return rpm;
|
||||||
|
|
||||||
_current_rpm = rpm;
|
|
||||||
|
|
||||||
// TODO add the speed modifiers override, linearization, etc.
|
|
||||||
|
|
||||||
rpm_cmd.tx_length = 7;
|
|
||||||
rpm_cmd.rx_length = 6;
|
|
||||||
|
|
||||||
rpm_cmd.msg[0] = HUANYANG_ADDR;
|
|
||||||
rpm_cmd.msg[1] = 0x05;
|
|
||||||
rpm_cmd.msg[2] = 0x02;
|
|
||||||
|
|
||||||
uint16_t data = (uint16_t)(rpm * 100 / 60); // send Hz * 10 (Ex:1500 RPM = 25Hz .... Send 2500)
|
|
||||||
|
|
||||||
rpm_cmd.msg[3] = (data & 0xFF00) >> 8;
|
|
||||||
rpm_cmd.msg[4] = (data & 0xFF);
|
|
||||||
|
|
||||||
add_ModRTU_CRC(rpm_cmd.msg, rpm_cmd.tx_length);
|
|
||||||
|
|
||||||
rpm_cmd.critical = false;
|
|
||||||
|
|
||||||
if (xQueueSend(hy_cmd_queue, &rpm_cmd, 0) != pdTRUE)
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD Queue Full");
|
|
||||||
|
|
||||||
return rpm;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This appears to read the control register and will return an RPM running or not.
|
|
||||||
void HuanyangSpindle ::read_value(uint8_t reg) {
|
|
||||||
uint16_t ret_value = 0;
|
|
||||||
hy_command_t read_cmd;
|
|
||||||
uint8_t rx_message[HUANYANG_MAX_MSG_SIZE];
|
|
||||||
|
|
||||||
read_cmd.tx_length = 8;
|
|
||||||
read_cmd.rx_length = 8;
|
|
||||||
|
|
||||||
read_cmd.msg[0] = HUANYANG_ADDR;
|
|
||||||
read_cmd.msg[1] = 0x04;
|
|
||||||
read_cmd.msg[2] = 0x03;
|
|
||||||
|
|
||||||
read_cmd.msg[3] = reg;
|
|
||||||
|
|
||||||
read_cmd.msg[4] = 0x00;
|
|
||||||
read_cmd.msg[5] = 0x00;
|
|
||||||
|
|
||||||
read_cmd.critical = (sys.state == STATE_CYCLE); // only critical if running a job TBD.... maybe spindle on?
|
|
||||||
|
|
||||||
add_ModRTU_CRC(read_cmd.msg, read_cmd.tx_length);
|
|
||||||
|
|
||||||
if (xQueueSend(hy_cmd_queue, &read_cmd, 0) != pdTRUE)
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD Queue Full");
|
|
||||||
}
|
|
||||||
|
|
||||||
void HuanyangSpindle ::stop() {
|
|
||||||
set_mode(SPINDLE_DISABLE, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// state is cached rather than read right now to prevent delays
|
|
||||||
uint8_t HuanyangSpindle ::get_state() {
|
|
||||||
return _state;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the CRC on all of the byte except the last 2
|
|
||||||
// It then added the CRC to those last 2 bytes
|
|
||||||
// full_msg_len This is the length of the message including the 2 crc bytes
|
|
||||||
// Source: https://ctlsys.com/support/how_to_compute_the_modbus_rtu_message_crc/
|
|
||||||
void HuanyangSpindle ::add_ModRTU_CRC(char* buf, int full_msg_len) {
|
|
||||||
uint16_t crc = 0xFFFF;
|
|
||||||
for (int pos = 0; pos < full_msg_len - 2; pos++) {
|
|
||||||
crc ^= (uint16_t)buf[pos]; // XOR byte into least sig. byte of crc
|
|
||||||
for (int i = 8; i != 0; i--) { // Loop over each bit
|
|
||||||
if ((crc & 0x0001) != 0) { // If the LSB is set
|
|
||||||
crc >>= 1; // Shift right and XOR 0xA001
|
|
||||||
crc ^= 0xA001;
|
|
||||||
} else // Else LSB is not set
|
|
||||||
crc >>= 1; // Just shift right
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// add the calculated Crc to the message
|
|
||||||
buf[full_msg_len - 1] = (crc & 0xFF00) >> 8;
|
// This appears to read the control register and will return an RPM running or not.
|
||||||
buf[full_msg_len - 2] = (crc & 0xFF);
|
void HuanyangSpindle::read_value(uint8_t reg) {
|
||||||
|
uint16_t ret_value = 0;
|
||||||
|
hy_command_t read_cmd;
|
||||||
|
uint8_t rx_message[HUANYANG_MAX_MSG_SIZE];
|
||||||
|
|
||||||
|
read_cmd.tx_length = 8;
|
||||||
|
read_cmd.rx_length = 8;
|
||||||
|
|
||||||
|
read_cmd.msg[0] = HUANYANG_ADDR;
|
||||||
|
read_cmd.msg[1] = 0x04;
|
||||||
|
read_cmd.msg[2] = 0x03;
|
||||||
|
|
||||||
|
read_cmd.msg[3] = reg;
|
||||||
|
|
||||||
|
read_cmd.msg[4] = 0x00;
|
||||||
|
read_cmd.msg[5] = 0x00;
|
||||||
|
|
||||||
|
read_cmd.critical = (sys.state == STATE_CYCLE); // only critical if running a job TBD.... maybe spindle on?
|
||||||
|
|
||||||
|
add_ModRTU_CRC(read_cmd.msg, read_cmd.tx_length);
|
||||||
|
|
||||||
|
if (xQueueSend(hy_cmd_queue, &read_cmd, 0) != pdTRUE)
|
||||||
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "VFD Queue Full");
|
||||||
|
}
|
||||||
|
|
||||||
|
void HuanyangSpindle::stop() { set_mode(SPINDLE_DISABLE, false); }
|
||||||
|
|
||||||
|
// state is cached rather than read right now to prevent delays
|
||||||
|
uint8_t HuanyangSpindle::get_state() { return _state; }
|
||||||
|
|
||||||
|
// Calculate the CRC on all of the byte except the last 2
|
||||||
|
// It then added the CRC to those last 2 bytes
|
||||||
|
// full_msg_len This is the length of the message including the 2 crc bytes
|
||||||
|
// Source: https://ctlsys.com/support/how_to_compute_the_modbus_rtu_message_crc/
|
||||||
|
void HuanyangSpindle::add_ModRTU_CRC(char* buf, int full_msg_len) {
|
||||||
|
uint16_t crc = 0xFFFF;
|
||||||
|
for (int pos = 0; pos < full_msg_len - 2; pos++) {
|
||||||
|
crc ^= (uint16_t)buf[pos]; // XOR byte into least sig. byte of crc
|
||||||
|
for (int i = 8; i != 0; i--) { // Loop over each bit
|
||||||
|
if ((crc & 0x0001) != 0) { // If the LSB is set
|
||||||
|
crc >>= 1; // Shift right and XOR 0xA001
|
||||||
|
crc ^= 0xA001;
|
||||||
|
} else // Else LSB is not set
|
||||||
|
crc >>= 1; // Just shift right
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add the calculated Crc to the message
|
||||||
|
buf[full_msg_len - 1] = (crc & 0xFF00) >> 8;
|
||||||
|
buf[full_msg_len - 2] = (crc & 0xFF);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
62
Grbl_Esp32/src/Spindles/HuanyangSpindle.h
Normal file
62
Grbl_Esp32/src/Spindles/HuanyangSpindle.h
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/*
|
||||||
|
HuanyangSpindle.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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "Spindle.h"
|
||||||
|
|
||||||
|
namespace Spindles {
|
||||||
|
class HuanyangSpindle : public Spindle {
|
||||||
|
private:
|
||||||
|
uint16_t ModRTU_CRC(char* buf, int len);
|
||||||
|
|
||||||
|
bool set_mode(uint8_t mode, bool critical);
|
||||||
|
|
||||||
|
bool get_pins_and_settings();
|
||||||
|
|
||||||
|
uint32_t _current_rpm;
|
||||||
|
uint8_t _txd_pin;
|
||||||
|
uint8_t _rxd_pin;
|
||||||
|
uint8_t _rts_pin;
|
||||||
|
uint8_t _state;
|
||||||
|
bool _task_running;
|
||||||
|
|
||||||
|
public:
|
||||||
|
HuanyangSpindle() : _task_running(false) {}
|
||||||
|
|
||||||
|
HuanyangSpindle(const HuanyangSpindle&) = delete;
|
||||||
|
HuanyangSpindle(HuanyangSpindle&&) = delete;
|
||||||
|
HuanyangSpindle& operator=(const HuanyangSpindle&) = delete;
|
||||||
|
HuanyangSpindle& operator=(HuanyangSpindle&&) = delete;
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void config_message();
|
||||||
|
void set_state(uint8_t state, uint32_t rpm);
|
||||||
|
uint8_t get_state();
|
||||||
|
uint32_t set_rpm(uint32_t rpm);
|
||||||
|
void stop();
|
||||||
|
static void read_value(uint8_t reg);
|
||||||
|
static void add_ModRTU_CRC(char* buf, int full_msg_len);
|
||||||
|
|
||||||
|
virtual ~HuanyangSpindle() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint32_t _min_rpm;
|
||||||
|
uint32_t _max_rpm;
|
||||||
|
};
|
||||||
|
}
|
@@ -19,22 +19,24 @@
|
|||||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#include "SpindleClass.h"
|
#include "Laser.h"
|
||||||
|
|
||||||
// ===================================== Laser ==============================================
|
// ===================================== Laser ==============================================
|
||||||
|
|
||||||
bool Laser ::isRateAdjusted() {
|
namespace Spindles {
|
||||||
return true; // can use M4 (CCW) laser mode.
|
bool Laser::isRateAdjusted() {
|
||||||
}
|
return true; // can use M4 (CCW) laser mode.
|
||||||
|
}
|
||||||
|
|
||||||
void Laser ::config_message() {
|
void Laser::config_message() {
|
||||||
grbl_msg_sendf(CLIENT_SERIAL,
|
grbl_msg_sendf(CLIENT_SERIAL,
|
||||||
MSG_LEVEL_INFO,
|
MSG_LEVEL_INFO,
|
||||||
"Laser spindle on Pin:%s, Freq:%.2fHz, Res:%dbits Laser mode:$32=%d",
|
"Laser spindle on Pin:%s, Freq:%.2fHz, Res:%dbits Laser mode:$32=%d",
|
||||||
pinName(_output_pin).c_str(),
|
pinName(_output_pin).c_str(),
|
||||||
_pwm_freq,
|
_pwm_freq,
|
||||||
_pwm_precision,
|
_pwm_precision,
|
||||||
isRateAdjusted()); // the current mode
|
isRateAdjusted()); // the current mode
|
||||||
|
|
||||||
use_delays = false; // this will override the value set in PWMSpindle intit()
|
use_delays = false; // this will override the value set in PWMSpindle intit()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
42
Grbl_Esp32/src/Spindles/Laser.h
Normal file
42
Grbl_Esp32/src/Spindles/Laser.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/*
|
||||||
|
Laser.h
|
||||||
|
|
||||||
|
This is similar the the PWM Spindle except that it allows the
|
||||||
|
M4 speed vs. power copensation.
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "PWMSpindle.h"
|
||||||
|
|
||||||
|
namespace Spindles {
|
||||||
|
// this is the same as a PWM spindle but the M4 compensation is supported.
|
||||||
|
class Laser : public PWMSpindle {
|
||||||
|
public:
|
||||||
|
Laser() = default;
|
||||||
|
|
||||||
|
Laser(const Laser&) = delete;
|
||||||
|
Laser(Laser&&) = delete;
|
||||||
|
Laser& operator=(const Laser&) = delete;
|
||||||
|
Laser& operator=(Laser&&) = delete;
|
||||||
|
|
||||||
|
bool isRateAdjusted() override;
|
||||||
|
void config_message() override;
|
||||||
|
|
||||||
|
virtual ~Laser() {}
|
||||||
|
};
|
||||||
|
}
|
@@ -19,24 +19,20 @@
|
|||||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#include "SpindleClass.h"
|
#include "NullSpindle.h"
|
||||||
|
|
||||||
// ======================= NullSpindle ==============================
|
namespace Spindles {
|
||||||
// NullSpindle is just bunch of do nothing (ignore) methods to be used when you don't want a spindle
|
// ======================= NullSpindle ==============================
|
||||||
|
// NullSpindle is just bunch of do nothing (ignore) methods to be used when you don't want a spindle
|
||||||
|
|
||||||
void NullSpindle ::init() {
|
void NullSpindle::init() {
|
||||||
is_reversable = false;
|
is_reversable = false;
|
||||||
use_delays = false;
|
use_delays = false;
|
||||||
config_message();
|
config_message();
|
||||||
}
|
}
|
||||||
uint32_t NullSpindle ::set_rpm(uint32_t rpm) {
|
uint32_t NullSpindle::set_rpm(uint32_t rpm) { return rpm; }
|
||||||
return rpm;
|
void NullSpindle::set_state(uint8_t state, uint32_t rpm) {}
|
||||||
}
|
uint8_t NullSpindle::get_state() { return (SPINDLE_STATE_DISABLE); }
|
||||||
void NullSpindle ::set_state(uint8_t state, uint32_t rpm) {}
|
void NullSpindle::stop() {}
|
||||||
uint8_t NullSpindle ::get_state() {
|
void NullSpindle::config_message() { grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "No spindle"); }
|
||||||
return (SPINDLE_STATE_DISABLE);
|
|
||||||
}
|
|
||||||
void NullSpindle ::stop() {}
|
|
||||||
void NullSpindle ::config_message() {
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "No spindle");
|
|
||||||
}
|
}
|
||||||
|
47
Grbl_Esp32/src/Spindles/NullSpindle.h
Normal file
47
Grbl_Esp32/src/Spindles/NullSpindle.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/*
|
||||||
|
NullSpindle.h
|
||||||
|
|
||||||
|
This is used when you don't want to use a spindle No I/O will be used
|
||||||
|
and most methods don't do anything
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "Spindle.h"
|
||||||
|
|
||||||
|
namespace Spindles {
|
||||||
|
// This is a dummy spindle that has no I/O.
|
||||||
|
// It is used to ignore spindle commands when no spinde is desired
|
||||||
|
class NullSpindle : public Spindle {
|
||||||
|
public:
|
||||||
|
NullSpindle() = default;
|
||||||
|
|
||||||
|
NullSpindle(const NullSpindle&) = delete;
|
||||||
|
NullSpindle(NullSpindle&&) = delete;
|
||||||
|
NullSpindle& operator=(const NullSpindle&) = delete;
|
||||||
|
NullSpindle& operator=(NullSpindle&&) = delete;
|
||||||
|
|
||||||
|
void init() override;
|
||||||
|
uint32_t set_rpm(uint32_t rpm) override;
|
||||||
|
void set_state(uint8_t state, uint32_t rpm) override;
|
||||||
|
uint8_t get_state() override;
|
||||||
|
void stop() override;
|
||||||
|
void config_message() override;
|
||||||
|
|
||||||
|
virtual ~NullSpindle() {}
|
||||||
|
};
|
||||||
|
}
|
@@ -19,7 +19,7 @@
|
|||||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#include "SpindleClass.h"
|
#include "PWMSpindle.h"
|
||||||
|
|
||||||
// ======================= PWMSpindle ==============================
|
// ======================= PWMSpindle ==============================
|
||||||
/*
|
/*
|
||||||
@@ -29,230 +29,230 @@
|
|||||||
|
|
||||||
//#include "grbl.h"
|
//#include "grbl.h"
|
||||||
|
|
||||||
void PWMSpindle ::init() {
|
namespace Spindles {
|
||||||
get_pins_and_settings();
|
void PWMSpindle::init() {
|
||||||
|
get_pins_and_settings();
|
||||||
|
|
||||||
if (_output_pin == UNDEFINED_PIN) {
|
if (_output_pin == UNDEFINED_PIN) {
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Spindle output pin not defined");
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Spindle output pin not defined");
|
||||||
return; // We cannot continue without the output pin
|
return; // We cannot continue without the output pin
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_output_pin >= I2S_OUT_PIN_BASE) {
|
||||||
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Spindle output pin %s cannot do PWM", pinName(_output_pin).c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ledcSetup(_spindle_pwm_chan_num, (double)_pwm_freq, _pwm_precision); // setup the channel
|
||||||
|
ledcAttachPin(_output_pin, _spindle_pwm_chan_num); // attach the PWM to the pin
|
||||||
|
|
||||||
|
pinMode(_enable_pin, OUTPUT);
|
||||||
|
pinMode(_direction_pin, OUTPUT);
|
||||||
|
|
||||||
|
use_delays = true;
|
||||||
|
|
||||||
|
config_message();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_output_pin >= I2S_OUT_PIN_BASE) {
|
// Get the GPIO from the machine definition
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Spindle output pin %s cannot do PWM", pinName(_output_pin).c_str());
|
void PWMSpindle::get_pins_and_settings() {
|
||||||
return;
|
// setup all the pins
|
||||||
}
|
|
||||||
|
|
||||||
ledcSetup(_spindle_pwm_chan_num, (double)_pwm_freq, _pwm_precision); // setup the channel
|
|
||||||
ledcAttachPin(_output_pin, _spindle_pwm_chan_num); // attach the PWM to the pin
|
|
||||||
|
|
||||||
pinMode(_enable_pin, OUTPUT);
|
|
||||||
pinMode(_direction_pin, OUTPUT);
|
|
||||||
|
|
||||||
use_delays = true;
|
|
||||||
|
|
||||||
config_message();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the GPIO from the machine definition
|
|
||||||
void PWMSpindle ::get_pins_and_settings() {
|
|
||||||
// setup all the pins
|
|
||||||
|
|
||||||
#ifdef SPINDLE_OUTPUT_PIN
|
#ifdef SPINDLE_OUTPUT_PIN
|
||||||
_output_pin = SPINDLE_OUTPUT_PIN;
|
_output_pin = SPINDLE_OUTPUT_PIN;
|
||||||
#else
|
#else
|
||||||
_output_pin = UNDEFINED_PIN;
|
_output_pin = UNDEFINED_PIN;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef INVERT_SPINDLE_OUTPUT_PIN
|
#ifdef INVERT_SPINDLE_OUTPUT_PIN
|
||||||
_invert_pwm = true;
|
_invert_pwm = true;
|
||||||
#else
|
#else
|
||||||
_invert_pwm = false;
|
_invert_pwm = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SPINDLE_ENABLE_PIN
|
#ifdef SPINDLE_ENABLE_PIN
|
||||||
_enable_pin = SPINDLE_ENABLE_PIN;
|
_enable_pin = SPINDLE_ENABLE_PIN;
|
||||||
# ifdef SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED
|
# ifdef SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED
|
||||||
_off_with_zero_speed = true;
|
_off_with_zero_speed = true;
|
||||||
# endif
|
# endif
|
||||||
#else
|
#else
|
||||||
_enable_pin = UNDEFINED_PIN;
|
_enable_pin = UNDEFINED_PIN;
|
||||||
_off_with_zero_speed = false;
|
_off_with_zero_speed = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SPINDLE_DIR_PIN
|
#ifdef SPINDLE_DIR_PIN
|
||||||
_direction_pin = SPINDLE_DIR_PIN;
|
_direction_pin = SPINDLE_DIR_PIN;
|
||||||
#else
|
#else
|
||||||
_direction_pin = UNDEFINED_PIN;
|
_direction_pin = UNDEFINED_PIN;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
is_reversable = (_direction_pin != UNDEFINED_PIN);
|
is_reversable = (_direction_pin != UNDEFINED_PIN);
|
||||||
|
|
||||||
_pwm_freq = spindle_pwm_freq->get();
|
_pwm_freq = spindle_pwm_freq->get();
|
||||||
_pwm_precision = calc_pwm_precision(_pwm_freq); // detewrmine the best precision
|
_pwm_precision = calc_pwm_precision(_pwm_freq); // detewrmine the best precision
|
||||||
_pwm_period = (1 << _pwm_precision);
|
_pwm_period = (1 << _pwm_precision);
|
||||||
|
|
||||||
if (spindle_pwm_min_value->get() > spindle_pwm_min_value->get())
|
if (spindle_pwm_min_value->get() > spindle_pwm_min_value->get())
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Spindle min pwm is greater than max. Check $35 and $36");
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Spindle min pwm is greater than max. Check $35 and $36");
|
||||||
|
|
||||||
// pre-caculate some PWM count values
|
// pre-caculate some PWM count values
|
||||||
_pwm_off_value = (_pwm_period * spindle_pwm_off_value->get() / 100.0);
|
_pwm_off_value = (_pwm_period * spindle_pwm_off_value->get() / 100.0);
|
||||||
_pwm_min_value = (_pwm_period * spindle_pwm_min_value->get() / 100.0);
|
_pwm_min_value = (_pwm_period * spindle_pwm_min_value->get() / 100.0);
|
||||||
_pwm_max_value = (_pwm_period * spindle_pwm_max_value->get() / 100.0);
|
_pwm_max_value = (_pwm_period * spindle_pwm_max_value->get() / 100.0);
|
||||||
|
|
||||||
#ifdef ENABLE_PIECEWISE_LINEAR_SPINDLE
|
#ifdef ENABLE_PIECEWISE_LINEAR_SPINDLE
|
||||||
_min_rpm = RPM_MIN;
|
_min_rpm = RPM_MIN;
|
||||||
_max_rpm = RPM_MAX;
|
_max_rpm = RPM_MAX;
|
||||||
_piecewide_linear = true;
|
_piecewide_linear = true;
|
||||||
#else
|
#else
|
||||||
_min_rpm = rpm_min->get();
|
_min_rpm = rpm_min->get();
|
||||||
_max_rpm = rpm_max->get();
|
_max_rpm = rpm_max->get();
|
||||||
_piecewide_linear = false;
|
_piecewide_linear = false;
|
||||||
#endif
|
#endif
|
||||||
// The pwm_gradient is the pwm duty cycle units per rpm
|
// The pwm_gradient is the pwm duty cycle units per rpm
|
||||||
// _pwm_gradient = (_pwm_max_value - _pwm_min_value) / (_max_rpm - _min_rpm);
|
// _pwm_gradient = (_pwm_max_value - _pwm_min_value) / (_max_rpm - _min_rpm);
|
||||||
|
|
||||||
_spindle_pwm_chan_num = 0; // Channel 0 is reserved for spindle use
|
_spindle_pwm_chan_num = 0; // Channel 0 is reserved for spindle use
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t PWMSpindle::set_rpm(uint32_t rpm) {
|
|
||||||
uint32_t pwm_value;
|
|
||||||
|
|
||||||
if (_output_pin == UNDEFINED_PIN)
|
|
||||||
return rpm;
|
|
||||||
|
|
||||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "set_rpm(%d)", rpm);
|
|
||||||
|
|
||||||
// apply override
|
|
||||||
rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (uint8_t percent)
|
|
||||||
|
|
||||||
// apply limits
|
|
||||||
if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm))
|
|
||||||
rpm = _max_rpm;
|
|
||||||
else if (rpm != 0 && rpm <= _min_rpm)
|
|
||||||
rpm = _min_rpm;
|
|
||||||
|
|
||||||
sys.spindle_speed = rpm;
|
|
||||||
|
|
||||||
if (_piecewide_linear) {
|
|
||||||
//pwm_value = piecewise_linear_fit(rpm); TODO
|
|
||||||
pwm_value = 0;
|
|
||||||
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Linear fit not implemented yet.");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (rpm == 0)
|
|
||||||
pwm_value = _pwm_off_value;
|
|
||||||
else
|
|
||||||
pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set_output(pwm_value);
|
uint32_t PWMSpindle::set_rpm(uint32_t rpm) {
|
||||||
|
uint32_t pwm_value;
|
||||||
|
|
||||||
return 0;
|
if (_output_pin == UNDEFINED_PIN)
|
||||||
}
|
return rpm;
|
||||||
|
|
||||||
void PWMSpindle::set_state(uint8_t state, uint32_t rpm) {
|
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "set_rpm(%d)", rpm);
|
||||||
if (sys.abort)
|
|
||||||
return; // Block during abort.
|
|
||||||
|
|
||||||
if (state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm.
|
// apply override
|
||||||
sys.spindle_speed = 0;
|
rpm = rpm * sys.spindle_speed_ovr / 100; // Scale by spindle speed override value (uint8_t percent)
|
||||||
stop();
|
|
||||||
if (use_delays && (_current_state != state)) {
|
// apply limits
|
||||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinDown Start ");
|
if ((_min_rpm >= _max_rpm) || (rpm >= _max_rpm))
|
||||||
mc_dwell(spindle_delay_spindown->get());
|
rpm = _max_rpm;
|
||||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinDown Done");
|
else if (rpm != 0 && rpm <= _min_rpm)
|
||||||
}
|
rpm = _min_rpm;
|
||||||
} else {
|
|
||||||
set_spindle_dir_pin(state == SPINDLE_ENABLE_CW);
|
sys.spindle_speed = rpm;
|
||||||
set_rpm(rpm);
|
|
||||||
set_enable_pin(state != SPINDLE_DISABLE); // must be done after setting rpm for enable features to work
|
if (_piecewide_linear) {
|
||||||
if (use_delays && (_current_state != state)) {
|
//pwm_value = piecewise_linear_fit(rpm); TODO
|
||||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinUp Start %d", rpm);
|
pwm_value = 0;
|
||||||
mc_dwell(spindle_delay_spinup->get());
|
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Warning: Linear fit not implemented yet.");
|
||||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinUp Done");
|
|
||||||
|
} else {
|
||||||
|
if (rpm == 0)
|
||||||
|
pwm_value = _pwm_off_value;
|
||||||
|
else
|
||||||
|
pwm_value = map_uint32_t(rpm, _min_rpm, _max_rpm, _pwm_min_value, _pwm_max_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_output(pwm_value);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_current_state = state;
|
void PWMSpindle::set_state(uint8_t state, uint32_t rpm) {
|
||||||
|
if (sys.abort)
|
||||||
|
return; // Block during abort.
|
||||||
|
|
||||||
sys.report_ovr_counter = 0; // Set to report change immediately
|
if (state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm.
|
||||||
}
|
sys.spindle_speed = 0;
|
||||||
|
stop();
|
||||||
|
if (use_delays && (_current_state != state)) {
|
||||||
|
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinDown Start ");
|
||||||
|
mc_dwell(spindle_delay_spindown->get());
|
||||||
|
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinDown Done");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
set_spindle_dir_pin(state == SPINDLE_ENABLE_CW);
|
||||||
|
set_rpm(rpm);
|
||||||
|
set_enable_pin(state != SPINDLE_DISABLE); // must be done after setting rpm for enable features to work
|
||||||
|
if (use_delays && (_current_state != state)) {
|
||||||
|
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinUp Start %d", rpm);
|
||||||
|
mc_dwell(spindle_delay_spinup->get());
|
||||||
|
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "SpinUp Done");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t PWMSpindle::get_state() {
|
_current_state = state;
|
||||||
if (_current_pwm_duty == 0 || _output_pin == UNDEFINED_PIN)
|
|
||||||
return (SPINDLE_STATE_DISABLE);
|
|
||||||
if (_direction_pin != UNDEFINED_PIN)
|
|
||||||
return digitalRead(_direction_pin) ? SPINDLE_STATE_CW : SPINDLE_STATE_CCW;
|
|
||||||
return (SPINDLE_STATE_CW);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PWMSpindle::stop() {
|
sys.report_ovr_counter = 0; // Set to report change immediately
|
||||||
// inverts are delt with in methods
|
}
|
||||||
set_enable_pin(false);
|
|
||||||
set_output(_pwm_off_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// prints the startup message of the spindle config
|
uint8_t PWMSpindle::get_state() {
|
||||||
void PWMSpindle ::config_message() {
|
if (_current_pwm_duty == 0 || _output_pin == UNDEFINED_PIN)
|
||||||
grbl_msg_sendf(CLIENT_SERIAL,
|
return (SPINDLE_STATE_DISABLE);
|
||||||
MSG_LEVEL_INFO,
|
if (_direction_pin != UNDEFINED_PIN)
|
||||||
"PWM spindle Output:%s, Enbl:%s, Dir:%s, Freq:%dHz, Res:%dbits",
|
return digitalRead(_direction_pin) ? SPINDLE_STATE_CW : SPINDLE_STATE_CCW;
|
||||||
pinName(_output_pin).c_str(),
|
return (SPINDLE_STATE_CW);
|
||||||
pinName(_enable_pin).c_str(),
|
}
|
||||||
pinName(_direction_pin).c_str(),
|
|
||||||
_pwm_freq,
|
|
||||||
_pwm_precision);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PWMSpindle::set_output(uint32_t duty) {
|
void PWMSpindle::stop() {
|
||||||
if (_output_pin == UNDEFINED_PIN)
|
// inverts are delt with in methods
|
||||||
return;
|
set_enable_pin(false);
|
||||||
|
set_output(_pwm_off_value);
|
||||||
|
}
|
||||||
|
|
||||||
// to prevent excessive calls to ledcWrite, make sure duty hass changed
|
// prints the startup message of the spindle config
|
||||||
if (duty == _current_pwm_duty)
|
void PWMSpindle::config_message() {
|
||||||
return;
|
grbl_msg_sendf(CLIENT_SERIAL,
|
||||||
|
MSG_LEVEL_INFO,
|
||||||
|
"PWM spindle Output:%s, Enbl:%s, Dir:%s, Freq:%dHz, Res:%dbits",
|
||||||
|
pinName(_output_pin).c_str(),
|
||||||
|
pinName(_enable_pin).c_str(),
|
||||||
|
pinName(_direction_pin).c_str(),
|
||||||
|
_pwm_freq,
|
||||||
|
_pwm_precision);
|
||||||
|
}
|
||||||
|
|
||||||
_current_pwm_duty = duty;
|
void PWMSpindle::set_output(uint32_t duty) {
|
||||||
|
if (_output_pin == UNDEFINED_PIN)
|
||||||
|
return;
|
||||||
|
|
||||||
if (_invert_pwm)
|
// to prevent excessive calls to ledcWrite, make sure duty hass changed
|
||||||
duty = (1 << _pwm_precision) - duty;
|
if (duty == _current_pwm_duty)
|
||||||
|
return;
|
||||||
|
|
||||||
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "set_output(%d)", duty);
|
_current_pwm_duty = duty;
|
||||||
|
|
||||||
ledcWrite(_spindle_pwm_chan_num, duty);
|
if (_invert_pwm)
|
||||||
}
|
duty = (1 << _pwm_precision) - duty;
|
||||||
|
|
||||||
void PWMSpindle::set_enable_pin(bool enable) {
|
//grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "set_output(%d)", duty);
|
||||||
if (_enable_pin == UNDEFINED_PIN)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_off_with_zero_speed && sys.spindle_speed == 0)
|
ledcWrite(_spindle_pwm_chan_num, duty);
|
||||||
enable = false;
|
}
|
||||||
|
|
||||||
|
void PWMSpindle::set_enable_pin(bool enable) {
|
||||||
|
if (_enable_pin == UNDEFINED_PIN)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_off_with_zero_speed && sys.spindle_speed == 0)
|
||||||
|
enable = false;
|
||||||
|
|
||||||
#ifndef INVERT_SPINDLE_ENABLE_PIN
|
#ifndef INVERT_SPINDLE_ENABLE_PIN
|
||||||
digitalWrite(_enable_pin, enable);
|
digitalWrite(_enable_pin, enable);
|
||||||
#else
|
#else
|
||||||
digitalWrite(_enable_pin, !enable);
|
digitalWrite(_enable_pin, !enable);
|
||||||
#endif
|
#endif
|
||||||
digitalWrite(_enable_pin, enable);
|
digitalWrite(_enable_pin, enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PWMSpindle::set_spindle_dir_pin(bool Clockwise) {
|
void PWMSpindle::set_spindle_dir_pin(bool Clockwise) { digitalWrite(_direction_pin, Clockwise); }
|
||||||
digitalWrite(_direction_pin, Clockwise);
|
|
||||||
}
|
/*
|
||||||
|
Calculate the highest precision of a PWM based on the frequency in bits
|
||||||
/*
|
|
||||||
Calculate the highest precision of a PWM based on the frequency in bits
|
80,000,000 / freq = period
|
||||||
|
determine the highest precision where (1 << precision) < period
|
||||||
80,000,000 / freq = period
|
*/
|
||||||
determine the highest precision where (1 << precision) < period
|
uint8_t PWMSpindle::calc_pwm_precision(uint32_t freq) {
|
||||||
*/
|
uint8_t precision = 0;
|
||||||
uint8_t PWMSpindle ::calc_pwm_precision(uint32_t freq) {
|
|
||||||
uint8_t precision = 0;
|
// increase the precision (bits) until it exceeds allow by frequency the max or is 16
|
||||||
|
while ((1 << precision) < (uint32_t)(80000000 / freq) && precision <= 16)
|
||||||
// increase the precision (bits) until it exceeds allow by frequency the max or is 16
|
precision++;
|
||||||
while ((1 << precision) < (uint32_t)(80000000 / freq) && precision <= 16)
|
|
||||||
precision++;
|
return precision - 1;
|
||||||
|
}
|
||||||
return precision - 1;
|
|
||||||
}
|
}
|
||||||
|
72
Grbl_Esp32/src/Spindles/PWMSpindle.h
Normal file
72
Grbl_Esp32/src/Spindles/PWMSpindle.h
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/*
|
||||||
|
PWMSpindle.h
|
||||||
|
|
||||||
|
This is a full featured TTL PWM spindle This does not include speed/power
|
||||||
|
compensation. Use the Laser class for that.
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "Spindle.h"
|
||||||
|
|
||||||
|
namespace Spindles {
|
||||||
|
// This adds support for PWM
|
||||||
|
class PWMSpindle : public Spindle {
|
||||||
|
public:
|
||||||
|
PWMSpindle() = default;
|
||||||
|
|
||||||
|
PWMSpindle(const PWMSpindle&) = delete;
|
||||||
|
PWMSpindle(PWMSpindle&&) = delete;
|
||||||
|
PWMSpindle& operator=(const PWMSpindle&) = delete;
|
||||||
|
PWMSpindle& operator=(PWMSpindle&&) = delete;
|
||||||
|
|
||||||
|
void init() override;
|
||||||
|
virtual uint32_t set_rpm(uint32_t rpm) override;
|
||||||
|
void set_state(uint8_t state, uint32_t rpm) override;
|
||||||
|
uint8_t get_state() override;
|
||||||
|
void stop() override;
|
||||||
|
void config_message() override;
|
||||||
|
|
||||||
|
virtual ~PWMSpindle() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int32_t _current_pwm_duty;
|
||||||
|
uint32_t _min_rpm;
|
||||||
|
uint32_t _max_rpm;
|
||||||
|
uint32_t _pwm_off_value;
|
||||||
|
uint32_t _pwm_min_value;
|
||||||
|
uint32_t _pwm_max_value;
|
||||||
|
uint8_t _output_pin;
|
||||||
|
uint8_t _enable_pin;
|
||||||
|
uint8_t _direction_pin;
|
||||||
|
uint8_t _spindle_pwm_chan_num;
|
||||||
|
uint32_t _pwm_freq;
|
||||||
|
uint32_t _pwm_period; // how many counts in 1 period
|
||||||
|
uint8_t _pwm_precision;
|
||||||
|
bool _piecewide_linear;
|
||||||
|
bool _off_with_zero_speed;
|
||||||
|
bool _invert_pwm;
|
||||||
|
//uint32_t _pwm_gradient; // Precalulated value to speed up rpm to PWM conversions.
|
||||||
|
|
||||||
|
virtual void set_spindle_dir_pin(bool Clockwise);
|
||||||
|
virtual void set_output(uint32_t duty);
|
||||||
|
virtual void set_enable_pin(bool enable_pin);
|
||||||
|
|
||||||
|
void get_pins_and_settings();
|
||||||
|
uint8_t calc_pwm_precision(uint32_t freq);
|
||||||
|
};
|
||||||
|
}
|
@@ -19,51 +19,54 @@
|
|||||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#include "SpindleClass.h"
|
#include "RelaySpindle.h"
|
||||||
|
|
||||||
// ========================= RelaySpindle ==================================
|
// ========================= RelaySpindle ==================================
|
||||||
/*
|
|
||||||
|
namespace Spindles {
|
||||||
|
/*
|
||||||
This is a sub class of PWMSpindle but is a digital rather than PWM output
|
This is a sub class of PWMSpindle but is a digital rather than PWM output
|
||||||
*/
|
*/
|
||||||
void RelaySpindle::init() {
|
void RelaySpindle::init() {
|
||||||
get_pins_and_settings();
|
get_pins_and_settings();
|
||||||
|
|
||||||
if (_output_pin == UNDEFINED_PIN)
|
if (_output_pin == UNDEFINED_PIN)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pinMode(_output_pin, OUTPUT);
|
pinMode(_output_pin, OUTPUT);
|
||||||
pinMode(_enable_pin, OUTPUT);
|
pinMode(_enable_pin, OUTPUT);
|
||||||
pinMode(_direction_pin, OUTPUT);
|
pinMode(_direction_pin, OUTPUT);
|
||||||
|
|
||||||
is_reversable = (_direction_pin != UNDEFINED_PIN);
|
is_reversable = (_direction_pin != UNDEFINED_PIN);
|
||||||
use_delays = true;
|
use_delays = true;
|
||||||
|
|
||||||
config_message();
|
config_message();
|
||||||
}
|
}
|
||||||
|
|
||||||
// prints the startup message of the spindle config
|
// prints the startup message of the spindle config
|
||||||
void RelaySpindle ::config_message() {
|
void RelaySpindle ::config_message() {
|
||||||
grbl_msg_sendf(CLIENT_SERIAL,
|
grbl_msg_sendf(CLIENT_SERIAL,
|
||||||
MSG_LEVEL_INFO,
|
MSG_LEVEL_INFO,
|
||||||
"Relay spindle Output:%s, Enbl:%s, Dir:%s",
|
"Relay spindle Output:%s, Enbl:%s, Dir:%s",
|
||||||
pinName(_output_pin).c_str(),
|
pinName(_output_pin).c_str(),
|
||||||
pinName(_enable_pin).c_str(),
|
pinName(_enable_pin).c_str(),
|
||||||
pinName(_direction_pin).c_str());
|
pinName(_direction_pin).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t RelaySpindle::set_rpm(uint32_t rpm) {
|
||||||
|
if (_output_pin == UNDEFINED_PIN)
|
||||||
|
return rpm;
|
||||||
|
|
||||||
|
sys.spindle_speed = rpm;
|
||||||
|
set_output(rpm != 0);
|
||||||
|
|
||||||
uint32_t RelaySpindle::set_rpm(uint32_t rpm) {
|
|
||||||
if (_output_pin == UNDEFINED_PIN)
|
|
||||||
return rpm;
|
return rpm;
|
||||||
|
}
|
||||||
|
|
||||||
sys.spindle_speed = rpm;
|
void RelaySpindle::set_output(uint32_t duty) {
|
||||||
set_output(rpm != 0);
|
|
||||||
|
|
||||||
return rpm;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RelaySpindle::set_output(uint32_t duty) {
|
|
||||||
#ifdef INVERT_SPINDLE_PWM
|
#ifdef INVERT_SPINDLE_PWM
|
||||||
duty = (duty == 0); // flip duty
|
duty = (duty == 0); // flip duty
|
||||||
#endif
|
#endif
|
||||||
digitalWrite(_output_pin, duty > 0); // anything greater
|
digitalWrite(_output_pin, duty > 0); // anything greater
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
46
Grbl_Esp32/src/Spindles/RelaySpindle.h
Normal file
46
Grbl_Esp32/src/Spindles/RelaySpindle.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/*
|
||||||
|
RelaySpindle.h
|
||||||
|
|
||||||
|
This is used for a basic on/off spindle All S Values above 0
|
||||||
|
will turn the spindle on.
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "PWMSpindle.h"
|
||||||
|
|
||||||
|
namespace Spindles {
|
||||||
|
// This is for an on/off spindle all RPMs above 0 are on
|
||||||
|
class RelaySpindle : public PWMSpindle {
|
||||||
|
public:
|
||||||
|
RelaySpindle() = default;
|
||||||
|
|
||||||
|
RelaySpindle(const RelaySpindle&) = delete;
|
||||||
|
RelaySpindle(RelaySpindle&&) = delete;
|
||||||
|
RelaySpindle& operator=(const RelaySpindle&) = delete;
|
||||||
|
RelaySpindle& operator=(RelaySpindle&&) = delete;
|
||||||
|
|
||||||
|
void init() override;
|
||||||
|
void config_message() override;
|
||||||
|
uint32_t set_rpm(uint32_t rpm) override;
|
||||||
|
|
||||||
|
virtual ~RelaySpindle() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void set_output(uint32_t duty);
|
||||||
|
};
|
||||||
|
}
|
81
Grbl_Esp32/src/Spindles/Spindle.cpp
Normal file
81
Grbl_Esp32/src/Spindles/Spindle.cpp
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
SpindleClass.cpp
|
||||||
|
|
||||||
|
A Base class for spindles and spinsle like things such as lasers
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
TODO
|
||||||
|
Add Spindle spin up/down delays
|
||||||
|
|
||||||
|
Get rid of dependance on machine definition #defines
|
||||||
|
SPINDLE_OUTPUT_PIN
|
||||||
|
SPINDLE_ENABLE_PIN
|
||||||
|
SPINDLE_DIR_PIN
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "Spindle.h"
|
||||||
|
|
||||||
|
#include "NullSpindle.h"
|
||||||
|
#include "PWMSpindle.h"
|
||||||
|
#include "RelaySpindle.h"
|
||||||
|
#include "Laser.h"
|
||||||
|
#include "DacSpindle.h"
|
||||||
|
#include "HuanyangSpindle.h"
|
||||||
|
#include "BESCSpindle.h"
|
||||||
|
#include "10vSpindle.h"
|
||||||
|
|
||||||
|
namespace Spindles {
|
||||||
|
// An instance of each type of spindle is created here.
|
||||||
|
// This allows the spindle to be dynamicly switched
|
||||||
|
NullSpindle null_spindle;
|
||||||
|
PWMSpindle pwm_spindle;
|
||||||
|
RelaySpindle relay_spindle;
|
||||||
|
Laser laser;
|
||||||
|
DacSpindle dac_spindle;
|
||||||
|
HuanyangSpindle huanyang_spindle;
|
||||||
|
BESCSpindle besc_spindle;
|
||||||
|
_10vSpindle _10v_spindle;
|
||||||
|
|
||||||
|
void Spindle::spindle_select() {
|
||||||
|
switch (spindle_type->get()) {
|
||||||
|
case SPINDLE_TYPE_PWM: spindle = &pwm_spindle; break;
|
||||||
|
case SPINDLE_TYPE_RELAY: spindle = &relay_spindle; break;
|
||||||
|
case SPINDLE_TYPE_LASER: spindle = &laser; break;
|
||||||
|
case SPINDLE_TYPE_DAC: spindle = &dac_spindle; break;
|
||||||
|
case SPINDLE_TYPE_HUANYANG: spindle = &huanyang_spindle; break;
|
||||||
|
case SPINDLE_TYPE_BESC: spindle = &besc_spindle; break;
|
||||||
|
case SPINDLE_TYPE_10V: spindle = &_10v_spindle; break;
|
||||||
|
case SPINDLE_TYPE_NONE:
|
||||||
|
default: spindle = &null_spindle; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
spindle->init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========================= Spindle ==================================
|
||||||
|
|
||||||
|
bool Spindle::isRateAdjusted() {
|
||||||
|
return false; // default for basic spindle is false
|
||||||
|
}
|
||||||
|
|
||||||
|
void Spindle::spindle_sync(uint8_t state, uint32_t rpm) {
|
||||||
|
if (sys.state == STATE_CHECK_MODE)
|
||||||
|
return;
|
||||||
|
protocol_buffer_synchronize(); // Empty planner buffer to ensure spindle is set when programmed.
|
||||||
|
set_state(state, rpm);
|
||||||
|
}
|
||||||
|
}
|
80
Grbl_Esp32/src/Spindles/Spindle.h
Normal file
80
Grbl_Esp32/src/Spindles/Spindle.h
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/*
|
||||||
|
Spindle.h
|
||||||
|
|
||||||
|
Header file for a Spindle Class
|
||||||
|
See SpindleClass.cpp for more details
|
||||||
|
|
||||||
|
Part of Grbl_ESP32
|
||||||
|
|
||||||
|
2020 - Bart Dring This file was modified for use on the ESP32
|
||||||
|
CPU. Do not use this with Grbl for atMega328P
|
||||||
|
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
See SpindleClass.cpp for more info and references
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SPINDLE_STATE_DISABLE 0 // Must be zero.
|
||||||
|
#define SPINDLE_STATE_CW bit(0)
|
||||||
|
#define SPINDLE_STATE_CCW bit(1)
|
||||||
|
|
||||||
|
#define SPINDLE_TYPE_NONE 0
|
||||||
|
#define SPINDLE_TYPE_PWM 1
|
||||||
|
#define SPINDLE_TYPE_RELAY 2
|
||||||
|
#define SPINDLE_TYPE_LASER 3
|
||||||
|
#define SPINDLE_TYPE_DAC 4
|
||||||
|
#define SPINDLE_TYPE_HUANYANG 5
|
||||||
|
#define SPINDLE_TYPE_BESC 6
|
||||||
|
#define SPINDLE_TYPE_10V 7
|
||||||
|
|
||||||
|
#include "../grbl.h"
|
||||||
|
#include <driver/dac.h>
|
||||||
|
#include <driver/uart.h>
|
||||||
|
|
||||||
|
// =============== No floats! ===========================
|
||||||
|
// ================ NO FLOATS! ==========================
|
||||||
|
|
||||||
|
namespace Spindles {
|
||||||
|
// This is the base class. Do not use this as your spindle
|
||||||
|
class Spindle {
|
||||||
|
public:
|
||||||
|
Spindle() = default;
|
||||||
|
|
||||||
|
Spindle(const Spindle&) = delete;
|
||||||
|
Spindle(Spindle&&) = delete;
|
||||||
|
Spindle& operator=(const Spindle&) = delete;
|
||||||
|
Spindle& operator=(Spindle&&) = delete;
|
||||||
|
|
||||||
|
virtual void init() = 0; // not in constructor because this also gets called when $$ settings change
|
||||||
|
virtual uint32_t set_rpm(uint32_t rpm) = 0;
|
||||||
|
virtual void set_state(uint8_t state, uint32_t rpm) = 0;
|
||||||
|
virtual uint8_t get_state() = 0;
|
||||||
|
virtual void stop() = 0;
|
||||||
|
virtual void config_message() = 0;
|
||||||
|
virtual bool isRateAdjusted();
|
||||||
|
virtual void spindle_sync(uint8_t state, uint32_t rpm);
|
||||||
|
|
||||||
|
virtual ~Spindle() {}
|
||||||
|
|
||||||
|
bool is_reversable;
|
||||||
|
bool use_delays; // will SpinUp and SpinDown delays be used.
|
||||||
|
uint8_t _current_state;
|
||||||
|
|
||||||
|
static void spindle_select();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extern Spindles::Spindle* spindle;
|
@@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
SpindleClass.cpp
|
|
||||||
|
|
||||||
A Base class for spindles and spinsle like things such as lasers
|
|
||||||
|
|
||||||
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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
TODO
|
|
||||||
Add Spindle spin up/down delays
|
|
||||||
|
|
||||||
Get rid of dependance on machine definition #defines
|
|
||||||
SPINDLE_OUTPUT_PIN
|
|
||||||
SPINDLE_ENABLE_PIN
|
|
||||||
SPINDLE_DIR_PIN
|
|
||||||
|
|
||||||
*/
|
|
||||||
#include "SpindleClass.h"
|
|
||||||
|
|
||||||
// An instance of each type of spindle is created here.
|
|
||||||
// This allows the spindle to be dynamicly switched
|
|
||||||
NullSpindle null_spindle;
|
|
||||||
PWMSpindle pwm_spindle;
|
|
||||||
RelaySpindle relay_spindle;
|
|
||||||
Laser laser;
|
|
||||||
DacSpindle dac_spindle;
|
|
||||||
HuanyangSpindle huanyang_spindle;
|
|
||||||
BESCSpindle besc_spindle;
|
|
||||||
_10vSpindle _10v_spindle;
|
|
||||||
|
|
||||||
void spindle_select() {
|
|
||||||
switch (spindle_type->get()) {
|
|
||||||
case SPINDLE_TYPE_PWM: spindle = &pwm_spindle; break;
|
|
||||||
case SPINDLE_TYPE_RELAY: spindle = &relay_spindle; break;
|
|
||||||
case SPINDLE_TYPE_LASER: spindle = &laser; break;
|
|
||||||
case SPINDLE_TYPE_DAC: spindle = &dac_spindle; break;
|
|
||||||
case SPINDLE_TYPE_HUANYANG: spindle = &huanyang_spindle; break;
|
|
||||||
case SPINDLE_TYPE_BESC: spindle = &besc_spindle; break;
|
|
||||||
case SPINDLE_TYPE_10V: spindle = &_10v_spindle; break;
|
|
||||||
case SPINDLE_TYPE_NONE:
|
|
||||||
default: spindle = &null_spindle; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
spindle->init();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ========================= Spindle ==================================
|
|
||||||
|
|
||||||
bool Spindle::isRateAdjusted() {
|
|
||||||
return false; // default for basic spindle is false
|
|
||||||
}
|
|
||||||
|
|
||||||
void Spindle ::spindle_sync(uint8_t state, uint32_t rpm) {
|
|
||||||
if (sys.state == STATE_CHECK_MODE)
|
|
||||||
return;
|
|
||||||
protocol_buffer_synchronize(); // Empty planner buffer to ensure spindle is set when programmed.
|
|
||||||
set_state(state, rpm);
|
|
||||||
}
|
|
@@ -1,217 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
/*
|
|
||||||
SpindleClass.h
|
|
||||||
|
|
||||||
Header file for a Spindle Class
|
|
||||||
See SpindleClass.cpp for more details
|
|
||||||
|
|
||||||
Part of Grbl_ESP32
|
|
||||||
|
|
||||||
2020 - Bart Dring This file was modified for use on the ESP32
|
|
||||||
CPU. Do not use this with Grbl for atMega328P
|
|
||||||
|
|
||||||
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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
See SpindleClass.cpp for more info and references
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define SPINDLE_STATE_DISABLE 0 // Must be zero.
|
|
||||||
#define SPINDLE_STATE_CW bit(0)
|
|
||||||
#define SPINDLE_STATE_CCW bit(1)
|
|
||||||
|
|
||||||
#define SPINDLE_TYPE_NONE 0
|
|
||||||
#define SPINDLE_TYPE_PWM 1
|
|
||||||
#define SPINDLE_TYPE_RELAY 2
|
|
||||||
#define SPINDLE_TYPE_LASER 3
|
|
||||||
#define SPINDLE_TYPE_DAC 4
|
|
||||||
#define SPINDLE_TYPE_HUANYANG 5
|
|
||||||
#define SPINDLE_TYPE_BESC 6
|
|
||||||
#define SPINDLE_TYPE_10V 7
|
|
||||||
|
|
||||||
#include "../grbl.h"
|
|
||||||
#include <driver/dac.h>
|
|
||||||
#include "driver/uart.h"
|
|
||||||
|
|
||||||
// =============== No floats! ===========================
|
|
||||||
// ================ NO FLOATS! ==========================
|
|
||||||
|
|
||||||
// This is the base class. Do not use this as your spindle
|
|
||||||
class Spindle {
|
|
||||||
public:
|
|
||||||
virtual void init(); // not in constructor because this also gets called when $$ settings change
|
|
||||||
virtual uint32_t set_rpm(uint32_t rpm);
|
|
||||||
virtual void set_state(uint8_t state, uint32_t rpm);
|
|
||||||
virtual uint8_t get_state();
|
|
||||||
virtual void stop();
|
|
||||||
virtual void config_message();
|
|
||||||
virtual bool isRateAdjusted();
|
|
||||||
virtual void spindle_sync(uint8_t state, uint32_t rpm);
|
|
||||||
|
|
||||||
bool is_reversable;
|
|
||||||
bool use_delays; // will SpinUp and SpinDown delays be used.
|
|
||||||
uint8_t _current_state;
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is a dummy spindle that has no I/O.
|
|
||||||
// It is used to ignore spindle commands when no spinde is desired
|
|
||||||
class NullSpindle : public Spindle {
|
|
||||||
public:
|
|
||||||
void init();
|
|
||||||
uint32_t set_rpm(uint32_t rpm);
|
|
||||||
void set_state(uint8_t state, uint32_t rpm);
|
|
||||||
uint8_t get_state();
|
|
||||||
void stop();
|
|
||||||
void config_message();
|
|
||||||
};
|
|
||||||
|
|
||||||
// This adds support for PWM
|
|
||||||
class PWMSpindle : public Spindle {
|
|
||||||
public:
|
|
||||||
void init();
|
|
||||||
virtual uint32_t set_rpm(uint32_t rpm);
|
|
||||||
void set_state(uint8_t state, uint32_t rpm);
|
|
||||||
uint8_t get_state();
|
|
||||||
void stop();
|
|
||||||
void config_message();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void set_spindle_dir_pin(bool Clockwise);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
int32_t _current_pwm_duty;
|
|
||||||
uint32_t _min_rpm;
|
|
||||||
uint32_t _max_rpm;
|
|
||||||
uint32_t _pwm_off_value;
|
|
||||||
uint32_t _pwm_min_value;
|
|
||||||
uint32_t _pwm_max_value;
|
|
||||||
uint8_t _output_pin;
|
|
||||||
uint8_t _enable_pin;
|
|
||||||
uint8_t _direction_pin;
|
|
||||||
uint8_t _spindle_pwm_chan_num;
|
|
||||||
uint32_t _pwm_freq;
|
|
||||||
uint32_t _pwm_period; // how many counts in 1 period
|
|
||||||
uint8_t _pwm_precision;
|
|
||||||
bool _piecewide_linear;
|
|
||||||
bool _off_with_zero_speed;
|
|
||||||
bool _invert_pwm;
|
|
||||||
//uint32_t _pwm_gradient; // Precalulated value to speed up rpm to PWM conversions.
|
|
||||||
|
|
||||||
virtual void set_output(uint32_t duty);
|
|
||||||
void set_enable_pin(bool enable_pin);
|
|
||||||
void get_pins_and_settings();
|
|
||||||
uint8_t calc_pwm_precision(uint32_t freq);
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is for an on/off spindle all RPMs above 0 are on
|
|
||||||
class RelaySpindle : public PWMSpindle {
|
|
||||||
public:
|
|
||||||
void init();
|
|
||||||
void config_message();
|
|
||||||
uint32_t set_rpm(uint32_t rpm);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void set_output(uint32_t duty);
|
|
||||||
};
|
|
||||||
|
|
||||||
// this is the same as a PWM spindle but the M4 compensation is supported.
|
|
||||||
class Laser : public PWMSpindle {
|
|
||||||
public:
|
|
||||||
bool isRateAdjusted();
|
|
||||||
void config_message();
|
|
||||||
};
|
|
||||||
|
|
||||||
// This uses one of the (2) DAC pins on ESP32 to output a voltage
|
|
||||||
class DacSpindle : public PWMSpindle {
|
|
||||||
public:
|
|
||||||
void init();
|
|
||||||
void config_message();
|
|
||||||
uint32_t set_rpm(uint32_t rpm);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool _gpio_ok; // DAC is on a valid pin
|
|
||||||
protected:
|
|
||||||
void set_output(uint32_t duty); // sets DAC instead of PWM
|
|
||||||
};
|
|
||||||
|
|
||||||
class HuanyangSpindle : public Spindle {
|
|
||||||
private:
|
|
||||||
uint16_t ModRTU_CRC(char* buf, int len);
|
|
||||||
|
|
||||||
bool set_mode(uint8_t mode, bool critical);
|
|
||||||
|
|
||||||
bool get_pins_and_settings();
|
|
||||||
|
|
||||||
uint32_t _current_rpm;
|
|
||||||
uint8_t _txd_pin;
|
|
||||||
uint8_t _rxd_pin;
|
|
||||||
uint8_t _rts_pin;
|
|
||||||
uint8_t _state;
|
|
||||||
bool _task_running;
|
|
||||||
|
|
||||||
public:
|
|
||||||
HuanyangSpindle() { _task_running = false; }
|
|
||||||
void init();
|
|
||||||
void config_message();
|
|
||||||
void set_state(uint8_t state, uint32_t rpm);
|
|
||||||
uint8_t get_state();
|
|
||||||
uint32_t set_rpm(uint32_t rpm);
|
|
||||||
void stop();
|
|
||||||
static void read_value(uint8_t reg);
|
|
||||||
static void add_ModRTU_CRC(char* buf, int full_msg_len);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
uint32_t _min_rpm;
|
|
||||||
uint32_t _max_rpm;
|
|
||||||
};
|
|
||||||
|
|
||||||
class BESCSpindle : public PWMSpindle {
|
|
||||||
public:
|
|
||||||
void init();
|
|
||||||
void config_message();
|
|
||||||
uint32_t set_rpm(uint32_t rpm);
|
|
||||||
};
|
|
||||||
|
|
||||||
class _10vSpindle : public PWMSpindle {
|
|
||||||
public:
|
|
||||||
void init();
|
|
||||||
void config_message();
|
|
||||||
uint32_t set_rpm(uint32_t rpm);
|
|
||||||
uint8_t _forward_pin;
|
|
||||||
uint8_t _reverse_pin;
|
|
||||||
|
|
||||||
//void set_state(uint8_t state, uint32_t rpm);
|
|
||||||
|
|
||||||
uint8_t get_state();
|
|
||||||
void stop();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void set_enable_pin(bool enable_pin);
|
|
||||||
void set_spindle_dir_pin(bool Clockwise);
|
|
||||||
};
|
|
||||||
|
|
||||||
extern Spindle* spindle;
|
|
||||||
|
|
||||||
extern NullSpindle null_spindle;
|
|
||||||
extern PWMSpindle pwm_spindle;
|
|
||||||
extern RelaySpindle relay_spindle;
|
|
||||||
extern Laser laser;
|
|
||||||
extern DacSpindle dac_spindle;
|
|
||||||
extern HuanyangSpindle huanyang_spindle;
|
|
||||||
extern BESCSpindle besc_spindle;
|
|
||||||
extern _10vSpindle _10v_spindle;
|
|
||||||
|
|
||||||
void spindle_select();
|
|
||||||
|
|
||||||
// in HuanyangSpindle.cpp
|
|
||||||
void vfd_cmd_task(void* pvParameters);
|
|
@@ -56,7 +56,7 @@
|
|||||||
#include "report.h"
|
#include "report.h"
|
||||||
#include "serial.h"
|
#include "serial.h"
|
||||||
#include "Pins.h"
|
#include "Pins.h"
|
||||||
#include "Spindles/SpindleClass.h"
|
#include "Spindles/Spindle.h"
|
||||||
#include "Motors/Motors.h"
|
#include "Motors/Motors.h"
|
||||||
#include "stepper.h"
|
#include "stepper.h"
|
||||||
#include "jog.h"
|
#include "jog.h"
|
||||||
|
Reference in New Issue
Block a user