// https://wokwi.com/projects/385290804310887425
// modified from
// https://forum.arduino.cc/t/generation-of-three-phase-square-wave-using-arduino-simple-coding/407769
// for
// https://forum.arduino.cc/t/generation-of-three-phase-square-wave-using-arduino-bwod-style/1204347
// See https://blog.orientalmotor.com/stepper-motor-basics-pm-vs-vr-vs-hybrid
// for the layout of a 3 phase motor with a 12 coil stator and 8 pole rotor
// 12coils/3 phases = 4 cycles per rev

unsigned long delayInterval = 3333UL; // 500UL*1000; //
unsigned long nowUs = 0;
unsigned long nowMs = 0;
unsigned long now = 0;

const byte pinA = 7;
const byte pinB = 8;
const byte pinC = 9;
const byte speedPin = A0;


const byte phaseTable6[] = {0b001, 0b011, 0b010, 0b110, 0b100, 0b101};

// one coil at a time:
const byte phaseTable3[] = {0b001, 0b010, 0b100, 0b001, 0b010, 0b100};

byte phase = 0; // global variable to track phase state

void setup() {

  Serial.begin(115200);
  // initialize digital pin 13,12&8 as an output.
  pinMode(pinA, OUTPUT);
  pinMode(pinB, OUTPUT);
  pinMode(pinC, OUTPUT);
}

void loop() {
  now = micros();
  stepPhases6(delayInterval);
  //  stepPhases6Blocking(delayInterval);
  updateSpeed();
}

void writePhases(byte phase) {
  digitalWrite(pinA, phase & 0b001);
  digitalWrite(pinB, phase & 0b010);
  digitalWrite(pinC, phase & 0b100);
}

void stepPhases6(unsigned long interval) {
  static long last = -10000;
  int dir = 1;
  if (now - last > interval) {
    writePhases(phaseTable6[phase++]);
    if (phase >= 6) phase = 0;
    last = now;
  }
}

void stepPhases6Blocking(unsigned long interval) {
  // closer to https://forum.arduino.cc/t/generation-of-three-phase-square-wave-using-arduino-simple-coding/407769
  // but simplified with functions and a lookup table
  writePhases(phaseTable6[phase++]);
  if (phase >= 6) {
    phase = 0;
  }
  delay(interval);
}

void updateSpeed(void) {
  const unsigned long interval = 100000UL;
  static unsigned long last = 0;
  const int poles = 3;
  const int phases = 3;
  constexpr int stepsPerRev = 6 * poles / phases;
  if (now - last >= interval ) {
    static int lastReading = -1;
    int currentReading = 1023 - analogRead(speedPin);
    if (currentReading != lastReading) {
      lastReading = currentReading;
      float speed = 600.0 * pow(10, 3*log((1023.1 - currentReading) / 1023.1) / log(10));
      //delayInterval = (currentReading) * 4096UL + 1000;
      //delayInterval = 1*log((currentReading+1.0)/1023)/log(10);
      delayInterval = 1000000 / (speed / 60) / stepsPerRev;
      Serial.println(speed, 4);
      Serial.print(delayInterval);
      Serial.print("us ");
      Serial.print(60UL * 1000000.0 / delayInterval / stepsPerRev, 4);
      Serial.println("RPM ");
    }
    last = now;
  }
}