1
0
mirror of https://github.com/bdring/Grbl_Esp32.git synced 2025-09-02 10:53:01 +02:00

Merge pull request #356 from bdring/Devt

Auto assigned PWM channels
This commit is contained in:
bdring
2020-03-22 20:41:01 +01:00
committed by GitHub
16 changed files with 354 additions and 414 deletions

View File

@@ -1,10 +1,10 @@
/*
atari_1020.cpp
Part of Grbl_ESP32
copyright (c) 2018 - 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
@@ -19,9 +19,9 @@
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
--------------------------------------------------------------
This contains all the special features required to control an
Atari 1010 Pen Plotter
This contains all the special features required to control an
Atari 1010 Pen Plotter
*/
// This file is enabled by defining CUSTOM_CODE_FILENAME "atari_1020.cpp"
@@ -35,311 +35,254 @@
static TaskHandle_t solenoidSyncTaskHandle = 0;
static TaskHandle_t atariHomingTaskHandle = 0;
int8_t solenoid_pwm_chan_num;
uint16_t solenoid_pull_count;
bool atari_homing = false;
uint8_t homing_phase = HOMING_PHASE_FULL_APPROACH;
uint8_t current_tool;
void machine_init()
{
solenoid_pull_count = 0; // initialize
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Atari 1020 Solenoid");
// setup PWM channel
ledcSetup(SOLENOID_CHANNEL_NUM, SOLENOID_PWM_FREQ, SOLENOID_PWM_RES_BITS);
ledcAttachPin(SOLENOID_PEN_PIN, SOLENOID_CHANNEL_NUM);
pinMode(SOLENOID_DIRECTION_PIN, OUTPUT); // this sets the direction of the solenoid current
pinMode(REED_SW_PIN, INPUT_PULLUP); // external pullup required
// setup a task that will calculate solenoid position
xTaskCreatePinnedToCore(solenoidSyncTask, // task
"solenoidSyncTask", // name for task
4096, // size of task stack
NULL, // parameters
1, // priority
&solenoidSyncTaskHandle,
0 // core
);
// setup a task that will do the custom homing sequence
xTaskCreatePinnedToCore(atari_home_task, // task
"atari_home_task", // name for task
4096, // size of task stack
NULL, // parameters
1, // priority
&atariHomingTaskHandle,
0 // core
);
void machine_init() {
solenoid_pull_count = 0; // initialize
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Atari 1020 Solenoid");
// setup PWM channel
solenoid_pwm_chan_num = sys_get_next_PWM_chan_num();
ledcSetup(solenoid_pwm_chan_num, SOLENOID_PWM_FREQ, SOLENOID_PWM_RES_BITS);
ledcAttachPin(SOLENOID_PEN_PIN, solenoid_pwm_chan_num);
pinMode(SOLENOID_DIRECTION_PIN, OUTPUT); // this sets the direction of the solenoid current
pinMode(REED_SW_PIN, INPUT_PULLUP); // external pullup required
// setup a task that will calculate solenoid position
xTaskCreatePinnedToCore(solenoidSyncTask, // task
"solenoidSyncTask", // name for task
4096, // size of task stack
NULL, // parameters
1, // priority
&solenoidSyncTaskHandle,
0 // core
);
// setup a task that will do the custom homing sequence
xTaskCreatePinnedToCore(atari_home_task, // task
"atari_home_task", // name for task
4096, // size of task stack
NULL, // parameters
1, // priority
&atariHomingTaskHandle,
0 // core
);
}
// this task tracks the Z position and sets the solenoid
void solenoidSyncTask(void *pvParameters)
{
int32_t current_position[N_AXIS]; // copy of current location
float m_pos[N_AXIS]; // machine position in mm
TickType_t xLastWakeTime;
const TickType_t xSolenoidFrequency = SOLENOID_TASK_FREQ; // in ticks (typically ms)
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
while (true)
{ // don't ever return from this or the task dies
memcpy(current_position, sys_position, sizeof(sys_position)); // get current position in step
system_convert_array_steps_to_mpos(m_pos, current_position); // convert to millimeters
calc_solenoid(m_pos[Z_AXIS]); // calculate kinematics and move the servos
vTaskDelayUntil(&xLastWakeTime, xSolenoidFrequency);
}
void solenoidSyncTask(void* pvParameters) {
int32_t current_position[N_AXIS]; // copy of current location
float m_pos[N_AXIS]; // machine position in mm
TickType_t xLastWakeTime;
const TickType_t xSolenoidFrequency = SOLENOID_TASK_FREQ; // in ticks (typically ms)
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
while (true) {
// don't ever return from this or the task dies
memcpy(current_position, sys_position, sizeof(sys_position)); // get current position in step
system_convert_array_steps_to_mpos(m_pos, current_position); // convert to millimeters
calc_solenoid(m_pos[Z_AXIS]); // calculate kinematics and move the servos
vTaskDelayUntil(&xLastWakeTime, xSolenoidFrequency);
}
}
// to do...have this return a true or false. This could be used by the normal homing feature to
// continue with regular homing after setup
// return true if this completes homing
bool user_defined_homing()
{
// create and start a task to do the special homing
homing_phase = HOMING_PHASE_FULL_APPROACH;
atari_homing = true;
return true; // this does it...skip the rest of mc_homing_cycle(...)
bool user_defined_homing() {
// create and start a task to do the special homing
homing_phase = HOMING_PHASE_FULL_APPROACH;
atari_homing = true;
return true; // this does it...skip the rest of mc_homing_cycle(...)
}
/*
Do a custom homing routine.
A task is used because it needs to wait until until idle after each move.
1) Do a full travel move to the right. OK to stall if the pen started closer
2) Check for pen 1
3) If fail Retract
4) move to right end
5) Check...
....repeat up to 12 times to try to find pen one
....repeat up to 12 times to try to find pen one
TODO can the retract, move back be 1 phase rather than 2?
*/
void atari_home_task(void *pvParameters)
{
uint8_t homing_attempt = 0; // how many times have we tried to home
TickType_t xLastWakeTime;
const TickType_t xHomingTaskFrequency = 100; // in ticks (typically ms) .... need to make sure there is enough time to get out of idle
char gcode_line[20];
while (true)
{ // this task will only last as long as it is homing
if (atari_homing)
{
// must be in idle or alarm state
if (sys.state == STATE_IDLE)
{
switch (homing_phase)
{
case HOMING_PHASE_FULL_APPROACH: // a full width move to insure it hits left end
inputBuffer.push("G90G0Z1\r"); // lift the pen
sprintf(gcode_line, "G91G0X%3.2f\r", -ATARI_PAPER_WIDTH + ATARI_HOME_POS - 3.0); // plus a little extra
inputBuffer.push(gcode_line);
homing_attempt = 1;
homing_phase = HOMING_PHASE_CHECK;
break;
case HOMING_PHASE_CHECK: // check the limits switch
if (digitalRead(REED_SW_PIN) == 0)
{ // see if reed switch is grounded
inputBuffer.push("G4P0.1\n"); // dramtic pause
sys_position[X_AXIS] = ATARI_HOME_POS * settings.steps_per_mm[X_AXIS];
sys_position[Y_AXIS] = 0.0;
sys_position[Z_AXIS] = 1.0 * settings.steps_per_mm[Y_AXIS];
gc_sync_position();
plan_sync_position();
sprintf(gcode_line, "G90G0X%3.2f\r", ATARI_PAPER_WIDTH); // alway return to right side to reduce home travel stalls
inputBuffer.push(gcode_line);
current_tool = 1; // local copy for reference...until actual M6 change
gc_state.tool = current_tool;
atari_homing = false; // done with homing sequence
}
else
{
homing_phase = HOMING_PHASE_RETRACT;
homing_attempt++;
}
break;
case HOMING_PHASE_RETRACT:
sprintf(gcode_line, "G0X%3.2f\r", -ATARI_HOME_POS);
inputBuffer.push(gcode_line);
sprintf(gcode_line, "G0X%3.2f\r", ATARI_HOME_POS);
inputBuffer.push(gcode_line);
homing_phase = HOMING_PHASE_CHECK;
break;
default:
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Homing phase error %d", homing_phase);
atari_homing = false;
; // kills task
break;
}
if (homing_attempt > ATARI_HOMING_ATTEMPTS)
{ // try all positions plus 1
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Atari homing failed");
inputBuffer.push("G90\r");
atari_homing = false;
;
}
}
}
vTaskDelayUntil(&xLastWakeTime, xHomingTaskFrequency);
}
void atari_home_task(void* pvParameters) {
uint8_t homing_attempt = 0; // how many times have we tried to home
TickType_t xLastWakeTime;
const TickType_t xHomingTaskFrequency = 100; // in ticks (typically ms) .... need to make sure there is enough time to get out of idle
char gcode_line[20];
while (true) {
// this task will only last as long as it is homing
if (atari_homing) {
// must be in idle or alarm state
if (sys.state == STATE_IDLE) {
switch (homing_phase) {
case HOMING_PHASE_FULL_APPROACH: // a full width move to insure it hits left end
inputBuffer.push("G90G0Z1\r"); // lift the pen
sprintf(gcode_line, "G91G0X%3.2f\r", -ATARI_PAPER_WIDTH + ATARI_HOME_POS - 3.0); // plus a little extra
inputBuffer.push(gcode_line);
homing_attempt = 1;
homing_phase = HOMING_PHASE_CHECK;
break;
case HOMING_PHASE_CHECK: // check the limits switch
if (digitalRead(REED_SW_PIN) == 0) {
// see if reed switch is grounded
inputBuffer.push("G4P0.1\n"); // dramtic pause
sys_position[X_AXIS] = ATARI_HOME_POS * settings.steps_per_mm[X_AXIS];
sys_position[Y_AXIS] = 0.0;
sys_position[Z_AXIS] = 1.0 * settings.steps_per_mm[Y_AXIS];
gc_sync_position();
plan_sync_position();
sprintf(gcode_line, "G90G0X%3.2f\r", ATARI_PAPER_WIDTH); // alway return to right side to reduce home travel stalls
inputBuffer.push(gcode_line);
current_tool = 1; // local copy for reference...until actual M6 change
gc_state.tool = current_tool;
atari_homing = false; // done with homing sequence
} else {
homing_phase = HOMING_PHASE_RETRACT;
homing_attempt++;
}
break;
case HOMING_PHASE_RETRACT:
sprintf(gcode_line, "G0X%3.2f\r", -ATARI_HOME_POS);
inputBuffer.push(gcode_line);
sprintf(gcode_line, "G0X%3.2f\r", ATARI_HOME_POS);
inputBuffer.push(gcode_line);
homing_phase = HOMING_PHASE_CHECK;
break;
default:
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Homing phase error %d", homing_phase);
atari_homing = false;
; // kills task
break;
}
if (homing_attempt > ATARI_HOMING_ATTEMPTS) {
// try all positions plus 1
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Atari homing failed");
inputBuffer.push("G90\r");
atari_homing = false;
;
}
}
}
vTaskDelayUntil(&xLastWakeTime, xHomingTaskFrequency);
}
}
// calculate and set the PWM value for the servo
void calc_solenoid(float penZ)
{
bool isPenUp;
static bool previousPenState = false;
uint32_t solenoid_pen_pulse_len; // duty cycle of solenoid
isPenUp = ((penZ > 0) || (sys.state == STATE_ALARM)); // is pen above Z0 or is there an alarm
// if the state has not change, we only count down to the pull time
if (previousPenState == isPenUp)
{ // if state is unchanged
if (solenoid_pull_count > 0)
{
solenoid_pull_count--;
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_PULL; // stay at full power while counting down
}
else
{
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_HOLD; // pull in delay has expired so lower duty cycle
}
}
else
{ // pen direction has changed
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_PULL; // go to full power
solenoid_pull_count = SOLENOID_PULL_DURATION; // set the time to count down
}
previousPenState = isPenUp; // save the prev state
digitalWrite(SOLENOID_DIRECTION_PIN, isPenUp);
// skip setting value if it is unchanged
if (ledcRead(SOLENOID_CHANNEL_NUM) == solenoid_pen_pulse_len)
return;
// update the PWM value
// ledcWrite appears to have issues with interrupts, so make this a critical section
portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL(&myMutex);
ledcWrite(SOLENOID_CHANNEL_NUM, solenoid_pen_pulse_len);
portEXIT_CRITICAL(&myMutex);
void calc_solenoid(float penZ) {
bool isPenUp;
static bool previousPenState = false;
uint32_t solenoid_pen_pulse_len; // duty cycle of solenoid
isPenUp = ((penZ > 0) || (sys.state == STATE_ALARM)); // is pen above Z0 or is there an alarm
// if the state has not change, we only count down to the pull time
if (previousPenState == isPenUp) {
// if state is unchanged
if (solenoid_pull_count > 0) {
solenoid_pull_count--;
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_PULL; // stay at full power while counting down
} else {
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_HOLD; // pull in delay has expired so lower duty cycle
}
} else {
// pen direction has changed
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_PULL; // go to full power
solenoid_pull_count = SOLENOID_PULL_DURATION; // set the time to count down
}
previousPenState = isPenUp; // save the prev state
digitalWrite(SOLENOID_DIRECTION_PIN, isPenUp);
// skip setting value if it is unchanged
if (ledcRead(solenoid_pwm_chan_num) == solenoid_pen_pulse_len)
return;
// update the PWM value
// ledcWrite appears to have issues with interrupts, so make this a critical section
portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL(&myMutex);
ledcWrite(solenoid_pwm_chan_num, solenoid_pen_pulse_len);
portEXIT_CRITICAL(&myMutex);
}
/*
A tool (pen) change is done by bumping the carriage against the right edge 3 times per
position change. Pen 1-4 is valid range.
*/
void user_tool_change(uint8_t new_tool)
{
uint8_t move_count;
char gcode_line[20];
protocol_buffer_synchronize(); // wait for all previous moves to complete
if ((new_tool < 1) || (new_tool > MAX_PEN_NUMBER))
{
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Requested Pen#%d is out of 1-4 range", new_tool);
return;
}
if (new_tool == current_tool)
return;
if (new_tool > current_tool)
{
move_count = BUMPS_PER_PEN_CHANGE * (new_tool - current_tool);
}
else
{
move_count = BUMPS_PER_PEN_CHANGE * ((MAX_PEN_NUMBER - current_tool) + new_tool);
}
sprintf(gcode_line, "G0Z%3.2f\r", ATARI_TOOL_CHANGE_Z); // go to tool change height
inputBuffer.push(gcode_line);
for (uint8_t i = 0; i < move_count; i++)
{
sprintf(gcode_line, "G0X%3.2f\r", ATARI_HOME_POS); //
inputBuffer.push(gcode_line);
inputBuffer.push("G0X0\r");
}
current_tool = new_tool;
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Change to Pen#%d", current_tool);
void user_tool_change(uint8_t new_tool) {
uint8_t move_count;
char gcode_line[20];
protocol_buffer_synchronize(); // wait for all previous moves to complete
if ((new_tool < 1) || (new_tool > MAX_PEN_NUMBER)) {
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Requested Pen#%d is out of 1-4 range", new_tool);
return;
}
if (new_tool == current_tool)
return;
if (new_tool > current_tool)
move_count = BUMPS_PER_PEN_CHANGE * (new_tool - current_tool);
else
move_count = BUMPS_PER_PEN_CHANGE * ((MAX_PEN_NUMBER - current_tool) + new_tool);
sprintf(gcode_line, "G0Z%3.2f\r", ATARI_TOOL_CHANGE_Z); // go to tool change height
inputBuffer.push(gcode_line);
for (uint8_t i = 0; i < move_count; i++) {
sprintf(gcode_line, "G0X%3.2f\r", ATARI_HOME_POS); //
inputBuffer.push(gcode_line);
inputBuffer.push("G0X0\r");
}
current_tool = new_tool;
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Change to Pen#%d", current_tool);
}
// move from current tool to next tool....
void atari_next_pen()
{
if (current_tool < MAX_PEN_NUMBER)
{
gc_state.tool = current_tool + 1;
}
else
{
gc_state.tool = 1;
}
user_tool_change(gc_state.tool);
void atari_next_pen() {
if (current_tool < MAX_PEN_NUMBER)
gc_state.tool = current_tool + 1;
else
gc_state.tool = 1;
user_tool_change(gc_state.tool);
}
// Polar coaster has macro buttons, this handles those button pushes.
void user_defined_macro(uint8_t index)
{
char gcode_line[20];
switch (index)
{
void user_defined_macro(uint8_t index) {
char gcode_line[20];
switch (index) {
#ifdef MACRO_BUTTON_0_PIN
case CONTROL_PIN_INDEX_MACRO_0:
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Pen switch");
inputBuffer.push("$H\r");
break;
case CONTROL_PIN_INDEX_MACRO_0:
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Pen switch");
inputBuffer.push("$H\r");
break;
#endif
#ifdef MACRO_BUTTON_1_PIN
case CONTROL_PIN_INDEX_MACRO_1:
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Color switch");
atari_next_pen();
sprintf(gcode_line, "G90G0X%3.2f\r", ATARI_PAPER_WIDTH); // alway return to right side to reduce home travel stalls
inputBuffer.push(gcode_line);
break;
case CONTROL_PIN_INDEX_MACRO_1:
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Color switch");
atari_next_pen();
sprintf(gcode_line, "G90G0X%3.2f\r", ATARI_PAPER_WIDTH); // alway return to right side to reduce home travel stalls
inputBuffer.push(gcode_line);
break;
#endif
#ifdef MACRO_BUTTON_2_PIN
case CONTROL_PIN_INDEX_MACRO_2:
// feed out some paper and reset the Y 0
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Paper switch");
inputBuffer.push("G0Y-25\r");
inputBuffer.push("G4P0.1\r"); // sync...forces wait for planner to clear
sys_position[Y_AXIS] = 0.0; // reset the Y position
gc_sync_position();
plan_sync_position();
break;
case CONTROL_PIN_INDEX_MACRO_2:
// feed out some paper and reset the Y 0
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Paper switch");
inputBuffer.push("G0Y-25\r");
inputBuffer.push("G4P0.1\r"); // sync...forces wait for planner to clear
sys_position[Y_AXIS] = 0.0; // reset the Y position
gc_sync_position();
plan_sync_position();
break;
#endif
default:
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Unknown Switch %d", index);
break;
}
default:
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Unknown Switch %d", index);
break;
}
}
void user_m30()
{
char gcode_line[20];
sprintf(gcode_line, "G90G0X%3.2f\r", ATARI_PAPER_WIDTH); //
inputBuffer.push(gcode_line);
void user_m30() {
char gcode_line[20];
sprintf(gcode_line, "G90G0X%3.2f\r", ATARI_PAPER_WIDTH); //
inputBuffer.push(gcode_line);
}

View File

@@ -33,7 +33,7 @@
#define CUSTOM_CODE_FILENAME "Custom/atari_1020.cpp"
#ifdef USE_RMT_STEPS
#undef USE_RMT_STEPS
#undef USE_RMT_STEPS
#endif
#define USE_UNIPOLAR
@@ -52,32 +52,31 @@
#define SOLENOID_DIRECTION_PIN GPIO_NUM_4
#define SOLENOID_PEN_PIN GPIO_NUM_2
#define SOLENOID_CHANNEL_NUM 6
#ifdef HOMING_CYCLE_0
#undef HOMING_CYCLE_0
#undef HOMING_CYCLE_0
#endif
#define HOMING_CYCLE_0 (1 << X_AXIS) // this 'bot only homes the X axis
#ifdef HOMING_CYCLE_1
#undef HOMING_CYCLE_1
#undef HOMING_CYCLE_1
#endif
#ifdef HOMING_CYCLE_2
#undef HOMING_CYCLE_2
#undef HOMING_CYCLE_2
#endif
#define REED_SW_PIN GPIO_NUM_17
#define LIMIT_MASK 0
#ifdef IGNORE_CONTROL_PINS // maybe set in config.h
#undef IGNORE_CONTROL_PINS
#undef IGNORE_CONTROL_PINS
#endif
#ifndef ENABLE_CONTROL_SW_DEBOUNCE
#define ENABLE_CONTROL_SW_DEBOUNCE
#define ENABLE_CONTROL_SW_DEBOUNCE
#endif
#ifdef INVERT_CONTROL_PIN_MASK
#undef INVERT_CONTROL_PIN_MASK
#undef INVERT_CONTROL_PIN_MASK
#endif
#define INVERT_CONTROL_PIN_MASK B01110000
@@ -86,7 +85,7 @@
#define MACRO_BUTTON_2_PIN GPIO_NUM_36 // Paper Switch
#ifdef DEFAULTS_GENERIC
#undef DEFAULTS_GENERIC // undefine generic then define each default below
#undef DEFAULTS_GENERIC // undefine generic then define each default below
#endif
#define DEFAULT_STEP_PULSE_MICROSECONDS 3
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 200 // 200ms
@@ -160,11 +159,11 @@
#define USE_M30 // use the user defined end of program
#ifndef atari_h
#define atari_h
#define atari_h
void solenoid_disable();
void solenoidSyncTask(void *pvParameters);
void calc_solenoid(float penZ);
void atari_home_task(void *pvParameters);
void atari_next_pen();
void solenoid_disable();
void solenoidSyncTask(void* pvParameters);
void calc_solenoid(float penZ);
void atari_home_task(void* pvParameters);
void atari_next_pen();
#endif

View File

@@ -24,9 +24,8 @@
#define MACHINE_NAME "MACHINE_FOO_6X"
// Be sure to change to N_AXIS 6 in nuts_bolts.h
#ifdef N_AXIS
#undef N_AXIS
#undef N_AXIS
#endif
#define N_AXIS 6
@@ -50,7 +49,6 @@
// servos
#define USE_SERVO_AXES
#define SERVO_Z_PIN GPIO_NUM_22
#define SERVO_Z_CHANNEL_NUM 6
#define SERVO_Z_RANGE_MIN 0.0
#define SERVO_Z_RANGE_MAX 5.0
#define SERVO_Z_HOMING_TYPE SERVO_HOMING_TARGET // during homing it will instantly move to a target value
@@ -58,7 +56,6 @@
#define SERVO_Z_MPOS false // will not use mpos, uses work coordinates
#define SERVO_C_PIN GPIO_NUM_2
#define SERVO_C_CHANNEL_NUM 7
#define SERVO_C_RANGE_MIN 0.0
#define SERVO_C_RANGE_MAX 5.0
#define SERVO_C_HOMING_TYPE SERVO_HOMING_TARGET // during homing it will instantly move to a target value
@@ -76,20 +73,20 @@
#define STEPPERS_DISABLE_PIN GPIO_NUM_13
#ifdef HOMING_CYCLE_0 // undefine from config.h
#undef HOMING_CYCLE_0
#undef HOMING_CYCLE_0
#endif
//#define HOMING_CYCLE_0 (1<<X_AXIS)
#define HOMING_CYCLE_0 ((1<<X_AXIS)|(1<<Y_AXIS))
//#define HOMING_CYCLE_0 ((1<<X_AXIS)|(1<<Y_AXIS) |(1<<A_AXIS)|(1<<B_AXIS))
#ifdef HOMING_CYCLE_1 // undefine from config.h
#undef HOMING_CYCLE_1
#undef HOMING_CYCLE_1
#endif
//#define HOMING_CYCLE_1 (1<<A_AXIS)
#define HOMING_CYCLE_1 ((1<<A_AXIS)|(1<<B_AXIS))
#ifdef HOMING_CYCLE_2 // undefine from config.h
#undef HOMING_CYCLE_2
#undef HOMING_CYCLE_2
#endif
/*
#define HOMING_CYCLE_2 (1<<Y_AXIS)

View File

@@ -31,7 +31,7 @@
#define Y_DIRECTION_PIN GPIO_NUM_25
#ifndef COREXY // maybe set in config.h
#define COREXY
#define COREXY
#endif
#define STEPPERS_DISABLE_PIN GPIO_NUM_13
@@ -41,11 +41,10 @@
#define LIMIT_MASK B11
#ifndef USE_SERVO_AXES // maybe set in config.h
#define USE_SERVO_AXES
#define USE_SERVO_AXES
#endif
#define SERVO_Z_PIN GPIO_NUM_27
#define SERVO_Z_CHANNEL_NUM 5
#define SERVO_Z_RANGE_MIN 0.0
#define SERVO_Z_RANGE_MAX 5.0
#define SERVO_Z_HOMING_TYPE SERVO_HOMING_TARGET // during homing it will instantly move to a target value
@@ -53,24 +52,24 @@
#define SERVO_Z_MPOS false // will not use mpos, uses work coordinates
#ifndef IGNORE_CONTROL_PINS // maybe set in config.h
#define IGNORE_CONTROL_PINS
#define IGNORE_CONTROL_PINS
#endif
// redefine some stuff from config.h
#ifdef HOMING_CYCLE_0
#undef HOMING_CYCLE_0
#undef HOMING_CYCLE_0
#endif
#define HOMING_CYCLE_0 (1<<Y_AXIS)
#ifdef HOMING_CYCLE_1
#undef HOMING_CYCLE_1
#undef HOMING_CYCLE_1
#endif
#define HOMING_CYCLE_1 (1<<X_AXIS)
#ifdef HOMING_CYCLE_2
#undef HOMING_CYCLE_2
#undef HOMING_CYCLE_2
#endif
#define SERVO_PEN_PIN GPIO_NUM_27

View File

@@ -41,10 +41,10 @@
#define STEPPERS_DISABLE_PIN GPIO_NUM_13
#ifdef PEN_LASER_V1
#define X_LIMIT_PIN GPIO_NUM_2
#define X_LIMIT_PIN GPIO_NUM_2
#endif
#ifdef PEN_LASER_V2
#define X_LIMIT_PIN GPIO_NUM_15
#define X_LIMIT_PIN GPIO_NUM_15
#endif
#define Y_LIMIT_PIN GPIO_NUM_4
#define LIMIT_MASK B11
@@ -57,17 +57,15 @@
//#define USING_SOLENOID // uncomment to use this feature
#ifdef USING_SERVO
#define USE_SERVO_AXES
#define SERVO_Z_PIN GPIO_NUM_27
#define SERVO_Z_CHANNEL_NUM 3
#define SERVO_Z_RANGE_MIN 0
#define SERVO_Z_RANGE_MAX 10
#define USE_SERVO_AXES
#define SERVO_Z_PIN GPIO_NUM_27
#define SERVO_Z_RANGE_MIN 0
#define SERVO_Z_RANGE_MAX 10
#endif
#ifdef USING_SOLENOID
#define USE_PEN_SOLENOID
#define SOLENOID_PEN_PIN GPIO_NUM_16
#define SOLENOID_CHANNEL_NUM 6
#define USE_PEN_SOLENOID
#define SOLENOID_PEN_PIN GPIO_NUM_16
#endif
// defaults

View File

@@ -44,11 +44,10 @@
#define STEPPERS_DISABLE_PIN GPIO_NUM_17
#ifndef USE_SERVO_AXES // maybe set in config.h
#define USE_SERVO_AXES
#define USE_SERVO_AXES
#endif
#define SERVO_Z_PIN GPIO_NUM_16
#define SERVO_Z_CHANNEL_NUM 5
#define SERVO_Z_RANGE_MIN 0.0
#define SERVO_Z_RANGE_MAX 5.0
#define SERVO_Z_HOMING_TYPE SERVO_HOMING_TARGET // during homing it will instantly move to a target value
@@ -59,20 +58,20 @@
#define LIMIT_MASK B1
#ifdef IGNORE_CONTROL_PINS // maybe set in config.h
#undef IGNORE_CONTROL_PINS
#undef IGNORE_CONTROL_PINS
#endif
#ifndef ENABLE_CONTROL_SW_DEBOUNCE
#define ENABLE_CONTROL_SW_DEBOUNCE
#define ENABLE_CONTROL_SW_DEBOUNCE
#endif
#ifdef CONTROL_SW_DEBOUNCE_PERIOD
#undef CONTROL_SW_DEBOUNCE_PERIOD
#undef CONTROL_SW_DEBOUNCE_PERIOD
#endif
#define CONTROL_SW_DEBOUNCE_PERIOD 100 // really long debounce
#ifdef INVERT_CONTROL_PIN_MASK
#undef INVERT_CONTROL_PIN_MASK
#undef INVERT_CONTROL_PIN_MASK
#endif
#define INVERT_CONTROL_PIN_MASK B11111111
@@ -82,14 +81,14 @@
// redefine some stuff from config.h
#ifdef HOMING_CYCLE_0
#undef HOMING_CYCLE_0
#undef HOMING_CYCLE_0
#endif
#define HOMING_CYCLE_0 (1<<X_AXIS) // this 'bot only homes the X axis
#ifdef HOMING_CYCLE_1
#undef HOMING_CYCLE_1
#undef HOMING_CYCLE_1
#endif
#ifdef HOMING_CYCLE_2
#undef HOMING_CYCLE_2
#undef HOMING_CYCLE_2
#endif
// ============= End CPU MAP ==================

View File

@@ -39,11 +39,11 @@
#define STEPPERS_DISABLE_PIN GPIO_NUM_13
#ifdef PEN_LASER_V1
#define X_LIMIT_PIN GPIO_NUM_2
#define X_LIMIT_PIN GPIO_NUM_2
#endif
#ifdef PEN_LASER_V2
#define X_LIMIT_PIN GPIO_NUM_15
#define X_LIMIT_PIN GPIO_NUM_15
#endif
#define Y_LIMIT_PIN GPIO_NUM_4
@@ -61,16 +61,14 @@
#define SPINDLE_PWM_OFF_VALUE 0
#ifndef SPINDLE_PWM_MIN_VALUE
#define SPINDLE_PWM_MIN_VALUE 1 // Must be greater than zero.
#define SPINDLE_PWM_MIN_VALUE 1 // Must be greater than zero.
#endif
#define SERVO_Y_PIN GPIO_NUM_14
#define SERVO_Y_CHANNEL_NUM 6
#define SERVO_Y_RANGE_MIN 0.0
#define SERVO_Y_RANGE_MAX 30.0
#define SERVO_Z_PIN GPIO_NUM_27
#define SERVO_Z_CHANNEL_NUM 5
#define SERVO_Z_RANGE_MIN 0.0
#define SERVO_Z_RANGE_MAX 20.0

View File

@@ -1,6 +1,6 @@
/*
template.h
Part of Grbl_ESP32
template.h
Part of Grbl_ESP32
Template for a machine configuration file.
@@ -135,7 +135,6 @@
// #define USE_SERVO_AXES
// #define SERVO_Z_PIN GPIO_NUM_22
// #define SERVO_Z_CHANNEL_NUM 6
// #define SERVO_Z_RANGE_MIN 0.0
// #define SERVO_Z_RANGE_MAX 5.0
// #define SERVO_Z_HOMING_TYPE SERVO_HOMING_TARGET // during homing it will instantly move to a target value

View File

@@ -4,7 +4,7 @@
Pin assignments for the TMC2130 Pen/Laser controller
https://github.com/bdring/Grbl_ESP32_TMC2130_Plotter_Controller
2018 - Bart Dring
2020 - Mitch Bradley
@@ -28,11 +28,11 @@
#define MACHINE_V2 // version 2 PCB
#ifdef MACHINE_V1
#define MACHINE_NAME "ESP32_TMC2130_PEN V1"
#define X_LIMIT_PIN GPIO_NUM_2
#define MACHINE_NAME "ESP32_TMC2130_PEN V1"
#define X_LIMIT_PIN GPIO_NUM_2
#else
#define MACHINE_NAME "ESP32_TMC2130_PEN V2"
#define X_LIMIT_PIN GPIO_NUM_32
#define MACHINE_NAME "ESP32_TMC2130_PEN V2"
#define X_LIMIT_PIN GPIO_NUM_32
#endif
#define USE_TRINAMIC // Using at least 1 trinamic driver
@@ -59,7 +59,6 @@
#endif
#define SERVO_Z_PIN GPIO_NUM_27 // comment this out if PWM spindle/laser control.
#define SERVO_Z_CHANNEL_NUM 5
#define SERVO_Z_RANGE_MIN 0.0
#define SERVO_Z_RANGE_MAX 5.0
#define SERVO_Z_HOMING_TYPE SERVO_HOMING_TARGET // during homing it will instantly move to a target value

View File

@@ -6,7 +6,6 @@
#endif
#define SPINDLE_PWM_MAX_VALUE ((1<<SPINDLE_PWM_BIT_PRECISION) - 1)
#define SPINDLE_PWM_CHANNEL 0
// Grbl setting that are common to all machines
// It should not be necessary to change anything herein

View File

@@ -29,122 +29,116 @@
static TaskHandle_t servosSyncTaskHandle = 0;
#ifdef SERVO_X_PIN
ServoAxis X_Servo_Axis(X_AXIS, SERVO_X_PIN, SERVO_X_CHANNEL_NUM);
ServoAxis X_Servo_Axis(X_AXIS, SERVO_X_PIN);
#endif
#ifdef SERVO_Y_PIN
ServoAxis Y_Servo_Axis(Y_AXIS, SERVO_Y_PIN, SERVO_Y_CHANNEL_NUM);
ServoAxis Y_Servo_Axis(Y_AXIS, SERVO_Y_PIN);
#endif
#ifdef SERVO_Z_PIN
ServoAxis Z_Servo_Axis(Z_AXIS, SERVO_Z_PIN, SERVO_Z_CHANNEL_NUM);
ServoAxis Z_Servo_Axis(Z_AXIS, SERVO_Z_PIN);
#endif
#ifdef SERVO_A_PIN
ServoAxis A_Servo_Axis(A_AXIS, SERVO_A_PIN, SERVO_A_CHANNEL_NUM);
ServoAxis A_Servo_Axis(A_AXIS, SERVO_A_PIN);
#endif
#ifdef SERVO_B_PIN
ServoAxis B_Servo_Axis(B_AXIS, SERVO_B_PIN, SERVO_B_CHANNEL_NUM);
ServoAxis B_Servo_Axis(B_AXIS, SERVO_B_PIN);
#endif
#ifdef SERVO_C_PIN
ServoAxis C_Servo_Axis(C_AXIS, SERVO_C_PIN, SERVO_C_CHANNEL_NUM);
ServoAxis C_Servo_Axis(C_AXIS, SERVO_C_PIN);
#endif
void init_servos() {
// ======================== X Axis ===========================
#ifdef SERVO_X_PIN
#ifdef SERVO_X_PIN
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "X Servo range %4.3f to %4.3f", SERVO_X_RANGE_MIN, SERVO_X_RANGE_MAX);
X_Servo_Axis.init();
X_Servo_Axis.set_range(SERVO_X_RANGE_MIN, SERVO_X_RANGE_MAX);
#ifdef SERVO_X_HOMING_TYPE
#ifdef SERVO_X_HOMING_TYPE
X_Servo_Axis.set_homing_type(SERVO_X_HOMING_TYPE);
#endif
#ifdef SERVO_X_HOME_POS
#endif
#ifdef SERVO_X_HOME_POS
X_Servo_Axis.set_homing_position(SERVO_X_HOME_POS);
#endif
#ifdef SERVO_X_MPOS // value should be true or false
#endif
#ifdef SERVO_X_MPOS // value should be true or false
X_Servo_Axis.set_use_mpos(SERVO_X_MPOS);
#endif
#endif
#endif
#endif
// ======================== Y Axis ===========================
#ifdef SERVO_Y_PIN
#ifdef SERVO_Y_PIN
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Y Servo range %4.3f to %4.3f", SERVO_Y_RANGE_MIN, SERVO_Y_RANGE_MAX);
Y_Servo_Axis.init();
Y_Servo_Axis.set_range(SERVO_Y_RANGE_MIN, SERVO_Y_RANGE_MAX);
#ifdef SERVO_Y_HOMING_TYPE
#ifdef SERVO_Y_HOMING_TYPE
Y_Servo_Axis.set_homing_type(SERVO_Y_HOMING_TYPE);
#endif
#ifdef SERVO_Y_HOME_POS
#endif
#ifdef SERVO_Y_HOME_POS
Y_Servo_Axis.set_homing_position(SERVO_Y_HOME_POS);
#endif
#ifdef SERVO_Y_MPOS // value should be true or false
#endif
#ifdef SERVO_Y_MPOS // value should be true or false
Y_Servo_Axis.set_use_mpos(SERVO_Y_MPOS);
#endif
#endif
#endif
#endif
// ======================== Z Axis ===========================
#ifdef SERVO_Z_PIN
#ifdef SERVO_Z_PIN
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "Z Servo range %4.3f to %4.3f", SERVO_Z_RANGE_MIN, SERVO_Z_RANGE_MAX);
Z_Servo_Axis.init();
Z_Servo_Axis.set_range(SERVO_Z_RANGE_MIN, SERVO_Z_RANGE_MAX);
#ifdef SERVO_Z_HOMING_TYPE
#ifdef SERVO_Z_HOMING_TYPE
Z_Servo_Axis.set_homing_type(SERVO_Z_HOMING_TYPE);
#endif
#ifdef SERVO_Z_HOME_POS
#endif
#ifdef SERVO_Z_HOME_POS
Z_Servo_Axis.set_homing_position(SERVO_Z_HOME_POS);
#endif
#ifdef SERVO_Z_MPOS // value should be true or false
#endif
#ifdef SERVO_Z_MPOS // value should be true or false
Z_Servo_Axis.set_use_mpos(SERVO_Z_MPOS);
#endif
#endif
#endif
#endif
// ======================== A Axis ===========================
#ifdef SERVO_A_PIN
#ifdef SERVO_A_PIN
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "A Servo range %4.3f to %4.3f", SERVO_A_RANGE_MIN, SERVO_A_RANGE_MAX);
A_Servo_Axis.init();
A_Servo_Axis.set_range(SERVO_A_RANGE_MIN, SERVO_A_RANGE_MAX);
#ifdef SERVO_A_HOMING_TYPE
#ifdef SERVO_A_HOMING_TYPE
A_Servo_Axis.set_homing_type(SERVO_A_HOMING_TYPE);
#endif
#ifdef SERVO_A_HOME_POS
#endif
#ifdef SERVO_A_HOME_POS
A_Servo_Axis.set_homing_position(SERVO_A_HOME_POS);
#endif
#ifdef SERVO_A_MPOS // value should be true or false
#endif
#ifdef SERVO_A_MPOS // value should be true or false
A_Servo_Axis.set_use_mpos(SERVO_A_MPOS);
#endif
#endif
#endif
#endif
// ======================== B Axis ===========================
#ifdef SERVO_B_PIN
#ifdef SERVO_B_PIN
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "B Servo range %4.3f to %4.3f", SERVO_B_RANGE_MIN, SERVO_B_RANGE_MAX);
B_Servo_Axis.init();
B_Servo_Axis.set_range(SERVO_B_RANGE_MIN, SERVO_B_RANGE_MAX);
#ifdef SERVO_B_HOMING_TYPE
#ifdef SERVO_B_HOMING_TYPE
B_Servo_Axis.set_homing_type(SERVO_B_HOMING_TYPE);
#endif
#ifdef SERVO_B_HOME_POS
#endif
#ifdef SERVO_B_HOME_POS
B_Servo_Axis.set_homing_position(SERVO_B_HOME_POS);
#endif
#ifdef SERVO_B_MPOS // value should be true or false
#endif
#ifdef SERVO_B_MPOS // value should be true or false
B_Servo_Axis.set_use_mpos(SERVO_B_MPOS);
#endif
#endif
#endif
#endif
// ======================== C Axis ===========================
#ifdef SERVO_C_PIN
#ifdef SERVO_C_PIN
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_INFO, "C Servo range %4.3f to %4.3f", SERVO_C_RANGE_MIN, SERVO_C_RANGE_MAX);
C_Servo_Axis.init();
C_Servo_Axis.set_range(SERVO_C_RANGE_MIN, SERVO_C_RANGE_MAX);
#ifdef SERVO_C_HOMING_TYPE
#ifdef SERVO_C_HOMING_TYPE
C_Servo_Axis.set_homing_type(SERVO_C_HOMING_TYPE);
#endif
#ifdef SERVO_C_HOME_POS
#endif
#ifdef SERVO_C_HOME_POS
C_Servo_Axis.set_homing_position(SERVO_C_HOME_POS);
#endif
#ifdef SERVO_C_MPOS // value should be true or false
#endif
#ifdef SERVO_C_MPOS // value should be true or false
C_Servo_Axis.set_use_mpos(SERVO_C_MPOS);
#endif
#endif
#endif
#endif
// setup a task that will calculate the determine and set the servo positions
xTaskCreatePinnedToCore(servosSyncTask, // task
"servosSyncTask", // name for task
@@ -163,34 +157,34 @@ void servosSyncTask(void* pvParameters) {
const TickType_t xServoFrequency = SERVO_TIMER_INT_FREQ; // in ticks (typically ms)
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
while (true) { // don't ever return from this or the task dies
#ifdef SERVO_X_PIN
#ifdef SERVO_X_PIN
X_Servo_Axis.set_location();
#endif
#ifdef SERVO_Y_PIN
#endif
#ifdef SERVO_Y_PIN
Y_Servo_Axis.set_location();
#endif
#ifdef SERVO_Z_PIN
#endif
#ifdef SERVO_Z_PIN
Z_Servo_Axis.set_location();
#endif
#ifdef SERVO_A_PIN
#endif
#ifdef SERVO_A_PIN
A_Servo_Axis.set_location();
#endif
#ifdef SERVO_B_PIN
#endif
#ifdef SERVO_B_PIN
B_Servo_Axis.set_location();
#endif
#ifdef SERVO_C_PIN
#endif
#ifdef SERVO_C_PIN
C_Servo_Axis.set_location();
#endif
#endif
vTaskDelayUntil(&xLastWakeTime, xServoFrequency);
}
}
// =============================== Class Stuff ================================= //
ServoAxis::ServoAxis(uint8_t axis, uint8_t pin_num, uint8_t channel_num) { // constructor
ServoAxis::ServoAxis(uint8_t axis, uint8_t pin_num) { // constructor
_axis = axis;
_pin_num = pin_num;
_channel_num = channel_num;
_channel_num = sys_get_next_PWM_chan_num();
_showError = true; // this will be used to show calibration error only once
_use_mpos = true; // default is to use the machine position rather than work position
}

View File

@@ -36,7 +36,6 @@
2. In the machine definition file in Machines/, define servo pins and PWM channels like this ....
#define SERVO_Y_PIN GPIO_NUM_14
#define SERVO_Y_CHANNEL_NUM 6
undefine any step and direction pins associated with that axis
@@ -93,7 +92,7 @@ void servosSyncTask(void* pvParameters);
class ServoAxis {
public:
ServoAxis(uint8_t axis, uint8_t pin_num, uint8_t channel_num); // constructor
ServoAxis(uint8_t axis, uint8_t pin_num); // constructor
void init();
void set_location();
void disable(); // sets PWM to 0% duty cycle. Most servos can be manually moved in this state

View File

@@ -23,6 +23,8 @@
#ifdef USE_PEN_SOLENOID
int8_t solenoid_pwm_chan_num;
static TaskHandle_t solenoidSyncTaskHandle = 0;
// used to delay turn on
@@ -35,8 +37,9 @@ void solenoid_init() {
solenoid_pen_enable = false; // start delay has not completed yet.
solenoide_hold_count = 0; // initialize
// setup PWM channel
ledcSetup(SOLENOID_CHANNEL_NUM, SOLENOID_PWM_FREQ, SOLENOID_PWM_RES_BITS);
ledcAttachPin(SOLENOID_PEN_PIN, SOLENOID_CHANNEL_NUM);
solenoid_pwm_chan_num = sys_get_next_PWM_chan_num();
ledcSetup(solenoid_pwm_chan_num, SOLENOID_PWM_FREQ, SOLENOID_PWM_RES_BITS);
ledcAttachPin(SOLENOID_PEN_PIN, solenoid_pwm_chan_num);
solenoid_disable(); // start it it off
// setup a task that will calculate the determine and set the servo position
xTaskCreatePinnedToCore(solenoidSyncTask, // task
@@ -51,7 +54,7 @@ void solenoid_init() {
// turn off the PWM (0 duty)
void solenoid_disable() {
ledcWrite(SOLENOID_CHANNEL_NUM, 0);
ledcWrite(solenoid_pwm_chan_num, 0);
}
// this is the task
@@ -91,13 +94,13 @@ void calc_solenoid(float penZ) {
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_HOLD;
}
// skip setting value if it is unchanged
if (ledcRead(SOLENOID_CHANNEL_NUM) == solenoid_pen_pulse_len)
if (ledcRead(solenoid_pwm_chan_num) == solenoid_pen_pulse_len)
return;
// update the PWM value
// ledcWrite appears to have issues with interrupts, so make this a critical section
portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL(&myMutex);
ledcWrite(SOLENOID_CHANNEL_NUM, solenoid_pen_pulse_len);
ledcWrite(solenoid_pwm_chan_num, solenoid_pen_pulse_len);
portEXIT_CRITICAL(&myMutex);
}

View File

@@ -20,6 +20,8 @@
#include "grbl.h"
int8_t spindle_pwm_chan_num;
#ifdef SPINDLE_PWM_PIN
static float pwm_gradient; // Precalulated value to speed up rpm to PWM conversions.
uint32_t spindle_pwm_period; // how many counts in 1 period
@@ -54,8 +56,9 @@ void spindle_init() {
pinMode(SPINDLE_DIR_PIN, OUTPUT);
#endif
// use the LED control feature to setup PWM https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/ledc.html
ledcSetup(SPINDLE_PWM_CHANNEL, (double)settings.spindle_pwm_freq, SPINDLE_PWM_BIT_PRECISION); // setup the channel
ledcAttachPin(SPINDLE_PWM_PIN, SPINDLE_PWM_CHANNEL); // attach the PWM to the pin
spindle_pwm_chan_num - sys_get_next_PWM_chan_num();
ledcSetup(spindle_pwm_chan_num, (double)settings.spindle_pwm_freq, SPINDLE_PWM_BIT_PRECISION); // setup the channel
ledcAttachPin(SPINDLE_PWM_PIN, spindle_pwm_chan_num); // attach the PWM to the pin
// Start with spindle off off
spindle_stop();
#endif
@@ -65,9 +68,9 @@ void spindle_stop() {
spindle_set_enable(false);
#ifdef SPINDLE_PWM_PIN
#ifndef INVERT_SPINDLE_PWM
grbl_analogWrite(SPINDLE_PWM_CHANNEL, spindle_pwm_off_value);
grbl_analogWrite(spindle_pwm_chan_num, spindle_pwm_off_value);
#else
grbl_analogWrite(SPINDLE_PWM_CHANNEL, (1 << SPINDLE_PWM_BIT_PRECISION)); // TO DO...wrong for min_pwm
grbl_analogWrite(spindle_pwm_chan_num, (1 << SPINDLE_PWM_BIT_PRECISION)); // TO DO...wrong for min_pwm
#endif
#endif
}
@@ -77,7 +80,7 @@ uint8_t spindle_get_state() { // returns SPINDLE_STATE_DISABLE, SPINDLE_STATE_CW
#ifndef SPINDLE_PWM_PIN
return (SPINDLE_STATE_DISABLE);
#else
if (ledcRead(SPINDLE_PWM_CHANNEL) == 0) // Check the PWM value
if (ledcRead(spindle_pwm_chan_num) == 0) // Check the PWM value
return (SPINDLE_STATE_DISABLE);
else {
#ifdef SPINDLE_DIR_PIN
@@ -103,9 +106,9 @@ void spindle_set_speed(uint32_t pwm_value) {
spindle_set_enable(pwm_value != 0);
#endif
#ifndef INVERT_SPINDLE_PWM
grbl_analogWrite(SPINDLE_PWM_CHANNEL, pwm_value);
grbl_analogWrite(spindle_pwm_chan_num, pwm_value);
#else
grbl_analogWrite(SPINDLE_PWM_CHANNEL, (1 << SPINDLE_PWM_BIT_PRECISION) - pwm_value);
grbl_analogWrite(spindle_pwm_chan_num, (1 << SPINDLE_PWM_BIT_PRECISION) - pwm_value);
#endif
#endif
}

View File

@@ -587,4 +587,14 @@ int8_t sys_get_next_RMT_chan_num() {
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_ERROR, "Error: out of RMT channels");
return -1;
}
}
int8_t sys_get_next_PWM_chan_num() {
static uint8_t next_PWM_chan_num = 0; // channels 0-7 are valid
if (next_PWM_chan_num < 8) // 7 is the max PWM channel number
return next_PWM_chan_num++;
else {
grbl_msg_sendf(CLIENT_SERIAL, MSG_LEVEL_ERROR, "Error: out of PWM channels");
return -1;
}
}

View File

@@ -229,5 +229,6 @@ void sys_io_control(uint8_t io_num_mask, bool turnOn);
//
int8_t sys_get_next_RMT_chan_num();
int8_t sys_get_next_PWM_chan_num();
#endif
#endif