Inrush current problem with our bldc driver board

Hey everyone,
we have developed an stm32 based bldc driver board for running the simpleFoc library, But when the driver is initialized in this line:

  driver.init();

there is a really large inrush current which seems like a dead short, and this does not occur when the board is powered through a series resistance of 2.5R or larger. And this does not occur frequently when powering with 12v. The board was actually intended for running on 36V.
What might be the issue here? What can we do to solve this issue?

Also, there is noise in the power rails when the motor is running we tried adding larger capacitors, LC filter, etc but nothing improves this situation.

we are currently using 6 Inch 250W 24V BLDC motor

The schematic is attached

Firmware running on STM32

#include <SimpleFOC.h>

BLDCMotor motor = BLDCMotor(15);

BLDCDriver6PWM driver = BLDCDriver6PWM(PA_10,PB_1,  PA_9,PB_14,  PA_8,PB_13);
HallSensor sensor = HallSensor(PA_6, PA_7, PB_0, 15);
InlineCurrentSense current_sense  = InlineCurrentSense(0.01, 5.4, PB10, PB2);

// Interrupt routine intialisation
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();}

void setup() { 

  Serial.begin(115200);
  // initialize encoder sensor hardware
  sensor.init();
  sensor.enableInterrupts(doA, doB, doC); 

  motor.linkSensor(&sensor); // link the motor to the sensor

  // init current sense
  current_sense.init();

  // link motor and current sense
  motor.linkCurrentSense(&current_sense);
  driver.init();
  motor.linkDriver(&driver); // link driver

  motor.controller = MotionControlType::velocity;
  motor.torque_controller = TorqueControlType::voltage;

  motor.voltage_limit = 24;
  driver.voltage_power_supply = 24;

  current_sense.skip_align = true;
  motor.init();
  motor.initFOC(0, Direction::CW);
}
void loop() {
  motor.loopFOC();
  motor.target = 3;
  motor.move();
}

@Adharsh_K

Hello and welcome to the forum. It’s always good to see people using the library.

On a more general note, you may find very few people who understand hardware and schematics on a level to help you. Nevertheless, let’s wait and see if anyone could help you.

Meanwhile, could you please try open loop velocity with 12V and limiting the voltage to 3V max, and see if you still get the inrush current?

There are many things that could happen. You are developing and testing a virgin schematics design and you need very sophisticated modeling and analysis to determine the source of the noise. There may not be people able to help at all on this here, but again, let’s see if anyone responds.

Cheers,
Valentine

Hi Valentine,
Thank you for your reply, by limiting the voltage to 3V I assume you meant to set motor.voltage_limit = 3; and setting driver.voltage_power_supply = 12; I tried this but this doesn’t help.

Also, I found that simple foc has got an update to v2.2.2 which has a lot of changes in the src/drivers/hardware_specific/stm32_mcu.cpp file which was initially where I found the issue, so I updated the library, and now am getting this inrush the moment when the board is connected to the power source and this happens even if the motors are unplugged.
Along with that at times while running, the board goes to a weird state where the motor stops spinning and pulls enormous amounts of current.

Hi @Adharsh_K ,

It is true that I made extensive changes to the STM32 driver last release. But these changes have to do with how the PWM timers are initialised, the sequence of initialization steps should not have changed.

I think we don’t explicitly set pins of the driver to be low until late in the initialisation. You could try setting them to output digital low right at the start of the setup, and see if it helps.

But the way you describe it, if the inrush happens immediately on powering up, I suspect it is not to do with the initialisation, but with the pin state on boot up. If you get the inrush even with the motor unconnected, you’re probably having shoot-through, i.e. both mosfets of a half-bridge are open at the same time and you get a short circuit.

The driver you’re using has no shoot-through protection, the channels are independent. So if not careful, you can cause this short-circuit situation by having both inputs high. It seems to have internal pull-downs to prevent this from happening when the inputs aren’t powered, but perhaps they are too weak?
Or perhaps the STM32 starts with some its pins in the high state, this could be checked in the datasheet…

An easy way to test whether the problem is electrical, or caused by software, would be to insert a delay at the beginning of the setup() function. If you add a delay(5000) at the start, and the in-rush problem then occurs only 5s after powering up, then we have a software issue. If the problem still happens right after powering up, it’s nothing to do with the software.

If its a software problem, I will gladly help to find and solve it.

@runger

You are correct, I believe. Probably the drivers are not set correctly during initialization. Four things happen to add to the inrush current.

  1. The bulk capacitors are charged.
  2. The three separate driver internal enables are at random states allowing for shoot-through. You are correct, that’s a really basic cheap driver with no protection.
  3. If the motor is attached, this is a huge hoverboard motor with massive coils which take a lot of current to energize.
  4. If the MCU outputs are at random state, then may be they must be set low by the code.

The result of all four combined is a giant current spike at the beginning.

The IR2101 is a really basic driver without enable and limited shoot-through protection. The user must add extra circuitry to the high/low to set it to High-Z at the very beginning as well as limit the VS at the beginning. In other words, the driver must be initialized in sequence.

The possible solution is 1. external hardware pull downs of the high/low and 2. slowly bring the 12V up by redesigning the circuit and 3. set in the code the output pins low at the very beginning of the setup, and 4. add up a soft-charge circuit to the bulk capacitors.

Ad that point it’s so much work I’d probably redesign the entire schematics with a much better driver.

I’m not sure modifying the SimpleFOC to pull the PWM pins low during init would make a difference because the MCU takes time to boot before pulling the pins, and by then the drivers have already shot through and fried the circuit.

Cheers,
Valentine

Hi @Valentine and @runger, thankyou so much for your replays and suggestions.
As you guys have suggested we have changed the driver to IR2104 half-bridge drivers and the inrush problem is solved. Currently, it doesn’t have that huge peaks at the start.
But the problem of the motor stops rotating randomly is still there.
I’ll explain this better:

  • We have two motor drivers running 2 BLDC hub motors with 24V.
  • Randomly one of the motors will stop rotating.
  • When you try to spin this motor manually after it stops you feel resistance (the same resistance that you feel when the 3phases of the bldc motors are shorted).
  • The stm32 will be still running at this point (haven’t crashed).
  • We can observe a constant PWM on the Mosfet-driver pins.

I think STm32 has default PWM frequency set to 32k in simpleFOC and that might be too much for ir2104. Try setting it 10-20khz.

Ir2101 didn’t work for you because, as @runger mentioned, you had shoot-through. For that IC, you must configure dead zone parameter to avoid that scenario (dead-time must be introduced in the software), while ir2104 introduce the deat-time as a function of the IC (in the hardware).

I also got some weird behavior on my ir2101 board that used to work 6 months before, but I didn’t look much into it and will probably abandon the driver.

Let us know if iyou got it working

Hi @Adharsh_K,

Glad to hear there is some progress! Not sure what could be the problem from your description alone, I’m afraid…
Could you share the current version of your code? Do I understand correctly that the same STM32 MCU is controlling both motors?

Hi, @Aleksandar_Markovic, thank you so much for your reply,
I changed the PWM frequency to 20kHz and 10kHz, but the problem still remains.

@runger
We have a robot with a differential drive system where there are 2 motors + 2 drivers which are controlled by an esp32 as master which sends the velocity over Modbus to both the drivers.
And while running one of the motors just stops randomly.
When I probe the PWM pin I can see a constant pulse.
And this is the code that is currently running on the board:

#include <SimpleFOC.h>
#include <Modbus.h>
#include <ModbusSerial.h>
 
#define VELOCITY_REG  0x2000 
#define DIRECTION_REG 0x3000

// #define SLAVE_ID 10 //left motor
#define SLAVE_ID 11 //right Motor

#define LED PC13    // LED pin
#define EN485 PA4   // MAX485 send or recieve

ModbusSerial mb;

// BLDC motor & driver instance
BLDCMotor motor = BLDCMotor(15);

BLDCDriver3PWM driver = BLDCDriver3PWM(PA10, PA9, PA8,   PB1, PB14, PB13);

// hall sensor instance
HallSensor sensor = HallSensor(PA_6, PA_7, PB_0, 15);

// Interrupt routine intialisation
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();}

void setup() { 

  Serial.begin(115200);

  pinMode(LED, OUTPUT);
  digitalWrite(LED, HIGH);

// Modbus setup
  mb.config(&Serial, 115200,SERIAL_8N1, EN485);
  mb.setSlaveId(SLAVE_ID);
  mb.addHreg(VELOCITY_REG, 0);
  mb.addCoil(DIRECTION_REG, 0);

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

// driver config
  driver.voltage_power_supply = 24;
  driver.voltage_limit = 24;
  driver.pwm_frequency = 10000;

  driver.init();
  motor.linkDriver(&driver); // link driver

// set motion control
 motor.controller = MotionControlType::velocity;
 motor.torque_controller = TorqueControlType::voltage;

  // contoller configuration based on the controll type
  motor.PID_velocity.P = 0.2f;
  motor.PID_velocity.I = 5;
  motor.PID_velocity.D = 0;

  motor.LPF_velocity.Tf = 0.01f;
  motor.P_angle.P = 20;
  motor.velocity_limit = 50;

// initialize motor and start FOC
  motor.init();
  motor.initFOC(0, Direction::CW);
}

void loop() {
  mb.task (); // Modbus task
  motor.loopFOC();// FOC algorithm function

// Set target velocity using modbus reg
  int8_t dir =  mb.Coil(DIRECTION_REG)?1:-1;
  motor.target = dir * (mb.Hreg(VELOCITY_REG) / 10.0f);

  motor.move();
}

Hey,

I don’t really know much about modbus…
Your code looks ok, but also doesn’t really produce any debug output, so its hard to know what is happening.

Of course the problem could be with SimpleFOC, but let me ask the question: how certain are you that the functions mb.task() mb.Coil() and mb.Hreg() are returning?

I note that you have a LED on PC13… how about using it to check? Something like this:

void loop() {
  digitalWrite(LED, 1);
  mb.task (); // Modbus task
  int RegDir = mb.Coil(DIRECTION_REG);
  float RegVel = mb.Hreg(VELOCITY_REG);
  digitalWrite(LED, 0);

  motor.loopFOC();// FOC algorithm function

  // Set target velocity using modbus reg
  int8_t dir =  RegDir?1:-1;
  motor.target = dir * (RegVel / 10.0f);

  motor.move();

In this way the LED should stay on if the mb functions take a long time or don’t return.

Another question:

motor.initFOC(0, Direction::CW);

You’re setting the electrical angle to 0 here - does this mean you’ve pre-aligned the motor to the sensor, so that it lines up in this way?

Hi, @runger Thanks for your hard work on this,
I had a non-blocking blink code inside the loop to test if stm32 was stopping in between and it was not and led was blinking, so I was sure there is no function inside the loop which is blocking or making the stm crash.
And I am sorry that I haven’t provided any debug logs and couldn’t get any debug output because the only serial pins available on the board are used for the Modbus communication.
I also tried the code that you have suggested and the led is blinking as expected.
The time led stays off is 340ÎĽ Seconds and the time it is on is 5ÎĽ Seconds

And yes I set the electrical angle to 0 by pre-aligning the motor and sensor.

@Adharsh_K
If I understood correctly, you are running 2 motors on one MCU.
They “worked” with IR2101 but with a significant inrush current, and one motor would stop randomly.
You swapped IR2101 with IR2104 and the inrush current issue disappeared, but one of the motors still stops randomly (but the motors are turning).

If that is the case, your MCU is feeding the controller the right signals (otherwise, you would see funky motor behavior from the beginning).

Is it always the same motor that stops or does the issue affect both controllers randomly?

If your schematics are correct, your bootstrap capacitor seems rather small (0.1uF) - most of the IR2*** setups I’ve seen had capacitors of at least 1uF (ie Deadtime 6pwm - hacking 10$ 36v/500w bldc controller to run simplefoc - #12 by Aleksandar_Markovic - that board is a piece of junk btw). Did you calculate it to provide the current needed to operate the selected mosfets or is that an arbitrary value that worked for you?

@Aleksandar_Markovic
Actually, one stm32-based motor driver board controls one motor. And totally there are two motors that are controlled separately by 2 two driver boards. (ie one stm32 MCU drives one motor).
Thes two driver boards communicate over Modbus to esp32.

Yes, that’s correct one of the motors stops randomly (but when it stops you can turn that motor manually with your hand; ie the stm is not trying to control that motor anymore)
And it is not the same motor that is stopping.

Also, I forgot to mention that I also increased the bootstrap capacitor to 2.2uF (though it was an arbitrary value that I got from the internet)

If you can move the motor by hand without any resistance, that means that the motor coils have no current flowing which suggests that simpleFoc stopped generating PWMs for it.

Since you used the serial pins for modbus, the only way I see for you to be 100% sure that the smt32 MCU driver is working with the right data is to send the debug data back via modbus and read it remotely where you have a way of doing so.

I have no experience with modbus, so this may sound to you like a stupid question, but are you sure you have RegDir and RegVel available values for each main loop? Is it possible that one loop on one motor controller fails to grab the values and you end up with an arithmetic operation that’s impossible to calculate (no value divided by 10.0f)?

  // Set target velocity using modbus reg
  int8_t dir =  RegDir?1:-1;
  motor.target = dir * (RegVel / 10.0f);

This kind of thing would also be my next guess. It would certainly also be nicer if it were a software problem of some kind rather than an electronics one.

But since you’re taking in values via modbus from an external source, its good practice anyway to check them. I don’t know modbus, so perhaps the library has already solved it for you, but if not then I would definately put in a check to see if the values are in the expected range and make sense in the context of the current program state.
If you have an unexpected value, you could use the LED to indicate it.

I assume you checked it? Because most STM32s have several serial peripherals and several UART pins… Do you program via SWD? The SWO pin (if available) would be another way to get debug output.

Otherwise, getting some telemetry via modbus might be a good idea. If not, its down to the LED :slight_smile:

Smoke signals? :scream:

1 Like

On the MCU you’re using, serial should be on USART2: PB2/PB3, PA14/PA15 and USART1: PA9/PA10, PB6/PB7

According to your schematic above, PB6/PB7 look like they’re free? Did you route them out to headers?

You could add a simple empty value checking and light the led in case you run into it.
It sure would be better to have serial output, but this is just an idea for a quick debug and get info for a specific possible root cause.