BLDC 1900KV motor controller design help (motor spins back and forth)

I could use some assistance. So I have been working on this motor controller for different designs. The most recent attempt is using three timers. Based on design I made my own since I don't have an UNO, I have a mega. Speed wise I have no issue but the problem I am having are as follows:

  1. The motor periodically spins the opposite direction and back again, this indicates an BEMF issue. I have a comparator for each phase that looks at the BEMF voltage and creates an external interrupt clamping the BEMF and pushing the motor to the next step, this doesn't seem to work.

  2. I have tried modifying the timers namely T2A and T2B using OCR2A and OCR2B. This does not work.

  3. There is a odd state where the code seems to be caught in a loop with BEMFR interrupt even when throttle is zero, after some time of waiting the motor picks up after not moving or doing anything. The signals for phase ABC show no voltage flow, yet I can see the output of the comparator concerning BEMF to be oscillating, which is what is causing the ripple. I think the input on both the positve and negative of the comparator are oscillating on each other, yet this is the circuit I see online.

  4. I am uncertain of this since the instructable (below) I have been referring doesn't mention it but I think the motor operating frequency would be 32Hz (1900/60), would this be correct? Either way I am uncertain how to articulate the correct on times and how this might affect BEMF. As I have said, I have been working at this for a while.

The video I have been relying on is from Great Scott on youtube + his code found here, Part 2 (most of the troubleshooting is in part 2)

His instructable is here, BLDC Instructable

My Code
(You can start reviewing my code after "byte step = 0;")
(I can increase the speed of the motor by reducing the value in the "delayl" variable.)

int qgateHApin = 7;  //Q1 pin 7 designation HS pwm
int qgateHBpin = 5;  //Q3 pin 5 designation HS pwm
int qgateHCpin = 3;  //Q5 pin 3 designation HS pwm
int qgateLApin = 6;  //Q0 pin 6 designation LS on/off
int qgateLBpin = 4;  //Q2 pin 4 designation LS on/off
int qgateLCpin = 2;  //Q4 pin 2 designation LS on/off
int qgateHAd = 0;
int qgateHBd = 0;
int qgateHCd = 0;
int qgateLAd = 0;
int qgateLBd = 0;
int qgateLCd = 0;
int edgevector = -1;    //0;  //0 is falling, 1 is rising
int edgevectorpin = 3;  //20;

//Coding variables
int McurrentA = 0;  //current flowing in HA fet
int McurrentB = 0;  //current flowing in HB fet
int McurrentC = 0;  //current flowing in HC fet
int MTa = 0;        //Temperature on HA fet
int MTb = 0;        //Temperature on HB fet
int MTc = 0;        //Temperature on HC Fet
int HA = 0;         //hall1
int HB = 0;         //hall2
int HC = 0;         //hall3
int Hlimit = 389;
//normal = 300, advance = 250, recess = 340 : note 5V @ 1024bit resolution.
//300bit = 1.46484375V,
//410bit = 2.0V (logical 0), anything above value is 1
//int HBlimit = 389;
//int HClimit = 389;
int scheck_delay = 6;     //delay in milliseconds for checking sensor values.
int cerror = 0;           //Error code
int cerrordelay = 0;      //error LED flasher delay
int counter = 0;          //simple reusable counter
int cstate = 8;           //current state motor is presently in, make default val not real state val, 8 used since state is undefined, motor has not been used since on
int pstate = 8;           //previous state motor was last in, make default val not real state val, 8 used since state is undefined, motor has not been used since on
int sstate = 0;           //sstate is the start state to move to nex position
int staterate = 0;        //Rate of motor turning
int statecount = 0;       //state counter, how many times motor stays in same state based on throttle
int ustatecount = 500;    //upper limit to statcount, multiply by Tper to get approx time
double throttle = 0;      //throttle position 0k to 10k, can use this for regen control along with g sensor
double throttlel = 150;   //Throttle min resolution
double throttleh = 1023;  //1023;//438;  //438;1023 //throttle max resolution, 2.74V throttle in and 10.7V avg to motor
double throttleavg = 0;
double driveDelay = 0;
double delayl = 100000;  //5000;  //300;  //This directly reduces or increases RPM
double delayh = 120;    //;   //100; //was 100ms
unsigned long lpCmicros = 0;
unsigned long lpPmicros = 0;
unsigned long Cmicros = 0;
unsigned long Pmicros = 0;
unsigned long interval = 0;

//double dutyl = 255;
//double dutyh = 0;
int hipot = 0;        //throttle hi detection on start only
int hipotlimit = 25;  //100 = 0.489V, hipot detection maximum
int timerpreload = 24199;

byte step = 0;
bool wait = 0;
bool doonce = 0;
const unsigned char PS_128 = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
const unsigned int maxcurrent = 482;  // 1024, 0.2v/5v = 0.04*1024

void setup() {
  Serial.begin(115200);
  Serial1.begin(115200);
  cstate = 0;
  //timer0 will interrupt at 2khz
  //timer1 will interrupt at 1hz
  //timer2 will interrupt at 8khz
  ADCSRA &= ~PS_128;
  ADCSRA |= (1 << ADPS1);
  //set timer1 interupt at Xhz
  TCCR1A = 0;                            //set entire TCCR1A register to 0
  TCCR1B = 0;                            //same for TCCR1B
  TCNT1 = 0;                             //initialize counter value to 0, set compare match register for 1hz increments
  //ICR1 = 0;
  OCR1A = 31250;                         //set compare match register for Xhz increments
  TCCR1B |= (1 << WGM12) | (1 << CS12);  //turn on CTC mode, WGM12 = parallel interrupt mode
  TIMSK1 |= (1 << OCIE1A);               /// enable timer when interrupt reaches OCR1A

  //set timer2 interrupt at Xhz
  TCCR2A = 0;                               //set to 0
  TCCR2B = 0;                               //set to 0
  TCNT2 = 0;                                //initialize counter value to 0
  OCR2A = 36;                                //A gate. on time, set compare match register for Xhz increments
  OCR2B = 200;                              //B gate, BEMF time, wait = 1 on set compare match register for Xhz increments
  TCCR2A |= (1 << WGM21);                   //turn on CTC mode, WGM21 = parallel interrupt mode
  TCCR2B |= (1 << CS21);                    //set prescaler
  TIMSK2 |= (1 << OCIE2A) | (1 << OCIE2B);  // enable interrupt when timer reaches OCR2A or OCR2B
  sei();
  // EICRA = 0;
  // EICRA |= (1 << ISC11) | (1 << ISC10);
  // EIMSK = 0;
  // EIMSK |= (1 << INT1);

  // DDRD = B11111100;
  // DDRB = B00000001;
  // PORTD = B00000000;
  // PORTB = B00000001;

  attachInterrupt(edgevectorpin, BEMFR, RISING);
  interrupts();
  clearstate();  //Set up gates, braking mode

  Serial.println("Starting...");
  //Initial read of throttle on start, disables motor if high
  throttle = 0;
  for (int i = 0; i < 11; i++) {  // exits loop at 200
    throttle = throttle + analogRead(A12);
  }
  throttle = throttle / 10;
  if (throttle > throttleh) {
    throttle = throttleh;
  } else if (throttle < 0) {
    throttle = 0;
  }

  //Ask to press brake and shift to D then apply throttle
  if (throttle >= hipotlimit) {  //Check resolution on A4, if greater than high throttle limit, throttle is high
    hipot = 1;
    cerror = 1;
    statecount = ustatecount;
    //debug();  //throttle position high on start, throttle off for 2sec, try again
  }
  //digitalWrite(cerrorpin, HIGH); //turn on error light, default on
}

//Timer 2 has higher priority then Timer 1
ISR(TIMER1_COMPA_vect) {  //frequency?
  //Output compqare with OCIE1A
  //Registers TCCR1A TCCR1A
  Serial.println("WDT...");
  throttle = 0;
  for (int i = 0; i < 11; i++) {  // exits loop at 200
    throttle = throttle + analogRead(A12);
  }
  if (throttle > throttlel) {
    throttle = throttle / 10;
    if (throttle > throttleh) {
      throttle = throttleh;
    } else if (throttle < 0) {
      throttle = 0;
    }
    // digitalWrite(49, HIGH);
    // digitalWrite(49, LOW);
    OCR1A = map(throttle, throttlel, throttleh, delayl, delayh);
    driveDelay = OCR1A;
    // Serial.println("Throttling...");
    Serial.print("throttle read: ");
    Serial.println(throttle);
    Serial.print("OCR1A: ");
    Serial.println(OCR1A);
    // Serial.print("OCR1A: ");
    // Serial.println(OCR1A);
    // Serial.println("Driving Motor...");
    // Serial.print("");
    // Serial.println("");
    // Serial.print("Duty: ");
    // Serial.println(duty);
    // Serial.print("Delay (ms) ");
    // Serial.println(driveDelay);

    // duty = (1 - (driveDelay / delayl));
    // if (driveDelay > delayl) {
    //   driveDelay = delayl;
    // } else if (driveDelay < delayh) {
    //   driveDelay = delayh;
    // }

    cstate++;
    Serial.print("cstate: ");
    Serial.println(cstate);
    doonce = 0;
    if (cstate == 6) {
      cstate = 0;
    }
    Serial.println("WDT... done");
  } else {  //Throttle is off
    //regen here?
    clearstate();
    OCR1A = 31250;
  }
}

ISR(TIMER2_COMPB_vect) {  //frequency?, B drives gate off time
  //Output compqare with OCIE2B
  //Registers TCCR2B
  if (wait == 0) {
    wait = 1;
    doonce = 0;
  }
}

ISR(TIMER2_COMPA_vect) {  //frequency?, A drives gate on time
                          //Output compqare with OCIE2A
  //Registers TCCR2A
  if (wait == 1) {
    wait = 0;
    doonce = 0;
  }
  //Serial.println(wait);
}

// void loop() {
//   int j = 5000;
//   while (j > 100) {
//     //delayMicroseconds(j);
//     throttleControl();
//     cstate++;
//     cstate %= 6;
//     j = j - 20;
//     // }
//     changeThrottleDelay();
//   }
// }

void throttleControl() {
  if (throttle > throttlel) {  //Prevents forcing duty high even though throttle is not on
    Serial.println("Throttling...");
    //throttle is up
    if (throttle > throttleh) {
      throttle = throttleh;
    }
    Serial.println("Driving Motor...");

    //motorAction();  //drive one phase
    delay(driveDelay);
  }
}

void changeThrottleDelay() {
  //use map for upper throttle limit based on motor temp and current draw
  //call motorphase current
  for (int i = 0; i < 201; i++) {  // exits loop at 200
    throttle = throttle + analogRead(A12);
  }
  throttle = throttle / 200;
  Serial.print("throttle read: ");
  Serial.println(throttle);
  driveDelay = map(throttle, throttlel, throttleh, delayl, delayh);
  duty = (1 - (driveDelay / delayl));
  if (driveDelay > delayl) {
    driveDelay = delayl;
  } else if (driveDelay < delayh) {
    driveDelay = delayh;
  }
  Serial.print("");
  Serial.println("");
  Serial.print("Duty: ");
  Serial.println(duty);
  Serial.print("Delay (ms) ");
  Serial.println(driveDelay);
}

void BEMFR() {
  Serial.println("   >>Rising Edge 49, High");
  digitalWrite(49, HIGH);
  clearstate();
  if (cstate == 0) {
    GateLowerAHigh();
    GateLowerBHigh();
  } else if (cstate == 1) {
    GateLowerAHigh();
    GateLowerCHigh();
  } else if (cstate == 2) {
    GateLowerBHigh();
    GateLowerCHigh();
  } else if (cstate == 3) {
    GateLowerBHigh();
    GateLowerAHigh();
  } else if (cstate == 4) {
    GateLowerCHigh();
    GateLowerAHigh();
  } else if (cstate == 5) {
    GateLowerCHigh();
    GateLowerBHigh();
  }
  cstate++;
  if (cstate == 6) {
    cstate = 0;
  }
  clearstate();
  digitalWrite(49, LOW);
  Serial.println("49, Low");
  doonce = 1;
  wait = 1;
  TCNT2 = 0;
  cli();
}

void edgedetectF() {
  //   HA = digitalRead(A15);
  //   HB = digitalRead(A14);
  //   HC = digitalRead(A13);
  //   digitalWrite(49, HIGH);
  //   Serial.println("Falling Edge 49, High");
  //   digitalWrite(49, LOW);
  //   Serial.println("49, Low");
  //   //noInterrupts();
}

void clearstate() {
  //Turns all fets off
  //HIGHSIDE
  analogWrite(qgateHApin, 0);
  analogWrite(qgateHBpin, 0);
  analogWrite(qgateHCpin, 0);
  //documenting state change
  qgateHAd = LOW;
  qgateHBd = LOW;
  qgateHCd = LOW;

  //LOWSIDE
  analogWrite(qgateLApin, 0);
  analogWrite(qgateLBpin, 0);
  analogWrite(qgateLCpin, 0);
  //document state change
  qgateLAd = LOW;
  qgateLBd = LOW;
  qgateLCd = LOW;
}

//void motorAction() {
void loop() {
  Serial.println("Main loop");
  Serial.print("Loop doonce: ");
  Serial.println(doonce);
  Serial.print("Loop wait: ");
  Serial.println(wait);
  //throttle = analogRead(A12);
  Serial.print("throttle: ");
  Serial.println(throttle);
  Serial.print("throttlel: ");
  Serial.println(throttlel);
  Serial.print("OCR1A: ");
  Serial.println(OCR1A);

  //check gear position
  //Serial.println("Motor Action");
  //Serial.print(doonce);
  if (cstate > 5) {
    cstate = 5;
  } else if (cstate < 0) {
    cstate = 0;
  }
  if (doonce == 0) {
    if (throttle > throttlel) {
      Serial.println("Powering Gates - cstate: ");
      Serial.println(cstate);
      clearstate();
      switch (cstate) {
        case 0:
          if (wait == 0) {
            //PORTD = B10010000;  //PIN 7,4 AB
            GateUpperAHigh();
            GateLowerBHigh();
            doonce = 1;
          } else {
            GateLowerAHigh();
            GateLowerBHigh();
            doonce = 1;
            TCNT2 = 0;
          }
          break;
        case 1:
          if (wait == 0) {
            //PORTD = B10000100;  //PIN 7,2 AC
            GateUpperAHigh();
            GateLowerCHigh();
            doonce = 1;
          } else {
            GateLowerAHigh();
            GateLowerCHigh();
            doonce = 1;
            TCNT2 = 0;
          }
          break;
        case 2:
          if (wait == 0) {
            //PORTD = B00100100;  //PIN 5,2 BC
            GateUpperBHigh();
            clearstate();
            GateLowerCHigh();
            doonce = 1;
          } else {
            GateLowerBHigh();
            GateLowerCHigh();
            doonce = 1;
            TCNT2 = 0;
          }
          break;
        case 3:
          if (wait == 0) {
            //PORTD = B01100000;  //PIN 5,6 BA
            GateUpperBHigh();
            GateLowerAHigh();
            doonce = 1;
          } else {
            GateLowerBHigh();
            GateLowerAHigh();
            doonce = 1;
            TCNT2 = 0;
          }
          break;
        case 4:
          if (wait == 0) {
            //PORTD = B01001000;  //PIN 3,6 CA
            GateUpperCHigh();
            GateLowerAHigh();
            doonce = 1;
          } else {
            GateLowerCHigh();
            GateLowerAHigh();
            doonce = 1;
            TCNT2 = 0;
          }
          break;
        case 5:
          if (wait == 0) {
            //PORTD = B00011000;  //PIN 3,4 CB
            GateUpperCHigh();
            GateLowerBHigh();
            doonce = 1;
          } else {
            GateLowerCHigh();
            GateLowerBHigh();
            doonce = 1;
            TCNT2 = 0;
          }
          break;
      }
      clearstate();
    }
  }
}
void motor1phasecurrent() {
  //phase current check and motor temperature check
  //check motor or gate temperature?
  //analog read for temperature if too high reduce current
  //analog read for current check if too high reduce current
  //change duty cycle
}

//Gate A Upper Lower
void GateUpperAHigh() {
  qgateHAd = HIGH;
  analogWrite(qgateHApin, 255);
  //digitalWrite(qgateHApin, HIGH);
  Serial.print("  GateHA ");
  Serial.print("  ");
  Serial.println(qgateHAd);
}
void GateUpperALow() {
  qgateHAd = LOW;
  analogWrite(qgateHApin, 0);
  //digitalWrite(qgateHApin, LOW);
  Serial.print("  GateHA ");
  Serial.print("  ");
  Serial.println(qgateHAd);
}
void GateLowerAHigh() {
  qgateLAd = HIGH;
  analogWrite(qgateLApin, 255);
  //digitalWrite(qgateLApin, HIGH);
  Serial.print("  GateLA ");
  Serial.print("  ");
  Serial.println(qgateLAd);
}
void GateLowerALow() {
  qgateLAd = LOW;
  analogWrite(qgateLApin, 0);
  //digitalWrite(qgateLApin, LOW);
  Serial.print("  GateLA ");
  Serial.print("  ");
  Serial.println(qgateLAd);
}
//Gate B Upper Lower
void GateUpperBHigh() {
  qgateHBd = HIGH;
  analogWrite(qgateHBpin, 255);
  //digitalWrite(qgateHBpin, HIGH);
  Serial.print("  GateHB ");
  Serial.print("  ");
  Serial.println(qgateHBd);
}
void GateUpperBLow() {
  qgateHBd = LOW;
  analogWrite(qgateHBpin, 0);
  //digitalWrite(qgateHBpin, LOW);
  Serial.print("  GateHB ");
  Serial.print("  ");
  Serial.println(qgateHBd);
}
void GateLowerBHigh() {
  qgateLBd = HIGH;
  analogWrite(qgateLBpin, 255);
  //digitalWrite(qgateLBpin, HIGH);
  Serial.print("  GateLB ");
  Serial.print("  ");
  Serial.println(qgateLBd);
}
void GateLowerBLow() {
  qgateLBd = LOW;
  analogWrite(qgateLBpin, 0);
  //digitalWrite(qgateLBpin, LOW);
  Serial.print("  GateLB ");
  Serial.print("  ");
  Serial.println(qgateLBd);
}
//Gate C Upper Lower
void GateUpperCHigh() {
  qgateHCd = HIGH;
  analogWrite(qgateHCpin, 255);
  //digitalWrite(qgateHCpin, HIGH);
  Serial.print("  GateHC ");
  Serial.print("  ");
  Serial.println(qgateHCd);
}
void GateUpperCLow() {
  qgateHCd = LOW;
  analogWrite(qgateHCpin, 0);
  //digitalWrite(qgateHCpin, LOW);
  Serial.print("  GateHC ");
  Serial.print("  ");
  Serial.println(qgateHCd);
}
void GateLowerCHigh() {
  qgateLCd = HIGH;
  analogWrite(qgateLCpin, 255);
  //digitalWrite(qgateLCpin, HIGH);
  Serial.print("  GateLC ");
  Serial.print("  ");
  Serial.println(qgateLCd);
}
void GateLowerCLow() {
  qgateLCd = LOW;
  analogWrite(qgateLCpin, 0);
  //digitalWrite(qgateLCpin, LOW);
  Serial.print("  GateLC ");
  Serial.print("  ");
  Serial.println(qgateLCd);
}

Thanks for any advice.

You might add a link, BLDC 1900 KV takes me to a high voltage synchronous motor. I did find what I think is your motor.

Sorry about that,
Motor

I've just glanced over the code but it appears that you are setting variables in an ISR and using these outside the ISR. These should be declared as volatile. This is to prevent a compiler optimisation which could result in stale copies of these variables being used.
Care is also required if variables larger than a byte are used in an ISR and also used elsewhere (non atomic operation 8bit CPU).