cancel
Showing results for 
Search instead for 
Did you mean: 

How to setting TIM CHx/CHxN for six step BLDC motor control?

Kenji1
Senior

I want to control BLDC motor in six step method using STM32G474RE (nucleo board). 

I'm using TIM1 CHx/CHxN complementary PWM output for 6 pwm signal, like below:

 0693W000008zFe0QAE.pngThe problem I have is that the PWM output does not switch synchronously when switching steps, like below:

0693W000008zFePQAU.pngThe desired switch looks like this:

0693W000008zFhdQAE.pngHow can I synchronaize the PWM when switching the steps, with STM32G474 MPU?

Please give me some advice.

My setting for TIM1 PWM:

 0693W000008zFtqQAE.png0693W000008zG5VQAU.pngAnd, a part of code for six step:

void MC_NEXT_step(mc_six_step_t *p)

{

    switch (p->step_count)

    {

    case 0:

        HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3);

        HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_3);

        __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, p->compare_value);

        HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);

        HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);

        break;

    case 1:

        HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_2);

        __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, p->pwm.period);

        HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_3);

        break;

    case 2:

        HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);

        HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_1);

        __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, p->compare_value);

        HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);

        HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);

        break;

    case 3:

        HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_3);

        __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, p->pwm.period);

        HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);

        break;

    case 4:

        HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_2);

        HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_2);

        __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, p->compare_value);

        HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);

        HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_3);

        break;

    case 5:

        HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_1);

        __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, p->pwm.period);

        HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_2);

        break;

    default:

        break;

    }

}

15 REPLIES 15
Javier1
Principal

i also had this issue, dont remember exactly how we fixed it but check the datasheet about the pwm modes.

You should check the pwm forced inactive modes of every pwm channel driving each one of your H bridge´s low branch mosfet.

#define TIM_OCMODE_TIMING                  0x00000000U                                             /*!< Frozen                                */

#define TIM_OCMODE_ACTIVE                  TIM_CCMR1_OC1M_0                                        /*!< Set channel to active level on match  */

#define TIM_OCMODE_INACTIVE                TIM_CCMR1_OC1M_1                                        /*!< Set channel to inactive level on match */

#define TIM_OCMODE_TOGGLE                  (TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0)                   /*!< Toggle                                */

#define TIM_OCMODE_PWM1                    (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1)                   /*!< PWM mode 1                            */

#define TIM_OCMODE_PWM2                    (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0) /*!< PWM mode 2                            */

#define TIM_OCMODE_FORCED_ACTIVE           (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_0)                   /*!< Force active level                    */

#define TIM_OCMODE_FORCED_INACTIVE         TIM_CCMR1_OC1M_2                                        /*!< Force inactive level                  */

we dont need to firmware by ourselves, lets talk
Kenji1
Senior

Javier-san

Thank you. I will check the data sheet.

Kenji1
Senior

Hi Javier-san

I had modified the code with reference to a AN4776 and your advice. I can synchronize the six step output using TIM1 and TIM2. 

Now, I have another problem.

Please show the figure above, PWM-UH, PWM-H and Six Step Trig signal.

#1. When switch, PWM-UL output set to high. The desired output is low. I set TIM_OCMODE_FORCED_INACTIVE in the code. I've tried other settings, but I can't get it to low. Do you know the way to set low both PWM-UL and PWM-UH on switching timing?

#2. When use TIM_OCMODE_FORCED_INACTIVE, I restarted the output with TIM_OCMODE_FORCED_ACTIVE and the PWM output does not come out. It possible to use TIM_OCMODE_INACTIVE/TIM_OCMODE_ACTIVE, but there problem on switching. It have a problem that the output does not switch properly when switching six steps. Do you have any experience about this?

0693W000008zkgMQAQ.pngAlso, the code I used for this test:

void MC_SixStep_SetNextStep(void)
{
 
  HAL_GPIO_TogglePin(DBG2_GPIO_Port, DBG2_Pin);
 
  switch (hBLDC.sixStepCount)
  {
    case 0:
      /* UH, VL */
      htim1.Instance->CCER &= (uint16_t) ~TIM_CCER_CC2NE;
 
      __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, hBLDC.pwm.period);
      htim1.Instance->CCER |= (uint16_t) TIM_CCER_CC3NE;
      break;
 
    case 1:
      /* UH, WL */
//      htim1.Instance->CCER &= (uint16_t) ~TIM_CCER_CC1E;
//      htim1.Instance->CCER &= (uint16_t) ~TIM_CCER_CC1NE;
 
      /* Reset the OC1M bits in the CCMR1 register */
      TIM1->CCMR1 &= TIM_CCMR1_OC2M;
      TIM1->CCMR1 |= TIM_OCMODE_FORCED_INACTIVE;
 
      __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, hBLDC.pwm.width - 1);
      htim1.Instance->CCER |= (uint16_t) TIM_CCER_CC2E;
      htim1.Instance->CCER |= (uint16_t) TIM_CCER_CC2NE;
      break;
 
    case 2:
      /* VH, WL */
      htim1.Instance->CCER &= (uint16_t) ~TIM_CCER_CC3NE;
 
      __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, hBLDC.pwm.period);
      htim1.Instance->CCER |= (uint16_t) TIM_CCER_CC1NE;
 
      break;
 
    case 3:
      /* VH, UL */
      htim1.Instance->CCER &= (uint16_t) ~TIM_CCER_CC2E;
      htim1.Instance->CCER &= (uint16_t) ~TIM_CCER_CC2NE;
 
      __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, hBLDC.pwm.width - 1);
      htim1.Instance->CCER |= (uint16_t) TIM_CCER_CC3E;
      htim1.Instance->CCER |= (uint16_t) TIM_CCER_CC3NE;
      break;
 
    case 4:
      /* WH, UL */
      htim1.Instance->CCER &= (uint16_t) ~TIM_CCER_CC1NE;
 
      __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, hBLDC.pwm.period);
      htim1.Instance->CCER |= (uint16_t) TIM_CCER_CC2NE;
      break;
 
    case 5:
      /* WH, VL */
 
      __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, hBLDC.pwm.width - 1);
//      htim1.Instance->CCER |= (uint16_t) TIM_CCER_CC1E;
//      htim1.Instance->CCER |= (uint16_t) TIM_CCER_CC1NE;
 
      TIM1->CCMR1 |= TIM_OCMODE_FORCED_ACTIVE;
      TIM1->CCER |= TIM_CCER_CC1E;
      TIM1->CCER |= TIM_CCER_CC1NE;
 
      htim1.Instance->CCER &= (uint16_t) ~TIM_CCER_CC3E;
      htim1.Instance->CCER &= (uint16_t) ~TIM_CCER_CC3NE;
 
      break;
 
    default:
      break;
  }
 
  hBLDC.sixStepCount++;
  hBLDC.sixStepCount %= 6;
}

Draw a table with content of individual bits/bitfields of relevant timer registers, corresponding to the individual fields in the captured waveform.

JW

Kenji1
Senior

Hi Jan-san

I'm a little confused. You want to see the TIM1/TIM2 setting?

For each "field" in the waveform snapshot, post what is the conten of TIM registers.

In other words, in debugger, stop execution after you've made every change for given step, and read out the content of TIM registers and write them down for that step; then repeat for all steps. Post the resulting table.

JW

Hi Jan-san

These are setting of the TIM1 after preset the commutation.

How you see, Is there anything wrong with TIM1 setting?

Step0:

  switch (hBLDC.sixStepCount)
  {
    case 0:
      /* UH, VL */
      htim1.Instance->CCER &= (uint16_t) ~TIM_CCER_CC2NE;
 
      __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, hBLDC.pwm.period);
      htim1.Instance->CCER |= (uint16_t) TIM_CCER_CC3NE;
      break;

0693W000008zq6ZQAQ.pngStep1:

  switch (hBLDC.sixStepCount)
  {
    case 1:
      /* UH, WL */
//      htim1.Instance->CCER &= (uint16_t) ~TIM_CCER_CC1E;
//      htim1.Instance->CCER &= (uint16_t) ~TIM_CCER_CC1NE;
 
      /* Reset the OC1M bits in the CCMR1 register */
      TIM1->CCMR1 &= TIM_CCMR1_OC2M;
      TIM1->CCMR1 |= TIM_OCMODE_FORCED_INACTIVE;
 
      __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, hBLDC.pwm.width - 1);
      htim1.Instance->CCER |= (uint16_t) TIM_CCER_CC2E;
      htim1.Instance->CCER |= (uint16_t) TIM_CCER_CC2NE;
      break;

0693W000008zq6eQAA.pngStep2:

  switch (hBLDC.sixStepCount)
  {
    case 2:
      /* VH, WL */
      htim1.Instance->CCER &= (uint16_t) ~TIM_CCER_CC3NE;
 
      __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, hBLDC.pwm.period);
      htim1.Instance->CCER |= (uint16_t) TIM_CCER_CC1NE;
 
      break;

0693W000008zq6tQAA.pngStep3:

switch (hBLDC.sixStepCount)
  {
    case 3:
      /* VH, UL */
      htim1.Instance->CCER &= (uint16_t) ~TIM_CCER_CC2E;
      htim1.Instance->CCER &= (uint16_t) ~TIM_CCER_CC2NE;
 
      __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, hBLDC.pwm.width - 1);
      htim1.Instance->CCER |= (uint16_t) TIM_CCER_CC3E;
      htim1.Instance->CCER |= (uint16_t) TIM_CCER_CC3NE;
      break;

0693W000008zq6yQAA.pngStep4:

 switch (hBLDC.sixStepCount)
  {
    case 4:
      /* WH, UL */
      htim1.Instance->CCER &= (uint16_t) ~TIM_CCER_CC1NE;
 
      __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, hBLDC.pwm.period);
      htim1.Instance->CCER |= (uint16_t) TIM_CCER_CC2NE;
      break;

0693W000008zq7DQAQ.pngStep5:

 switch (hBLDC.sixStepCount)
  {
    case 5:
      /* WH, VL */
 
      __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, hBLDC.pwm.width - 1);
//      htim1.Instance->CCER |= (uint16_t) TIM_CCER_CC1E;
//      htim1.Instance->CCER |= (uint16_t) TIM_CCER_CC1NE;
 
      TIM1->CCMR1 |= TIM_OCMODE_FORCED_ACTIVE;
      TIM1->CCER |= TIM_CCER_CC1E;
      TIM1->CCER |= TIM_CCER_CC1NE;
 
      htim1.Instance->CCER &= (uint16_t) ~TIM_CCER_CC3E;
      htim1.Instance->CCER &= (uint16_t) ~TIM_CCER_CC3NE;
 
      break;

0693W000008zq7IQAQ.png

I don't do motor control and I don't know what are the expected waveforms, but I would expect the CCMR and CCER settings for the 3 channels to "rotate" between the steps, which they don't.

JW

@Kenji​  sorry i didnt noticed your reply, for some reason this forum only notifies me if my name is mentioned.

for your problem 1 Do you know the way to set low both PWM-UL and PWM-UH on switching timing?

Yo should disable the channels during that step.

for your problem 2 i didnt understood sorry

we dont need to firmware by ourselves, lets talk