Help with Nucleo 144 -- no output on pins

Owen might know more about it, but for 6-PWM I believe only certain combinations of Pins will work, because of the way the timers have to be set up to do hardware dead time insertion. The STM32 has certain timer outputs on certain pins, and for 6-PWM they need to come from the same timer?
So when you choose the wrong pins the code tries to configure an illegal timer configuration and the MCU hangs.
Something along those lines.

Hey guys,

The 6pwm mode is very tricky and it is normal that the combinations that you’ve entered do not pass the init. What’s not good is that it doesn’t show any debugging messages, but unfortunately for now we have opted for simplicity and avoided these checks in the hardware specific implementations. That might change in future.

So there are two 6pwm modes we support for stm32 devices:

  • hardware 6pwm - only one timer with fixed (regular and inverted) channels
  • software 6pwm - can be up to 3 timers where it’s important that each pair of channels (low/high, inverted/noninverted) belongs to the same timer. And we do the inversion+dead time in software.

The code checks if all the pins that you provided belong to the same timer. If they do, it will try to configure hardware 6pwm and if not then it will try to configure the software 6pwm.

Now in the constructor of the 6pwm driver you need to provide in order

  • high side pin ch 1
  • low side pin ch 1
  • high side pin ch 2
  • low side pin ch2
  • high side pin ch 3
  • low side pin ch 3
  • enable pin optional

So in order for the init to work either all the pins have to belong to the same timer which has the hardware owl interface. Most of the stm32 boards have it on timer 1 and on pins PA8,9,10 for high side and PB13,14,15 for low side.
That’s why those ones are used in the code. You can find this infor for all the stm32 chips easily.

For the software 6pwm you need to use at least two timers because the timers have no more that 4 channels and you need 6 to run the 6pwm. The only thing you need to be careful is that you specify the high-low side pin pairs that belong to the same timer.

I hope this makes sense.

I am answering my own question, but just got to it because time was not on my side back then and I was quickly and randomly testing a lot of boards.

For STM32F103 the 6PWM alternative channel arrangement on a single timer, with hardware timers is:

BLDCDriver6PWM(PA8, PA7, PA9, PB0, PA10, PB1);

Which solved my problem of freeing the two SPI channels.

Hopefully I’ll save someone in the future the headache of reading the STM32 documentation.

The actual 6PWM alternative pins code controlling open loop with two potentiometers for voltage and velocity.

Using potentiometers instead of serial commander makes the tuning very smooth.

// Open loop motor control example
#include <SimpleFOC.h>


// BLDC motor & driver instance
// BLDCMotor motor = BLDCMotor(pole pair number);
BLDCMotor motor = BLDCMotor(3);
//BLDCDriver6PWM driver = BLDCDriver6PWM(PA8, PB13, PA9, PB14, PA10, PB15, PB12);
BLDCDriver6PWM driver = BLDCDriver6PWM(PA8, PA7, PA9, PB0, PA10, PB1);

//target variable
float target_velocity = 1;
float target_voltage = 1;

int analog_read_A0 = 0;
int analog_read_A1 = 0;

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

void setup() {

  // driver config
  // power supply voltage [V]
  driver.voltage_power_supply = 12;

  // pwm frequency to be used [Hz]
  driver.pwm_frequency = 15000;

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

  // limiting motor movements
  motor.voltage_limit = 12;   // [V]
  motor.velocity_limit = 100; // [rad/s] cca 50rpm
 
  // open loop control config
  motor.controller = MotionControlType::velocity_openloop;

  // init motor hardware
  motor.init();

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

  Serial.begin(115200);
  Serial.println("Motor ready!");
  Serial.println("Set target velocity [rad/s]");
  _delay(1000);
}

void loop() {

  analog_read_A0 = analogRead(PA0);
  analog_read_A1 = analogRead(PA1);

  target_velocity = float(map(analog_read_A0, 0, 4096, 0, 10000))/100.0;

  target_voltage = float(map(analog_read_A1, 0, 4096, 0, 1200))/100.0;

  motor.voltage_limit = target_voltage;

  // open loop velocity movement
  // using motor.voltage_limit and motor.velocity_limit
  motor.move(target_velocity);

  // user communication
  //command.run();
}
1 Like