Teensy 4.x support for 6pwm

Hi guys,

Finally, 6pwm drivers will be supported on Teensy 4.x boards. The code is in the dev branch and will be officially included in the next release.

For now simplefoc will support the 6PWM using the FlexTimers and its channels A and B. Similar could be done using QuadTimers but it would add a lot of complexity, so no support for now, but if there is an interest in such a solution we’d be happy to try it out. :smiley:

Supported pinouts

Teensy4.x 6pwm driver generates a 6pwm signal using FlexTimers.
Each high-low pair of the 6pwm has to be A and B channels of the same FlexTimer and to the same submodule .

You can find more info about the available FlexTimer pwm pins per teensy 4.x board in the teensy documentation:
https://www.pjrc.com/teensy/td_pulse.html

List of available Teensy 4.1 pins which can be used for the 6pwm driver with their respective submodules and channels:

FlexTimer submodule channel pin number
FlexPWM4 2 A pin 2
FlexPWM4 2 B pin 3
FlexPWM1 3 B pin 7
FlexPWM1 3 A pin 8
FlexPWM2 2 A pin 6
FlexPWM2 2 B pin 9
FlexPWM3 1 B pin 28
FlexPWM3 1 A pin 29
FlexPWM2 3 A pin 36
FlexPWM2 3 B pin 37
FlexPWM1 1 B pin 42
FlexPWM1 1 A pin 43
FlexPWM1 0 B pin 44
FlexPWM1 0 A pin 45
FlexPWM1 2 B pin 46
FlexPWM1 2 A pin 47

IMPORTANT

Make sure that you connect your driver’s high side input to the Teensy pin which corresponds to the channel A and the low-side to the channel B!

For each hiigh-low combination of your driver make sure to choose the pins which belong to the same t FlexTimer and the same submodule.

Example code

There is an example code in the library examples folder that you can use to start off your applications.

// 6pwm standalone example code for Teensy 4.x boards
// 
// Teensy4.x 6pwm driver generates a 6pwm signal using FlexTimers and it doesn't support the QuadTimers
//  - Each high-low pair of the 6pwm has to be A and B channels of the same FlexTimer and to the same submodule 
// 
// List of available teensy 4.1 pins with their respective submodules and channels 
// FlexPWM(timer number)_(submodule)_(channel) 
// FlexPWM4_2_A   pin 2
// FlexPWM4_2_B   pin 3  
// FlexPWM1_3_B   pin 7  
// FlexPWM1_3_A   pin 8  
// FlexPWM2_2_A   pin 6  
// FlexPWM2_2_B   pin 9  
// FlexPWM3_1_B   pin 28  
// FlexPWM3_1_A   pin 29  
// FlexPWM2_3_A   pin 36  
// FlexPWM2_3_B   pin 37  
#include <SimpleFOC.h>


// BLDC driver instance
// make sure to provide channel A for high side and channel B for low side
// BLDCDriver6PWM(pwmA_H, pwmA_L, pwmB_H,pwmB_L, pwmC_H, pwmC_L)
// Example configuration 
BLDCDriver6PWM driver = BLDCDriver6PWM(2,3, 6,9, 8,7);

void setup() {
  Serial.begin(115200);
  // Enable debugging
  // Driver init will show debugging output
  SimpleFOCDebug::enable(&Serial);

  // pwm frequency to be used [Hz]
  driver.pwm_frequency = 30000;
  // dead zone percentage of the duty cycle - default 0.02 - 2%
  driver.dead_zone=0.02;
  // power supply voltage [V]
  driver.voltage_power_supply = 12;
  // Max DC voltage allowed - default voltage_power_supply
  driver.voltage_limit = 12;
  
  // driver init
  driver.init();
  
  // enable driver
  driver.enable();
  
  _delay(1000);
}

void loop() {
  // setting pwm
  // phase A: 3V
  // phase B: 6V
  // phase C: 5V
  driver.setPwm(3,6,5);
}

Quick tip

We suggest using the SimpleFOCDebug in order to get a bit more information about the driver initialization. The debugging interface will output more information about the driver init procedure in the Serial and will let you know if some of the pins that you’ve chosen are not suitable for 6PWM.

In order to enable it add these lines before calling the driver.init().

  Serial.begin(115200);
  // Enable debugging
  // Driver init will show debugging output
  SimpleFOCDebug::enable(&Serial);

As usual, the code has been tested and it outputs proper center-aligned PWM signal as well as correct dead-zone and pwm frequency provided by the driver.dead_zone and driver.pwm_frequency.

Let us know what you think.

1 Like

And a simple open loop velocity code example with the 6pwm driver can be found in the library examples as well.

Here is the code:

// 6pwm openloop velocity example
// 
// Teensy4.x 6pwm driver generates a 6pwm signal using FlexTimers and it doesn't support the QuadTimers
//  - Each high-low pair of the 6pwm has to be A and B channels of the same FlexTimer and to the same submodule 
// 
// List of available teensy 4.1 pins with their respective submodules and channels 
// FlexPWM(timer number)_(submodule)_(channel) 
// FlexPWM4_2_A   pin 2
// FlexPWM4_2_B   pin 3  
// FlexPWM1_3_B   pin 7  
// FlexPWM1_3_A   pin 8  
// FlexPWM2_2_A   pin 6  
// FlexPWM2_2_B   pin 9  
// FlexPWM3_1_B   pin 28  
// FlexPWM3_1_A   pin 29  
// FlexPWM2_3_A   pin 36  
// FlexPWM2_3_B   pin 37  
#include <SimpleFOC.h>


// BLDC motor & driver instance
// BLDCMotor motor = BLDCMotor(pole pair number);
BLDCMotor motor = BLDCMotor(11);
// make sure to provide channel A for high side and channel B for low side
// BLDCDriver6PWM(pwmA_H, pwmA_L, pwmB_H,pwmB_L, pwmC_H, pwmC_L)
// Example configuration 
BLDCDriver6PWM driver = BLDCDriver6PWM(2,3, 6,9, 8,7);

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

void setup() {

  // 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;
  driver.init();
  // 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 = resistance*voltage, so try to be well under 1Amp
  motor.voltage_limit = 3;   // [V]
 
  // open loop control config
  motor.controller = MotionControlType::velocity_openloop;

  // init motor hardware
  motor.init();

  //initial motor target
  motor.target=0;

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

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

void loop() {

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

  // user communication
  command.run();
}

1 Like