diff --git a/platformio.ini b/platformio.ini index 9772eeb..88d4d36 100644 --- a/platformio.ini +++ b/platformio.ini @@ -21,8 +21,9 @@ build_src_filter = +<*> -<./angular/> board_build.filesystem = littlefs check_tool = cppcheck, clangtidy build_flags = - -D OLED_ENABLED=false + -D OLED_ENABLED=true -D PWM_MOTOR_CONTROL=false + -D STEPPER_MOTOR_CONTROL=true -D HOME_ASSISTANT_ENABLED=false check_flags = clangtidy: -fix-errors,--format-style=google @@ -36,3 +37,5 @@ lib_deps = adafruit/Adafruit SSD1306@^2.5.9 electromagus/ESPMX1508@^1.0.5 dawidchyrzynski/home-assistant-integration@^2.1.0 + teemuatlut/TMCStepper@^0.7.3 + plerup/EspSoftwareSerial@^8.2.0 diff --git a/src/platformio/osww-server/src/main.cpp b/src/platformio/osww-server/src/main.cpp index 528577a..e39a9df 100644 --- a/src/platformio/osww-server/src/main.cpp +++ b/src/platformio/osww-server/src/main.cpp @@ -94,11 +94,19 @@ AsyncWebServer server(80); HTTPClient http; WiFiClient client; ESP32Time rtc; -String winderooVersion = "3.0.0"; +String winderooVersion = "3.1.0"; -#if PWM_MOTOR_CONTROL +#if PWM_MOTOR_CONTROL && STEPPER_MOTOR_CONTROL + #error "You can only have one optional motor control method enabled at a time. You must disable either PWM_MOTOR_CONTROL or STEPPER_MOTOR_CONTROL in the platformio.ini file." +#endif + +// PWM control +#if PWM_MOTOR_CONTROL && !STEPPER_MOTOR_CONTROL MotorControl motor(directionalPinA, directionalPinB, true); -#else +#endif + +// Stepper motor control || Regular DC motor control +#if STEPPER_MOTOR_CONTROL && !PWM_MOTOR_CONTROL || !STEPPER_MOTOR_CONTROL && !WM_MOTOR_CONTROL MotorControl motor(directionalPinA, directionalPinB); #endif @@ -389,6 +397,17 @@ unsigned long calculateWindingTime() */ void beginWindingRoutine() { + + + if (userDefinedSettings.direction == "CW" ) + { + motor.setMotorDirection(1); + } + else if (userDefinedSettings.direction == "CCW") + { + motor.setMotorDirection(0); + } + startTimeEpoch = rtc.getEpoch(); previousEpoch = startTimeEpoch; routineRunning = true; @@ -1184,6 +1203,11 @@ void setup() display.invertDisplay(OLED_INVERT_SCREEN); display.setRotation(rotate); drawNotification("Winderoo"); + + + String savedNetworkMessage[2] = {"Winderoo build", "v" + winderooVersion}; + drawMultiLineText(savedNetworkMessage); + delay(1200); } String savedNetworkMessage[2] = {"Connecting to", "saved network..."}; @@ -1302,6 +1326,7 @@ void setup() drawNotification("Starting webserver..."); startWebserver(); + delay(750); // delay to show notification if (strcmp(userDefinedSettings.status.c_str(), "Winding") == 0) { diff --git a/src/platformio/osww-server/src/utils/MotorControl.cpp b/src/platformio/osww-server/src/utils/MotorControl.cpp index 896f503..d4a103c 100644 --- a/src/platformio/osww-server/src/utils/MotorControl.cpp +++ b/src/platformio/osww-server/src/utils/MotorControl.cpp @@ -1,5 +1,8 @@ #include "MotorControl.h" +// Define the static instance variable +MotorControl* MotorControl::instance = nullptr; + #if PWM_MOTOR_CONTROL #include #define CH1 1 @@ -7,12 +10,108 @@ int motorSpeed = 145; #endif +#ifdef STEPPER_MOTOR_CONTROL + #include + #include + + const uint16_t EN_PIN = 4; // Enable + const uint16_t DIR_PIN = 16; // Direction + const uint16_t STEP_PIN = 17; // Step + + const signed long RUN_VELOCITY = 20000; + const signed long STOP_VELOCITY = 0; + + #define SW_RX 3 // TMC2208/TMC2224 SoftwareSerial receive pin + #define SW_TX 1 // TMC2208/TMC2224 SoftwareSerial transmit pin + #define SERIAL_PORT Serial1 // TMC2208/TMC2224 HardwareSerial port + #define DRIVER_ADDRESS 0b00 // TMC2209 Driver address according to MS1 and MS2 + + const uint16_t R_SENSE = 0.11f; // TMC2209 - SilentStepStick series use 0.11 + + SoftwareSerial softwareSerial(SW_RX, SW_TX); // Create SoftwareSerial object + TMC2208Stepper driver = TMC2208Stepper(&softwareSerial, R_SENSE); // Use SoftwareSerial object + + // For non-blocking stepper movement + hw_timer_t *timer = NULL; + volatile bool stepPinState = LOW; + static bool timerConfigured = false; + + // For stepper timing control (RPM) + uint16_t microSteps = 4; + uint16_t rmsCurrent = 600; + uint64_t timerMicroSecondInterval = 400; // 937 microseconds for 40 RPM / 400 microseconds for 100 RPM + +#endif + MotorControl::MotorControl(int pinA, int pinB, bool pwmMotorControl) { - _pinA = pinA; - _pinB = pinB; - _motorDirection = 0; - _pwmMotorControl = pwmMotorControl; + #ifdef STEPPER_MOTOR_CONTROL + instance = this; + stepperSetup(); + + _motorDirection = 0; + #else + _pinA = pinA; + _pinB = pinB; + _motorDirection = 0; + _pwmMotorControl = pwmMotorControl; + #endif +} + +void MotorControl::stepperSetup() { + + softwareSerial.begin(9600); + + pinMode(EN_PIN, OUTPUT); + pinMode(STEP_PIN, OUTPUT); + pinMode(DIR_PIN, OUTPUT); + digitalWrite(EN_PIN, LOW); + + driver.begin(); + driver.toff(5); // Enables driver in software + driver.rms_current(rmsCurrent); // Set motor RMS current in mA + driver.microsteps(microSteps); // Set microsteps to 1/8th because reasons + driver.stealth(); // Enable stealthChop +} + +// This private function is used to toggle the step pin by the timer +void IRAM_ATTR MotorControl::onTimer() +{ + digitalWrite(STEP_PIN, stepPinState); + stepPinState = !stepPinState; +} + +void IRAM_ATTR MotorControl::onTimerStatic() +{ + instance->onTimer(); +} + +void killTimer() +{ + Serial.println("[INFO] - Killing timer"); + + timerAlarmDisable(timer); // Disable the timer to stop + timerDetachInterrupt(timer); // Detach the interrupt + timerEnd(timer); // End the timer + + stepPinState = LOW; + digitalWrite(STEP_PIN, stepPinState); + + timer = NULL; + timerConfigured = false; +} + +void MotorControl::configureHardwareTimer() +{ + if (!timerConfigured) + { + timer = timerBegin(0, 80, true); // Timer 0, prescaler 80 (1 MHz clock) + timerAttachInterrupt(timer, &onTimerStatic, true); // Attach onTimer function to timer + timerAlarmWrite(timer, timerMicroSecondInterval, true); // Set timer interval 937 microseconds for 40 RPM + timerAlarmEnable(timer); // Enable the timer + timerConfigured = true; + } + } void MotorControl::clockwise() @@ -20,6 +119,15 @@ void MotorControl::clockwise() #if PWM_MOTOR_CONTROL MX1508 pwmControl(_pinA, _pinB, CH1, CH2); pwmControl.motorGo(motorSpeed); + #elif STEPPER_MOTOR_CONTROL + // Set the direction pin + if (timerConfigured) timerAlarmDisable(timer); + + digitalWrite(DIR_PIN, HIGH); + delay(10); + + if (timerConfigured) timerAlarmEnable(timer); + // Non-blocking step handling is now through the timer function; "configureHardwareTimer()" #else digitalWrite(_pinA, HIGH); digitalWrite(_pinB, LOW); @@ -32,6 +140,15 @@ void MotorControl::countClockwise() #if PWM_MOTOR_CONTROL MX1508 pwmControl(_pinA, _pinB, CH1, CH2); pwmControl.motorRev(motorSpeed); + #elif STEPPER_MOTOR_CONTROL + // Set the direction pin + if (timerConfigured) timerAlarmDisable(timer); + + digitalWrite(DIR_PIN, LOW); + delay(10); + + if (timerConfigured) timerAlarmEnable(timer); + // Non-blocking step handling is now through the timer function; "configureHardwareTimer()" #else digitalWrite(_pinA, LOW); digitalWrite(_pinB, HIGH); @@ -44,6 +161,11 @@ void MotorControl::stop() #if PWM_MOTOR_CONTROL MX1508 pwmControl(_pinA, _pinB, CH1, CH2); pwmControl.motorBrake(); + #elif STEPPER_MOTOR_CONTROL + if (timerConfigured) + { + killTimer(); + } #else digitalWrite(_pinA, LOW); digitalWrite(_pinB, LOW); @@ -53,16 +175,27 @@ void MotorControl::stop() void MotorControl::determineMotorDirectionAndBegin() { - // @todo - investigate if this is still needed - // stop(); - if (_motorDirection) { - clockwise(); + #if STEPPER_MOTOR_CONTROL + clockwise(); // We call this for logging purposes + if (!timerConfigured) { + configureHardwareTimer(); + } + #else + clockwise(); + #endif } else { - countClockwise(); + #if STEPPER_MOTOR_CONTROL + countClockwise(); // We call this for logging purposes + if (!timerConfigured) { + configureHardwareTimer(); + } + #else + countClockwise(); + #endif } } @@ -74,4 +207,7 @@ int MotorControl::getMotorDirection() void MotorControl::setMotorDirection(int direction) { _motorDirection = direction; + + Serial.print("[INFO] - MOTOR CONTROLLER - Setting direction to: "); + Serial.println(_motorDirection ? "CW" : "CCW"); } diff --git a/src/platformio/osww-server/src/utils/MotorControl.h b/src/platformio/osww-server/src/utils/MotorControl.h index b47c6a7..04dc6aa 100644 --- a/src/platformio/osww-server/src/utils/MotorControl.h +++ b/src/platformio/osww-server/src/utils/MotorControl.h @@ -12,6 +12,16 @@ class MotorControl int _motorDirection; bool _pwmMotorControl; + void stepperSetup(); + + static void IRAM_ATTR onTimerStatic(); // Add this line + + void onTimer(); + + void configureHardwareTimer(); + + static MotorControl* instance; // Add this line + public: MotorControl(int _pinA, int _pinB, bool pwmMotorControl = false);