Teensy + DRV8301

Hello,

I’m new to the forum. First of all I appreciate the time reading my concern.
I’m using a Teensy 4.1 with the BOSTXL-DRV8301 to test the Controller with the Teensy. When I run the motor another interrupt gets activated. I’ve spent several days trying to find why this is happening but I can’t figure out. I attached a screen capture of my results. I did the 3 new prototypes and still get the same results; can anyone point out what I’m missing?

Constraints: I need to use Teensy and I need to measure the RPM from the interrupt specified in my code. I’m open to change the Driver but It needs to handle a lot of RPM/Current (100K RPM, ~30-50A) for an RC application.

Here is my code:

// Open loop motor control example
#include <SimpleFOC.h>
#include <DRV8301.h>


#define rpm_PIN   5

#define INHA 3
#define INLA 2
#define INHB 8 
#define INLB 7
#define INHC 29
#define INLC 28

#define HALLA 6
#define HALLB 9
#define HALLC 14

#define DRV_EN_GATE 17
#define DRV_CS 10
#define DRV_MOSI 11
#define DRV_MISO 12
#define DRV_CLK 13

#define FAULT 24


// Motor instance
BLDCMotor motor = BLDCMotor(4);
BLDCDriver3PWM driver = BLDCDriver3PWM(INHA, INHB, INHC);
// DRV8301 gate_driver = DRV8301(MOSI, MISO, SCLK, CS, EN_GATE, FAULT);
DRV8301 gate_driver = DRV8301(DRV_MOSI, DRV_MISO, DRV_CLK, DRV_CS, DRV_EN_GATE, FAULT);

// hall sensor instance
HallSensor sensor = HallSensor(HALLA, HALLB, HALLC, 4);

// Interrupt routine intialisation
// channel A, B and C callbacks
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();}

void setup()
{

  // initialize encoder sensor hardware
  //sensor.init();
  //sensor.enableInterrupts(doA, doB, doC);
 // link the motor to the sensor
  //motor.linkSensor(&sensor);

  
    // driver config
    // power supply voltage [V]
    driver.voltage_power_supply = 6;
    driver.init();
    gate_driver.begin(PWM_INPUT_MODE_3PWM);
    // link the motor and the driver
    motor.linkDriver(&driver);

    // limiting motor movements
    motor.voltage_limit = 0.2;   // [V]
    motor.velocity_limit = 20; // [rad/s]

    // open loop control config
    motor.controller = MotionControlType::velocity_openloop;

    // init motor hardware
    motor.init();

    Serial.begin(115200);
    Serial.println("Motor ready!");
    _delay(1000);

    
  pinMode(rpm_PIN, INPUT_PULLDOWN);
  attachInterrupt(rpm_PIN, interrupt_BLDC_RPM, FALLING );
  
}

float target_velocity = 0; // [rad/s]

void loop()
{ 
    // open loop velocity movement
    // using motor.voltage_limit and motor.velocity_limit
    motor.move(target_velocity);

    // receive the used commands from serial
    serialReceiveUserCommand();
}

// utility function enabling serial communication with the user to set the target values
// this function can be implemented in serialEvent function as well
void serialReceiveUserCommand()
{
    // a string to hold incoming data
    static String received_chars;

    while (Serial.available())
    {
        // get the new byte:
        char inChar = (char)Serial.read();
        // add it to the string buffer:
        received_chars += inChar;
        // end of user input
        if (inChar == '\n')
        {
            // change the motor target
            target_velocity = received_chars.toFloat();
            Serial.print("Target velocity ");
            Serial.println(target_velocity);

            // reset the command buffer
            received_chars = "";
        }
    }
}

void interrupt_BLDC_RPM()
{
  /*rev_count_t = micros();
  rev_count++;
  //read_sensors();
  Serial.print(rev_count_t);
  Serial.print("\t");
  Serial.println(rev_count);*/
  Serial.println("Test 1");
  
}

Hey @mendez,

I’m not sure what this could be. It might be an issue of noise in the wires triggering the interrupts.

Have you tried different pins?
Have you tried to see if your hall sensor shows a good position when the motor ks moving?

Also are you sure that whatever is connected to your pin 5 is not accidentally triggering the interrupt?
Also are you sure you need the pulldown?

Thanks for your reply @Antun_Skuric
Yes, all of the above. I even try 2 different teensys 4.1. Now, I did try two things:

  1. Today, I changed the “HallSensor.h” and added a Serial.print routine to each interrupt function; and guess what…is always called? Like if the motor is moving but is not. motor.move(0) is set. So why is this happening?

  2. I tested the code below (no library) and the motor and interrupts seems to work fine. Any ideas?

void setup(){
  setupPins();
  
  
  pinMode(rpm_PIN, INPUT_PULLDOWN);
  attachInterrupt(rpm_PIN, interrupt_BLDC_RPM, FALLING );

  analogWrite(INHA, 0);
  analogWrite(INHB, 0);
  analogWrite(INHC, 0);

  attachInterrupt(HALL1, hallISR, CHANGE);
  attachInterrupt(HALL2, hallISR, CHANGE);
  attachInterrupt(HALL3, hallISR, CHANGE);
}

void hallISR()
{
  uint8_t hall = getHalls();
  uint8_t pos = hallOrder[hall];
  if(pos > 6)
  {
    writeState(255);//error
    return;
  }

  pos = (pos + HALL_SHIFT) % 6;
  writeState(pos);
}

void loop(){
  uint32_t maxIsense = 0;
  for(uint32_t i = 0; i < ISENSE_LEN; i++)
  {
    if(isenseHistory[i] > maxIsense)
      maxIsense = isenseHistory[i];
  }
  
  uint32_t curTime = millis();
  if(curTime - lastTime > 50)
  {
    throttle = getThrottle() * 4095;
    hallISR();

    float current = (maxIsense - 468.0) / 40.0;
    Serial.println(current);

    lastTime = curTime;
  }
  
  isenseHistory[isensePos++] = analogRead(ISENSE1);
  isensePos %= ISENSE_LEN;

  serialReceiveUserCommand();
  /*if(digitalRead(FAULT) == LOW)
  {
    throttle = 0;
    SPIwrite(0x02, 0x04);//reset all
    delay(1);
    digitalWriteFast(DRV_EN_GATE, LOW);
    delay(1);
    digitalWriteFast(DRV_EN_GATE, HIGH);
    delay(5);
    Serial.println("Reset gate");
  }

  Serial.println(SPIread(0x00), HEX);
  Serial.println(SPIread(0x01), HEX);
  Serial.println();*/

  delay(1);
}

uint8_t getHalls()
{
  uint8_t hall = (digitalReadFast(HALL3) << 2) | (digitalReadFast(HALL2) << 1) | (digitalReadFast(HALL1) << 0);
  return hall & 0x07;
}

// write the phase to the low side gates
// 1-hot encoding for the phase
// 001 = A, 010 = B, 100 = C
void writeLow(uint8_t phase){
  digitalWriteFast(INLA, (phase&(1<<0)));
  digitalWriteFast(INLB, (phase&(1<<1)));
  digitalWriteFast(INLC, (phase&(1<<2)));
}


void writeState(uint8_t pos)
{
  //Maybe this is necessary? Might solve some problems with bad handshaking?
  writeHigh(0);
  writeLow(0);

  switch(pos){
    case 0://LOW A, HIGH B
      writeLow(0b001);
      writeHigh(0b010);
      break;
    case 1://LOW A, HIGH C
      writeLow(0b001);
      writeHigh(0b100);
      break;
    case 2://LOW B, HIGH C
      writeLow(0b010);
      writeHigh(0b100);
      break;
    case 3://LOW B, HIGH A
      writeLow(0b010);
      writeHigh(0b001);
      break;
    case 4://LOW C, HIGH A
      writeLow(0b100);
      writeHigh(0b001);
      break;
    case 5://LOW C, HIGH B
      writeLow(0b100);
      writeHigh(0b010);
      break;
  }
}

// write the phase to the high side gates
// 1-hot encoding for the phase
// 001 = A, 010 = B, 100 = C
void writeHigh(uint8_t phase){
  switch(phase){
  case 0b001: // Phase A
    analogWrite(INHB, 0);
    analogWrite(INHC, 0);
    analogWrite(INHA, throttle);
    break;
  case 0b010: // Phase B
    analogWrite(INHA, 0);
    analogWrite(INHC, 0);
    analogWrite(INHB, throttle);
    break;
  case 0b100:// Phase C
    analogWrite(INHA, 0);
    analogWrite(INHB, 0);
    analogWrite(INHC, throttle);
    break;
  default://ALL OFF
    analogWrite(INHA, 0);
    analogWrite(INHB, 0);
    analogWrite(INHC, 0);
  }
}


void serialReceiveUserCommand()
{
    // a string to hold incoming data
    static String received_chars;

    while (Serial.available())
    {
        // get the new byte:
        char inChar = (char)Serial.read();
        // add it to the string buffer:
        received_chars += inChar;
        // end of user input
        if (inChar == '\n')
        {
            // change the motor target
            target_velocity = received_chars.toFloat();

            /*if (target_velocity <= 200) 
            { 
              logData = false; 
              //showData();
            }
            else
            { 
              t_out = micros() + logging_rate;
              logData = true;
            }*/
            
            Serial.print("Target velocity ");
            Serial.println(target_velocity);

            // reset the command buffer
            received_chars = "";
        }
    }
}

//Config.h

#define INHA 3
#define INLA 2
#define INHB 8 
#define INLB 7
#define INHC 29
#define INLC 28

#define HALL1 6
#define HALL2 9
#define HALL3 14

#define THROTTLE 15

#define DRV_EN_GATE 17
#define DRV_CS 10
#define DRV_MOSI 11
#define DRV_MISO 12
#define DRV_CLK 13

#define FAULT 24
#define ISENSE1 23

#define LED 13



float target_velocity = 0; // [rad/s]


















#define MAX_THROTTLE  1000
#define MIN_THROTTLE  300

uint16_t SPIread(uint8_t addr);
void SPIwrite(uint8_t addr, uint16_t data);
void setupPins();
float getThrottle();

float getThrottle()
{
  uint16_t rawThrottle = target_velocity;//analogRead(THROTTLE);
  float throttle = (rawThrottle - MIN_THROTTLE) / (float)(MAX_THROTTLE - MIN_THROTTLE);
  
  if(throttle > 1)
    throttle = 1;
  if (throttle < 0)
    throttle = 0;

  return throttle;
}

void setupPins()
{
  //pinMode(LED, OUTPUT);
  pinMode(FAULT, INPUT);
  
  pinMode(INHA, OUTPUT);
  pinMode(INLA, OUTPUT);
  pinMode(INHB, OUTPUT);
  pinMode(INLB, OUTPUT);
  pinMode(INHC, OUTPUT);
  pinMode(INLC, OUTPUT);
  
  pinMode(HALL1, INPUT);
  pinMode(HALL2, INPUT);
  pinMode(HALL3, INPUT);
  
  pinMode(THROTTLE, INPUT);

  pinMode(DRV_EN_GATE, OUTPUT);

  pinMode(DRV_CLK, OUTPUT);
  pinMode(DRV_MOSI, OUTPUT);
  pinMode(DRV_MISO, INPUT);
  pinMode(DRV_CS, OUTPUT);
  digitalWriteFast(DRV_CS, HIGH);

  
  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV128);
  SPI.setDataMode(SPI_MODE1);
  
  pinMode(ISENSE1, INPUT);

  // change the analog write frequency to 8 kHz
  analogWriteFrequency(INHA, 8000);
  analogWriteFrequency(INHB, 8000);
  analogWriteFrequency(INHC, 8000);
  analogWriteResolution(12); // write from 0 to 2^12 = 4095

  Serial.begin(115200);

  digitalWriteFast(DRV_EN_GATE, LOW);
  delay(10);
  digitalWriteFast(DRV_EN_GATE, HIGH);
  delay(10);

  while(SPIread(0x01) != 0x01)
  {
    Serial.println("DRV init fail");
    delay(500);
  }

  //SPI.end();
}

uint16_t SPIread(uint8_t addr)
{
  digitalWrite(DRV_CS, LOW);

  delayMicroseconds(50);
  uint8_t d = 1 << 7;
  d |= addr << 3;
  SPI.transfer(d);
  SPI.transfer(0);

  digitalWrite(DRV_CS, HIGH);
  delayMicroseconds(30);
  digitalWrite(DRV_CS, LOW);
  
  d = SPI.transfer(1<<7);
  uint16_t resp = d << 8;
  resp |= SPI.transfer(0);

  digitalWrite(DRV_CS, HIGH);

  return resp & 0x7FF;
}

void SPIwrite(uint8_t addr, uint16_t data)
{
  digitalWriteFast(DRV_CS, LOW);

  delayMicroseconds(50);
  uint8_t d = data >> 8;
  d |= addr << 3;
  SPI.transfer(d);
  d = data & 0xFF;
  SPI.transfer(d);
    
  digitalWriteFast(DRV_CS, HIGH);