Timer4 PWM Not Starting: Cortex-M3


Last Update: May 22, 2024 @ 10:11

This is another Application Note relevent to using STM32CubeMX (MX) and True Studio (TS). 

IOC boards with LCDs have adjustable backlighting which can be controlled by a user app. Backlight control is either done directly via the LCD chip (e.g. SSD1963) or by providing a PWM waveform to a circuit on the LCD module.

One of the Cortex-M3 timer channels is configured for PWM output. When the mcu configuration is done in MX, some tweaking of the generated code in TS is required.

The problem we had was with an STM32F103VE board that required TIM4-CH2 on pin PD13 to be configured for PWM. We made the necessary changes (described below) in the MX_TIM4_Init() function in main.c, and the related HAL_TIM_PWM_MspInit() function in stm32f1xx_hal_msp.c. We’d done this with no problems on other boards (using other timers) with no problems.

With this board, TIM4-CH2 just would not start the PWM waveform, and so the backlight was not working.

Like many coding issues, once the fix is located, the answer becomes obvious. Here’s some code:

/* in main.c */
static void MX_TIM4_Init(void)
 {
     TIM_OC_InitTypeDef sConfigOC = {0};
     uint32_t D128Prescaler = 720; // gives a 100kHz pulse from the 72MHz APB1 timer clock.
     uint32_t Period =  256;      // PWM period ~= 2ms
   /* USER CODE END TIM4_Init 1 */
     htim4.Instance = TIM4;
     htim4.Init.Prescaler = D128Prescaler - 1;
     htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
     htim4.Init.Period = Period - 1;
     htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
     htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
     if (HAL_TIM_PWM_Init(&htim4) != HAL_OK)
     {
       Error_Handler();
     }
     sConfigOC.OCMode = TIM_OCMODE_PWM1;
     sConfigOC.Pulse = 128;
     sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
     sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
     if (HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
     {
       Error_Handler();
     }
     HAL_TIM_PWM_MspInit(&htim4);
 }
/* in  stm32f1xx_hal_msp.c  */
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* htim_pwm)
 {
     GPIO_InitTypeDef GPIO_InitStruct = {0};
    if(htim_pwm->Instance == TIM4)
    {
       __HAL_RCC_GPIOD_CLK_ENABLE();
      /**TIM2 GPIO Configuration  PD13     ------> TIM4_CH2  */
      GPIO_InitStruct.Pin = LCD_BL_PWM_Pin;
      GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
      GPIO_InitStruct.Pull = GPIO_NOPULL;
      GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
      HAL_GPIO_Init(LCD_BL_PWM_GPIO_Port, &GPIO_InitStruct);
      __HAL_AFIO_REMAP_TIM4_ENABLE(); // THIS is what we missed...
      __HAL_RCC_TIM4_CLK_ENABLE();
    }
 }
/* See also  HAL_TIM_PWM_MspDeInit() */

The key here is GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

For TIM4, Alternate Function (i.e. AF) has to be set. Hence the use of __HAL_AFIO_REMAP_TIM4_ENABLE();

With this added, the backlight PWM was fully functional.

Comments, clarifications and questions are welcome, see Contact.


Since you are here … do please have a look around my site. These devices may be of interest.

Decaf IOC-2xe   Decaf IOC-235  Decaf IOC-280Z-4   Decaf IOC-350   Decaf IOC-370


[xyz-ihs snippet=”PageCopyrightStatement”]



Copyright © 2025 PiXCL Automation Tech Notes, Canada. All Rights Reserved.