AnsweredAssumed Answered

Any "Working" LL Pwm example for Timer 1?

Question asked by Eric Kelly on Jul 15, 2017
Latest reply on Jul 16, 2017 by Eric Kelly

Hello, I am using the STM32L4x6ZG Nucleo,

 

I can get PWM for Timer 1 Channel 1 to work with HAL, Pin PA8.   Actually the HAL Example is part of the Cube for L4, and works perfectly.  

 

However i want to use LL instead.  I've modified the LL example (that uses the button) to use TIM1 channel 2, mapped to PA9 and no go.  No PWM is output at all.  button interrupt is working fine for this one (since you press the button but i can hard code it).  that LL example is fine on TIM3 LED pin and other pins it's mapped to.

 

I have generated Full LL Driver code with STM32 Cube with the same configuration, still it does not work.    I could be missing something but i've looked over it so many times.  i am hoping i missed something someplace but could be a LL bug as well.  Any Ideas?

 

Here is the Working HAL Code:

 

#define TIMx                           TIM1
#define TIMx_CLK_ENABLE()              __HAL_RCC_TIM1_CLK_ENABLE()
/* Definition for TIMx Channel Pins */
#define TIMx_CHANNEL_GPIO_PORT()       __HAL_RCC_GPIOA_CLK_ENABLE();
#define TIMx_GPIO_PORT_CHANNEL1        GPIOA
#define TIMx_GPIO_PORT_CHANNEL2        GPIOA
#define TIMx_GPIO_PORT_CHANNEL3        GPIOA
#define TIMx_GPIO_PORT_CHANNEL4        GPIOA
#define TIMx_GPIO_PIN_CHANNEL1         GPIO_PIN_8
#define TIMx_GPIO_PIN_CHANNEL2         GPIO_PIN_9
#define TIMx_GPIO_PIN_CHANNEL3         GPIO_PIN_10
#define TIMx_GPIO_PIN_CHANNEL4         GPIO_PIN_11
#define TIMx_GPIO_AF_CHANNEL1          GPIO_AF1_TIM1
#define TIMx_GPIO_AF_CHANNEL2          GPIO_AF1_TIM1
#define TIMx_GPIO_AF_CHANNEL3          GPIO_AF1_TIM1
#define TIMx_GPIO_AF_CHANNEL4          GPIO_AF1_TIM1


void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
  GPIO_InitTypeDef   GPIO_InitStruct;
  /*##-1- Enable peripherals and GPIO Clocks #################################*/
  /* TIMx Peripheral clock enable */
  TIMx_CLK_ENABLE();
  /* Enable all GPIO Channels Clock requested */
  TIMx_CHANNEL_GPIO_PORT();

  /* Configure PA.08 (pin 23 in CN12 connector) (TIM1_Channel1), PA.09 (pin 21 in CN12 connector) (TIM1_Channel2), PA.10 (pin 33 in CN12 connector) (TIM1_Channel3),
     PA.11 (pin 14 in CN12 connector) (TIM1_Channel4) in output, push-pull, alternate function mode*/
  /* Common configuration for all channels */

  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = TIMx_GPIO_AF_CHANNEL1;
  GPIO_InitStruct.Pin = TIMx_GPIO_PIN_CHANNEL1;
  HAL_GPIO_Init(TIMx_GPIO_PORT_CHANNEL1, &GPIO_InitStruct);

  GPIO_InitStruct.Alternate = TIMx_GPIO_AF_CHANNEL2;
  GPIO_InitStruct.Pin = TIMx_GPIO_PIN_CHANNEL2;
  HAL_GPIO_Init(TIMx_GPIO_PORT_CHANNEL2, &GPIO_InitStruct);

  GPIO_InitStruct.Alternate = TIMx_GPIO_AF_CHANNEL3;
  GPIO_InitStruct.Pin = TIMx_GPIO_PIN_CHANNEL3;
  HAL_GPIO_Init(TIMx_GPIO_PORT_CHANNEL3, &GPIO_InitStruct);

  GPIO_InitStruct.Alternate = TIMx_GPIO_AF_CHANNEL4;
  GPIO_InitStruct.Pin = TIMx_GPIO_PIN_CHANNEL4;
  HAL_GPIO_Init(TIMx_GPIO_PORT_CHANNEL4, &GPIO_InitStruct);
}

HAL_Init();
  /* Configure the system clock to 80 MHz */
  SystemClock_Config();
  /* Configure LED3 */
  BSP_LED_Init(LED3);
  /* Compute the prescaler value to have TIM1 counter clock equal to 16000000 Hz */
  uhPrescalerValue = (uint32_t)(SystemCoreClock / 8000000) - 1;
  TimHandle.Instance = TIMx;
  TimHandle.Init.Prescaler         = uhPrescalerValue;
  TimHandle.Init.Period            = PERIOD_VALUE;
  TimHandle.Init.ClockDivision     = 0;
  TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
  TimHandle.Init.RepetitionCounter = 0;

  if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK)
  {
    /* Initialization Error */
    Error_Handler();
  }
  /*##-2- Configure the PWM channels #########################################*/
  /* Common configuration for all channels */

  sConfig.OCMode       = TIM_OCMODE_PWM1;
  sConfig.OCPolarity   = TIM_OCPOLARITY_HIGH;
  sConfig.OCFastMode   = TIM_OCFAST_DISABLE;
  sConfig.OCNPolarity  = TIM_OCNPOLARITY_HIGH;
  sConfig.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  sConfig.OCIdleState  = TIM_OCIDLESTATE_RESET;

  /* Set the pulse value for channel 1 */
  sConfig.Pulse = PULSE1_VALUE;
  HAL_TIM_PWM_ConfigChannel(&TimHandle, &sConfig, TIM_CHANNEL_1);
 

Here is the non-working LL Code, uses TIM1 Channel 2, PA9 - Adapted from the LL TIM PWM example but it used to use TIM3 Channel 2.   But this one outputs no signal at all.   and looks correct as can be.   Note this is for 20Khz with prescaler 0-399.

 

__STATIC_INLINE void  Configure_TIMPWMOutput(void)

{

  /*************************/

  /* GPIO AF configuration */

  /*************************/

  /* Enable the peripheral clock of GPIOs */

  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);

  LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_9, LL_GPIO_MODE_ALTERNATE);

  LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_9, LL_GPIO_PULL_DOWN);

  LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_9, LL_GPIO_SPEED_FREQ_HIGH);

  LL_GPIO_SetAFPin_8_15(GPIOA, LL_GPIO_PIN_9, LL_GPIO_AF_1);

  LL_APB1_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM1);

  LL_TIM_SetPrescaler(TIM1, __LL_TIM_CALC_PSC(SystemCoreClock, 8000000));

  LL_TIM_EnableARRPreload(TIM1);

  LL_TIM_SetAutoReload(TIM1, __LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(TIM1), 20000));

  LL_TIM_OC_SetMode(TIM1, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_PWM1);

  LL_TIM_OC_SetPolarity(TIM1, LL_TIM_CHANNEL_CH2, LL_TIM_OCPOLARITY_HIGH);

  LL_TIM_OC_SetCompareCH2(TIM1, 0);

  LL_TIM_OC_EnablePreload(TIM1, LL_TIM_CHANNEL_CH2);

  LL_TIM_CC_EnableChannel(TIM1, LL_TIM_CHANNEL_CH2);

  LL_TIM_EnableCounter(TIM1);

  LL_TIM_GenerateEvent_UPDATE(TIM1);

}

 

/**

  * @brief  Changes the duty cycle of the PWM signal.

  *         D = (T/P)*100

  *           where T is the pulse duration and P is the PWM signal period

  * @param  D Duty cycle

  * @retval None

  */

__STATIC_INLINE void Configure_DutyCycle(uint32_t D)

{

  uint32_t P;    /* Pulse duration */

  uint32_t T;    /* PWM signal period */

 

  /* PWM signal period is determined by the value of the auto-reload register */

  T = LL_TIM_GetAutoReload(TIM1) + 1;

 

  /* Pulse duration is determined by the value of the compare register.       */

  /* Its value is calculated in order to match the requested duty cycle.      */

  P = (D*T)/100;

  LL_TIM_OC_SetCompareCH2(TIM1, P);

}

Outcomes