BLDCDriver6PWM for DRV8302 not working [SOLVED]

Hi,

I am trying to get the DRV8302 example to work with a STM32F405RTG6 based board.

I have been able to get the BLDCDriver3PWM to work, but when I test with the BLDCDriver6PWM by adding 3 additional pins it doesn’t work.

The 3 pins I add are PC6, PC7 and PC8 which are associated with the TIM8. It didn’t work. Tried swapping these pins for PA0, PA1, and PA2 which are related to the TIM5 … but haven’t been able to get it to work either.

The motor remains “dead”, unenergized. The hardware-level setup I don’t think contains any errors because if I run the example, for the BLDCDriver3PWM without touching a single cable, it works perfectly.

Does anyone know what combination of pins is needed for that setup with BLDCDriver6PWM?

Output:

MOT: Monitor enabled!
MOT: Initialise variables.
MOT: Enable driver.
MOT: Align sensor.
MOT: natural_direction==CW
MOT: Absolute zero align.
MOT: Success!
MOT: Motor ready.

platform.ini:

[env:genericSTM32F405RG]
platform = ststm32
board = genericSTM32F405RG
board_build.f_cpu = 168000000L
framework = arduino
debug_tool = stlink
upload_protocol = stlink
debug_init_cmds =
  set CPUTAPID 0x2ba01477
  target extended-remote $DEBUG_PORT
  $INIT_BREAK
  monitor reset halt
  $LOAD_CMDS
  monitor init
  monitor reset halt
build_flags =
    -D HSE_VALUE=8000000

	-D HAVE_HWSERIAL1
	
	-D PIN_WIRE_SDA=PB11
	-D PIN_WIRE_SCL=PB10

	-D PIN_SPI_MOSI=PA7
	-D PIN_SPI_MISO=PA6
	-D PIN_SPI_SCK=PA5
	-D PIN_SPI_SS=PA4

	-D HAL_CAN_MODULE_ENABLED

monitor_speed = 115200
lib_deps = 
	askuric/Simple FOC@^2.0.2
	Wire
	SPI

My code:

#include <SimpleFOC.h>

// This SystemClock_Config  is copy&paste from CubeIDE
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  // Configure the main internal regulator output voltage
  //
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  // Initializes the RCC Oscillators according to the specified parameters
  // in the RCC_OscInitTypeDef structure.
  //
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 100;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  // Initializes the CPU, AHB and APB buses clocks

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
  {
    Error_Handler();
  }
}

#define NUM_OF_BLINKS 15
void bootLedIndicator(){
  int counter = NUM_OF_BLINKS;
  pinMode(PA8, OUTPUT);
  while(counter>0){
    digitalToggle(PA8);
    delay(50);
    counter--;
  }
}


// DRV8302 pins connections
// don't forget to connect the common ground pin
#define   INH_A     PB6   // Green
#define   INH_B     PB7   // Orange
#define   INH_C     PB8   // Blue
#define   EN_GATE   PB9   // Red

#define   INL_A     PC6     //PA0   //  Purple
#define   INL_B     PC7     //PA1   //  Gray
#define   INL_C     PC8     //PA2   //  Yellow

#define   M_PWM     PB4   // White
#define   M_OC      PB5   // Brown
#define   OC_ADJ    PB3   // Black

#define MOSI PA7  // Blue
#define MISO PA6  // Green
#define CLK PA5   // Orange
#define CS PA4    // Yellow

MagneticSensorSPIConfig_s AS5047A_SPI_Config {
  .spi_mode = SPI_MODE1,
  .clock_speed = 10000000,
  .bit_resolution = 14, 
  .angle_register = 0x3FFF,
  .data_start_bit = 13,
  .command_rw_bit = 14,
  .command_parity_bit = 15
};

SPIClass spiConnection(MOSI,MISO,CLK);

// magnetic sensor instance - SPI
MagneticSensorSPI sensor = MagneticSensorSPI(AS5047A_SPI_Config, CS);


// Motor instance
BLDCMotor motor = BLDCMotor(12);

BLDCDriver6PWM driver = BLDCDriver6PWM(INH_A, INL_A, INH_B,INL_B, INH_C, INL_C, EN_GATE);

// utility function enabling serial communication the user
String serialReceiveUserCommand() {
  
  // a string to hold incoming data
  static String received_chars;
  
  String command = "";

  while (Serial1.available()) {
    // get the new byte:
    char inChar = (char)Serial1.read();
    // add it to the string buffer:
    received_chars += inChar;

    // end of user input
    if (inChar == '\n') {
      
      // execute the user command
      command = received_chars;

      // reset the command buffer 
      received_chars = "";
    }
  }
  return command;
}

double lastReport;

void setup() {

  // initialise magnetic sensor hardware
  sensor.init();
  // link the motor to the sensor
  motor.linkSensor(&sensor);
  // link the motor to the sensor

  // DRV8302 specific code
  // M_OC  - enable over-current protection
  pinMode(M_OC,OUTPUT);
  digitalWrite(M_OC,LOW);
  // M_PWM  - enable 6pwm mode (can be left open)
  pinMode(M_PWM,OUTPUT);
  digitalWrite(M_PWM,LOW);
  // OD_ADJ - set the maximum over-current limit possible
  // Better option would be to use voltage divisor to set exact value
  pinMode(OC_ADJ,OUTPUT);
  digitalWrite(OC_ADJ,HIGH);

  // configure driver
  driver.voltage_power_supply = 12;
  driver.init();
  motor.linkDriver(&driver);

  // choose FOC modulation
  motor.foc_modulation = FOCModulationType::SpaceVectorPWM;

  // set control loop type to be used
  motor.controller = ControlType::angle;

  // controller configuration based on the control type 
  motor.PID_velocity.P = 0.2;
  motor.PID_velocity.I = 20;

  // velocity low pass filtering time constant
  motor.LPF_velocity.Tf = 0.2;

  // angle loop controller
  motor.P_angle.P = 20;
  
  // angle loop velocity limit
  motor.velocity_limit = 50;
  // default voltage_power_supply
  motor.voltage_limit = 0.90;

  // use monitoring with serial for motor init
  // monitoring port
  Serial1.begin(115200);
  // comment out if not needed
  motor.useMonitoring(Serial1);

  // initialize motor
  motor.init();
  // align encoder and start FOC
  motor.initFOC();

  // set the initial target value
  motor.target = 2;
  lastReport = millis();
  bootLedIndicator();
  _delay(1000);
}

void loop() {
  // iterative setting FOC phase voltage
  motor.loopFOC();

  // iterative function setting the outer loop target
  // velocity, position or voltage
  // if target not set in parameter uses motor.target variable
  motor.move();
  double currentMillis = millis();
  if(( currentMillis-lastReport)>20)
  {
      motor.monitor();
      lastReport = currentMillis;
  }
  // user communication
  motor.command(serialReceiveUserCommand());
}

Hey @JorgeMaker,

Fort 6PWM mode it is really important to have low and high pairs belonging to the same timer!
That is the only way it is going to work. Here is the docs link:
https://docs.simplefoc.com/bldcdriver6pwm

Make sure that INH_A and INL_A are same timer, INH_B and INL_B are the same and INH_C and INL_C are the same timer.

They can all the on three different timers but pair-wise they need to be on the same.

There are two ways you can do it really:

  1. Use only one timer for all 6 pins. (this we call hardware 6pwm mode) that features the stm32 pwm inverted channels. To enable this one you will need to use either timer 0 or timer 8, (this is what I was able to find in STM32CubeMX - that might be wrong).
    image

So use either:

BLDCDriver6PWM(PA8,PA7,PA9,PB0,PA10,PB1); // TIM1
BLDCDriver6PWM(PC6, PA5,  PC7,AB14, PC8,PB15); //TIM8
  1. Find the pairwise timer configuration either 2 or 3 different timers (this we call software 6pwm mode). You can use 4 pins of the timer 8 and 2 pins of the timer 1. Something like:
BLDCDriver6PWM(PA8,PA9,  PC6,PC7,PC8,PC9); // TIM1 + TIM8

image

Let us know how it goes :smiley:

1 Like

Hei @Antun_Skuric ,

Since my board has assigned USART1 (PA10, PA9) to a CH340C that I use for serial communications and was using the SPI1, I tried to use a setup with 3 timers that assigns different channels of each pair of INH_X, INL_X as shown in the following configuration:

// DRV8302 pins connections
// don't forget to connect the common ground pin
#define   INH_A    PC7    // Green   TIM8-CH2
#define   INL_A    PC6    // Purple  TIM8-CH3
#define   INH_B    PA0    // Orange  TIM2-CH1
#define   INL_B    PA1    // Gray    TIM2-CH2
#define   INH_C    PA2    // Blue    TIM2-CH3
#define   INL_C    PA3    // Yellow  TIM2-CH4

#define   EN_GATE  PB1     // Red


#define   M_PWM     PC8    // White
#define   M_OC      PB10   // Brown
#define   OC_ADJ    PB11   // Black

#define MOSI PA7  // Blue
#define MISO PA6  // Green
#define CLK PA5   // Orange
#define CS PA4    // Yellow

It worked with 3PWM but kept failing with 6PWM. Maybe I have not understood the rule, each pair has to be assigned to the same timer as it is. It should work, but it doesn’t.

Now I am trying to see if I can use the following configuration:

#define   INH_A    PC6     // Green    TIM8-CH1
#define   INL_A    PA5     // Purple   TIM8-CH1N
#define   INH_B    PC7     // Orange   TIM8-CH2
#define   INL_B    PB14    // Gray     TIM8-CH2N
#define   INH_C    PC8     // Blue     TIM8-CH3
#define   INL_C    PB15    // Yellow   TIM8-CH3N

#define   EN_GATE  PB1     // Red


#define   M_PWM     PC8    // White
#define   M_OC      PB10   // Brown
#define   OC_ADJ    PB11   // Black

#define MOSI PC3     // Blue
#define MISO PC2     // Green
#define CLK  PB10    // Orange
#define CS   PB12    // Yellow

to be able to use : BLDCDriver6PWM(PC6, PA5, PC7,AB14, PC8,PB15);

That implies that I have to change change from SPI1 to SPI2. At the moment the magnetic encoder readings have become random :(, so I have to try to solve it before I know if with this pin configuration for the PWMs I can get it to work.

Thanks for your answers, let’s see if I can make it work with the pin assignment that you have suggested since the one that I have “cooked” by applying the rule does not seem to resolve the issue.

Hey @JorgeMaker - you are working on very similar things to me!! I’ve got this working on stm32f405 + drv8302. Check out the video/code on my last video which I link to in:

I’m not sure how carefully you have selected your pins for PWM but ideally they should be on TIM1CH1,TIM1CH2,TIM1CH3,TIM1CH1N,TIM1CH2N,TIM1CH3N
The VESC hardware uses slightly different pins to what Antun said (there are a few valid options).

#define H3            PA8
#define H2            PA9
#define H1            PA10
#define L3            PB13
#define L2            PB14
#define L1            PB15
#define EN_GATE       PC10

I’ve also had to override the peripheral pin maps because some of the pins (PB14 and PB15 I think) default to a differrent timer.

There is a code repo linked in my video with more details.

Hi @Owen_Williams,

Thanks for your answer :slight_smile: My board has the USART1 (PA9, PA10) connected to a C340C for serial communication via USB and the PA8 connected to an LED, which makes using the pins associated with the TIM1 not the most convenient.

I have tried to apply the rule of using pins for each INH_X, INL_X pair associated to the same TIM in two different ways:

  1. With 3 different TIMs using for each pair of pins a single TIM.
#define   INH_A    PC7    // Green   TIM8-CH2
#define   INL_A    PC6    // Purple  TIM8-CH3
#define   INH_B    PA0    // Orange  TIM2-CH1
#define   INL_B    PA1    // Gray    TIM2-CH2
#define   INH_C    PA2    // Blue    TIM2-CH3
#define   INL_C    PA3    // Yellow  TIM2-CH4
  1. Instead of using all pins from TIM1 using pins from TIM8:
#define   INH_A    PC6     // Green    TIM8-CH1
#define   INL_A    PA5     // Purple   TIM8-CH1N
#define   INH_B    PC7     // Orange   TIM8-CH2
#define   INL_B    PB14    // Gray     TIM8-CH2N
#define   INH_C    PC8     // Blue     TIM8-CH3
#define   INL_C    PB15    // Yellow   TIM8-CH3N

In both cases I was able to get it to work for 3PWM but it didn’t work for 6PWM :frowning:

Do you have any alternative suggestion that you know that works without using pins associated with the TIM1?

Hey @JorgeMaker,

Since many stm32 board pins can be used with many different timers, the guys who develop stm32duino support decide one fixed combination and stick with it.
For example in the case of the STM32F4x5RGthe ...\AppData\Local\Arduino15\packages\STM32\hardware\stm32\1.9.0\variants\Generic_F4x5RG\PeripheralPins.c
they have chosen these pins associations:

WEAK const PinMap PinMap_PWM[] = {
  {PA_0,  TIM2,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1
  //  {PA_0,  TIM5,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 1, 0)}, // TIM5_CH1
  //  {PA_1,  TIM2,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 2, 0)}, // TIM2_CH2
  {PA_1,  TIM5,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 2, 0)}, // TIM5_CH2
  //  {PA_2,  TIM2,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 3, 0)}, // TIM2_CH3
  {PA_2,  TIM5,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 3, 0)}, // TIM5_CH3
  //  {PA_2,  TIM9,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 1, 0)}, // TIM9_CH1
  //  {PA_3,  TIM2,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 4, 0)}, // TIM2_CH4
  {PA_3,  TIM5,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 4, 0)}, // TIM5_CH4
  //  {PA_3,  TIM9,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 2, 0)}, // TIM9_CH2
  {PA_5,  TIM2,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1
  //  {PA_5,  TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 1)}, // TIM8_CH1N
  //  {PA_6,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1
  {PA_6,  TIM13,  STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM13, 1, 0)}, // TIM13_CH1
  //  {PA_7,  TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N
  //  {PA_7,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2
  //  {PA_7,  TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 1)}, // TIM8_CH1N
  {PA_7,  TIM14,  STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM14, 1, 0)}, // TIM14_CH1
  {PA_8,  TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 0)}, // TIM1_CH1
  {PA_9,  TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 0)}, // TIM1_CH2
  {PA_10, TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 0)}, // TIM1_CH3
  {PA_11, TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 4, 0)}, // TIM1_CH4
  {PA_15, TIM2,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1
  //  {PB_0,  TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N
  //  {PB_0,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 3, 0)}, // TIM3_CH3
  {PB_0,  TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 1)}, // TIM8_CH2N
  //  {PB_1,  TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N
  //  {PB_1,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 4, 0)}, // TIM3_CH4
  {PB_1,  TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 1)}, // TIM8_CH3N
  {PB_3,  TIM2,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 2, 0)}, // TIM2_CH2
  {PB_4,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1
  {PB_5,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2
  {PB_6,  TIM4,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 1, 0)}, // TIM4_CH1
  {PB_7,  TIM4,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 2, 0)}, // TIM4_CH2
  {PB_8,  TIM4,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 3, 0)}, // TIM4_CH3
  //  {PB_8,  TIM10,  STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM10, 1, 0)}, // TIM10_CH1
  //  {PB_9,  TIM4,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 4, 0)}, // TIM4_CH4
  {PB_9,  TIM11,  STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM11, 1, 0)}, // TIM11_CH1
  {PB_10, TIM2,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 3, 0)}, // TIM2_CH3
  {PB_11, TIM2,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 4, 0)}, // TIM2_CH4
  {PB_13, TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N
  //  {PB_14, TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N
  //  {PB_14, TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 1)}, // TIM8_CH2N
  {PB_14, TIM12,  STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM12, 1, 0)}, // TIM12_CH1
  //  {PB_15, TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N
  //  {PB_15, TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 1)}, // TIM8_CH3N
  {PB_15, TIM12,  STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM12, 2, 0)}, // TIM12_CH2
  {PC_6,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1
  //  {PC_6,  TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 0)}, // TIM8_CH1
  //  {PC_7,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2
  {PC_7,  TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 0)}, // TIM8_CH2
  {PC_8,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 3, 0)}, // TIM3_CH3
  //  {PC_8,  TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 0)}, // TIM8_CH3
  //  {PC_9,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 4, 0)}, // TIM3_CH4
  {PC_9,  TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 4, 0)}, // TIM8_CH4
  {NC,    NP,    0}
};

So you can either choose the ones that belong to the same timer from this table or modify the table (uncomment the ones that make more sense for you).
Also I believe @Owen_Williams has redefined this map in the Arduino code, that might be possible too. :smiley:

1 Like

TIM8 also supports CHxN so presents another alternative.

Personally, I’d prioritise PWM (i.e. use TIM1 pins known to work) and choose your Serial after. There are loads of options for Serial.

Does your board of have USB? I’ve got SerialUSB working on stm32f405.

Hi @Owen_Williams,

The board has a couple of USB connectors. One is wired to USART1 (PA9, PA10) through an C340C and de secondone is connected to USB (PA11, PA12) …but i do not know how to activate Serial USB on it. Do you have a working recipie to make available serial communications through USB? This would allow me to use TIM1 for PWM generation while keping seral communications :slight_smile:

I added to my platforming file the following flags and a new /dev/cu.usbmodem206F3969394E1 serial port appeared on my computer buts I was not able to use it to produce any serial output. :

    -D USBCON
    -D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC
    -D USBD_USE_CDC

Hi @Antun_Skuric, @Owen_Williams,

After a few hours “playing Tetris” with pins, peripherals and timers and getting around more than one wiring problem, … I managed to find a combination that the 6PWM works with :slight_smile:

Thank you very much for your help :slight_smile: … The key was to modify the PinMap_PWM . Once this modificationwas done , I had managed to make it work using TIM8, TIM2 and TIM4

I paste here the combination that has worked for me, just in case someone else in the future runs in the same problem and can save some battle time.

main.cpp:


#include "STM32F405RTG6Board.h"
#include <SimpleFOC.h>

#define NUM_OF_BLINKS 15
void bootLedIndicator(){
  int counter = NUM_OF_BLINKS;
  pinMode(PA8, OUTPUT);
  while(counter>0){
    digitalToggle(PA8);
    delay(50);
    counter--;
  }
}

// Open loop motor control example  
#define     INH_A   PC7     // Green    TIM8_CH2
#define     INH_B   PA1     // Orange   TIM2_CH2
#define     INH_C   PA3     // Blue     TIM2_CH4

#define     INL_A   PC6    // Purple    TIM8-CH3
#define     INL_B   PA0    // Gray      TIM2-CH1
#define     INL_C   PA2    // Yellow    TIM2-CH3

#define EN_GATE  PC13  // Red

// Added for DRV83002
#define   M_PWM     PC1    // White
#define   M_OC      PC2   // Brown
#define   OC_ADJ    PC3  // Black

///       SPI 1

#define MOSI PA7    // Blue
#define MISO PA6    // Green
#define CLK  PA5    // Orange
#define CS   PA4    // Yellow


MagneticSensorSPIConfig_s AS5047A_SPI_Config {
  .spi_mode = SPI_MODE1,
  .clock_speed = 10000000,
  .bit_resolution = 14, 
  .angle_register = 0x3FFF,
  .data_start_bit = 13,
  .command_rw_bit = 14,
  .command_parity_bit = 15
};

SPIClass spiConnection(MOSI,MISO,CLK);

// magnetic sensor instance - SPI
MagneticSensorSPI sensor = MagneticSensorSPI(AS5047A_SPI_Config, CS);


// Motor instance
BLDCMotor motor = BLDCMotor(12);
BLDCDriver6PWM driver = BLDCDriver6PWM (INH_A, INL_A, INH_B, INL_B, INH_C, INL_C, EN_GATE);
//BLDCDriver3PWM driver = BLDCDriver3PWM(INH_A, INH_B, INH_C, EN_GATE);

// utility function enabling serial communication the user
String serialReceiveUserCommand() {
  
  // a string to hold incoming data
  static String received_chars;
  
  String command = "";

  while (Serial1.available()) {
    // get the new byte:
    char inChar = (char)Serial1.read();
    // add it to the string buffer:
    received_chars += inChar;

    // end of user input
    if (inChar == '\n') {
      
      // execute the user command
      command = received_chars;

      // reset the command buffer 
      received_chars = "";
    }
  }
  return command;
}

double lastReport;

void setup() {

  // initialise magnetic sensor hardware
  sensor.init();
  // link the motor to the sensor
  motor.linkSensor(&sensor);
  // link the motor to the sensor


  // DRV8302 specific code
  // M_OC  - enable over-current protection
  pinMode(M_OC,OUTPUT);
  digitalWrite(M_OC,LOW);
  // M_PWM  - enable 6pwm mode (can be left open)
  pinMode(M_PWM,OUTPUT);
  digitalWrite(M_PWM,LOW);
  // OD_ADJ - set the maximum over-current limit possible
  // Better option would be to use voltage divisor to set exact value
  pinMode(OC_ADJ,OUTPUT);
  digitalWrite(OC_ADJ,HIGH);

  // configure driver
  driver.voltage_power_supply = 12;
  driver.init();
  motor.linkDriver(&driver);

  // choose FOC modulation
  motor.foc_modulation = FOCModulationType::SpaceVectorPWM;

  // set control loop type to be used
  motor.controller = ControlType::velocity;

  // controller configuration based on the control type 
  motor.PID_velocity.P = 0.2;
  motor.PID_velocity.I = 20;

  // velocity low pass filtering time constant
  motor.LPF_velocity.Tf = 0.2;

  // angle loop controller
  motor.P_angle.P = 20;
  
  // angle loop velocity limit
  motor.velocity_limit = 50;
  // default voltage_power_supply
  motor.voltage_limit = 0.5;

  // use monitoring with serial for motor init
  // monitoring port
  Serial1.begin(115200);
  // comment out if not needed
  motor.useMonitoring(Serial1);

  // initialize motor
  motor.init();
  // align encoder and start FOC
  motor.initFOC();

  // set the initial target value
  motor.target = 2;
  lastReport = millis();
  bootLedIndicator();
  _delay(1000);
}

void loop() {
  // iterative setting FOC phase voltage
  motor.loopFOC();

  // iterative function setting the outer loop target
  // velocity, position or voltage
  // if target not set in parameter uses motor.target variable
  motor.move();
  double currentMillis = millis();
  if(( currentMillis-lastReport)>100)
  {
      motor.monitor();
      lastReport = currentMillis;
  }
  // user communication
  motor.command(serialReceiveUserCommand());
}

STM32F405RTG6Board.h

#include <Arduino.h>

// This SystemClock_Config  is copy&paste from CubeIDE
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  // Configure the main internal regulator output voltage
  //
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
  // Initializes the RCC Oscillators according to the specified parameters
  // in the RCC_OscInitTypeDef structure.
  //
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 100;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  // Initializes the CPU, AHB and APB buses clocks

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
  {
    Error_Handler();
  }
}

const PinMap PinMap_PWM[] = {
  {PA_0,  TIM2,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1
  //  {PA_0,  TIM5,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 1, 0)}, // TIM5_CH1
  {PA_1,  TIM2,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 2, 0)}, // TIM2_CH2
  //{PA_1,  TIM5,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 2, 0)}, // TIM5_CH2
  {PA_2,  TIM2,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 3, 0)}, // TIM2_CH3
  //{PA_2,  TIM5,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 3, 0)}, // TIM5_CH3
  //  {PA_2,  TIM9,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 1, 0)}, // TIM9_CH1
  {PA_3,  TIM2,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 4, 0)}, // TIM2_CH4
  //  {PA_3,  TIM5,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM5, 4, 0)}, // TIM5_CH4
  //  {PA_3,  TIM9,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM9, 2, 0)}, // TIM9_CH2
  {PA_5,  TIM2,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1
  //  {PA_5,  TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 1)}, // TIM8_CH1N
  //  {PA_6,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1
  {PA_6,  TIM13,  STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM13, 1, 0)}, // TIM13_CH1
  //  {PA_7,  TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N
  //  {PA_7,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2
  //  {PA_7,  TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 1)}, // TIM8_CH1N
  {PA_7,  TIM14,  STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM14, 1, 0)}, // TIM14_CH1
  {PA_8,  TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 0)}, // TIM1_CH1
  {PA_9,  TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 0)}, // TIM1_CH2
  {PA_10, TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 0)}, // TIM1_CH3
  {PA_11, TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 4, 0)}, // TIM1_CH4
  {PA_15, TIM2,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 1, 0)}, // TIM2_CH1
  //  {PB_0,  TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N
  //  {PB_0,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 3, 0)}, // TIM3_CH3
  {PB_0,  TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 1)}, // TIM8_CH2N
  //  {PB_1,  TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N
  //  {PB_1,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 4, 0)}, // TIM3_CH4
  {PB_1,  TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 1)}, // TIM8_CH3N
  {PB_3,  TIM2,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 2, 0)}, // TIM2_CH2
  {PB_4,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1
  {PB_5,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2
  {PB_6,  TIM4,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 1, 0)}, // TIM4_CH1
  {PB_7,  TIM4,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 2, 0)}, // TIM4_CH2
  {PB_8,  TIM4,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 3, 0)}, // TIM4_CH3
  //  {PB_8,  TIM10,  STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM10, 1, 0)}, // TIM10_CH1
  //  {PB_9,  TIM4,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM4, 4, 0)}, // TIM4_CH4
  {PB_9,  TIM11,  STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM11, 1, 0)}, // TIM11_CH1
  {PB_10, TIM2,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 3, 0)}, // TIM2_CH3
  {PB_11, TIM2,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM2, 4, 0)}, // TIM2_CH4
  {PB_13, TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 1, 1)}, // TIM1_CH1N
   {PB_14, TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 2, 1)}, // TIM1_CH2N
  //  {PB_14, TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 1)}, // TIM8_CH2N
  // {PB_14, TIM12,  STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM12, 1, 0)}, // TIM12_CH1
   {PB_15, TIM1,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF1_TIM1, 3, 1)}, // TIM1_CH3N
  //  {PB_15, TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 1)}, // TIM8_CH3N
  // {PB_15, TIM12,  STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF9_TIM12, 2, 0)}, // TIM12_CH2
  //{PC_6,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 1, 0)}, // TIM3_CH1
  {PC_6,  TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 1, 0)}, // TIM8_CH1
  //  {PC_7,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 2, 0)}, // TIM3_CH2
  {PC_7,  TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 2, 0)}, // TIM8_CH2
  {PC_8,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 3, 0)}, // TIM3_CH3
  //  {PC_8,  TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 3, 0)}, // TIM8_CH3
  //  {PC_9,  TIM3,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF2_TIM3, 4, 0)}, // TIM3_CH4
  {PC_9,  TIM8,   STM_PIN_DATA_EXT(STM_MODE_AF_PP, GPIO_PULLUP, GPIO_AF3_TIM8, 4, 0)}, // TIM8_CH4
  {NC,    NP,    0}
};

What I am not very clear about is what advantages it provides in terms of performance using the 6PWMs interface compared to the 3PWMs interface … although I suppose that if 3 extra pins are dedicated to it, there must be one. I have tried to google the answer but without much success.

Thanky you very much again :slight_smile:

1 Like

@JorgeMaker - great to hear you got this working. Your are now the pwm peripheral map king! :crown:

I also wonder about the benefits of 6PWM vs 3PWM. Does it mean that you can turn one phase’s high/low mosfets completely off (to perhaps read bemf to do sensorless switching)?

Regarding getting SerialUSB working, the last step that I was missing was the magic 48Mhz speed that the stm32f405 needs for usb. It is mentioned in section 2.2.30 of the datasheet

To obtain 48Mhz for serial without sacrificing the overall speed of 168Mhz is tricky. 168/48 = 3.5 which I found difficult to achieve using PLL divisors/multipliers particularly because PLL_Q is uneditable in the stm timer config tool (I wanted to set it to 7).
The clock config here is what I finally ended up with.

1 Like