From 1d2c44cad3201e020e096712c59c1f71ee04416b Mon Sep 17 00:00:00 2001 From: bdring Date: Tue, 22 Oct 2019 10:53:15 -0500 Subject: [PATCH 1/2] Change input client index to avoid overflow This commit replaces PR 221, that got out of sync. --- Grbl_Esp32/espresponse.cpp | 4 ++-- Grbl_Esp32/grbl.h | 2 +- Grbl_Esp32/report.cpp | 4 ++-- Grbl_Esp32/report.h | 6 +++--- Grbl_Esp32/serial.cpp | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Grbl_Esp32/espresponse.cpp b/Grbl_Esp32/espresponse.cpp index 3c2a36b0..7c51da9b 100644 --- a/Grbl_Esp32/espresponse.cpp +++ b/Grbl_Esp32/espresponse.cpp @@ -35,7 +35,7 @@ ESPResponseStream::ESPResponseStream(WebServer * webserver){ #endif ESPResponseStream::ESPResponseStream(){ - _client = CLIENT_NONE; + _client = CLIENT_INPUT; #if defined (ENABLE_HTTP) && defined(ENABLE_WIFI) _header_sent=false; _webserver = NULL; @@ -72,7 +72,7 @@ String ESPResponseStream::formatBytes (uint64_t bytes) } void ESPResponseStream::print(const char *data){ - if (_client == CLIENT_NONE) return; + if (_client == CLIENT_INPUT) return; #if defined (ENABLE_HTTP) && defined(ENABLE_WIFI) if (_webserver) { if (!_header_sent) { diff --git a/Grbl_Esp32/grbl.h b/Grbl_Esp32/grbl.h index 389125f5..645fbbcd 100644 --- a/Grbl_Esp32/grbl.h +++ b/Grbl_Esp32/grbl.h @@ -20,7 +20,7 @@ // Grbl versioning system #define GRBL_VERSION "1.1f" -#define GRBL_VERSION_BUILD "20191018" +#define GRBL_VERSION_BUILD "20191022" //#include #include diff --git a/Grbl_Esp32/report.cpp b/Grbl_Esp32/report.cpp index ce67c3c9..34dbe274 100644 --- a/Grbl_Esp32/report.cpp +++ b/Grbl_Esp32/report.cpp @@ -53,7 +53,7 @@ // this is a generic send function that everything should use, so interfaces could be added (Bluetooth, etc) void grbl_send(uint8_t client, const char *text) { - if (client == CLIENT_NONE) return; + if (client == CLIENT_INPUT) return; #ifdef ENABLE_BLUETOOTH if (SerialBT.hasClient() && ( client == CLIENT_BT || client == CLIENT_ALL ) ) { @@ -81,7 +81,7 @@ void grbl_send(uint8_t client, const char *text) // This is a formating version of the grbl_send(CLIENT_ALL,...) function that work like printf void grbl_sendf(uint8_t client, const char *format, ...) { - if (client == CLIENT_NONE) return; + if (client == CLIENT_INPUT) return; char loc_buf[64]; char * temp = loc_buf; va_list arg; diff --git a/Grbl_Esp32/report.h b/Grbl_Esp32/report.h index 82cd68b0..55f2a422 100644 --- a/Grbl_Esp32/report.h +++ b/Grbl_Esp32/report.h @@ -99,13 +99,13 @@ #define MESSAGE_SLEEP_MODE 11 #define MESSAGE_SD_FILE_QUIT 60 // mc_reset was called during an SD job -#define CLIENT_NONE 0 -#define CLIENT_SERIAL 1 +#define CLIENT_SERIAL 1 #define CLIENT_BT 2 #define CLIENT_WEBUI 3 #define CLIENT_TELNET 4 +#define CLIENT_INPUT 5 #define CLIENT_ALL 0xFF -#define CLIENT_COUNT 5 // total number of client types regardless if they are used +#define CLIENT_COUNT 5 // total number of client types regardless if they are used // functions to send data to the user. void grbl_send(uint8_t client, const char *text); diff --git a/Grbl_Esp32/serial.cpp b/Grbl_Esp32/serial.cpp index b8db738d..5a00714e 100644 --- a/Grbl_Esp32/serial.cpp +++ b/Grbl_Esp32/serial.cpp @@ -89,7 +89,7 @@ void serialCheckTask(void *pvParameters) data = Serial.read(); } else if (inputBuffer.available()){ - client = CLIENT_NONE; + client = CLIENT_INPUT; data = inputBuffer.read(); } else @@ -228,7 +228,7 @@ void serialCheck() } else if (inputBuffer.available()) { - client = CLIENT_NONE; + client = CLIENT_INPUT; data = inputBuffer.read(); } #if defined (ENABLE_BLUETOOTH) || (defined (ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN)) From 21814214910bde9325186813de157f4c4201edee Mon Sep 17 00:00:00 2001 From: bdring Date: Wed, 23 Oct 2019 07:30:31 -0500 Subject: [PATCH 2/2] Support for custom machines - Added optional machine_init - Added user defined homing - Added Unipolar Stepper motor support - Added Tool changing - Added M30 Support --- Grbl_Esp32/Grbl_Esp32.ino | 4 + Grbl_Esp32/atari_1020.cpp | 324 ++++++++++++++++++++++++++++++++++ Grbl_Esp32/atari_1020.h | 63 +++++++ Grbl_Esp32/cpu_map.h | 112 ++++++++++++ Grbl_Esp32/gcode.cpp | 16 +- Grbl_Esp32/gcode.h | 4 +- Grbl_Esp32/grbl.h | 6 +- Grbl_Esp32/grbl_unipolar.cpp | 236 +++++++++++++++++++++++++ Grbl_Esp32/grbl_unipolar.h | 54 ++++++ Grbl_Esp32/motion_control.cpp | 6 + Grbl_Esp32/stepper.cpp | 16 +- Grbl_Esp32/system.cpp | 31 ++-- 12 files changed, 854 insertions(+), 18 deletions(-) create mode 100644 Grbl_Esp32/atari_1020.cpp create mode 100644 Grbl_Esp32/atari_1020.h create mode 100644 Grbl_Esp32/grbl_unipolar.cpp create mode 100644 Grbl_Esp32/grbl_unipolar.h diff --git a/Grbl_Esp32/Grbl_Esp32.ino b/Grbl_Esp32/Grbl_Esp32.ino index 9775e4e2..1d4ee718 100644 --- a/Grbl_Esp32/Grbl_Esp32.ino +++ b/Grbl_Esp32/Grbl_Esp32.ino @@ -56,6 +56,10 @@ void setup() { #ifdef USE_PEN_SOLENOID solenoid_init(); #endif + + #ifdef USE_MACHINE_INIT + machine_init(); // user supplied function for special initialization + #endif // Initialize system state. #ifdef FORCE_INITIALIZATION_ALARM diff --git a/Grbl_Esp32/atari_1020.cpp b/Grbl_Esp32/atari_1020.cpp new file mode 100644 index 00000000..f26741e1 --- /dev/null +++ b/Grbl_Esp32/atari_1020.cpp @@ -0,0 +1,324 @@ +/* + 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 + (at your option) any later version. + + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . + + -------------------------------------------------------------- + + This contains all the special features required to control an + Atari 1010 Pen Plotter +*/ +#include "grbl.h" + +#ifdef ATARI_1020 + +#define HOMING_PHASE_FULL_APPROACH 0 // move to right end +#define HOMING_PHASE_CHECK 1 // check reed switch +#define HOMING_PHASE_RETRACT 2 // retract +#define HOMING_PHASE_SHORT_APPROACH 3 // retract + +static TaskHandle_t solenoidSyncTaskHandle = 0; +static TaskHandle_t atariHomingTaskHandle = 0; +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_send(CLIENT_SERIAL, "[MSG:Atari 1020 Solenoid]\r\n"); + + // 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 + ); +} + +// 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); + } +} + +// 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(...) +} + +/* + 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 + + 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_sendf(CLIENT_SERIAL, "[MSG:Homing phase error %d]\r\n", homing_phase); + atari_homing = false;; // kills task + break; + } + + if (homing_attempt > ATARI_HOMING_ATTEMPTS) { // try all positions plus 1 + grbl_send(CLIENT_SERIAL, "[MSG: Atari homing failed]\r\n"); + 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); +} + + +/* + 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_sendf(CLIENT_ALL, "[MSG: Requested Pen#%d is out of 1-4 range]\r\n", 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_sendf(CLIENT_ALL, "[MSG: Change to Pen#%d]\r\n", 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); +} + +// Polar coaster has macro buttons, this handles those button pushes. +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_send(CLIENT_SERIAL, "[MSG: Pen Switch]\r\n"); + inputBuffer.push("$H\r"); + break; + #endif + + #ifdef MACRO_BUTTON_1_PIN + case CONTROL_PIN_INDEX_MACRO_1: + grbl_send(CLIENT_SERIAL, "[MSG: Color Switch]\r\n"); + 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_send(CLIENT_SERIAL, "[MSG: Paper Switch]\r\n"); + 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_sendf(CLIENT_SERIAL, "[MSG: Unknown Switch %d]\r\n", index); + break; + } +} + +void user_m30() { + char gcode_line[20]; + sprintf(gcode_line, "G90G0X%3.2f\r", ATARI_PAPER_WIDTH); // + inputBuffer.push(gcode_line); +} + +#endif + diff --git a/Grbl_Esp32/atari_1020.h b/Grbl_Esp32/atari_1020.h new file mode 100644 index 00000000..b0dcf80b --- /dev/null +++ b/Grbl_Esp32/atari_1020.h @@ -0,0 +1,63 @@ +/* + atari_1020.h + 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 + (at your option) any later version. + + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . + + This contains all the special features required to control an + Atari 1010 Pen Plotter +*/ + +#define SOLENOID_PWM_FREQ 5000 +#define SOLENOID_PWM_RES_BITS 8 + +#define SOLENOID_PULSE_LEN_PULL 255 +#define SOLENOID_PULL_DURATION 50 // in task counts...after this delay power will change to hold level see SOLENOID_TASK_FREQ +#define SOLENOID_PULSE_LEN_HOLD 40 // solenoid hold level ... typically a lower value to prevent overheating + +#define SOLENOID_TASK_FREQ 50 // this is milliseconds + +#define MAX_PEN_NUMBER 4 +#define BUMPS_PER_PEN_CHANGE 3 + + +#define ATARI_HOME_POS -10.0f // this amound to the left of the paper 0 +#define ATARI_PAPER_WIDTH 100.0f // +#define ATARI_HOMING_ATTEMPTS 13 + +// tells grbl we have some special functions to call +#define USE_MACHINE_INIT +#define USE_CUSTOM_HOMING +#define USE_TOOL_CHANGE +#define ATARI_TOOL_CHANGE_Z 5.0 +#define USE_M30 // use the user defined end of program + +#ifndef atari_h + #define atari_h + + void machine_init(); + void solenoid_disable(); + void solenoidSyncTask(void *pvParameters); + void calc_solenoid(float penZ); + bool user_defined_homing(); + void atari_home_task(void *pvParameters); + void user_tool_change(uint8_t new_tool); + void user_defined_macro(uint8_t index); + void user_m30(); + void atari_next_pen(); + +#endif \ No newline at end of file diff --git a/Grbl_Esp32/cpu_map.h b/Grbl_Esp32/cpu_map.h index 6577b6b3..730d6f6f 100644 --- a/Grbl_Esp32/cpu_map.h +++ b/Grbl_Esp32/cpu_map.h @@ -1346,6 +1346,118 @@ #define DEFAULT_B_MAX_TRAVEL 250.0 // mm NOTE: Must be a positive value. #define DEFAULT_C_MAX_TRAVEL 100.0 // This is percent in servo mode +#endif + +#ifdef CPU_MAP_ATARI_1020 + + #include "atari_1020.h" + + #define CPU_MAP_NAME "CPU_MAP_ATARI_1020" + + #define ATARI_1020 + + #define USE_UNIPOLAR + + #define X_UNIPOLAR + #define X_PIN_PHASE_0 GPIO_NUM_13 + #define X_PIN_PHASE_1 GPIO_NUM_21 + #define X_PIN_PHASE_2 GPIO_NUM_16 + #define X_PIN_PHASE_3 GPIO_NUM_22 + + #define Y_UNIPOLAR + #define Y_PIN_PHASE_0 GPIO_NUM_25 + #define Y_PIN_PHASE_1 GPIO_NUM_27 + #define Y_PIN_PHASE_2 GPIO_NUM_26 + #define Y_PIN_PHASE_3 GPIO_NUM_32 + + + #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 + #endif + #define HOMING_CYCLE_0 (1< #include @@ -89,3 +89,7 @@ #include "grbl_trinamic.h" #endif +#ifdef USE_UNIPOLAR + #include "grbl_unipolar.h" +#endif + diff --git a/Grbl_Esp32/grbl_unipolar.cpp b/Grbl_Esp32/grbl_unipolar.cpp new file mode 100644 index 00000000..aaef0761 --- /dev/null +++ b/Grbl_Esp32/grbl_unipolar.cpp @@ -0,0 +1,236 @@ +/* + unipolar.cpp + Part of Grbl_ESP32 + + copyright (c) 2019 - Bart Dring. This file was intended 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 . + + Unipolar Class + + This class allows you to control a unipolar motor. Unipolar motors have 5 wires. One + is typically tied to a voltage, while the other 4 are switched to ground in a + sequence + + To take a step simply call the step(step, direction) function. + +*/ +#include "grbl.h" + +#ifdef USE_UNIPOLAR + + // assign the I/O pins used for each coil of the motors + #ifdef X_UNIPOLAR + Unipolar X_Unipolar(X_PIN_PHASE_0, X_PIN_PHASE_1, X_PIN_PHASE_2, X_PIN_PHASE_3, true); + #endif + + #ifdef Y_UNIPOLAR + Unipolar Y_Unipolar(Y_PIN_PHASE_0, Y_PIN_PHASE_1, Y_PIN_PHASE_2, Y_PIN_PHASE_3, true); + #endif + + #ifdef Z_UNIPOLAR + Unipolar Z_Unipolar(Z_PIN_PHASE_0, Z_PIN_PHASE_1, Z_PIN_PHASE_2, Z_PIN_PHASE_3, true); + #endif + + void unipolar_init(){ + #ifdef X_UNIPOLAR + X_Unipolar.init(); + grbl_send(CLIENT_SERIAL, "[MSG:X Unipolar]\r\n"); + #endif + #ifdef Y_UNIPOLAR + Y_Unipolar.init(); + grbl_send(CLIENT_SERIAL, "[MSG:Y Unipolar]\r\n"); + #endif + #ifdef Z_UNIPOLAR + Z_Unipolar.init(); + grbl_send(CLIENT_SERIAL, "[MSG:Z Unipolar]\r\n"); + #endif + } + + void unipolar_step(uint8_t step_mask, uint8_t dir_mask) + { + #ifdef X_UNIPOLAR + X_Unipolar.step(step_mask & (1<. + + Unipolar Class + + This class allows you to control a unipolar motor. Unipolar motors have 5 wires. One + is typically tied to a voltage, while the other 4 are switched to ground in a + sequence + + To take a step simply call the step(direction) function. It will take + +*/ +#ifndef grbl_unipolar_h + #define grbl_unipolar_h + + void unipolar_init(); + void unipolar_step(uint8_t step_mask, uint8_t dir_mask); + void unipolar_disable(bool enable); + + class Unipolar{ + public: + Unipolar(uint8_t pin_phase0, uint8_t pin_phase1, uint8_t pin_phase2, uint8_t pin_phase3, bool half_step); // constructor + void set_enabled(bool enabled); + void step(bool step, bool dir_forward); + void init(); + + private: + uint8_t _current_phase = 0; + bool _enabled = false; + bool _half_step = true; // default is half step, full step + uint8_t _pin_phase0; + uint8_t _pin_phase1; + uint8_t _pin_phase2; + uint8_t _pin_phase3; + + }; +#endif \ No newline at end of file diff --git a/Grbl_Esp32/motion_control.cpp b/Grbl_Esp32/motion_control.cpp index 692d6c56..440f091a 100644 --- a/Grbl_Esp32/motion_control.cpp +++ b/Grbl_Esp32/motion_control.cpp @@ -231,6 +231,12 @@ void mc_dwell(float seconds) // executing the homing cycle. This prevents incorrect buffered plans after homing. void mc_homing_cycle(uint8_t cycle_mask) { + #ifdef USE_CUSTOM_HOMING + if (user_defined_homing()) + { + return; + } + #endif // This give kinematics a chance to do something before normal homing // if it returns true, the homing is canceled. diff --git a/Grbl_Esp32/stepper.cpp b/Grbl_Esp32/stepper.cpp index fe68ae1c..08417cd7 100644 --- a/Grbl_Esp32/stepper.cpp +++ b/Grbl_Esp32/stepper.cpp @@ -234,7 +234,11 @@ void IRAM_ATTR onStepperDriverTimer(void *para) // ISR It is time to take a ste #else set_stepper_pins_on(st.step_outbits); step_pulse_off_time = esp_timer_get_time() + (settings.pulse_microseconds); // determine when to turn off pulse - #endif + #endif + + #ifdef USE_UNIPOLAR + unipolar_step(st.step_outbits, st.dir_outbits); + #endif busy = true; // If there is no step segment, attempt to pop one from the stepper buffer @@ -435,9 +439,9 @@ void stepper_init() set_stepper_disable(true); #endif - //#ifdef USE_TMC2130 - // TMC2130_Init(); - //#endif + #ifdef USE_UNIPOLAR + unipolar_init(); + #endif #ifdef USE_TRINAMIC Trinamic_Init(); @@ -1505,6 +1509,10 @@ void set_stepper_disable(uint8_t isOn) // isOn = true // to disable isOn = !isOn; // Apply pin invert. } + #ifdef USE_UNIPOLAR + unipolar_disable(isOn); + #endif + #ifdef STEPPERS_DISABLE_PIN digitalWrite(STEPPERS_DISABLE_PIN, isOn ); #endif diff --git a/Grbl_Esp32/system.cpp b/Grbl_Esp32/system.cpp index 84d1b288..41aa4ea9 100644 --- a/Grbl_Esp32/system.cpp +++ b/Grbl_Esp32/system.cpp @@ -22,6 +22,7 @@ #include "config.h" xQueueHandle control_sw_queue; // used by control switch debouncing +bool debouncing = false; // debouncing in process void system_ini() // Renamed from system_init() due to conflict with esp32 files { @@ -46,21 +47,25 @@ void system_ini() // Renamed from system_init() due to conflict with esp32 files #endif #ifdef MACRO_BUTTON_0_PIN + grbl_send(CLIENT_SERIAL, "[MSG:Macro Pin 0]\r\n"); pinMode(MACRO_BUTTON_0_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(MACRO_BUTTON_0_PIN), isr_control_inputs, CHANGE); #endif #ifdef MACRO_BUTTON_1_PIN + grbl_send(CLIENT_SERIAL, "[MSG:Macro Pin 1]\r\n"); pinMode(MACRO_BUTTON_1_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(MACRO_BUTTON_1_PIN), isr_control_inputs, CHANGE); #endif #ifdef MACRO_BUTTON_2_PIN + grbl_send(CLIENT_SERIAL, "[MSG:Macro Pin 2]\r\n"); pinMode(MACRO_BUTTON_2_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(MACRO_BUTTON_2_PIN), isr_control_inputs, CHANGE); #endif #ifdef MACRO_BUTTON_3_PIN + grbl_send(CLIENT_SERIAL, "[MSG:Macro Pin 3]\r\n"); pinMode(MACRO_BUTTON_3_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(MACRO_BUTTON_3_PIN), isr_control_inputs, CHANGE); #endif @@ -86,22 +91,24 @@ void system_ini() // Renamed from system_init() due to conflict with esp32 files // Setup USER_DIGITAL_PINs controlled by M62 and M63 #ifdef USER_DIGITAL_PIN_1 - pinMode(USER_DIGITAL_PIN_1, OUTPUT); + pinMode(USER_DIGITAL_PIN_1, OUTPUT); + sys_io_control(1<<1, false); // turn off #endif #ifdef USER_DIGITAL_PIN_2 pinMode(USER_DIGITAL_PIN_2, OUTPUT); + sys_io_control(1<<2, false); // turn off #endif #ifdef USER_DIGITAL_PIN_3 pinMode(USER_DIGITAL_PIN_3, OUTPUT); + sys_io_control(1<<3, false); // turn off #endif #ifdef USER_DIGITAL_PIN_4 pinMode(USER_DIGITAL_PIN_4, OUTPUT); - #endif - - sys_io_control(0xFF, false); // turn them all off + sys_io_control(1<<4, false); // turn off + #endif } #ifdef ENABLE_CONTROL_SW_DEBOUNCE @@ -111,22 +118,26 @@ void controlCheckTask(void *pvParameters) while(true) { int evt; xQueueReceive(control_sw_queue, &evt, portMAX_DELAY); // block until receive queue - vTaskDelay( CONTROL_SW_DEBOUNCE_PERIOD / portTICK_PERIOD_MS ); // delay a while + vTaskDelay(CONTROL_SW_DEBOUNCE_PERIOD); // delay a while uint8_t pin = system_control_get_state(); if (pin) { system_exec_control_pin(pin); } + debouncing = false; } } #endif void IRAM_ATTR isr_control_inputs() -{ +{ #ifdef ENABLE_CONTROL_SW_DEBOUNCE // we will start a task that will recheck the switches after a small delay int evt; - xQueueSendFromISR(control_sw_queue, &evt, NULL); + if (!debouncing) { // prevent resending until debounce is done + debouncing = true; + xQueueSendFromISR(control_sw_queue, &evt, NULL); + } #else uint8_t pin = system_control_get_state(); system_exec_control_pin(pin); @@ -541,17 +552,17 @@ void system_exec_control_pin(uint8_t pin) { bit_true(sys_rt_exec_state, EXEC_SAFETY_DOOR); } #ifdef MACRO_BUTTON_0_PIN - else if (pin == 96) { + else if (bit_istrue(pin,CONTROL_PIN_INDEX_MACRO_0)) { user_defined_macro(CONTROL_PIN_INDEX_MACRO_0); // function must be implemented by user } #endif #ifdef MACRO_BUTTON_1_PIN - else if (pin == 80) { + else if (bit_istrue(pin,CONTROL_PIN_INDEX_MACRO_1)) { user_defined_macro(CONTROL_PIN_INDEX_MACRO_1); // function must be implemented by user } #endif #ifdef MACRO_BUTTON_2_PIN - else if (pin == 48) { + else if (bit_istrue(pin,CONTROL_PIN_INDEX_MACRO_2)) { user_defined_macro(CONTROL_PIN_INDEX_MACRO_2); // function must be implemented by user } #endif