Custom DRV8301 board help - motor makes noise, doesn't spin

I made some custom PCBs using the DRV8301 chips from TI. I’m trying to use them to spin a bldc with 7 pole pairs. I’m using the AS5600 sensor and 6 PWM control. My code is just a slightly modified velocity control example:

`/**
 * 
 * Velocity motion control example
 * Steps:
 * 1) Configure the motor and magnetic sensor 
 * 2) Run the code
 * 3) Set the target velocity (in radians per second) from serial terminal
 * 
 * 
 * By using the serial terminal set the velocity value you want to motor to obtain
 *
 */
#include <SimpleFOC.h>

// magnetic sensor instance - SPI
//MagneticSensorSPI sensor = MagneticSensorSPI(AS5147_SPI, 10);
// magnetic sensor instance - MagneticSensorI2C
MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);
// magnetic sensor instance - analog output
// MagneticSensorAnalog sensor = MagneticSensorAnalog(A1, 14, 1020);

// BLDC motor & driver instance
BLDCMotor motor = BLDCMotor(7);
BLDCDriver6PWM driver = BLDCDriver6PWM(10, 9, 6, 5, 11, 3);
// Stepper motor & driver instance
//StepperMotor motor = StepperMotor(50);
//StepperDriver4PWM driver = StepperDriver4PWM(9, 5, 10, 6,  8);

void setup() {
 
  // initialise magnetic sensor hardware
  sensor.init();
  // link the motor to the sensor
  motor.linkSensor(&sensor);

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

  // set motion control loop to be used
  motor.controller = ControlType::velocity;

  // contoller configuration 
  // default parameters in defaults.h

  // velocity PI controller parameters
  motor.PID_velocity.P = 0.2;
  motor.PID_velocity.I = 20;
  motor.PID_velocity.D = 0;
  // default voltage_power_supply
  motor.voltage_limit = 12;
  // jerk control using voltage voltage ramp
  // default value is 300 volts per sec  ~ 0.3V per millisecond
  motor.PID_velocity.output_ramp = 1000;
  
  // velocity low pass filtering
  // default 5ms - try different values to see what is the best. 
  // the lower the less filtered
  motor.LPF_velocity.Tf = 0.01;

  // use monitoring with serial 
  Serial.begin(115200);
  // comment out if not needed
  motor.useMonitoring(Serial);

  // initialize motor
  motor.init();
  // align sensor and start FOC
  motor.initFOC();

  Serial.println("Motor ready.");
  Serial.println("Set the target velocity using serial terminal:");
  _delay(1000);
}

// velocity set point variable
float target_velocity = 0;

void loop() {
  // main FOC algorithm function
  // the faster you run this function the better
  // Arduino UNO loop  ~1kHz
  // Bluepill loop ~10kHz 
  motor.loopFOC();

  // Motion control function
  // velocity, position or voltage (defined in motor.controller)
  // this function can be run at much lower frequency than loopFOC() function
  // You can also use motor.move() and set the motor.target in the code
  motor.move(target_velocity);

  // function intended to be used with serial plotter to monitor motor variables
  // significantly slowing the execution down!!!!
  // motor.monitor();
  
  // user communication
  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 = "";
    }
  }
}

When I power the board and driver on, it makes noises, jiggles around a bit, then stops and makes weird noises again. The serial monitor shows me the following:

MOT: Monitor enabled!
MOT: Initialise variables.
MOT: Enable driver.
MOT: Align sensor.
MOT: natural_direction==CCW
MOT: Absolute zero align.
MOT: Success!
MOT: Motor ready.
Motor ready.

Set the target velocity using serial terminal:
Target velocity: 1.00

Since this is a custom board, I would expect this to be a hardware issue, however when I looked at the inputs and outputs with my scope, it seems to be fine (e. g. when INH_A is high, output A is HIGH, when INL_A is high, A is low). Any help would be greatly appreciated :slight_smile:

Hi @slasowy,
is it your motor moves, have you tried 10 rd/s, or 100 rd/s, otherwise try this:

motor.PID_velocity.P = 0.02;
motor.PID_velocity.I = 0.02;
motor.PID_velocity.D = 0;

Then increase a little bit “velocity.I” up to 0.2 in a first time, and tell me.

Thanks! I’ll try it, however I think there is a problem with my board, as it starts behaving unpredictably under load - I may not have enough capacitance or a too long path to ground on one of the regulators, so maybe it’s voltage can fall under the under voltage protection of the IC… It may have worked before because the battery was more charged. Welp, back to troubleshooting :slight_smile:

I think I know what it is! During operation PVDD, the voltage from the battery, falls to only 7.5V… I think I really need to charge the battery.
EDIT: No, it don’t think it’s that, according to the datasheet the PVDD undervoltage protection should kick in at 6 V. I’ll charge the battery anyway, it’s possible that such a low voltage can lead to the other regulator not functioning properly.

Hey, some ideas you could look at:

What is the resistance of the motor you’re using? A drop in voltage from 12 to 7.5V could indicate a large current draw - perhaps it isn’t the under-voltage but rather the over-current protection that is activating? If your motor’s winding resistance is low, you need to set a voltage_limit to prevent too much current being drawn.

Can you see the output of the nFault pin of the DRV8301? This should be low if the protections kick in…

Otherwise, if you leave the motor off, and just read the sensor values (print them to Serial for example), is it working correctly? Do the sensor values change as you turn the motor with your hand?

Hey @slasowy,

In your code I dont see any DRV8301 configuration?
It should have an spi interface to configure it. Are you setting it in some manner or am I missing somthing?

If you use a new version of the library (v2.1) it would give us a bit more info in the monitor so we could be able to tell you a bit more what is going on from the code perspective.

Did you check that your sensor work?
Did you check that the driver works in open-loop mode?

Thanks so much for the help! Did a bit of measuring, I don’t think the overcurrent protection is kicking in, as the nFAULT goes low, only pulsing high periodically, and the nOCTW pin is high most of the time, only pulsing low rarely for some reason… The winding resistance of the motor is really small, doesn’t even show up on my multimeter. I’m using one of these: https://www.amazon.in/Robotbanao-Outrunner-Brushless-Controller-Multi-copter/dp/B07D4MB55V. The sensor works fine, the driver works fine if not under load or under a small load. I charged the battery and added more bulk capacitance and PVDD seems to be more stable (doesn’t fall under 11V now) and the motor behaves differently now - vibrates a lot, and I think it might be spinning, I’m not sure it may just be vibrating really fast, I’ll have to look at the encoder data. It also gets really hot, so I think I need to limit the voltage much more. I’ll run more tests, see if nFAULT still trips if so then I’ll probably have to look at the SPI registers to see what’s going on. I have to wait for the motor to cool down now, don’t want to melt my windings :slight_smile:
EDIT: This is getting kind of hard to test, because motor heats up so much so quickly… I can only have it on for a couple of seconds and it becomes too hot to touch. I have my voltage limit in software set to only 2V and some really low PID gains (P of 0.2, I of 0.2). I also decreased the output ramp to 300, didn’t really change that much. It would be really helpful to have a video of the proper startup sequence, would love it if anyone would be able to link one.

Hiya - yeah, be careful! I’m going to guess this motor’s winding resistance is less than 1Ω. You can check it with the resistance mode of your multimeter.

nFault is active-low… so if it gets pulled to GND it is indicating a fault state. If you’re getting GND asserted lots of the time then this could certainly be the source of your strange motor behaviour. nOCTW is also active low. The behaviour you describe could be one of the protections kicking in, and timing out or being reset?

Other motors of this type I can find that list their winding resistance list it at around 0.1Ω- which means at 2V the current would quickly rise to about 20A - can your FETs handle that?

But the DRV8301 is a fairly complex driver, and depending on how you set the different options like OC_MODE the behaviour can be different.
I would try setting the voltage limit to 0.2 or 0.1V and see if this helps.

Which MCU are you using? Which modes are set on the DRV8301, or is everything on default?

I am pretty sure it’s some sort of protection kicking in - I’m not sure which one, though. Everything in the SPI registers is set to the default values, but I think I’m going to try and communicate with the driver, see what fault is exactly occurring. My FETs should be able to handle 20A easily, they don’t even really get warm during operation. I was using just an arduino uno, but I’m going to switch to an STM32F103C today, because I want 6PWM control and SPI at the same time now.

I have doubts about it being the OC tripping, because on the default setting it only reports on the nOCTW, not the nFAULT.

Anyways, I’ll look at the SPI status registers when the fault occurs, and hope it gives us some more info.

Ok, I started using this library: DRV8301 board support to set the driver to the 3PWM mode and set the current limit to 0.2V and the (slightly modified) open loop control example works great :grin: Here is that code:
// Open loop motor control example
#include <SimpleFOC.h>
#include <DRV8301.h>

// Motor instance
// Motor instance
BLDCMotor motor = BLDCMotor(7);
BLDCDriver3PWM driver = BLDCDriver3PWM(6, 5, 3);
// DRV8301 gate_driver = DRV8301(MOSI, MISO, SCLK, CS, EN_GATE, FAULT);
DRV8301 gate_driver = DRV8301(11, 12, 13, 9, 8, 7);

void setup()
{
// driver config
// power supply voltage [V]
driver.voltage_power_supply = 12;
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.5;   // [V]
motor.velocity_limit = 100; // [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);

}

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 = "";
    }
}

}

Still trying to get the angle control working, I updated the library and now it sometimes shows me thisMOT: Monitor enabled! MOT: Init MOT: Enable driver. MOT: Align sensor. MOT: sensor_direction==CW MOT: PP check: fail - estimated pp:4095.9885 MOT: Zero elec. angle: 4.33 MOT: No current sense. MOT: Ready. Motor ready.
and seems to do and ok sensor align and then starts weirdly vibrating, sometimes it works. May or may not be a shoddy sensor connection, not sure what pp is.
Here is the angle control code:
/**

Position/angle motion control example
Steps:

  1. Configure the motor and magnetic sensor
  2. Run the code
  3. Set the target angle (in radians) from serial terminal

*/
#include <SimpleFOC.h>
#include <DRV8301.h>

// Motor instance
// Motor instance
BLDCMotor motor = BLDCMotor(7);
BLDCDriver3PWM driver = BLDCDriver3PWM(6, 5, 3);
DRV8301 gate_driver = DRV8301(11, 12, 13, 9, 8, 7);
MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);

void setup() {

// initialise magnetic sensor hardware
sensor.init();
// link the motor to the sensor
motor.linkSensor(&sensor);

// driver config
// power supply voltage [V]
driver.voltage_power_supply = 12;
driver.init();
gate_driver.begin(PWM_INPUT_MODE_3PWM);

// link the motor and the driver
motor.linkDriver(&driver);

// choose FOC modulation (optional)
motor.foc_modulation = FOCModulationType::SpaceVectorPWM;

// set motion control loop to be used
motor.controller = MotionControlType::angle;

// contoller configuration
// default parameters in defaults.h

// velocity PI controller parameters
motor.PID_velocity.P = 0.2;
motor.PID_velocity.I = 20;
motor.PID_velocity.D = 0;
// maximal voltage to be set to the motor
motor.voltage_limit = 0.2;

// velocity low pass filtering time constant
// the lower the less filtered
motor.LPF_velocity.Tf = 0.01;

// angle P controller
motor.P_angle.P = 20;
// maximal velocity of the position control
motor.velocity_limit = 20;

// use monitoring with serial
Serial.begin(115200);
// comment out if not needed
motor.useMonitoring(Serial);

// initialize motor
motor.init();
// align sensor and start FOC
motor.initFOC();

Serial.println(“Motor ready.”);
Serial.println(“Set the target angle using serial terminal:”);
_delay(1000);
}

// angle set point variable
float target_angle = 0;

void loop() {

// main FOC algorithm function
// the faster you run this function the better
// Arduino UNO loop ~1kHz
// Bluepill loop ~10kHz
motor.loopFOC();

// Motion control function
// velocity, position or voltage (defined in motor.controller)
// this function can be run at much lower frequency than loopFOC() function
// You can also use motor.move() and set the motor.target in the code
motor.move(target_angle);

// function intended to be used with serial plotter to monitor motor variables
// significantly slowing the execution down!!!
//motor.monitor();

// user communication
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_angle = received_chars.toFloat();
  Serial.print("Target angle: ");
  Serial.println(target_angle);

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

}
}
Anyways, thank you all so much for the help, this community is just so lovely :slight_smile:

2 Likes

Hi @slasowy,

Because your motor works in open loop but not in closed loop mode: Check your magnet of the AS5600!

Lots of the AliExpress variants are delivered with the wrong one… I also had issues once with working open loop code and that it would not move with weird shakes in closed loop mode thanks to the wrong magnet…

Maybe it is something that you already checked, but I did not saw someone mentioning it in this chat.

Good luck with your problem!

Thanks for the suggestion, I did the test with a compass, and it behaved really strangely, I changed the magnet to one from another sensor, and the compass behaves great :slight_smile:. However, after I installed it on the motor, it does the sensor aligns great, it gives me an ok on the PP check. After the align the motor just starts vibrating, doesn’t respond to any commands. Would someone mind looking over my code?
/**

Position/angle motion control example
Steps:

  1. Configure the motor and magnetic sensor
  2. Run the code
  3. Set the target angle (in radians) from serial terminal

*/
#include <SimpleFOC.h>
#include <DRV8301.h>

// Motor instance
// Motor instance
BLDCMotor motor = BLDCMotor(7);
BLDCDriver3PWM driver = BLDCDriver3PWM(6, 5, 3);
DRV8301 gate_driver = DRV8301(11, 12, 13, 9, 8, 7);
MagneticSensorI2C sensor = MagneticSensorI2C(AS5600_I2C);

void setup() {

// initialise magnetic sensor hardware
sensor.init();
// link the motor to the sensor
motor.linkSensor(&sensor);

// driver config
// power supply voltage [V]
driver.voltage_power_supply = 12;
driver.init();
gate_driver.begin(PWM_INPUT_MODE_3PWM);

// link the motor and the driver
motor.linkDriver(&driver);

// choose FOC modulation (optional)
motor.foc_modulation = FOCModulationType::SpaceVectorPWM;

// set motion control loop to be used
motor.controller = MotionControlType::angle;

// contoller configuration
// default parameters in defaults.h

// velocity PI controller parameters
motor.PID_velocity.P = 0.2;
motor.PID_velocity.I = 0.2;
motor.PID_velocity.D = 0;
// maximal voltage to be set to the motor
motor.voltage_limit = 0.2;

// velocity low pass filtering time constant
// the lower the less filtered
motor.LPF_velocity.Tf = 0.01;

// angle P controller
motor.P_angle.P = 20;
// maximal velocity of the position control
motor.velocity_limit = 20;

// use monitoring with serial
Serial.begin(115200);
// comment out if not needed
motor.useMonitoring(Serial);

// initialize motor
motor.init();
// align sensor and start FOC
motor.initFOC();

Serial.println(“Motor ready.”);
Serial.println(“Set the target angle using serial terminal:”);
_delay(1000);
}

// angle set point variable
float target_angle = 0;

void loop() {

// main FOC algorithm function
// the faster you run this function the better
// Arduino UNO loop ~1kHz
// Bluepill loop ~10kHz
motor.loopFOC();

// Motion control function
// velocity, position or voltage (defined in motor.controller)
// this function can be run at much lower frequency than loopFOC() function
// You can also use motor.move() and set the motor.target in the code
motor.move(target_angle);

// function intended to be used with serial plotter to monitor motor variables
// significantly slowing the execution down!!!
//motor.monitor();

// user communication
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_angle = received_chars.toFloat();
  Serial.print("Target angle: ");
  Serial.println(target_angle);

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

}
}
Thanks!

The code looks ok to me… maybe someone else can see a mistake I’ve missed?

The magnet is also something I would have suggested, many people describing your behaviour turns out its the wrong magnet.

Other times its been incorrect number of pole-pairs - you’re sure your motor has 7?

PWM frequency can be an issue - which microcontroller are you using? Although this problem would also manifest in open-loop mode.

Do you have a higher-ohm motor you could use for testing? This would not get so hot so quickly…
Do you have access to an oscilloscope and/or logic analyser? Might be necessary in this case to get deeper into the problem.

If open-loop is working well, but closed loop is not, then that is indicative of sensor problems…

Your PID - the I value is kind of low - perhaps set them to the defaults until things are working?

Personally, I like to use closed loop velocity mode before trying position mode. I find that position mode generally works once (closed loop) velocity mode is working, and I set my target-value to some reasonable speed, say 2rad/s, as the initial value. That way, the moment the main loop starts, the motor starts to spin (or it doesn’t). That saves me a lot of time setting speeds when testing. I also don’t bother with the monitoring or serialReceiveUserCommand until things are working - its just another source of error.

Yeah, it stopped working even on open loop for some reason. It just throws a low nFAULT every couple of seconds and stops working for a couple of milliseconds, throwing all my SPI settings out so I have reset them - I have no clue what is causing this, and honestly I’m getting really frustrated with these boards. All the voltages are stable, this behavior also occurs when I disconnect the motor, so no OC tripping. I honestly have no clue what is happening :frowning:. The driver just “decides” to just stop working sometimes… really frustrating. Any ideas?

Wow, that sounds very frustrating! I feel for you, we’ve all been there… sometimes a night’s sleep really helps too :expressionless:

If you were planning to open source your design or don’t mind sharing, then you could post the schematics (or link to) and the people here could take a look and see if we can spot any circuit level problems… several members of the forum have designed motor shields/ESC boards so maybe they can see something…
Intermittent failures and strange behaviour like that sounds like it could be electrical too, brownouts or similar…

If it was working in open loop before, and now isn’t, this probably means:

  • the board or setup has somehow physically changed - something became disconnected, something got damaged on the PCB, you changed the wiring and forgot to change it back, battery is empty whereas before it was full, more devices are connected, etc…
  • the software is not exactly the same as in the previous test - something got changed and didn’t get completely reversed, or there is some compilation issue or library issue, etc…

I really think to debug a PCB for motor control you almost need to have an oscilloscope to see what’s going on. Modern ones often double up as logic analysers, but if you think the problem is on the digital side, and don’t already have one, this will be the best EUR10 you invest in a long time:
https://www.amazon.de/AZDelivery-Logic-Analyzer-Compatible-including/dp/B01MUFRHQ2/ref=sr_1_2_sspa
Don’t be put off by their cheapness - they work fine, and together with the Open Source software “Pulseview” you can debug things like SPI, I2C, and track the state of nFAULT and nOCTP.

The reason I ask about your MCU is because looking at your code you’re using a bunch of pins and default SPI/I2C configurations. Depending on the microcontroller and board wiring there could be a conflict? If the conflict were between I2C and the commutation, for example, this would explain why it works/worked in open-loop but not in closed…

Hi @slasowy,

Very frustrating that it also stopped working open loop… I do not have suggestions for solving that…

For the closed loop part, I do have another suggestion: Did you connect the DIR port of the AS5600 to ground or VCC? Theoretically it is not necessary for SimpleFOC but from the datasheets, it is recommended to connect it. One day, my DIR cable became loose and my motor behaved the same way as yours. Also my self-balancing cart could not balance anymore this week because I did not connect the DIR port which resulted in I2C errors……

Thanks, I’ll try it, but for now I have to get it working in open loop again :slight_smile:. I’m charging the battery again, we’ll see if that was maybe a problem. @runger I don’t think it’s a problem with the software - I’ve ran test with just setting the SPI registers and an analogWrite to the 3 phase pins, and it stills throws the same error. I have a hunch that it’s a brownout issue, I’m not sure. I have an oscilloscope, really came in handy debugging, and the logic analyzer you linked looks really cool, I might get one! Anyways, I’ll charge the battery again (it discharged back to 3.7V, which should be fine, but you never know), run a test and come back to you :slight_smile:

Alright, so I charged the battery and it still doesn’t work :frowning:. It’s quite strange, because none of the status fault registers seem to be set… Maybe I shorted something out without noticing? I don’t know, it seems to me that wouldn’t cause it to work just for a while… All of the regulator voltages seem fine, there’s no OC, all the FETs seem to work…

If you can share your schematic maybe someone can check if everything seems to be properly connected.

Sure! Here you go:


It’s basically just the typical application from the datasheet.
I measured DVDD (internal 3.3V supply) to be only 2.7V during operation maybe that’s a problem? The datasheet says that DVDD undervoltage causes the driver to report on the nFAULT pin, but not on the SPI register, which would match my experience.