SimpleFOC 3PWM cannot support more than 3 motors at a time

Hello,

@runger, @Antun_Skuric

Recent questions made me curious if/how the library can support more than one motor on a 3PWM timer set. I used STM32F767 and wrote a simple open loop for the six timers supporting PWM on a single timer per set.

It appears that any timer combination is limited to only three motors at a time. Adding any fourth motor regardless of the channel halts the MCU within the

driver.init();

step, and thus the whole MCU hangs.

Is there a hard limit on three instances of the driver, or this is some inherent bug just applicable to STM32?

Below is the code I used for Nucleo-144 STM32F767ZI

Any input would be highly appreciated. I can test whatever you discover/change/fix.

Open loop motor control example for six motors.

Please uncomment any motor after the init to trigger the hangup.

Perhaps I’m doing something wrong?

#include <SimpleFOC.h>

BLDCMotor motor1 = BLDCMotor(1);
BLDCMotor motor2 = BLDCMotor(1);
BLDCMotor motor3 = BLDCMotor(1);
BLDCMotor motor4 = BLDCMotor(1);
BLDCMotor motor5 = BLDCMotor(1);
BLDCMotor motor6 = BLDCMotor(1);

BLDCDriver3PWM driver1 = BLDCDriver3PWM(PE9,  PE11, PE13); //T1
BLDCDriver3PWM driver2 = BLDCDriver3PWM(PA5,  PB3,  PB10); //T2
BLDCDriver3PWM driver3 = BLDCDriver3PWM(PA6,  PA7,  PB0);  //T3
BLDCDriver3PWM driver4 = BLDCDriver3PWM(PD12, PD13, PD14); //T4
BLDCDriver3PWM driver5 = BLDCDriver3PWM(PA1,PA2, PA3); //T5 (CH2,CH3,CH4)
BLDCDriver3PWM driver6 = BLDCDriver3PWM(PC6,PC7, PC8); //T8

//target variable
float target_velocity = 2;
float target_voltage = 5;
float maxVelo = 20; //rad/s
float maxVolt = 2;

//int analog_read_A0 = 0;
//int analog_read_A1 = 0;
unsigned long prev = 0;
unsigned long current = 0;
unsigned long threshold = 500;

void setup() {

  driver1.voltage_power_supply = 12;
  driver2.voltage_power_supply = 12;
  driver3.voltage_power_supply = 12;
  driver4.voltage_power_supply = 12;
  driver5.voltage_power_supply = 12;
  driver6.voltage_power_supply = 12;


  driver1.pwm_frequency = 15000;
  driver2.pwm_frequency = 15000;
  driver3.pwm_frequency = 15000;
  driver4.pwm_frequency = 15000;
  driver5.pwm_frequency = 15000;
  driver6.pwm_frequency = 15000;

  //driver.enable_active_high = false; // Reverse logic driver, low is enable

  // driver init creates a hangup for more than 3 drivers
  //driver1.init();
  driver2.init();
  driver3.init();
  driver4.init();
  ///driver5.init();
  driver6.init();

  //motor1.linkDriver(&driver1);
  motor2.linkDriver(&driver2);
  motor3.linkDriver(&driver3);
  motor4.linkDriver(&driver4);
  //motor5.linkDriver(&driver5);
  motor6.linkDriver(&driver6);

  //motor1.voltage_limit = target_voltage;   // [V]
  motor2.voltage_limit = target_voltage;   // [V]
  motor3.voltage_limit = target_voltage;   // [V]
  motor4.voltage_limit = target_voltage;   // [V]
  //motor5.voltage_limit = target_voltage;   // [V]
  motor6.voltage_limit = target_voltage;   // [V]

  //motor1.velocity_limit = target_velocity; // [rad/s] cca 50rpm
  motor2.velocity_limit = target_velocity; // [rad/s] cca 50rpm
  motor3.velocity_limit = target_velocity; // [rad/s] cca 50rpm
  motor4.velocity_limit = target_velocity; // [rad/s] cca 50rpm
  //motor5.velocity_limit = target_velocity; // [rad/s] cca 50rpm
  motor6.velocity_limit = target_velocity; // [rad/s] cca 50rpm

  //motor1.controller = MotionControlType::velocity_openloop;
  motor2.controller = MotionControlType::velocity_openloop;
  motor3.controller = MotionControlType::velocity_openloop;
  motor4.controller = MotionControlType::velocity_openloop;
  //motor5.controller = MotionControlType::velocity_openloop;
  motor6.controller = MotionControlType::velocity_openloop;

  //motor1.init();
  motor2.init();
  motor3.init();
  motor4.init();
  //motor5.init();
  motor6.init();

  _delay(500);
  prev = millis();
  current = millis();
}

void loop() {

   //motor1.voltage_limit = target_voltage;
   motor2.voltage_limit = target_voltage;
   motor3.voltage_limit = target_voltage;
   motor4.voltage_limit = target_voltage;
   //motor5.voltage_limit = target_voltage;
   motor6.voltage_limit = target_voltage;

   //motor1.move(target_velocity);
   motor2.move(target_velocity);
   motor3.move(target_velocity);
   motor4.move(target_velocity);
   //motor5.move(target_velocity);
   motor6.move(target_velocity);

}

Cheers,
Valentine

Upon further investigation, it appears the Arduino optimizer has an inherent problem when compiling with the defaults. When compiling/linking with no optimization, the issue seems to disappear. I will investigate further. Stay tuned.

Upon even further investigation, when compiling/building with no optimization, I was able to make 4 motors run at the same time in open loop. Adding any 5-th motor would create a problem.

Any idea why that could be? You don’t even need to attach motors, PWM on the oscilloscope will show the problem immediately.

Cheers,
Valentine

Hey @Valentine ,

There is a number of things to note here:

  1. Speaking only in terms of the PWM capabilities, i.e. ignoring sensors and other peripherals that might need pins, F767ZI should be able to handle 6 motors in 3-PWM for sure on TIM1, TIM2, TIM3, TIM4, TIM5 and TIM8. I think it can even handle 2 more, by using the 4th PWM channel of all these channels you get another 6 PWM pins. And then you could use another 2 PWM pins each on TIM9 and TIM12, and one more each on TIM10 and TIM11, for another 2 motors, bringing the grand total to 10 motors in 3-PWM mode. TIM13 and TIM14 would have 1 more PWM channel each, but just 2 more it’s not enough. The LPTIM, TIM6 and TIM7 don’t support PWM.

  2. the clock configuration of the F767 is already fairly complex, so I would not necessarily rely on default arduino getting it right.

  3. personally I don’t think I’ve ever tested using TIM10 or TIM13 for example… YMMV…

  4. I fear we have introduced a bug recently with the timer synchronization in relation to multiple motors. In a recent test I did on F412, the order I initialised the drivers had an impact on whether it works or not. You may be better off with version 2.3.2 of SimpleFOC when testing multiple motor setups on STM32.

  5. Please set -DSIMPLEFOC_STM32_DEBUG and include the serial output from the driver initialisation. It should tell you exactly what went wrong with the timer pin configuration…

  6. To use more than 4 motors in 3-PWM or more than 2 motor in 6-PWM, please set
    -DSIMPLEFOC_STM32_MAX_PINTIMERSUSED=20
    (or even more).

    This is the max number of PWM pins you can use with SimpleFOC across all motors. The default is 12, which explains why you can only initialize 4 motors at the moment.

1 Like

@runger:

Awesome, I’ll try everything and come back to report!

I got this really crazy idea to check how many simultaneous 3pwm motors can be handled with a single H series MCU. I’m in the process of re-creating a really simple 3PWM test board using the infamous IFX007 to string them up and tryout.

Mhhwwaaaahahahahahahahaha!

But seriously, I’ll only try hall sensors voltage/velocity, else dealing with multiple SPI and sensoring multiple motors would genuinely be a crazy idea. As a proof of concept though closed loop hall sensor setup should give a good idea of the baseline and could be done on a weekend. Plenty of hall sensor pins on that board.

Cheers,
Valentine