1
0
mirror of https://github.com/bdring/Grbl_Esp32.git synced 2025-08-17 20:01:42 +02:00
* Oled2 (#834)

* WIP

* WIP

* Update platformio.ini

* WIP

* Cleanup

* Update platformio.ini

* Turn off soft limits with max travel (#836)

https://github.com/bdring/Grbl_Esp32/issues/831

* Yalang YL620 VFD (#838)

* New SpindleType YL620

Files for new SpindleType Yalang 620. So far the contents are a duplicate of H2ASpindle.h and H2ASpindle.cpp

* Added register documentation and implemented read and write data packets

* Some fixes, mostly regarding RX packet length

* OLED and Other Updates (#844)

* publish

* Updates - CoreXY and OLED

- Moved position calculation out of report_realtime_status(...) so other functions can access it.
- Added a function to check if a limit switch is defined
- CoreXY fixed bug in forward kinematics when midtbot is used.
- Modified OLED display.

* Cleanup for PR

* Delete midtbot_x2.h

* Incorporated PR 846

- Some OLED cleanup
- verified correct forward kinematics on MidTbot

* Pio down rev (#850)

* Update platformio.ini

* Update Grbl.h

* Use local UART driver not HardwareSerial (#857)

* Use local UART driver not HardwareSerial

The HardwareSerial driver is broken in Arduino framework versions
1.0.5 and 1.0.6 .  https://github.com/espressif/arduino-esp32/issues/5005
Instead of waiting for a fix, I wrote a very simple UART driver that
does exactly what we need with no unnecessary bells and whistles to
cause problems.

* Added missing files, changed method signatures

The methods implemented by the UART class now
have the same signatures as the HardwareSerial
class, so it will be easy to switch back if we
need to.

* Incorporated suggestions from Stefan

* Fixed TX_IDLE_NUM bug reported by mstrens

* Quick test for Bf: problem

This is not the final solution.

* Fixed stupid typo in last commit

* Another test - check for client_buffer space

* Use the esp-idf uart driver

You can revert to the direct driver for testing by
defining DIRECT_UART

* Uart class now supports VFD and TMC

* data bits, stop bits, parity as enum classes

The constants for data bits, stop bits, and parity
were changed to enum classes so the compiler can
check for argument order mismatches.

* Set half duplex after uart init

* Init TMC UART only once

* rx/tx pin order mixup, missing _uart_started

* Test: use Arduino Serial

This reverts to the Arduino serial driver for
UI communication, leaving the VFS comms on the
Uart class on top of the esp_idf UART driver.

You can switch back and forth with the
   define REVERT_TO_SERIAL
line in Serial.cpp

* REVERT_TO_ARDUINO_SERIAL off by default

* Added debug messages

* Update Grbl.h

* Update platformio.ini

Co-authored-by: bdring <barton.dring@gmail.com>

* Fixed spindle sync for all VFD spindles (#868)

* Implemented H2A spindle sync fix. Untested.

* Changed the spindle sync fix to be in the VFD code.

* Update Grbl.h

Co-authored-by: Stefan de Bruijn <stefan@nubilosoft.com>
Co-authored-by: bdring <barton.dring@gmail.com>

Co-authored-by: Mitch Bradley <wmb@firmworks.com>
Co-authored-by: marcosprojects <marco1601@web.de>
Co-authored-by: Stefan de Bruijn <atlaste@users.noreply.github.com>
Co-authored-by: Stefan de Bruijn <stefan@nubilosoft.com>
This commit is contained in:
bdring
2021-04-19 13:46:29 -05:00
committed by GitHub
parent 6c8c613790
commit 48e204e443
23 changed files with 437 additions and 282 deletions

View File

@@ -30,7 +30,7 @@ void grbl_init() {
WiFi.enableSTA(false); WiFi.enableSTA(false);
WiFi.enableAP(false); WiFi.enableAP(false);
WiFi.mode(WIFI_OFF); WiFi.mode(WIFI_OFF);
serial_init(); // Setup serial baud rate and interrupts client_init(); // Setup serial baud rate and interrupts
display_init(); display_init();
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Grbl_ESP32 Ver %s Date %s", GRBL_VERSION, GRBL_VERSION_BUILD); // print grbl_esp32 verion info grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Grbl_ESP32 Ver %s Date %s", GRBL_VERSION, GRBL_VERSION_BUILD); // print grbl_esp32 verion info
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Compiled with ESP32 SDK:%s", ESP.getSdkVersion()); // print the SDK version grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Compiled with ESP32 SDK:%s", ESP.getSdkVersion()); // print the SDK version
@@ -93,7 +93,7 @@ static void reset_variables() {
sys_rt_s_override = SpindleSpeedOverride::Default; sys_rt_s_override = SpindleSpeedOverride::Default;
// Reset Grbl primary systems. // Reset Grbl primary systems.
serial_reset_read_buffer(CLIENT_ALL); // Clear serial read buffer client_reset_read_buffer(CLIENT_ALL);
gc_init(); // Set g-code parser to default state gc_init(); // Set g-code parser to default state
spindle->stop(); spindle->stop();
coolant_init(); coolant_init();

View File

@@ -22,7 +22,7 @@
// Grbl versioning system // Grbl versioning system
const char* const GRBL_VERSION = "1.3a"; const char* const GRBL_VERSION = "1.3a";
const char* const GRBL_VERSION_BUILD = "20210401"; const char* const GRBL_VERSION_BUILD = "20210419";
//#include <sdkconfig.h> //#include <sdkconfig.h>
#include <Arduino.h> #include <Arduino.h>
@@ -51,8 +51,9 @@ const char* const GRBL_VERSION_BUILD = "20210401";
#include "Limits.h" #include "Limits.h"
#include "MotionControl.h" #include "MotionControl.h"
#include "Protocol.h" #include "Protocol.h"
#include "Report.h" #include "Uart.h"
#include "Serial.h" #include "Serial.h"
#include "Report.h"
#include "Pins.h" #include "Pins.h"
#include "Spindles/Spindle.h" #include "Spindles/Spindle.h"
#include "Motors/Motors.h" #include "Motors/Motors.h"

View File

@@ -48,6 +48,7 @@
#include "WebUI/ESPResponse.h" #include "WebUI/ESPResponse.h"
#include "Probe.h" #include "Probe.h"
#include "System.h" #include "System.h"
#include "Serial.h"
#include "Report.h" #include "Report.h"
#include <FreeRTOS.h> #include <FreeRTOS.h>

View File

@@ -55,10 +55,12 @@ void IRAM_ATTR isr_limit_switches() {
# ifdef HARD_LIMIT_FORCE_STATE_CHECK # ifdef HARD_LIMIT_FORCE_STATE_CHECK
// Check limit pin state. // Check limit pin state.
if (limits_get_state()) { if (limits_get_state()) {
grbl_msg_sendf(CLIENT_ALL, MsgLevel::Debug, "Hard limits");
mc_reset(); // Initiate system kill. mc_reset(); // Initiate system kill.
sys_rt_exec_alarm = ExecAlarm::HardLimit; // Indicate hard limit critical event sys_rt_exec_alarm = ExecAlarm::HardLimit; // Indicate hard limit critical event
} }
# else # else
grbl_msg_sendf(CLIENT_ALL, MsgLevel::Debug, "Hard limits");
mc_reset(); // Initiate system kill. mc_reset(); // Initiate system kill.
sys_rt_exec_alarm = ExecAlarm::HardLimit; // Indicate hard limit critical event sys_rt_exec_alarm = ExecAlarm::HardLimit; // Indicate hard limit critical event
# endif # endif
@@ -195,6 +197,7 @@ void limits_go_home(uint8_t cycle_mask) {
if (sys_rt_exec_alarm != ExecAlarm::None) { if (sys_rt_exec_alarm != ExecAlarm::None) {
motors_set_homing_mode(cycle_mask, false); // tell motors homing is done...failed motors_set_homing_mode(cycle_mask, false); // tell motors homing is done...failed
grbl_msg_sendf(CLIENT_ALL, MsgLevel::Debug, "Homing fail");
mc_reset(); // Stop motors, if they are running. mc_reset(); // Stop motors, if they are running.
protocol_execute_realtime(); protocol_execute_realtime();
return; return;
@@ -351,6 +354,7 @@ void limits_soft_check(float* target) {
} }
} while (sys.state != State::Idle); } while (sys.state != State::Idle);
} }
grbl_msg_sendf(CLIENT_ALL, MsgLevel::Debug, "Soft limits");
mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown. mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
sys_rt_exec_alarm = ExecAlarm::SoftLimit; // Indicate soft limit critical event sys_rt_exec_alarm = ExecAlarm::SoftLimit; // Indicate soft limit critical event
protocol_execute_realtime(); // Execute to enter critical event loop and system abort protocol_execute_realtime(); // Execute to enter critical event loop and system abort
@@ -367,7 +371,7 @@ void limitCheckTask(void* pvParameters) {
AxisMask switch_state; AxisMask switch_state;
switch_state = limits_get_state(); switch_state = limits_get_state();
if (switch_state) { if (switch_state) {
//grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Limit Switch State %08d", switch_state); grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Debug, "Limit Switch State %08d", switch_state);
mc_reset(); // Initiate system kill. mc_reset(); // Initiate system kill.
sys_rt_exec_alarm = ExecAlarm::HardLimit; // Indicate hard limit critical event sys_rt_exec_alarm = ExecAlarm::HardLimit; // Indicate hard limit critical event
} }

View File

@@ -499,6 +499,7 @@ void mc_override_ctrl_update(uint8_t override_state) {
// lost, since there was an abrupt uncontrolled deceleration. Called at an interrupt level by // lost, since there was an abrupt uncontrolled deceleration. Called at an interrupt level by
// realtime abort command and hard limits. So, keep to a minimum. // realtime abort command and hard limits. So, keep to a minimum.
void mc_reset() { void mc_reset() {
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Debug, "mc_reset()");
// Only this function can set the system reset. Helps prevent multiple kill calls. // Only this function can set the system reset. Helps prevent multiple kill calls.
if (!sys_rt_exec_state.bit.reset) { if (!sys_rt_exec_state.bit.reset) {
sys_rt_exec_state.bit.reset = true; sys_rt_exec_state.bit.reset = true;

View File

@@ -21,6 +21,7 @@
#include "Motor.h" #include "Motor.h"
#include "StandardStepper.h" #include "StandardStepper.h"
#include "../Uart.h"
#include <TMCStepper.h> // https://github.com/teemuatlut/TMCStepper #include <TMCStepper.h> // https://github.com/teemuatlut/TMCStepper
@@ -63,7 +64,7 @@ const double TRINAMIC_UART_FCLK = 12700000.0; // Internal clock Approx (Hz) use
# define TMC_UART_TX UNDEFINED_PIN # define TMC_UART_TX UNDEFINED_PIN
#endif #endif
extern HardwareSerial tmc_serial; extern Uart tmc_serial;
namespace Motors { namespace Motors {
@@ -75,6 +76,9 @@ namespace Motors {
}; };
class TrinamicUartDriver : public StandardStepper { class TrinamicUartDriver : public StandardStepper {
private:
static bool _uart_started;
public: public:
TrinamicUartDriver(uint8_t axis_index, TrinamicUartDriver(uint8_t axis_index,
uint8_t step_pin, uint8_t step_pin,

View File

@@ -26,10 +26,12 @@
#include <TMCStepper.h> #include <TMCStepper.h>
HardwareSerial tmc_serial(TMC_UART); Uart tmc_serial(TMC_UART);
namespace Motors { namespace Motors {
bool TrinamicUartDriver::_uart_started = false;
TrinamicUartDriver* TrinamicUartDriver::List = NULL; // a static ist of all drivers for stallguard reporting TrinamicUartDriver* TrinamicUartDriver::List = NULL; // a static ist of all drivers for stallguard reporting
/* HW Serial Constructor. */ /* HW Serial Constructor. */
@@ -41,9 +43,11 @@ namespace Motors {
_r_sense = r_sense; _r_sense = r_sense;
this->addr = addr; this->addr = addr;
uart_set_pin(TMC_UART, TMC_UART_TX, TMC_UART_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); if (!_uart_started) {
tmc_serial.begin(115200, SERIAL_8N1, TMC_UART_RX, TMC_UART_TX); tmc_serial.setPins(TMC_UART_TX, TMC_UART_RX);
tmc_serial.setRxBufferSize(128); tmc_serial.begin(115200, Uart::Data::Bits8, Uart::Stop::Bits1, Uart::Parity::None);
_uart_started = true;
}
hw_serial_init(); hw_serial_init();
link = List; link = List;
@@ -231,7 +235,7 @@ namespace Motors {
tmcstepper->en_spreadCycle(false); tmcstepper->en_spreadCycle(false);
tmcstepper->pwm_autoscale(false); tmcstepper->pwm_autoscale(false);
tmcstepper->TCOOLTHRS(calc_tstep(homing_feed_rate->get(), 150.0)); tmcstepper->TCOOLTHRS(calc_tstep(homing_feed_rate->get(), 150.0));
tmcstepper->SGTHRS(constrain(axis_settings[_axis_index]->stallguard->get(),0,255)); tmcstepper->SGTHRS(constrain(axis_settings[_axis_index]->stallguard->get(), 0, 255));
break; break;
default: default:
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Unknown Trinamic mode:d", _mode); grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Unknown Trinamic mode:d", _mode);

View File

@@ -192,6 +192,7 @@ Error toggle_check_mode(const char* value, WebUI::AuthenticationLevel auth_level
// is idle and ready, regardless of alarm locks. This is mainly to keep things // is idle and ready, regardless of alarm locks. This is mainly to keep things
// simple and consistent. // simple and consistent.
if (sys.state == State::CheckMode) { if (sys.state == State::CheckMode) {
grbl_msg_sendf(CLIENT_ALL, MsgLevel::Debug, "Check mode");
mc_reset(); mc_reset();
report_feedback_message(Message::Disabled); report_feedback_message(Message::Disabled);
} else { } else {

View File

@@ -103,7 +103,7 @@ bool can_park() {
GRBL PRIMARY LOOP: GRBL PRIMARY LOOP:
*/ */
void protocol_main_loop() { void protocol_main_loop() {
serial_reset_read_buffer(CLIENT_ALL); client_reset_read_buffer(CLIENT_ALL);
empty_lines(); empty_lines();
//uint8_t client = CLIENT_SERIAL; // default client //uint8_t client = CLIENT_SERIAL; // default client
// Perform some machine checks to make sure everything is good to go. // Perform some machine checks to make sure everything is good to go.
@@ -135,7 +135,7 @@ void protocol_main_loop() {
// Primary loop! Upon a system abort, this exits back to main() to reset the system. // Primary loop! Upon a system abort, this exits back to main() to reset the system.
// This is also where Grbl idles while waiting for something to do. // This is also where Grbl idles while waiting for something to do.
// --------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------
uint8_t c; int c;
for (;;) { for (;;) {
#ifdef ENABLE_SD_CARD #ifdef ENABLE_SD_CARD
if (SD_ready_next) { if (SD_ready_next) {
@@ -157,7 +157,7 @@ void protocol_main_loop() {
uint8_t client = CLIENT_SERIAL; uint8_t client = CLIENT_SERIAL;
char* line; char* line;
for (client = 0; client < CLIENT_COUNT; client++) { for (client = 0; client < CLIENT_COUNT; client++) {
while ((c = serial_read(client)) != SERIAL_NO_DATA) { while ((c = client_read(client)) != -1) {
Error res = add_char_to_line(c, client); Error res = add_char_to_line(c, client);
switch (res) { switch (res) {
case Error::Ok: case Error::Ok:

View File

@@ -54,30 +54,8 @@ EspClass esp;
#endif #endif
const int DEFAULTBUFFERSIZE = 64; const int DEFAULTBUFFERSIZE = 64;
// 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) { void grbl_send(uint8_t client, const char* text) {
if (client == CLIENT_INPUT) { client_write(client, text);
return;
}
#ifdef ENABLE_BLUETOOTH
if (WebUI::SerialBT.hasClient() && (client == CLIENT_BT || client == CLIENT_ALL)) {
WebUI::SerialBT.print(text);
//delay(10); // possible fix for dropped characters
}
#endif
#if defined(ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_OUT)
if (client == CLIENT_WEBUI || client == CLIENT_ALL) {
WebUI::Serial2Socket.write((const uint8_t*)text, strlen(text));
}
#endif
#if defined(ENABLE_WIFI) && defined(ENABLE_TELNET)
if (client == CLIENT_TELNET || client == CLIENT_ALL) {
WebUI::telnet_server.write((const uint8_t*)text, strlen(text));
}
#endif
if (client == CLIENT_SERIAL || client == CLIENT_ALL) {
Serial.print(text);
}
} }
// This is a formating version of the grbl_send(CLIENT_ALL,...) function that work like printf // This is a formating version of the grbl_send(CLIENT_ALL,...) function that work like printf
@@ -658,7 +636,7 @@ void report_realtime_status(uint8_t client) {
} }
# endif //ENABLE_BLUETOOTH # endif //ENABLE_BLUETOOTH
if (client == CLIENT_SERIAL) { if (client == CLIENT_SERIAL) {
bufsize = serial_get_rx_buffer_available(CLIENT_SERIAL); bufsize = client_get_rx_buffer_available(CLIENT_SERIAL);
} }
sprintf(temp, "|Bf:%d,%d", plan_get_block_buffer_available(), bufsize); sprintf(temp, "|Bf:%d,%d", plan_get_block_buffer_available(), bufsize);
strcat(status, temp); strcat(status, temp);

View File

@@ -57,15 +57,26 @@
#include "Grbl.h" #include "Grbl.h"
// Define this to use the Arduino serial (UART) driver instead
// of the one in Uart.cpp, which uses the ESP-IDF UART driver.
// This is for regression testing, and can be removed after
// testing is complete.
// #define REVERT_TO_ARDUINO_SERIAL
portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED; portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED;
static TaskHandle_t serialCheckTaskHandle = 0; static TaskHandle_t clientCheckTaskHandle = 0;
WebUI::InputBuffer client_buffer[CLIENT_COUNT]; // create a buffer for each client WebUI::InputBuffer client_buffer[CLIENT_COUNT]; // create a buffer for each client
// Returns the number of bytes available in a client buffer. // Returns the number of bytes available in a client buffer.
uint8_t serial_get_rx_buffer_available(uint8_t client) { uint8_t client_get_rx_buffer_available(uint8_t client) {
return client_buffer[client].availableforwrite(); #ifdef REVERT_TO_ARDUINO_SERIAL
return 128 - Serial.available();
#else
return 128 - Uart0.available();
#endif
// return client_buffer[client].availableforwrite();
} }
void heapCheckTask(void* pvParameters) { void heapCheckTask(void* pvParameters) {
@@ -85,75 +96,84 @@ void heapCheckTask(void* pvParameters) {
} }
} }
void serial_init() { void client_init() {
#ifdef DEBUG_REPORT_HEAP_SIZE #ifdef DEBUG_REPORT_HEAP_SIZE
// For a 2000-word stack, uxTaskGetStackHighWaterMark reports 288 words available // For a 2000-word stack, uxTaskGetStackHighWaterMark reports 288 words available
xTaskCreatePinnedToCore(heapCheckTask, "heapTask", 2000, NULL, 1, NULL, 1); xTaskCreatePinnedToCore(heapCheckTask, "heapTask", 2000, NULL, 1, NULL, 1);
#endif #endif
Serial.begin(BAUD_RATE); #ifdef REVERT_TO_ARDUINO_SERIAL
Serial.setRxBufferSize(256); Serial.begin(BAUD_RATE, SERIAL_8N1, 3, 1, false);
// reset all buffers client_reset_read_buffer(CLIENT_ALL);
serial_reset_read_buffer(CLIENT_ALL); Serial.write("\r\n"); // create some white space after ESP32 boot info
grbl_send(CLIENT_SERIAL, "\r\n"); // create some white space after ESP32 boot info #else
serialCheckTaskHandle = 0; Uart0.setPins(1, 3); // Tx 1, Rx 3 - standard hardware pins
Uart0.begin(BAUD_RATE, Uart::Data::Bits8, Uart::Stop::Bits1, Uart::Parity::None);
client_reset_read_buffer(CLIENT_ALL);
Uart0.write("\r\n"); // create some white space after ESP32 boot info
#endif
clientCheckTaskHandle = 0;
// create a task to check for incoming data // create a task to check for incoming data
// For a 4096-word stack, uxTaskGetStackHighWaterMark reports 244 words available // For a 4096-word stack, uxTaskGetStackHighWaterMark reports 244 words available
// after WebUI attaches. // after WebUI attaches.
xTaskCreatePinnedToCore(serialCheckTask, // task xTaskCreatePinnedToCore(clientCheckTask, // task
"serialCheckTask", // name for task "clientCheckTask", // name for task
4096, // size of task stack 4096, // size of task stack
NULL, // parameters NULL, // parameters
1, // priority 1, // priority
&serialCheckTaskHandle, &clientCheckTaskHandle,
SUPPORT_TASK_CORE // must run the task on same core SUPPORT_TASK_CORE // must run the task on same core
// core // core
); );
} }
// this task runs and checks for data on all interfaces static uint8_t getClientChar(uint8_t* data) {
// REaltime stuff is acted upon, then characters are added to the appropriate buffer int res;
void serialCheckTask(void* pvParameters) { #ifdef REVERT_TO_ARDUINO_SERIAL
uint8_t data = 0; if (client_buffer[CLIENT_SERIAL].availableforwrite() && (res = Serial.read()) != -1) {
uint8_t client = CLIENT_ALL; // who sent the data #else
static UBaseType_t uxHighWaterMark = 0; if (client_buffer[CLIENT_SERIAL].availableforwrite() && (res = Uart0.read()) != -1) {
while (true) { // run continuously #endif
while (any_client_has_data()) { *data = res;
if (Serial.available()) { return CLIENT_SERIAL;
client = CLIENT_SERIAL; }
data = Serial.read(); if (WebUI::inputBuffer.available()) {
} else if (WebUI::inputBuffer.available()) { *data = WebUI::inputBuffer.read();
client = CLIENT_INPUT; return CLIENT_INPUT;
data = WebUI::inputBuffer.read(); }
} else {
//currently is wifi or BT but better to prepare both can be live //currently is wifi or BT but better to prepare both can be live
#ifdef ENABLE_BLUETOOTH #ifdef ENABLE_BLUETOOTH
if (WebUI::SerialBT.hasClient() && WebUI::SerialBT.available()) { if (WebUI::SerialBT.hasClient()) {
client = CLIENT_BT; if ((res = WebUI::SerialBT.read()) != -1) {
data = WebUI::SerialBT.read(); *data = res;
return CLIENT_BT;
// Serial.write(data); // echo all data to serial. }
} else { }
#endif #endif
#if defined(ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN) #if defined(ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN)
if (WebUI::Serial2Socket.available()) { if (WebUI::Serial2Socket.available()) {
client = CLIENT_WEBUI; *data = WebUI::Serial2Socket.read();
data = WebUI::Serial2Socket.read(); return CLIENT_WEBUI;
} else { }
#endif #endif
#if defined(ENABLE_WIFI) && defined(ENABLE_TELNET) #if defined(ENABLE_WIFI) && defined(ENABLE_TELNET)
if (WebUI::telnet_server.available()) { if (WebUI::telnet_server.available()) {
client = CLIENT_TELNET; *data = WebUI::telnet_server.read();
data = WebUI::telnet_server.read(); return CLIENT_TELNET;
} }
#endif #endif
#if defined(ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN) return CLIENT_ALL;
} }
#endif
#ifdef ENABLE_BLUETOOTH // this task runs and checks for data on all interfaces
} // REaltime stuff is acted upon, then characters are added to the appropriate buffer
#endif void clientCheckTask(void* pvParameters) {
} uint8_t data = 0;
uint8_t client; // who sent the data
static UBaseType_t uxHighWaterMark = 0;
while (true) { // run continuously
while ((client = getClientChar(&data)) != CLIENT_ALL) {
// Pick off realtime command characters directly from the serial stream. These characters are // Pick off realtime command characters directly from the serial stream. These characters are
// not passed into the main buffer, but these set system state flag bits for realtime execution. // not passed into the main buffer, but these set system state flag bits for realtime execution.
if (is_realtime_command(data)) { if (is_realtime_command(data)) {
@@ -194,7 +214,7 @@ void serialCheckTask(void* pvParameters) {
} }
} }
void serial_reset_read_buffer(uint8_t client) { void client_reset_read_buffer(uint8_t client) {
for (uint8_t client_num = 0; client_num < CLIENT_COUNT; client_num++) { for (uint8_t client_num = 0; client_num < CLIENT_COUNT; client_num++) {
if (client == client_num || client == CLIENT_ALL) { if (client == client_num || client == CLIENT_ALL) {
client_buffer[client_num].begin(); client_buffer[client_num].begin();
@@ -202,38 +222,12 @@ void serial_reset_read_buffer(uint8_t client) {
} }
} }
// Writes one byte to the TX serial buffer. Called by main program. // Fetches the first byte in the client read buffer. Called by protocol loop.
void serial_write(uint8_t data) { int client_read(uint8_t client) {
Serial.write((char)data);
}
// Fetches the first byte in the serial read buffer. Called by protocol loop.
uint8_t serial_read(uint8_t client) {
uint8_t data;
vTaskEnterCritical(&myMutex); vTaskEnterCritical(&myMutex);
if (client_buffer[client].available()) { int data = client_buffer[client].read();
data = client_buffer[client].read();
vTaskExitCritical(&myMutex); vTaskExitCritical(&myMutex);
//Serial.write((char)data);
return data; return data;
} else {
vTaskExitCritical(&myMutex);
return SERIAL_NO_DATA;
}
}
bool any_client_has_data() {
return (Serial.available() || WebUI::inputBuffer.available()
#ifdef ENABLE_BLUETOOTH
|| (WebUI::SerialBT.hasClient() && WebUI::SerialBT.available())
#endif
#if defined(ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN)
|| WebUI::Serial2Socket.available()
#endif
#if defined(ENABLE_WIFI) && defined(ENABLE_TELNET)
|| WebUI::telnet_server.available()
#endif
);
} }
// checks to see if a character is a realtime character // checks to see if a character is a realtime character
@@ -249,6 +243,7 @@ bool is_realtime_command(uint8_t data) {
void execute_realtime_command(Cmd command, uint8_t client) { void execute_realtime_command(Cmd command, uint8_t client) {
switch (command) { switch (command) {
case Cmd::Reset: case Cmd::Reset:
grbl_msg_sendf(CLIENT_ALL, MsgLevel::Debug, "Cmd::Reset");
mc_reset(); // Call motion control reset routine. mc_reset(); // Call motion control reset routine.
break; break;
case Cmd::StatusReport: case Cmd::StatusReport:
@@ -350,3 +345,32 @@ void execute_realtime_command(Cmd command, uint8_t client) {
break; break;
} }
} }
void client_write(uint8_t client, const char* text) {
if (client == CLIENT_INPUT) {
return;
}
#ifdef ENABLE_BLUETOOTH
if (WebUI::SerialBT.hasClient() && (client == CLIENT_BT || client == CLIENT_ALL)) {
WebUI::SerialBT.print(text);
//delay(10); // possible fix for dropped characters
}
#endif
#if defined(ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_OUT)
if (client == CLIENT_WEBUI || client == CLIENT_ALL) {
WebUI::Serial2Socket.write((const uint8_t*)text, strlen(text));
}
#endif
#if defined(ENABLE_WIFI) && defined(ENABLE_TELNET)
if (client == CLIENT_TELNET || client == CLIENT_ALL) {
WebUI::telnet_server.write((const uint8_t*)text, strlen(text));
}
#endif
if (client == CLIENT_SERIAL || client == CLIENT_ALL) {
#ifdef REVERT_TO_ARDUINO_SERIAL
Serial.write(text);
#else
Uart0.write(text);
#endif
}
}

View File

@@ -20,7 +20,7 @@
along with Grbl. If not, see <http://www.gnu.org/licenses/>. along with Grbl. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "Grbl.h" #include "stdint.h"
#ifndef RX_BUFFER_SIZE #ifndef RX_BUFFER_SIZE
# define RX_BUFFER_SIZE 256 # define RX_BUFFER_SIZE 256
@@ -33,24 +33,22 @@
# endif # endif
#endif #endif
const float SERIAL_NO_DATA = 0xff;
// a task to read for incoming data from serial port // a task to read for incoming data from serial port
void serialCheckTask(void* pvParameters); void clientCheckTask(void* pvParameters);
void client_write(uint8_t client, const char* text);
void serial_write(uint8_t data);
// Fetches the first byte in the serial read buffer. Called by main program. // Fetches the first byte in the serial read buffer. Called by main program.
uint8_t serial_read(uint8_t client); int client_read(uint8_t client);
// See if the character is an action command like feedhold or jogging. If so, do the action and return true // See if the character is an action command like feedhold or jogging. If so, do the action and return true
uint8_t check_action_command(uint8_t data); uint8_t check_action_command(uint8_t data);
void serial_init(); void client_init();
void serial_reset_read_buffer(uint8_t client); void client_reset_read_buffer(uint8_t client);
// Returns the number of bytes available in the RX serial buffer. // Returns the number of bytes available in the RX serial buffer.
uint8_t serial_get_rx_buffer_available(uint8_t client); uint8_t client_get_rx_buffer_available(uint8_t client);
void execute_realtime_command(Cmd command, uint8_t client); void execute_realtime_command(Cmd command, uint8_t client);
bool any_client_has_data();
bool is_realtime_command(uint8_t data); bool is_realtime_command(uint8_t data);

View File

@@ -28,17 +28,10 @@
managed to piece together. managed to piece together.
*/ */
#include <driver/uart.h>
namespace Spindles { namespace Spindles {
void H2A::default_modbus_settings(uart_config_t& uart) { H2A::H2A() : VFD() {
// sets the uart to 19200 8E1 _baudrate = 19200;
VFD::default_modbus_settings(uart); _parity = Uart::Parity::Even;
uart.baud_rate = 19200;
uart.data_bits = UART_DATA_8_BITS;
uart.parity = UART_PARITY_EVEN;
uart.stop_bits = UART_STOP_BITS_1;
} }
void H2A::direction_command(SpindleState mode, ModbusCommand& data) { void H2A::direction_command(SpindleState mode, ModbusCommand& data) {

View File

@@ -24,8 +24,6 @@
namespace Spindles { namespace Spindles {
class H2A : public VFD { class H2A : public VFD {
protected: protected:
void default_modbus_settings(uart_config_t& uart) override;
void direction_command(SpindleState mode, ModbusCommand& data) override; void direction_command(SpindleState mode, ModbusCommand& data) override;
void set_speed_command(uint32_t rpm, ModbusCommand& data) override; void set_speed_command(uint32_t rpm, ModbusCommand& data) override;
@@ -36,5 +34,8 @@ namespace Spindles {
bool supports_actual_rpm() const override { return true; } bool supports_actual_rpm() const override { return true; }
bool safety_polling() const override { return false; } bool safety_polling() const override { return false; }
public:
H2A();
}; };
} }

View File

@@ -149,15 +149,10 @@
If the frequency is -say- 25 Hz, Huanyang wants us to send 2500 (eg. 25.00 Hz). If the frequency is -say- 25 Hz, Huanyang wants us to send 2500 (eg. 25.00 Hz).
*/ */
#include <driver/uart.h>
namespace Spindles { namespace Spindles {
void Huanyang::default_modbus_settings(uart_config_t& uart) { Huanyang::Huanyang() : VFD() {
// sets the uart to 9600 8N1 // Baud rate is set in the PD164 setting. If it is not 9600, add, for example,
VFD::default_modbus_settings(uart); // _baudrate = 19200;
// uart.baud_rate = 9600;
// Baud rate is set in the PD164 setting.
} }
void Huanyang::direction_command(SpindleState mode, ModbusCommand& data) { void Huanyang::direction_command(SpindleState mode, ModbusCommand& data) {

View File

@@ -35,8 +35,6 @@ namespace Spindles {
void updateRPM(); void updateRPM();
void default_modbus_settings(uart_config_t& uart) override;
void direction_command(SpindleState mode, ModbusCommand& data) override; void direction_command(SpindleState mode, ModbusCommand& data) override;
void set_speed_command(uint32_t rpm, ModbusCommand& data) override; void set_speed_command(uint32_t rpm, ModbusCommand& data) override;
@@ -45,5 +43,8 @@ namespace Spindles {
response_parser get_current_rpm(ModbusCommand& data) override; response_parser get_current_rpm(ModbusCommand& data) override;
bool supports_actual_rpm() const override { return true; } bool supports_actual_rpm() const override { return true; }
public:
Huanyang();
}; };
} }

View File

@@ -42,11 +42,12 @@
// be plenty: assuming 9600 8N1, that's roughly 250 chars. A message of 2x16 chars with 4x4 // be plenty: assuming 9600 8N1, that's roughly 250 chars. A message of 2x16 chars with 4x4
// chars buffering is just 40 chars. // chars buffering is just 40 chars.
const uart_port_t VFD_RS485_UART_PORT = UART_NUM_2; // hard coded for this port right now const int VFD_RS485_UART_PORT = 2; // hard coded for this port right now
const int VFD_RS485_BUF_SIZE = 127; const int VFD_RS485_BUF_SIZE = 127;
const int VFD_RS485_QUEUE_SIZE = 10; // numv\ber of commands that can be queued up. const int VFD_RS485_QUEUE_SIZE = 10; // numv\ber of commands that can be queued up.
const int RESPONSE_WAIT_MILLIS = 1000; // how long to wait for a response in milliseconds const int RESPONSE_WAIT_MILLIS = 1000; // how long to wait for a response in milliseconds
const int VFD_RS485_POLL_RATE = 250; // in milliseconds between commands const int VFD_RS485_POLL_RATE = 250; // in milliseconds between commands
const TickType_t response_ticks = RESPONSE_WAIT_MILLIS / portTICK_PERIOD_MS; // in milliseconds between commands
// OK to change these // OK to change these
// #define them in your machine definition file if you want different values // #define them in your machine definition file if you want different values
@@ -55,9 +56,48 @@ const int VFD_RS485_POLL_RATE = 250; // in milliseconds between comma
#endif #endif
namespace Spindles { namespace Spindles {
Uart _uart(VFD_RS485_UART_PORT);
QueueHandle_t VFD::vfd_cmd_queue = nullptr; QueueHandle_t VFD::vfd_cmd_queue = nullptr;
TaskHandle_t VFD::vfd_cmdTaskHandle = nullptr; TaskHandle_t VFD::vfd_cmdTaskHandle = nullptr;
VFD::VFD() :
_txd_pin(
#ifdef VFD_RS485_TXD_PIN
VFD_RS485_TXD_PIN
#else
-1
#endif
),
_rxd_pin(
#ifdef VFD_RS485_RXD_PIN
VFD_RS485_RXD_PIN
#else
-1
#endif
),
_rts_pin(
#ifdef VFD_RS485_RTS_PIN
VFD_RS485_RTS_PIN
#else
-1
#endif
),
_baudrate(
#ifdef VFD_RS485_BAUD_RATE
VFD_RS485_BAUD_RATE
#else
9600
#endif
),
_dataBits(Uart::Data::Bits8), _stopBits(Uart::Stop::Bits1), _parity(
#ifdef VFD_RS485_PARITY
VFD_RS485_PARITY
#else
Uart::Parity::None
#endif
) {
}
// The communications task // The communications task
void VFD::vfd_cmd_task(void* pvParameters) { void VFD::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
@@ -145,16 +185,15 @@ namespace Spindles {
int retry_count = 0; int retry_count = 0;
for (; retry_count < MAX_RETRIES; ++retry_count) { for (; retry_count < MAX_RETRIES; ++retry_count) {
// Flush the UART: // Flush the UART:
uart_flush(VFD_RS485_UART_PORT); _uart.flush();
// Write the data: // Write the data:
uart_write_bytes(VFD_RS485_UART_PORT, reinterpret_cast<const char*>(next_cmd.msg), next_cmd.tx_length); _uart.write(reinterpret_cast<const char*>(next_cmd.msg), next_cmd.tx_length);
uart_wait_tx_done(VFD_RS485_UART_PORT, RESPONSE_WAIT_MILLIS / portTICK_PERIOD_MS); _uart.flushTxTimed(response_ticks);
// Read the response // Read the response
uint16_t read_length = 0; uint16_t read_length = 0;
uint16_t current_read = uint16_t current_read = _uart.readBytes(rx_message, next_cmd.rx_length, response_ticks);
uart_read_bytes(VFD_RS485_UART_PORT, rx_message, next_cmd.rx_length, RESPONSE_WAIT_MILLIS / portTICK_PERIOD_MS);
read_length += current_read; read_length += current_read;
// Apparently some Huanyang report modbus errors in the correct way, and the rest not. Sigh. // Apparently some Huanyang report modbus errors in the correct way, and the rest not. Sigh.
@@ -165,10 +204,7 @@ namespace Spindles {
while (read_length < next_cmd.rx_length && current_read > 0) { while (read_length < next_cmd.rx_length && current_read > 0) {
// Try to read more; we're not there yet... // Try to read more; we're not there yet...
current_read = uart_read_bytes(VFD_RS485_UART_PORT, current_read = _uart.readBytes(rx_message + read_length, next_cmd.rx_length - read_length, response_ticks);
rx_message + read_length,
next_cmd.rx_length - read_length,
RESPONSE_WAIT_MILLIS / portTICK_PERIOD_MS);
read_length += current_read; read_length += current_read;
} }
if (current_read < 0) { if (current_read < 0) {
@@ -257,13 +293,6 @@ namespace Spindles {
} }
// ================== Class methods ================================== // ================== Class methods ==================================
void VFD::default_modbus_settings(uart_config_t& uart) {
// Default is 9600 8N1, which is sane for most VFD's:
uart.baud_rate = 9600;
uart.data_bits = UART_DATA_8_BITS;
uart.parity = UART_PARITY_DISABLE;
uart.stop_bits = UART_STOP_BITS_1;
}
void VFD::init() { void VFD::init() {
vfd_ok = false; // initialize vfd_ok = false; // initialize
@@ -281,38 +310,16 @@ namespace Spindles {
// this allows us to init() again later. // this allows us to init() again later.
// If you change certain settings, init() gets called agian // If you change certain settings, init() gets called agian
uart_driver_delete(VFD_RS485_UART_PORT); // uart_driver_delete(VFD_RS485_UART_PORT);
uart_config_t uart_config; if (_uart.setPins(_txd_pin, _rxd_pin, _rts_pin)) {
default_modbus_settings(uart_config);
// Overwrite with user defined defines:
#ifdef VFD_RS485_BAUD_RATE
uart_config.baud_rate = VFD_RS485_BAUD_RATE;
#endif
#ifdef VFD_RS485_PARITY
uart_config.parity = VFD_RS485_PARITY;
#endif
uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
uart_config.rx_flow_ctrl_thresh = 122;
if (uart_param_config(VFD_RS485_UART_PORT, &uart_config) != ESP_OK) {
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "RS485 VFD uart parameters failed");
return;
}
if (uart_set_pin(VFD_RS485_UART_PORT, _txd_pin, _rxd_pin, _rts_pin, UART_PIN_NO_CHANGE) != ESP_OK) {
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "RS485 VFD uart pin config failed"); grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "RS485 VFD uart pin config failed");
return; return;
} }
if (uart_driver_install(VFD_RS485_UART_PORT, VFD_RS485_BUF_SIZE * 2, 0, 0, NULL, 0) != ESP_OK) { _uart.begin(_baudrate, _dataBits, _stopBits, _parity);
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "RS485 VFD uart driver install failed");
return;
}
if (uart_set_mode(VFD_RS485_UART_PORT, UART_MODE_RS485_HALF_DUPLEX) != ESP_OK) { if (_uart.setHalfDuplex()) {
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "RS485 VFD uart set half duplex failed"); grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "RS485 VFD uart set half duplex failed");
return; return;
} }
@@ -349,26 +356,20 @@ namespace Spindles {
bool VFD::get_pins_and_settings() { bool VFD::get_pins_and_settings() {
bool pins_settings_ok = true; bool pins_settings_ok = true;
#ifdef VFD_RS485_TXD_PIN if (_txd_pin == -1) {
_txd_pin = VFD_RS485_TXD_PIN;
#else
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Undefined VFD_RS485_TXD_PIN"); grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Undefined VFD_RS485_TXD_PIN");
pins_settings_ok = false; pins_settings_ok = false;
#endif }
#ifdef VFD_RS485_RXD_PIN if (_rxd_pin == -1) {
_rxd_pin = VFD_RS485_RXD_PIN;
#else
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Undefined VFD_RS485_RXD_PIN"); grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Undefined VFD_RS485_RXD_PIN");
pins_settings_ok = false; pins_settings_ok = false;
#endif }
#ifdef VFD_RS485_RTS_PIN if (_rts_pin == -1) {
_rts_pin = VFD_RS485_RTS_PIN;
#else
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Undefined VFD_RS485_RTS_PIN"); grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Undefined VFD_RS485_RTS_PIN");
pins_settings_ok = false; pins_settings_ok = false;
#endif }
if (laser_mode->get()) { if (laser_mode->get()) {
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "VFD spindle disabled in laser mode. Set $GCode/LaserMode=Off and restart"); grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "VFD spindle disabled in laser mode. Set $GCode/LaserMode=Off and restart");
@@ -564,9 +565,12 @@ namespace Spindles {
ModbusCommand rpm_cmd; ModbusCommand rpm_cmd;
rpm_cmd.msg[0] = VFD_RS485_ADDR; rpm_cmd.msg[0] = VFD_RS485_ADDR;
set_speed_command(rpm, rpm_cmd); set_speed_command(rpm, rpm_cmd);
// Sometimes sync_rpm is retained between different set_speed_command's. We don't want that - we want
// spindle sync to kick in after we set the speed. This forces that.
_sync_rpm = UINT32_MAX;
rpm_cmd.critical = (rpm == 0); rpm_cmd.critical = (rpm == 0);
if (xQueueSend(vfd_cmd_queue, &rpm_cmd, 0) != pdTRUE) { if (xQueueSend(vfd_cmd_queue, &rpm_cmd, 0) != pdTRUE) {
@@ -576,7 +580,12 @@ namespace Spindles {
return rpm; return rpm;
} }
void VFD::stop() { set_mode(SpindleState::Disable, true); } void VFD::stop() {
#ifdef VFD_DEBUG_MODE
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Debug, "VFD::stop()");
#endif
set_mode(SpindleState::Disable, true);
}
// state is cached rather than read right now to prevent delays // state is cached rather than read right now to prevent delays
SpindleState VFD::get_state() { return _current_state; } SpindleState VFD::get_state() { return _current_state; }

View File

@@ -20,11 +20,12 @@
*/ */
#include "Spindle.h" #include "Spindle.h"
#include <driver/uart.h> #include "../Uart.h"
// #define VFD_DEBUG_MODE // #define VFD_DEBUG_MODE
namespace Spindles { namespace Spindles {
extern Uart _uart;
class VFD : public Spindle { class VFD : public Spindle {
private: private:
@@ -34,9 +35,9 @@ namespace Spindles {
bool set_mode(SpindleState mode, bool critical); bool set_mode(SpindleState mode, bool critical);
bool get_pins_and_settings(); bool get_pins_and_settings();
uint8_t _txd_pin; int _txd_pin;
uint8_t _rxd_pin; int _rxd_pin;
uint8_t _rts_pin; int _rts_pin;
uint32_t _current_rpm = 0; uint32_t _current_rpm = 0;
bool _task_running = false; bool _task_running = false;
@@ -57,8 +58,6 @@ namespace Spindles {
uint8_t msg[VFD_RS485_MAX_MSG_SIZE]; uint8_t msg[VFD_RS485_MAX_MSG_SIZE];
}; };
virtual void default_modbus_settings(uart_config_t& uart);
// Commands: // Commands:
virtual void direction_command(SpindleState mode, ModbusCommand& data) = 0; virtual void direction_command(SpindleState mode, ModbusCommand& data) = 0;
virtual void set_speed_command(uint32_t rpm, ModbusCommand& data) = 0; virtual void set_speed_command(uint32_t rpm, ModbusCommand& data) = 0;
@@ -73,8 +72,14 @@ namespace Spindles {
virtual bool supports_actual_rpm() const { return false; } virtual bool supports_actual_rpm() const { return false; }
virtual bool safety_polling() const { return true; } virtual bool safety_polling() const { return true; }
// The constructor sets these
int _baudrate;
Uart::Data _dataBits;
Uart::Stop _stopBits;
Uart::Parity _parity;
public: public:
VFD() = default; VFD();
VFD(const VFD&) = delete; VFD(const VFD&) = delete;
VFD(VFD&&) = delete; VFD(VFD&&) = delete;
VFD& operator=(const VFD&) = delete; VFD& operator=(const VFD&) = delete;

View File

@@ -75,18 +75,8 @@
b11: reserved b11: reserved
*/ */
#include <driver/uart.h>
namespace Spindles { namespace Spindles {
void YL620::default_modbus_settings(uart_config_t& uart) { YL620::YL620() : VFD() {}
// sets the uart to 9600 8N1
VFD::default_modbus_settings(uart);
uart.baud_rate = 9600;
uart.data_bits = UART_DATA_8_BITS;
uart.parity = UART_PARITY_DISABLE;
uart.stop_bits = UART_STOP_BITS_1;
}
void YL620::direction_command(SpindleState mode, ModbusCommand& data) { void YL620::direction_command(SpindleState mode, ModbusCommand& data) {
// NOTE: data length is excluding the CRC16 checksum. // NOTE: data length is excluding the CRC16 checksum.
@@ -123,9 +113,9 @@ namespace Spindles {
uint16_t freqFromRPM = (uint16_t(rpm) * uint16_t(max_frequency)) / uint16_t(max_rpm); uint16_t freqFromRPM = (uint16_t(rpm) * uint16_t(max_frequency)) / uint16_t(max_rpm);
#ifdef VFD_DEBUG_MODE #ifdef VFD_DEBUG_MODE
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "For %d RPM the output frequency is set to %d Hz*10", int(rpm), int(freqFromRPM)); grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "For %d RPM the output frequency is set to %d Hz*10", int(rpm), int(freqFromRPM));
#endif #endif
data.msg[1] = 0x06; data.msg[1] = 0x06;
data.msg[2] = 0x20; data.msg[2] = 0x20;
@@ -136,7 +126,6 @@ namespace Spindles {
VFD::response_parser YL620::initialization_sequence(int index, ModbusCommand& data) { VFD::response_parser YL620::initialization_sequence(int index, ModbusCommand& data) {
if (index == -1) { if (index == -1) {
// NOTE: data length is excluding the CRC16 checksum. // NOTE: data length is excluding the CRC16 checksum.
data.tx_length = 6; data.tx_length = 6;
data.rx_length = 5; data.rx_length = 5;
@@ -153,14 +142,13 @@ namespace Spindles {
auto yl620 = static_cast<YL620*>(vfd); auto yl620 = static_cast<YL620*>(vfd);
yl620->_minFrequency = (uint16_t(response[3]) << 8) | uint16_t(response[4]); yl620->_minFrequency = (uint16_t(response[3]) << 8) | uint16_t(response[4]);
#ifdef VFD_DEBUG_MODE #ifdef VFD_DEBUG_MODE
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "YL620 allows minimum frequency of %d Hz", int(yl620->_minFrequency)); grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "YL620 allows minimum frequency of %d Hz", int(yl620->_minFrequency));
#endif #endif
return true; return true;
}; };
} } else if (index == -2) {
else if (index == -2) {
// NOTE: data length is excluding the CRC16 checksum. // NOTE: data length is excluding the CRC16 checksum.
data.tx_length = 6; data.tx_length = 6;
data.rx_length = 5; data.rx_length = 5;
@@ -177,18 +165,21 @@ namespace Spindles {
auto yl620 = static_cast<YL620*>(vfd); auto yl620 = static_cast<YL620*>(vfd);
yl620->_maxFrequency = (uint16_t(response[3]) << 8) | uint16_t(response[4]); yl620->_maxFrequency = (uint16_t(response[3]) << 8) | uint16_t(response[4]);
vfd->_min_rpm = uint32_t(yl620->_minFrequency) * uint32_t(vfd->_max_rpm) / uint32_t(yl620->_maxFrequency); // 1000 * 24000 / 4000 = 6000 RPM. vfd->_min_rpm = uint32_t(yl620->_minFrequency) * uint32_t(vfd->_max_rpm) /
uint32_t(yl620->_maxFrequency); // 1000 * 24000 / 4000 = 6000 RPM.
#ifdef VFD_DEBUG_MODE
#ifdef VFD_DEBUG_MODE
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "YL620 allows maximum frequency of %d Hz", int(yl620->_maxFrequency)); grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "YL620 allows maximum frequency of %d Hz", int(yl620->_maxFrequency));
grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Configured maxRPM of %d RPM results in minRPM of %d RPM", int(vfd->_max_rpm), int(vfd->_min_rpm)); grbl_msg_sendf(CLIENT_SERIAL,
#endif MsgLevel::Info,
"Configured maxRPM of %d RPM results in minRPM of %d RPM",
int(vfd->_max_rpm),
int(vfd->_min_rpm));
#endif
return true; return true;
}; };
} } else {
else {
return nullptr; return nullptr;
} }
} }

View File

@@ -27,8 +27,6 @@ namespace Spindles {
uint16_t _minFrequency = 0; // frequency lower limit. Factor 10 of actual frequency uint16_t _minFrequency = 0; // frequency lower limit. Factor 10 of actual frequency
uint16_t _maxFrequency = 4000; // max frequency the VFD will allow. Normally 400.0. Factor 10 of actual frequency uint16_t _maxFrequency = 4000; // max frequency the VFD will allow. Normally 400.0. Factor 10 of actual frequency
void default_modbus_settings(uart_config_t& uart) override;
void direction_command(SpindleState mode, ModbusCommand& data) override; void direction_command(SpindleState mode, ModbusCommand& data) override;
void set_speed_command(uint32_t rpm, ModbusCommand& data) override; void set_speed_command(uint32_t rpm, ModbusCommand& data) override;
@@ -39,5 +37,8 @@ namespace Spindles {
bool supports_actual_rpm() const override { return true; } bool supports_actual_rpm() const override { return true; }
bool safety_polling() const override { return false; } bool safety_polling() const override { return false; }
public:
YL620();
}; };
} }

94
Grbl_Esp32/src/Uart.cpp Normal file
View File

@@ -0,0 +1,94 @@
/*
* UART driver that accesses the ESP32 hardware FIFOs directly.
*/
#include "Grbl.h"
#include "esp_system.h"
#include "soc/uart_reg.h"
#include "soc/io_mux_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/dport_reg.h"
#include "soc/rtc.h"
Uart::Uart(int uart_num) : _uart_num(uart_port_t(uart_num)), _pushback(-1) {}
void Uart::begin(unsigned long baudrate, Data dataBits, Stop stopBits, Parity parity) {
// uart_driver_delete(_uart_num);
uart_config_t conf;
conf.baud_rate = baudrate;
conf.data_bits = uart_word_length_t(dataBits);
conf.parity = uart_parity_t(parity);
conf.stop_bits = uart_stop_bits_t(stopBits);
conf.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
conf.rx_flow_ctrl_thresh = 0;
conf.use_ref_tick = false;
if (uart_param_config(_uart_num, &conf) != ESP_OK) {
return;
};
uart_driver_install(_uart_num, 256, 0, 0, NULL, 0);
}
int Uart::available() {
size_t size = 0;
uart_get_buffered_data_len(_uart_num, &size);
return size + (_pushback >= 0);
}
int Uart::peek() {
_pushback = read();
return _pushback;
}
int Uart::read(TickType_t timeout) {
if (_pushback >= 0) {
int ret = _pushback;
_pushback = -1;
return ret;
}
uint8_t c;
int res = uart_read_bytes(_uart_num, &c, 1, timeout);
return res != 1 ? -1 : c;
}
int Uart::read() {
return read(0);
}
size_t Uart::readBytes(char* buffer, size_t length, TickType_t timeout) {
bool pushback = _pushback >= 0;
if (pushback && length) {
*buffer++ = _pushback;
_pushback = -1;
--length;
}
int res = uart_read_bytes(_uart_num, (uint8_t*)buffer, length, timeout);
// The Stream class version of readBytes never returns -1,
// so if uart_read_bytes returns -1, we change that to 0
return pushback + (res >= 0 ? res : 0);
}
size_t Uart::readBytes(char* buffer, size_t length) {
return readBytes(buffer, length, (TickType_t)0);
}
size_t Uart::write(uint8_t c) {
return uart_write_bytes(_uart_num, (char*)&c, 1);
}
size_t Uart::write(const uint8_t* buffer, size_t length) {
return uart_write_bytes(_uart_num, (const char*)buffer, length);
}
size_t Uart::write(const char* text) {
return uart_write_bytes(_uart_num, text, strlen(text));
}
bool Uart::setHalfDuplex() {
return uart_set_mode(_uart_num, UART_MODE_RS485_HALF_DUPLEX) != ESP_OK;
}
bool Uart::setPins(int tx_pin, int rx_pin, int rts_pin, int cts_pin) {
return uart_set_pin(_uart_num, tx_pin, rx_pin, rts_pin, cts_pin) != ESP_OK;
}
bool Uart::flushTxTimed(TickType_t ticks) {
return uart_wait_tx_done(_uart_num, ticks) != ESP_OK;
}
Uart Uart0(0);

49
Grbl_Esp32/src/Uart.h Normal file
View File

@@ -0,0 +1,49 @@
#pragma once
#include <driver/uart.h>
class Uart : public Stream {
private:
uart_port_t _uart_num;
int _pushback;
public:
enum class Data : int {
Bits5 = UART_DATA_5_BITS,
Bits6 = UART_DATA_6_BITS,
Bits7 = UART_DATA_7_BITS,
Bits8 = UART_DATA_8_BITS,
};
enum class Stop : int {
Bits1 = UART_STOP_BITS_1,
Bits1_5 = UART_STOP_BITS_1_5,
Bits2 = UART_STOP_BITS_2,
};
enum class Parity : int {
None = UART_PARITY_DISABLE,
Even = UART_PARITY_EVEN,
Odd = UART_PARITY_ODD,
};
Uart(int uart_num);
bool setHalfDuplex();
bool setPins(int tx_pin, int rx_pin, int rts_pin = -1, int cts_pin = -1);
void begin(unsigned long baud, Data dataBits, Stop stopBits, Parity parity);
int available(void) override;
int read(void) override;
int read(TickType_t timeout);
size_t readBytes(char* buffer, size_t length, TickType_t timeout);
size_t readBytes(uint8_t* buffer, size_t length, TickType_t timeout) { return readBytes((char*)buffer, length, timeout); }
size_t readBytes(char* buffer, size_t length) override;
int peek(void) override;
size_t write(uint8_t data);
size_t write(const uint8_t* buffer, size_t length);
inline size_t write(const char* buffer, size_t size) { return write((uint8_t*)buffer, size); }
size_t write(const char* text);
void flush() { uart_flush(_uart_num); }
bool flushTxTimed(TickType_t ticks);
};
extern Uart Uart0;

View File

@@ -63,10 +63,10 @@ src_filter =
[env:release] [env:release]
lib_deps = lib_deps =
TMCStepper@>=0.7.0,<1.0.0 TMCStepper@>=0.7.0,<1.0.0
squix78/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.2.0 ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.2.0
[env:debug] [env:debug]
build_type = debug build_type = debug
lib_deps = lib_deps =
TMCStepper@>=0.7.0,<1.0.0 TMCStepper@>=0.7.0,<1.0.0
squix78/ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.2.0 ESP8266 and ESP32 OLED driver for SSD1306 displays@^4.2.0