STM32f446RE, hall sensors two motor, one MCU control problem

Hello everyone!

First post on the forum so any advice is welcome.
I am trying to use a STM32f446re to control two BLDC’s (chinese hoverboard) motors with hall sensors.
I already succeeded in doing this on a STM32f103c8 MCU and this seemed to work good enough, but now I have been having trouble running both motors at the same time.
I have been switching pins around all week but the problems are:

  • one works and the other one doesn’t depending on which one gets declared first.
  • and a side problem: one of the motors usually, when using different pins then in my current code, does not want to turn by itself, it only turns in jerky motions when assisted.

If anyone has some good tips(also regarding the post itself, I am open to suggestions)

Here is the code I use:

#include <Arduino.h>
#include <SimpleFOC.h>
#include <HardwareSerial.h>

//HardwareSerial Serial(PB11, PB10); G = B11 W = B10
//HardwareSerial Serial(D0, D1);

#define pp 15

//connections with drv8302
#define EN_GATE PA8 //red
#define M_PWM PB15 //orange
#define M_OC PB6 //purple
#define OC_ADJ PB13 //brown

#define EN_GATE2 PA12 //red
#define M_PWM2 PA11 //orange
#define M_OC2 PB12 //purple
#define OC_ADJ2 PB13 //brown

//motor pins to drv8302
#define INH_A PA15
#define INH_B PB2
#define INH_C PB10

#define INH_A2 PC6 //PWM_A
#define INH_B2 PB5 //PWM_B
#define INH_C2 PC8 //PWM_C

//define hall pins A to C YGB !one of the connectors is wrong order!
#define hallA PA0
#define hallB PA1
#define hallC PA4

#define hallA2 PB4
#define hallB2 PC1
#define hallC2 PC0

//#define interval 5000

//motor
BLDCMotor motor = BLDCMotor(pp);
BLDCMotor motor2 = BLDCMotor(pp);

//driver
BLDCDriver3PWM driver = BLDCDriver3PWM(INH_A, INH_B, INH_C, EN_GATE);
BLDCDriver3PWM driver2 = BLDCDriver3PWM(INH_A2, INH_B2, INH_C2, EN_GATE2);

//hallsensor setup
HallSensor sensor = HallSensor(hallA, hallB , hallC , pp);

  void doA(){sensor.handleA();}
  void doB(){sensor.handleB();}
  void doC(){sensor.handleC();}

HallSensor sensor2 = HallSensor(hallA2, hallB2 , hallC2 , pp);
//create pointers to channel interrupt functions#define hallA2 A2
  void doA2(){sensor2.handleA();}
  void doB2(){sensor2.handleB();}
  void doC2(){sensor2.handleC();}



String inString = "";

void readString();

void setup() {

  Serial.begin(115200);
  SimpleFOCDebug::enable(&Serial);
  
  delay(5000);

  sensor.pullup = Pullup::USE_EXTERN; //2k2 ohm
  sensor2.pullup = Pullup::USE_EXTERN; //2k2 ohm

  pinMode(hallA,INPUT);
  pinMode(hallB,INPUT);
  pinMode(hallC,INPUT);

  pinMode(hallA2,INPUT);
  pinMode(hallB2,INPUT);
  pinMode(hallC2,INPUT);

  //motor1
  pinMode(M_OC,OUTPUT);
  digitalWrite(M_OC,LOW);

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

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

  //motor2
  pinMode(M_OC2,OUTPUT);
  digitalWrite(M_OC2,LOW);

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

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


  driver.voltage_power_supply = 30;
  driver.voltage_limit = 30;  
  driver.init();
  motor.linkDriver(&driver);
  motor.voltage_sensor_align = 1; //3

  driver2.voltage_power_supply = 30;
  driver2.voltage_limit = 30;
  driver2.init();
  motor2.linkDriver(&driver2);
  motor2.voltage_sensor_align = 1; 

  motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
  motor2.foc_modulation = FOCModulationType::SpaceVectorPWM;

  motor.controller = MotionControlType::velocity;
  motor2.controller = MotionControlType::velocity;

  motor.PID_velocity.P = 1; //0.2 //1
  motor.PID_velocity.I = 3.5; //20 //3.5 //6  
  // motor.PID_velocity.D = 0.0001; //0.0001
  motor.LPF_velocity.Tf = 0.2; //0.2

  motor2.PID_velocity.P = 1; //0.2
  motor2.PID_velocity.I = 3.5; //20
  // motor2.PID_velocity.D = 0.0001; //0.001
  motor2.LPF_velocity.Tf = 0.2; //0,1

  motor.voltage_limit = 2;//30
  motor.velocity_limit = 30;

  motor2.voltage_limit = 2;
  motor2.velocity_limit = 30;

  //monitoring port
  motor.useMonitoring(Serial);
  motor.monitor_variables = _MON_VEL; //| _MON_VOLT_Q

  motor2.useMonitoring(Serial); 
  motor2.monitor_variables =   _MON_VEL;  //| _MON_VOLT_Q 

  driver.pwm_frequency = 20000; //20000
  driver2.pwm_frequency = 20000;

  motor.PID_velocity.output_ramp = 60;
  motor2.PID_velocity.output_ramp = 60;//1000

  sensor.init();
  delay(100);
  sensor.enableInterrupts(doA,doB,doC);
  delay(100);
  motor.linkSensor(&sensor);
  delay(100);
  motor.init();
  delay(100);
  motor.initFOC();
  delay(100);
  motor.disable();

  _delay(1000);

  sensor2.init();
  delay(100);
  sensor2.enableInterrupts(doA2,doB2,doC2);
  delay(100); 
  motor2.linkSensor(&sensor2);
  delay(100);
  motor2.init();
  delay(100);
  motor2.initFOC();
  delay(100);
  motor.enable();
  _delay(1000);


}

int i = 1;
float target1 = 0.0;
float target2 = 0.0;

void loop() {  
  // FOC algorithm function
  readString();
  
  motor.loopFOC();
  motor.move(target1); 
  motor2.loopFOC();   
  motor2.move(target2);

  //motor.monitor();
  //motor2.monitor2();

}

void readString() {
   if (Serial.available()) {

    inString = Serial.readStringUntil('\n');

    if (inString.length() > 0) {
      int v1Index = inString.indexOf(",");
      if (v1Index != -1 ) {
         String v1Value = inString.substring(0 , v1Index);
         String v2Value = inString.substring(v1Index + 1);
         target1 = v1Value.toFloat();
         target2 = v2Value.toFloat();

    }
  }
}
}


Hi,
AFAIK, simpleFOC doesn’t work with two hall sensor definitions (yet)?
You could try to strip down your code to sensors_only and rotate motors by hand, to monitor if that works.

It should work with 2 hall sensors.
What is not supported on stm32 is 2 low side current sensing.

Well, I forgot to mention it, But I tried this and similarly to running the motors only the sensor declared last works properly. But I think @Candas1 is correct, I have seen some example code on here that is supposed to work with two hall sensors. Could it be a pin problem? I am not that familiar with these boards, I read that all pins can do interrupts but maybe there is some sort of conflict?

Hey @Peteh,

Did I understand correctly, 2x motors + 2x Hall sensors setup worked on f1 chip but not on f4 chip?

Hi @Antun_Skuric

I just came back from some testing and found the solution! It was a interrupt pin problem that had to do with there only being 16 external interrupt lines that were being multiplexed.

So in short for people with the same problem: External interrupt pins are grouped together by number for example: PA0, PB0 and PC0 all belong to the same group (external interrupt line) and if you use PA0 as an external interrupt you cannot use PB0, PC0,… as external interrupt pins anymore. You can still use them for other purposes! It is explained in more detail on this website I found: https://embedded-lab.com/blog/stm32-external-interrupt/

Thank you everyone for the fast responses!

I updated my code if anyone is interested in the pins I used:

#include <Arduino.h>
#include <SimpleFOC.h>
#include <HardwareSerial.h>

//HardwareSerial Serial(PB11, PB10); G = B11 W = B10
//HardwareSerial Serial(D0, D1);

#define pp 15

//connections with drv8302
#define M_OC PC4 //purple
#define M_PWM PB13 //orange
#define OC_ADJ PB14 //brown
#define EN_GATE PB15 //red

#define M_OC2 PB1 //purple
#define M_PWM2 PB12 //orange
#define OC_ADJ2 PA11 //brown
#define EN_GATE2 PA12 //red

//motor pins to drv8302
#define INH_A PA15
#define INH_B PB2
#define INH_C PB10

#define INH_A2 PC6 //PWM_A
#define INH_B2 PB5 //PWM_B
#define INH_C2 PC8 //PWM_C

//define hall pins A to C YGB beware of multiplexing of interrup lines
#define hallA PA9
#define hallB PA8
#define hallC PA10

#define hallA2 PB4
#define hallB2 PC7
#define hallC2 PB6

//#define interval 5000

//motor
BLDCMotor motor = BLDCMotor(pp);
BLDCMotor motor2 = BLDCMotor(pp);

//driver
BLDCDriver3PWM driver = BLDCDriver3PWM(INH_A, INH_B, INH_C, EN_GATE);
BLDCDriver3PWM driver2 = BLDCDriver3PWM(INH_A2, INH_B2, INH_C2, EN_GATE2);

//hallsensor setup
HallSensor sensor = HallSensor(hallA, hallB , hallC , pp);

  void doA(){sensor.handleA();}
  void doB(){sensor.handleB();}
  void doC(){sensor.handleC();}

HallSensor sensor2 = HallSensor(hallA2, hallB2 , hallC2 , pp);
//create pointers to channel interrupt functions#define hallA2 A2
  void doA2(){sensor2.handleA();}
  void doB2(){sensor2.handleB();}
  void doC2(){sensor2.handleC();}



String inString = "";

void readString();

void setup() {

  Serial.begin(115200);
  SimpleFOCDebug::enable(&Serial);
  
  delay(5000);

  sensor.pullup = Pullup::USE_EXTERN; //2k2 ohm
  sensor2.pullup = Pullup::USE_EXTERN; //2k2 ohm

  // pinMode(hallA,INPUT);
  // pinMode(hallB,INPUT);
  // pinMode(hallC,INPUT);

  // pinMode(hallA2,INPUT);
  // pinMode(hallB2,INPUT);
  // pinMode(hallC2,INPUT);

  //motor1
  pinMode(M_OC,OUTPUT);
  digitalWrite(M_OC,LOW);

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

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

  //motor2
  pinMode(M_OC2,OUTPUT);
  digitalWrite(M_OC2,LOW);

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

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


  driver.voltage_power_supply = 30;
  driver.voltage_limit = 30;  
  driver.init();
  motor.linkDriver(&driver);
  motor.voltage_sensor_align = 1; //3

  driver2.voltage_power_supply = 30;
  driver2.voltage_limit = 30;
  driver2.init();
  motor2.linkDriver(&driver2);
  motor2.voltage_sensor_align = 1; 

  motor.foc_modulation = FOCModulationType::SpaceVectorPWM;
  motor2.foc_modulation = FOCModulationType::SpaceVectorPWM;

  motor.controller = MotionControlType::velocity;
  motor2.controller = MotionControlType::velocity;

  motor.PID_velocity.P = 1; //0.2 //1
  motor.PID_velocity.I = 3.5; //20 //3.5 //6  
  // motor.PID_velocity.D = 0.0001; //0.0001
  motor.LPF_velocity.Tf = 0.2; //0.2

  motor2.PID_velocity.P = 1; //0.2
  motor2.PID_velocity.I = 3.5; //20
  // motor2.PID_velocity.D = 0.0001; //0.001
  motor2.LPF_velocity.Tf = 0.2; //0,1

  motor.voltage_limit = 2;//30
  motor.velocity_limit = 30;

  motor2.voltage_limit = 2;
  motor2.velocity_limit = 30;

  //monitoring port
  motor.useMonitoring(Serial);
  motor.monitor_variables = _MON_VEL; //| _MON_VOLT_Q

  motor2.useMonitoring(Serial); 
  motor2.monitor_variables =   _MON_VEL;  //| _MON_VOLT_Q 

  driver.pwm_frequency = 20000; //20000
  driver2.pwm_frequency = 20000;

  motor.PID_velocity.output_ramp = 60;
  motor2.PID_velocity.output_ramp = 60;//1000

  sensor.init();
  delay(100);
  sensor.enableInterrupts(doA,doB,doC);
  delay(100);
  motor.linkSensor(&sensor);
  delay(100);
  motor.init();
  delay(100);
  motor.initFOC();
  delay(100);
  motor.disable();

  _delay(1000);

  sensor2.init();
  delay(100);
  sensor2.enableInterrupts(doA2,doB2,doC2);
  delay(100); 
  motor2.linkSensor(&sensor2);
  delay(100);
  motor2.init();
  delay(100);
  motor2.initFOC();
  delay(100);
  motor.enable();
  _delay(1000);


}

int i = 1;
float target1 = 0.0;
float target2 = 0.0;

void loop() {  
  // FOC algorithm function
  readString();
  
  motor.loopFOC();
  motor.move(target1); 
  motor2.loopFOC();   
  motor2.move(target2);

  motor.monitor();
  //motor2.monitor2();

}

void readString() {
   if (Serial.available()) {

    inString = Serial.readStringUntil('\n');

    if (inString.length() > 0) {
      int v1Index = inString.indexOf(",");
      if (v1Index != -1 ) {
         String v1Value = inString.substring(0 , v1Index);
         String v2Value = inString.substring(v1Index + 1);
         target1 = v1Value.toFloat();
         target2 = v2Value.toFloat();

    }
  }
}
}


2 Likes

Nice!
Thanks for this, this is gonna help a lot of people!

1 Like