From 738d6a1b07c205ec063f27931d02fbab53df66d5 Mon Sep 17 00:00:00 2001
From: David Gauchard <gauchard@laas.fr>
Date: Wed, 27 Jul 2022 18:17:05 +0200
Subject: [PATCH] Use AccelStepper in interrupt mode

---
 pousseseringue-arduino.cpp | 172 ++++++++++++++++++-------------------
 pousseseringue-arduino.ino |   2 +-
 2 files changed, 84 insertions(+), 90 deletions(-)

diff --git a/pousseseringue-arduino.cpp b/pousseseringue-arduino.cpp
index 0286217..c755570 100644
--- a/pousseseringue-arduino.cpp
+++ b/pousseseringue-arduino.cpp
@@ -44,31 +44,23 @@
 
 #define STEPPER_RPM 60                  // some value is necessary for the driver XXXXX see below
 
-#define STEP_DURATION_MIN_MS     2
-#define STEP_DURATION_DEFAULT_MS 5
+#define STEPpS_MIN     2
+#define STEPpS_DEFAULT 5
 
 
 
 #include <ESP8266WiFi.h>        // internal, wifi library
 #include <DNSServer.h>          // internal, access point mode
+#include <Schedule.h>
 
 #if !CORE_MOCK
 
 #include <SSD1306AsciiWire.h>   // https://github.com/greiman/SSD1306Ascii
 SSD1306AsciiWire oled;
 
-#if USE_A4988
-
-#include <A4988.h>              // https://github.com/laurb9/StepperDriver
-A4988 a4988(MOTOR_STEPS, DIR, STEP, SLEEP);
-
-#else
-
 #include <AccelStepper.h>       // https://github.com/waspinator/AccelStepper
 AccelStepper stepper(AccelStepper::DRIVER, STEP, DIR);
 
-#endif
-
 #endif // !CORE_MOCK
 
 #include "Debouncer.h"          // local, debouncer, short counter, long detector
@@ -90,19 +82,19 @@ DNSServer dnsServer;
 
 char ssid[65];
 
-Modes mode = Modes::TURN;
+Modes mode = Modes::RPM;
+bool stepperMoving = false;
 
 millis_t lastMoveMs = 0;
 int move = 0;
 
 // TURN mode
 constexpr float step2deg = 360.0 / MOTOR_STEPS / MICROSTEPS_CONF;   // deg for 1 step
-int steps = MOTOR_STEPS * MICROSTEPS_CONF / 100;                    // =1/100 turn
+int steps = MOTOR_STEPS * MICROSTEPS_CONF / 4;                      // =1/4 turn
 
 // RPM mode
-int stepsPerDuration = 1;
-int stepDurationMs = STEP_DURATION_DEFAULT_MS;
-float stepsPerDuration2rpm () { return 60.0 * stepsPerDuration / ((MOTOR_STEPS * MICROSTEPS_CONF) * (stepDurationMs / 1000.0)); }
+int stepsPerSeconds = MOTOR_STEPS * MICROSTEPS_CONF / 2;
+float stepsPerSeconds2rpm () { return 60.0 * stepsPerSeconds / (MOTOR_STEPS * MICROSTEPS_CONF); }
 int rpming = 0; // -1, 0 or +1
 
 // single syringe global instance
@@ -137,28 +129,28 @@ void oledRedisplay ()
     switch (mode)
     {
     case Modes::TURN:
-        oled.printf("<%g dR <<turn", steps * step2deg);
+        oled.printf("<%g dR <<360 dR", steps * step2deg);
         oledPrintMode();
         oled.printf("\n");
-        oled.printf("\n<%g dL <<turn", steps * step2deg);
+        oled.printf("\n<%g dL <<360 d ", steps * step2deg);
         break;
     case Modes::TURNSetup:
-        oled.printf("<+1 << +10 steps");
+        oled.printf("<+1step << +1/16T");
         oledPrintMode();
-        oled.printf("\n current:%d (%g d)", steps, steps * step2deg);
-        oled.printf("\n<-1 << -10 steps");
+        oled.printf("\n steps:%d (%g d)", steps, steps * step2deg);
+        oled.printf("\n<-1step << -1/16T");
         break;
     case Modes::RPM:
         oled.printf("<stop <<start");
         oledPrintMode();
-        oled.printf("\n %g rpm", stepsPerDuration2rpm());
+        oled.printf("\n %g rpm", stepsPerSeconds2rpm());
         oled.printf("\n<stop <<start");
         break;
     case Modes::RPMSetup:
-        oled.printf("<+1st <<+1ms st:%d", stepsPerDuration);
+        oled.printf("<+1s/s <<+1/4T/s");
         oledPrintMode();
-        oled.printf("\n %g rpm", stepsPerDuration2rpm());
-        oled.printf("\n<-1st <<-1ms t:%dms", stepDurationMs);
+        oled.printf("\ns/s:%d RPM:%g", stepsPerSeconds, stepsPerSeconds2rpm());
+        oled.printf("\n<-1s/s <<-1/4T/s");
         break;
     case Modes::INFO:
         oled.printf("IP:%s", WiFi.localIP().toString().c_str());
@@ -189,7 +181,6 @@ void changeMode ()
 }
 
 
-
 // button status management, per mode
 
 void buttons (int shortp, int longp)
@@ -197,40 +188,82 @@ void buttons (int shortp, int longp)
     // log debug on serial console
     Serial.printf("button change: short:%d long:%d\n", shortp, longp);
 
+#if !CORE_MOCK
+    cli();
+    stepper.stop();
+    sei();
+    while (stepperMoving)
+        yield();
+#endif // !CORE_MOCK
+
+	auto oldrpming = rpming;
     rpming = 0; // anything stops rpming
 
     switch (mode)
     {
     case Modes::TURN:
+        Serial.printf("move: %d -> ", move);
         move += shortp * steps;
-        move += longp * MOTOR_STEPS * MICROSTEPS_CONF;
+        move += longp * MOTOR_STEPS * MICROSTEPS_CONF; // long: one turn
+        Serial.printf("%d\n", move);
+#if !CORE_MOCK
+        cli();
+		stepper.moveTo(move);
+        sei();
+#endif // !CORE_MOCK
         break;
+
     case Modes::TURNSetup:
         steps += shortp;
-        steps += longp * 10;
+        steps += longp * MOTOR_STEPS * MICROSTEPS_CONF / 16;
         oledRedisplay();
         break;
+
     case Modes::RPM:
         if (longp)
-            rpming = longp; // move will be increased in main loop
-        if (shortp)
-            move = 0; // stop moving
+		{
+            rpming = longp? (oldrpming > 1? -1: 1): 0;
+			if (rpming)
+			{
+#if !CORE_MOCK
+                cli();
+				stepper.setSpeed(stepsPerSeconds);
+                sei();
+#endif // !CORE_MOCK
+				Serial.printf("StepPerSecs=%d (%g RPM)\n", stepsPerSeconds, stepsPerSeconds2rpm());
+				//stepper.setMaxSpeed(400);
+			}
+		}
         break;
+
     case Modes::RPMSetup:
-        if ((stepDurationMs += longp) < STEP_DURATION_MIN_MS)
-            stepDurationMs = STEP_DURATION_MIN_MS;
-        if ((stepsPerDuration += shortp) < 1)
-            stepsPerDuration = 1;
+        if ((stepsPerSeconds += longp * MOTOR_STEPS * MICROSTEPS_CONF / 16) < 1)
+            stepsPerSeconds = 1;
+        if ((stepsPerSeconds += shortp) < 1)
+            stepsPerSeconds = 1;
         oledRedisplay();
         break;
+
     default:
         Serial.printf("press not handled in buttons()\n");
     }
 }
 
 
+#if !CORE_MOCK
 
+IRAM_ATTR
+void stepperRun ()
+{
+    cli();
+    if (rpming)
+        stepperMoving = stepper.runSpeed();
+    else
+        stepperMoving = stepper.run();
+    sei();
+}
 
+#endif // !CORE_MOCK
 
 void setup()
 {
@@ -251,16 +284,9 @@ void setup()
     oled.clear();
     oled.println("Booting...\n");
 
-#if USE_A4988
-    a4988.begin(STEPPER_RPM); // some value is necessary
-    a4988.setEnableActiveState(LOW);
-    a4988.setMicrostep(MICROSTEPS_CONF);
-    a4988.enable();
-#else
     stepper.setMaxSpeed(10000);
     stepper.setAcceleration(10000);
-    stepper.moveTo(200);
-#endif
+    
 
 #endif // !CORE_MOCK
 
@@ -289,6 +315,20 @@ void setup()
     pinMode(BTNC, INPUT_PULLUP);
 
     oledRedisplay();
+    
+#if !CORE_MOCK
+#ifdef ISR_ATTR
+    timer1_isr_init();
+    timer1_enable(TIM_DIV1, TIM_EDGE, TIM_LOOP);
+    timer1_attachInterrupt(stepperRun);
+    timer1_write(microsecondsToClockCycles(100));
+#else
+    #warning ===================================================================================================
+    #warning "Please use the ISR version of AccelStepper (git clone -b isr https://github.com/d-a-v/AccelStepper)"
+    #warning ===================================================================================================
+    schedule_recurrent_function_us([](){ stepperRun(); return true; }, 1);
+#endif
+#endif
 }
 
 
@@ -333,53 +373,7 @@ void loop()
         if (longB)
             changeMode();
         (void)shortB;
-
-        move = 0;
-    }
-
-#if !CORE_MOCK
-
-    // Stepper
-
-#if USE_A4988
-    // MOVE THIS BLOCK INTO A TIMER/ISR
-    //      (it is randomly slowed down by prints / web / wifi)
-    //      (or? use A4988 RPM mode, related: a4988.begin(STEPPER_RPM);)
-    if (lastMoveMs - nowMs > (millis_t)stepDurationMs)
-    {
-        if (rpming && move < MOTOR_STEPS * MICROSTEPS_CONF && move > -(MOTOR_STEPS * MICROSTEPS_CONF))
-        {
-            move += rpming * MOTOR_STEPS * MICROSTEPS_CONF;
-            //Serial.printf("feeding %d\n", move);
-        }
-
-        if (move >= stepsPerDuration)
-        {
-            move -= stepsPerDuration;
-            a4988.move(stepsPerDuration);    // forward revolution
-        }
-        if (move <= -stepsPerDuration)
-        {
-            move += stepsPerDuration;
-            a4988.move(-stepsPerDuration);   // backward revolution
-        }
-
-        lastMoveMs += stepDurationMs;
-
-    }
-#else
-
-    if (stepper.distanceToGo() == 0)
-    {
-        stepper.moveTo(-stepper.currentPosition());
-        Serial.println("Rotating Motor in opposite direction...");
     }
-    stepper.run();
-
-#endif
-
-#endif // !CORE_MOCK
-
 
     console.loop(Serial);
     webLoop();
diff --git a/pousseseringue-arduino.ino b/pousseseringue-arduino.ino
index 8629455..e3e70bc 100644
--- a/pousseseringue-arduino.ino
+++ b/pousseseringue-arduino.ino
@@ -1,7 +1,7 @@
 
 // please edit this file: pousseseringue-arduino.cpp
 
-// Pour la compilation locale sur le PC
+// needed for compilation on host
 #if CORE_MOCK
   #include "pousseseringue-arduino.cpp"
   #include "web.cpp"
-- 
GitLab