NUCLEO STM32H755ZI-Q - Configuration

Hi,

Long-time reader (as a guest), first-time poster!

First of all, congratulations on the awesome work you’ve been sharing here. I’ve learned a lot by going through your posts, code examples, hardware solutions, and everything else I could find!

I’ve been extensively testing your project on various MCUs (Arduino UNO, RP2340, ESP32, and Nucleo 144) along with different drivers (Deng Dual FOC, MKS Dual FOC V3.2, SimpleFOC Mini, and SimpleFOC Shield). Everything has gone smoothly using Arduino and PlatformIO IDE.

I’ve also tested the different branches kindly provided by @runger for the exotic boards I have—thanks for that!

Today I decided to level up my project and started working with a NUCLEO-H755ZI-Q paired with two SimpleFOC Shields, but it’s giving me a bit of a headache. I’m confident I’ve set up the hardware correctly (at least for the Shields), and I haven’t modified the Nucleo board yet.

However, I’m encountering two main issues and was wondering if anyone might have some insights:

1. After successfully flashing the board multiple times with working scripts (including blinking LEDs and serial communication), my board suddenly locked up, preventing me from reflashing any previously working scripts. I suspect it might be related to the issue discussed here:

https://www.stm32duino.com/viewtopic.php?t=2550

Before diving into creating a new configuration file for the H755ZI-Q—which doesn’t seem to exist yet in STM32Duino—I was wondering if anyone here has already faced this issue?

2. At some point, I managed to flash the board with the SimpleFOC open-loop position control, which previously worked fine on other MCUs. However, the driver wouldn’t supply power to the motor. I suspect it’s related to pin configuration. Since I’ve noticed a few posts from members who worked with STM32H7 MCUs, I thought I would ask if anyone had suggestions or specific points I should verify.

I can provide my code, though it doesn’t differ from what’s available on GitHub.

Thanks again for your great work. I’ll continue investigating while looking forward to your feedback! :slight_smile:

Hi @GregOb , welcome to SimpleFOC!

Working with the H7 dual core series is a little tricky, but I have a working setup and can share details with you. I hope that will solve your first issue.

You’ll need the dev branch of the library from GitHub where I have recently merged the H7 support to our STM32 driver.
That should solve your second issue.

Do you have a GitHub user?

Hi @runger, Thanks for your quick answer!

I do have a GitHub account.

I think I’ve checked one of your STM32 HAL branches but I’m unsure it was the right one! I’m more than happy to look at your work and let you know how it went for me.

For now, I’ll probably use only one Core from it as I’m planning to use the second for other things.

As soon as problem 1 is solved I will get back to the dev branch and try to make it work.
I also figured that the pinouts proposed by my Arduino-compatible pins from the Nucleo board do not offer enough PWM pins with a shared timer.
I may have only 1 shield able to work from being plugged in the Nucleo. The second shield will have to be wired to the proper Nucleo’s pins.

I will keep you posted on how things are going!

Hey,

At this point I’ve merged that HAL branch into the dev branch of the library, so that is the one I would recommend for now: GitHub - simplefoc/Arduino-FOC at dev

If you’re interested you can DM me your GitHub user and I can invite you to some repositories in which I was testing the H757ZI setup.

I’ve just sent you an email. Looking forward to check your repo.

So it seems that after reflashing the board using STM32CubeIDE example, and turning the CM4 to sleep, the board is back up and running !

I have decided to re apply SimpleFOC using dev branch and given example.

#include <SimpleFOC.h>

#define SERIAL_PORT Serial3  // Use USART3 (ST-Link Virtual COM)


// BLDC motor & driver instance
// BLDCMotor motor = BLDCMotor(pole pair number);
BLDCMotor motor = BLDCMotor(7);
// BLDCDriver3PWM driver = BLDCDriver3PWM(pwmA, pwmB, pwmC, Enable(optional));
BLDCDriver3PWM driver = BLDCDriver3PWM(6, 5, 3, 4);

//target variable
float target_position = 0;

// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target_position, cmd); }
void doLimit(char* cmd) { command.scalar(&motor.voltage_limit, cmd); }
void doVelocity(char* cmd) { command.scalar(&motor.velocity_limit, cmd); }

void setup() {

  // use monitoring with serial 
  Serial.begin(115200);
  // enable more verbose output for debugging
  // comment out if not needed
  SimpleFOCDebug::enable(&Serial);

  // driver config
  // power supply voltage [V]
  driver.voltage_power_supply = 12;
  // limit the maximal dc voltage the driver can set
  // as a protection measure for the low-resistance motors
  // this value is fixed on startup
  driver.voltage_limit = 6;
  if(!driver.init()){
    Serial.println("Driver init failed!");
    return;
  }
  // link the motor and the driver
  motor.linkDriver(&driver);

  // limiting motor movements
  // limit the voltage to be set to the motor
  // start very low for high resistance motors
  // currnet = voltage/resistance, so try to be well under 1Amp
  motor.voltage_limit = 3;   // [V]
  // limit/set the velocity of the transition in between 
  // target angles
  motor.velocity_limit = 5; // [rad/s] cca 50rpm
  // open loop control config
  motor.controller = MotionControlType::angle_openloop;

  // init motor hardware
  if(!motor.init()){
    Serial.println("Motor init failed!");
    return;
  }

  // add target command T
  command.add('T', doTarget, "target angle");
  command.add('L', doLimit, "voltage limit");
  command.add('V', doLimit, "movement velocity");

  Serial.println("Motor ready!");
  Serial.println("Set target position [rad]");
  _delay(1000);
}

void loop() {
  // open  loop angle movements
  // using motor.voltage_limit and motor.velocity_limit
  // angles can be positive or negative, negative angles correspond to opposite motor direction
  motor.move(target_position);
  
  // user communication
  command.run();
}

And I’m getting this as an output :

STM32-DRV: Timer resolution set to: 4800
STM32-DRV: Configured TIM1_CH1
STM32-DRV: Configured TIM1_CH2
STM32-DRV: Configured TIM1_CH3
STM32-DRV: Synchronising 1 timers
MOT: Init
MOT: Enable driver.
Motor ready!
Set target position [rad]
5.000
0.000

But that doesn’t make the motor rotate… It’s just shaking.
I’m pretty sure that my wiring is fine so I’m running out of idea :frowning:

I will keep you posted if things are changing.

I’m not sure whare Time resolution is doing to the code so I may start to investigate with this.

Hey, I finally got to it and sent you GitHub invites… I replied to your DM.

Thanks a lot. I had a quick look, but I will dig deeper tonight. :slight_smile:
At first, it seems you are assigning pins based on their name, which differs from what STM32Duino library is doing.

I may try adding the H755ZI-Q board configuration to that library so other programmers can benefit from it. Is there anything I should take into consideration while doing it?

It’s quite a complicated board to add because of the dual core and the power supply options. I guess you could assume the default config for power, and only enable the one of the two cores… that would be easier, and would be the same level of support as the other dual core nucleos board definitions.

To add it properly is still quite a bit of work. I think there’s one or two tickets related to that in the stm32duino GitHub issues.

I think the main problem is that Arduino itself uses the H7 in the Portenta and Nicla lines, but they base their framework support on the (now-defunct) mbed framework.
Within that framework there is a notion of dual core support and a few primitives for working with both cores.
But in stm32duino there is currently no concept of dual core, no way to link two binaries for the two cores into a single firmware elf file, no abstractions for communication between the cores, etc
So to do a “proper” job of it is still a big task.

Hi all,

Thanks again @runger for your help, as the code you provided was really helpful ! :slight_smile:

It’s been a while, as I had to focus on other tasks while waiting for the new motors to arrive. I finally got my hands on them, but I’m now facing some new issues.

I successfully tested your branch with the open-loop tests, but I’m struggling with the closed-loop ones.

Here’s the output I get during the initialization phase:

T:0.00 A:0.00 V:0.00 D:0.00 %:0.0 I:
Sensor angle: 0.00
Init current sense.
MOT: Monitor enabled!
MOT: Init
MOT: Enable driver.
MOT: Align sensor.
MOT: sensor_direction==CCW
MOT: PP check: OK!
MOT: Zero elec. angle: 3.14
MOT: Align current sense.
MOT: Success: 1
MOT: Ready.
Motor ready.
Set the target angle using serial terminal:
T:0.00 A:1.35 V:0.00 D:0.00 %:0.0 I:
Sensor angle: -1.35
T:0.00 A:1.35 V:0.00 D:0.00 %:0.0 I:
Sensor angle: -1.35
T:0.00 A:1.35 V:0.00 D:0.00 %:0.0 I:
Sensor angle: -1.35
T:0.00 A:1.35 V:0.00 D:0.00 %:0.0 I:
Sensor angle: -1.35
T:0.00 A:1.35 V:0.00 D:0.00 %:0.0 I:
Sensor angle: -1.35
T:0.00 A:1.35 V:0.00 D:0.00 %:0.0 I:
Sensor angle: -1.35
2.000
T:2.00 A:1.65 V:0.05 D:1.95 %:97.5 I:
Sensor angle: -1.65
T:2.00 A:1.65 V:0.00 D:2.00 %:100.0 I:
Sensor angle: -1.65
T:2.00 A:1.65 V:0.00 D:2.00 %:100.0 I:
Sensor angle: -1.65
T:2.00 A:1.65 V:0.00 D:2.00 %:100.0 I:
Sensor angle: -1.65

And this is from the code below:

#include <Arduino.h>
#include "./hw_config.h"
#include "SimpleFOC.h"
#include "SimpleFOCDrivers.h"
#include "encoders/stm32hwencoder/STM32HWEncoder.h"
#include "encoders/as5047/MagneticSensorAS5047.h"

#define PRODUCT_NAME "SH0002 brushless motor driver"
#define FIRMWARE_VERSION "1.0.0 (2024/11)"

// ==================== MOTOR & DRIVER ====================

// Example motor with 7 pole pairs
BLDCMotor motor(7, 2.30, 312.5, 0.00045);

// 3-PWM driver pins
//   PWM_A=PC6, PWM_B=PC7, PWM_C=PC8, enable pin=PC11 (adjust as needed)
BLDCDriver3PWM driver(PC6, PC7, PC8, PC11);

//7——Pole Pairs
HallSensor sensor = HallSensor(PB15, PB12, PA15, 7);// U V W Pole Pairs
void doA(){sensor.handleA();}
void doB(){sensor.handleB();}
void doC(){sensor.handleC();}

// inline current sensor instance
// ACS712-05B has the resolution of 0.185mV per Amp
InlineCurrentSense current_sense = InlineCurrentSense(185.0f, PA3, PC0);

// angle set point variable
float target_angle = 0;

uint32_t loop_ts, loop_ts2;

// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target_angle, cmd); }

void setup() {

  // initialize 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 = 24;
  driver.init();
  // link the motor and the driver
  motor.linkDriver(&driver);
  
  // link current sense and the driver
  analogReadResolution(12);
  current_sense.linkDriver(&driver);

  // aligning voltage [V]
  motor.voltage_sensor_align = 8;
  // index search velocity [rad/s]
  motor.velocity_index_search = 6;

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

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

  // velocity PI controller parameters
  motor.PID_velocity.P = 0.2f;
  motor.PID_velocity.I = 2;
  motor.PID_velocity.D = 0;
  // default voltage_power_supply
  motor.current_limit = 1.5;
  // 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 time constant
  motor.LPF_velocity.Tf = 0.1f;

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

  Serial.println(F("Init current sense."));
  // current sense init and linking
  current_sense.init();
  motor.linkCurrentSense(&current_sense);

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

  // initialize motor
  motor.init();

  // invert phase b gain
  current_sense.gain_b *=-1;
  // skip alignment
  current_sense.skip_align = true;
  // align sensor and start FOC
  motor.initFOC();

  // set the inital target value
  motor.target = 2;

  // add target command T
  command.add('T', doTarget, "target angle");

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

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);



  long now = micros();
  if (now < loop_ts) // handle overflow
    loop_ts = loop_ts2 = 0;

  if (now - loop_ts2 > 1000000) {
    Serial.print("T:");
    Serial.print(target_angle, 2);
    Serial.print(" A:");
    Serial.print(motor.shaft_angle, 2);
    Serial.print(" V:");
    Serial.print(motor.shaft_velocity, 2);
    Serial.print(" D:");
    float diff = fabs(motor.shaft_velocity-target_angle);
    Serial.print(diff, 2);
    Serial.print(" %:");
    float per = target_angle!=0.0f?diff/target_angle*100.0f:0.0f;
    Serial.print(per, 1);
    Serial.print(" I:");
    Serial.println();
    Serial.print("Sensor angle: ");
    Serial.println(sensor.getAngle());
    loop_ts2 = now;
  }
  

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

  // user communication
  command.run();
}

For some reason, the motor doesn’t respond when setting T to a specific value.
The current drawn by the motor increases slightly, and it seems like it’s trying to hold its position, but it’s not rotating—although it does rotate properly during initFOC().

Do you have any idea what might be causing this?

Hi,

The initFOC and pole pair check are passing, so that’s a good sign.

Hall Sensors can be hard to work with due to their low resolution compared to other sensors. You may have some improvement using our SmoothingSensor, depending on the use case.

Your code looks ok and you say open loop mode works… have you tested the simpler torque mode before trying velocit mode? If torque mode works but velocity mode does not it’s probably down to tuning. You may also want to try without current sensing before adding it. One step at a time :slight_smile:

Oh and actually looking at the code again I don’t agree with the way the timer variables are handled in the loop. You’re comparing against one of them but resetting the other one, I don’t think it can work. Probably you’re printing too much for that reason, which will also affect performance.

Thanks @runger! I will check that ASAP and get back to you with updates.
I will also try to sort out the tuning by getting more information from the supplier. Hopefully, that will help too.

I’m pretty sure that I tested the torque control and that it was functioning well, as I read in another post that it was the first thing to check in this kind of scenario. I will redo it just to be sure!

You are right to point out how timers are handled!
I may have played too much with my code without noticing the issues that slipped in.

So yes, I can confirm that torque control is doing perfectly fine !

I have fixed the printing part but I’m still stuck with the velocity and position control modes.

I will try to implement the smoothingSensor function and see how it goes with it ! :slight_smile:

So smoothing is added (or at least I think), as shown below:

#include <Arduino.h>
#include "./hw_config.h"
#include "SimpleFOC.h"
#include "SimpleFOCDrivers.h"
#include "encoders/stm32hwencoder/STM32HWEncoder.h"
#include "encoders/as5047/MagneticSensorAS5047.h"
#include "encoders/smoothing/SmoothingSensor.h"

#define PRODUCT_NAME "SH0002 brushless motor driver"
#define FIRMWARE_VERSION "1.0.0 (2024/11)"

// ==================== MOTOR & DRIVER ====================

// Example motor with 7 pole pairs
BLDCMotor motor(7, 2.30, 312.5, 0.00045);

// 3-PWM driver pins
//   PWM_A=PC6, PWM_B=PC7, PWM_C=PC8, enable pin=PC11 (adjust as needed)
BLDCDriver3PWM driver(PC6, PC7, PC8, PC11);

//7——Pole Pairs
HallSensor sensor = HallSensor(PB15, PB12, PA15, 7);// U V W Pole Pairs
SmoothingSensor smooth = SmoothingSensor(sensor, motor);

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

// inline current sensor instance
// ACS712-05B has the resolution of 0.185mV per Amp
//InlineCurrentSense current_sense = InlineCurrentSense(185.0f, PA3, PC0);

// angle set point variable
float target = 2;

uint32_t loop_ts;

// instantiate the commander
Commander command = Commander(Serial);
void doTarget(char* cmd) { command.scalar(&target, cmd); }

void setup() {
  pinMode(PC6, INPUT_PULLUP);  // LED_BUILTIN
  pinMode(PB11, INPUT_PULLUP);
  pinMode(PA3, INPUT_PULLUP);

  // initialize sensor hardware
  sensor.init();
  sensor.enableInterrupts(doA, doB, doC);

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

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

  // aligning voltage [V]
  motor.voltage_sensor_align = 6;
  // index search velocity [rad/s]
  motor.velocity_index_search = 6;



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

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

  // velocity PI controller parameters
  motor.PID_velocity.P = 0.4f;
  motor.PID_velocity.I = 4;
  motor.PID_velocity.D = 0;
  // default voltage_power_supply
  motor.current_limit = 1;
  // 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 time constant
  motor.LPF_velocity.Tf = 0.01f;

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

  Serial.println(F("Init current sense."));
  // current sense init and linking
  //current_sense.init();
  //motor.linkCurrentSense(&current_sense);

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

  // initialize motor
  motor.init();

  // invert phase b gain
  //current_sense.gain_b *=-1;
  // skip alignment
  //current_sense.skip_align = true;

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

  // set the inital target value
  motor.target = 2;

  // add target command T
  command.add('T', doTarget, "target angle");

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

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);

  long now = micros();
  
  if (now - loop_ts > 1000000) {
    Serial.print("T:");
    Serial.print(target, 2);
    Serial.print(" A:");
    Serial.print(motor.shaft_angle, 2);
    Serial.print(" V:");
    Serial.print(motor.shaft_velocity, 2);
    Serial.print(" D:");
    float diff = fabs(motor.shaft_velocity-target);
    Serial.print(diff, 2);
    Serial.print(" %:");
    float per = target!=0.0f?diff/target*100.0f:0.0f;
    Serial.print(per, 1);
    Serial.print(" I:");
    Serial.println();
    loop_ts = now;
  }
  

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

  // user communication
  command.run();
}

Still no movement from velocity but a weird thing happened in torque mode.
I force the shaft to move and after couple of rotation it started rotating (and vibrating).
Putting the torque back to 0 and to a value again got me in the same state:
Rotate the shaft by hand, forcing on the motor and getting the shaft to rotate.

Could it be related to the shaft not moving in velocity mode ?
And so to the tunning ?

Anyways I will try to tune my settings and see how it goes.

Update:
I put the motor in velocity mode, increased the target slowly and tried to help the shaft rotate to initiate the movement and I’m finnaly getting something !

100.000
T:100.00 A:715.24 V:0.00 D:100.00 %:100.0 I:
T:100.00 A:715.24 V:0.00 D:100.00 %:100.0 I:
T:100.00 A:823.99 V:100.54 D:0.54 %:0.5 I:
T:100.00 A:949.51 V:99.74 D:0.26 %:0.3 I:
T:100.00 A:1075.02 V:100.05 D:0.05 %:0.0 I:
T:100.00 A:1200.62 V:99.96 D:0.04 %:0.0 I:
T:100.00 A:1326.03 V:99.89 D:0.11 %:0.1 I:
T:100.00 A:1451.58 V:100.26 D:0.26 %:0.3 I:
T:100.00 A:1577.06 V:100.09 D:0.09 %:0.1 I:
T:100.00 A:1702.61 V:99.59 D:0.41 %:0.4 I:
T:100.00 A:1828.11 V:99.86 D:0.14 %:0.1 I:
T:100.00 A:1953.76 V:99.82 D:0.18 %:0.2 I:
T:100.00 A:2079.33 V:99.78 D:0.22 %:0.2 I:
T:100.00 A:2204.77 V:99.83 D:0.17 %:0.2 I:
T:100.00 A:2330.36 V:100.05 D:0.05 %:0.0 I:
T:100.00 A:2455.83 V:100.11 D:0.11 %:0.1 I:
T:100.00 A:2581.48 V:99.96 D:0.04 %:0.0 I:
T:100.00 A:2707.11 V:99.82 D:0.18 %:0.2 I:
T:100.00 A:2832.74 V:99.73 D:0.27 %:0.3 I:
T:100.00 A:2958.37 V:99.62 D:0.38 %:0.4 I:
T:100.00 A:3084.00 V:99.52 D:0.48 %:0.5 I:
T:100.00 A:3209.59 V:99.61 D:0.39 %:0.4 I:

It does vibrate a lot though, which suggests that the tunning is off but it’s at least a beginning !

I will continue my investigation :slight_smile:

You’re using current sense, so you need to tune those PID values also. At the moment you don’t set them in your code so you’re using default values.

And you have all the motor parameters set, these also can require tuning.

So I’d say at this point it does look like it’s down to the tuning. It can be easier to add the parameters one at a time and tune them one by one rather than all at once.

In the last code snippet I provided, I disabled the current sensing functions. Did I forget something or am I unaware of an important detail?

The motor parameters are based on the specifications provided in the motor datasheet. Are you suggesting that I should tweak these as well?

Sure! I will try to tidy things up by starting with one parameter and observing the results before adding others.

  1. Step 1: motor.PID_velocity.P
  2. Step 2: motor.PID_velocity.I
  3. Step 3: motor.PID_velocity.output_ramp
  4. Step 4: motor.LPF_velocity.Tf

Is this the right approach?

I forgot to talk about something quite important that might be related to the issue I’m facing.

The program often fails to detect movement when doing the initFOC() and specifically the BLDCMotor::alignSensor(). In these cases, I usually have to slightly rotate the motor shaft by hand to another position and restart the board for it to do a correct init. I feel that the init works a lot better in some specific shaft positions. What could explain that? Hall sensor position issues?
Is my zero electrical angle correct? What is usually the value obtained for a similar setup?

UPDATE:

I finnaly figured what was happening !

Interrupt callbacks didn’t work for PB15 Pin (Hall A) so the angle return was always wrong even though the hall sensor state returned was correct when read.

PB13 didn’t work either so I ended up using PB5, which si giving me much better results !

Now it’s all about tweeking the settings to make it as smooth as possible.

Thanks a lot @runger for your help and I hope that this thread will help others :slight_smile: