cancel
Showing results for 
Search instead for 
Did you mean: 

about STM32 Timer using HAL lib

dqsh06
Associate III

Hello,

I am now try to do a BLDC motor driver with STM32G474. I used the tim1 to get the 3 channel PWM and PWMN to drive the 3 full bridge with 6 step solution.

the problem is, I referred someone's code. the code is like below:

// Bridge FETs for Motor Phase U

if(BH1)

{

HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);

HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);

}

else

{

HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);

if(BL1)

{

TIM_SelectOCxM(&htim1, TIM_CHANNEL_1, TIM_ForcedAction_Active);

HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1);

}

else

{

HAL_TIMEx_PWMN_Stop(&htim1, TIM_CHANNEL_1);

}

}

when I compiled the code. the error is, no TIM_SelectOCxM() function. I think it is not a HAL lib function.

so if I want to do the same thing as TIM_SelectOCxM(), how should I do with HAL lib?

 

please reply, thanks!

@

 

1 ACCEPTED SOLUTION

Accepted Solutions

TIM_SelectOCxM() is a function from the older ST library, SPL. It does exactly what its name says, modifies the OCxM field of relevant TIMx_CCMRx.

Cube/HAL (and as far as I understand, Cube/LL too) employ a more complex model for timers, where you are not supposed to modify individual fields, only groups of fields described by the relevant initialization struct. Namely, for Output Compare, you are supposed to use HAL_TIM_OC_ConfigChannel(), where the mode is one field in the sConfig parameter which is of pointer to TIM_OC_InitTypeDef type (TIM Output Compare configuration structure).

You can perhaps simply use TIM_SelectOCxM()  as it is, too:

#define CCMR_OC13M_MASK    ((uint16_t)0xFF8F)
#define CCMR_OC24M_MASK    ((uint16_t)0x8FFF) 

/**
  * @brief  Selects the TIM Output Compare Mode.
  * @note   This function disables the selected channel before changing the Output
  *         Compare Mode. If needed, user has to enable this channel using
  *         TIM_CCxCmd() and TIM_CCxNCmd() functions.
  * @PAram  TIMx: where x can be 1 to 14 except 6 and 7, to select the TIM peripheral.
  * @PAram  TIM_Channel: specifies the TIM Channel
  *          This parameter can be one of the following values:
  *            @arg TIM_Channel_1: TIM Channel 1
  *            @arg TIM_Channel_2: TIM Channel 2
  *            @arg TIM_Channel_3: TIM Channel 3
  *            @arg TIM_Channel_4: TIM Channel 4
  * @PAram  TIM_OCMode: specifies the TIM Output Compare Mode.
  *           This parameter can be one of the following values:
  *            @arg TIM_OCMode_Timing
  *            @arg TIM_OCMode_Active
  *            @arg TIM_OCMode_Toggle
  *            @arg TIM_OCMode_PWM1
  *            @arg TIM_OCMode_PWM2
  *            @arg TIM_ForcedAction_Active
  *            @arg TIM_ForcedAction_InActive
  * @retval None
  */
void TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode)
{
  uint32_t tmp = 0;
  uint16_t tmp1 = 0;

  /* Check the parameters */
  assert_param(IS_TIM_LIST1_PERIPH(TIMx));
  assert_param(IS_TIM_CHANNEL(TIM_Channel));
  assert_param(IS_TIM_OCM(TIM_OCMode));

  tmp = (uint32_t) TIMx;
  tmp += CCMR_OFFSET;

  tmp1 = CCER_CCE_SET << (uint16_t)TIM_Channel;

  /* Disable the Channel: Reset the CCxE Bit */
  TIMx->CCER &= (uint16_t) ~tmp1;

  if((TIM_Channel == TIM_Channel_1) ||(TIM_Channel == TIM_Channel_3))
  {
    tmp += (TIM_Channel>>1);

    /* Reset the OCxM bits in the CCMRx register */
    *(__IO uint32_t *) tmp &= CCMR_OC13M_MASK;
   
    /* Configure the OCxM bits in the CCMRx register */
    *(__IO uint32_t *) tmp |= TIM_OCMode;
  }
  else
  {
    tmp += (uint16_t)(TIM_Channel - (uint16_t)4)>> (uint16_t)1;

    /* Reset the OCxM bits in the CCMRx register */
    *(__IO uint32_t *) tmp &= CCMR_OC24M_MASK;
    
    /* Configure the OCxM bits in the CCMRx register */
    *(__IO uint32_t *) tmp |= (uint16_t)(TIM_OCMode << 8);
  }
}

where

/** @defgroup TIM_Channel 
  * @{
  */

#define TIM_Channel_1                      ((uint16_t)0x0000)
#define TIM_Channel_2                      ((uint16_t)0x0004)
#define TIM_Channel_3                      ((uint16_t)0x0008)
#define TIM_Channel_4                      ((uint16_t)0x000C)

/** @defgroup TIM_Output_Compare_and_PWM_modes 
  * @{
  */

#define TIM_OCMode_Timing                  ((uint16_t)0x0000)
#define TIM_OCMode_Active                  ((uint16_t)0x0010)
#define TIM_OCMode_Inactive                ((uint16_t)0x0020)
#define TIM_OCMode_Toggle                  ((uint16_t)0x0030)
#define TIM_OCMode_PWM1                    ((uint16_t)0x0060)
#define TIM_OCMode_PWM2                    ((uint16_t)0x0070)


/** @defgroup TIM_Forced_Action 
  * @{
  */

#define TIM_ForcedAction_Active            ((uint16_t)0x0050)
#define TIM_ForcedAction_InActive          ((uint16_t)0x0040)

 

Or just simply write your own code to change that register field - for a fixed given channel, it's a single read-write-modify operation.

JW

View solution in original post

3 REPLIES 3

TIM_SelectOCxM() is a function from the older ST library, SPL. It does exactly what its name says, modifies the OCxM field of relevant TIMx_CCMRx.

Cube/HAL (and as far as I understand, Cube/LL too) employ a more complex model for timers, where you are not supposed to modify individual fields, only groups of fields described by the relevant initialization struct. Namely, for Output Compare, you are supposed to use HAL_TIM_OC_ConfigChannel(), where the mode is one field in the sConfig parameter which is of pointer to TIM_OC_InitTypeDef type (TIM Output Compare configuration structure).

You can perhaps simply use TIM_SelectOCxM()  as it is, too:

#define CCMR_OC13M_MASK    ((uint16_t)0xFF8F)
#define CCMR_OC24M_MASK    ((uint16_t)0x8FFF) 

/**
  * @brief  Selects the TIM Output Compare Mode.
  * @note   This function disables the selected channel before changing the Output
  *         Compare Mode. If needed, user has to enable this channel using
  *         TIM_CCxCmd() and TIM_CCxNCmd() functions.
  * @PAram  TIMx: where x can be 1 to 14 except 6 and 7, to select the TIM peripheral.
  * @PAram  TIM_Channel: specifies the TIM Channel
  *          This parameter can be one of the following values:
  *            @arg TIM_Channel_1: TIM Channel 1
  *            @arg TIM_Channel_2: TIM Channel 2
  *            @arg TIM_Channel_3: TIM Channel 3
  *            @arg TIM_Channel_4: TIM Channel 4
  * @PAram  TIM_OCMode: specifies the TIM Output Compare Mode.
  *           This parameter can be one of the following values:
  *            @arg TIM_OCMode_Timing
  *            @arg TIM_OCMode_Active
  *            @arg TIM_OCMode_Toggle
  *            @arg TIM_OCMode_PWM1
  *            @arg TIM_OCMode_PWM2
  *            @arg TIM_ForcedAction_Active
  *            @arg TIM_ForcedAction_InActive
  * @retval None
  */
void TIM_SelectOCxM(TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t TIM_OCMode)
{
  uint32_t tmp = 0;
  uint16_t tmp1 = 0;

  /* Check the parameters */
  assert_param(IS_TIM_LIST1_PERIPH(TIMx));
  assert_param(IS_TIM_CHANNEL(TIM_Channel));
  assert_param(IS_TIM_OCM(TIM_OCMode));

  tmp = (uint32_t) TIMx;
  tmp += CCMR_OFFSET;

  tmp1 = CCER_CCE_SET << (uint16_t)TIM_Channel;

  /* Disable the Channel: Reset the CCxE Bit */
  TIMx->CCER &= (uint16_t) ~tmp1;

  if((TIM_Channel == TIM_Channel_1) ||(TIM_Channel == TIM_Channel_3))
  {
    tmp += (TIM_Channel>>1);

    /* Reset the OCxM bits in the CCMRx register */
    *(__IO uint32_t *) tmp &= CCMR_OC13M_MASK;
   
    /* Configure the OCxM bits in the CCMRx register */
    *(__IO uint32_t *) tmp |= TIM_OCMode;
  }
  else
  {
    tmp += (uint16_t)(TIM_Channel - (uint16_t)4)>> (uint16_t)1;

    /* Reset the OCxM bits in the CCMRx register */
    *(__IO uint32_t *) tmp &= CCMR_OC24M_MASK;
    
    /* Configure the OCxM bits in the CCMRx register */
    *(__IO uint32_t *) tmp |= (uint16_t)(TIM_OCMode << 8);
  }
}

where

/** @defgroup TIM_Channel 
  * @{
  */

#define TIM_Channel_1                      ((uint16_t)0x0000)
#define TIM_Channel_2                      ((uint16_t)0x0004)
#define TIM_Channel_3                      ((uint16_t)0x0008)
#define TIM_Channel_4                      ((uint16_t)0x000C)

/** @defgroup TIM_Output_Compare_and_PWM_modes 
  * @{
  */

#define TIM_OCMode_Timing                  ((uint16_t)0x0000)
#define TIM_OCMode_Active                  ((uint16_t)0x0010)
#define TIM_OCMode_Inactive                ((uint16_t)0x0020)
#define TIM_OCMode_Toggle                  ((uint16_t)0x0030)
#define TIM_OCMode_PWM1                    ((uint16_t)0x0060)
#define TIM_OCMode_PWM2                    ((uint16_t)0x0070)


/** @defgroup TIM_Forced_Action 
  * @{
  */

#define TIM_ForcedAction_Active            ((uint16_t)0x0050)
#define TIM_ForcedAction_InActive          ((uint16_t)0x0040)

 

Or just simply write your own code to change that register field - for a fixed given channel, it's a single read-write-modify operation.

JW

thanks @waclawek.jan ,

so you recommend me to include the code above to my c code as a function, and then i call the TIM_SelectOCxM() function. got it. I will have a try.

thanks.

Well, I don't *recommend* that, just mentioned it as an option.

I personally recommend not using Cube/HAL or any other such "library" at all, but that of course precludes also using any Cube/HAL-based example or using CubeMX, too. Many find this recommendation harsh.

JW