cancel
Showing results for 
Search instead for 
Did you mean: 

PWM Output Not Generating Waveform for STM32F429ZI

EGold.3
Associate II

Hi everyone, I'm just trying to test and verify some clock frequencies for a PWM waveform are correct. I used CubeMX to generate some code that has set the clock frequency of the MCU to 72 mHz and I am trying to achieve a 20 kHz PWM frequency. I enabled Timer 1 with channel 1 as the output channel (Muxed to Pin E9 on my board). I also made sure to make the call to HAL_TIM_PWM_Start so my timer would actually start counting and thus generate the waveform. Currently I have the pulse set to a value which should generate a 100% duty rate, but no matter what duty rate I set to, I never get any waveform.

Connecting the pin to a logic analyzer shows that nothing is every captured and the pin stays low the whole time. I confirmed this by hooking the pin up to a breadboard with an LED and when I step through my code nothing ever drives the LED to be turned on. I noticed during my step through in Keil that the IDR register for Port E will toggle bit 9, so the PWM must be effecting the pin state in some way, but the ODR and BSRR register stays at 0 the whole time. Attached is my code:

int main(void)
{
  /* USER CODE BEGIN 1 */
 
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM1_Init();
  /* USER CODE BEGIN 2 */
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
  while (1)
  {
 
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
 
/**
  * @brief System Clock Configuration
  * @retval None
  */
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_SCALE3);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 144;
  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_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}
 
/**
  * @brief TIM1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_TIM1_Init(void)
{
 
  /* USER CODE BEGIN TIM1_Init 0 */
 
  /* USER CODE END TIM1_Init 0 */
 
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
 
  /* USER CODE BEGIN TIM1_Init 1 */
 
  /* USER CODE END TIM1_Init 1 */
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 35;
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 99;
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 99;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
  if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
  sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
  sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
  sBreakDeadTimeConfig.DeadTime = 0;
  sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
  sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
  sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
  if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM1_Init 2 */
 
  /* USER CODE END TIM1_Init 2 */
  HAL_TIM_MspPostInit(&htim1);
 
}
 
/**
  * @brief GPIO Initialization Function
  * @param None
  * @retval None
  */
static void MX_GPIO_Init(void)
{
 
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOE_CLK_ENABLE();
 
}

1 ACCEPTED SOLUTION

Accepted Solutions

Make sure the pin is actually connected as you suppose it to be. If it's a Nucleo or Disco board, check jumpers/solder bridges. As a test, set the given pin to Output and toggle it in GPIO_ODR, perhaps in debugger, to see the effect on the LED.

For timer operation, read out and check (or post) TIM and relevant GPIO registers content. Make sure GPIOx_MODER is set to AF and the proper AF is selected in GPIOx_AFR for given pin; and as Timer1 is an Advanced Timer, makes sure TIMx_BDTR.MOE is set.

Timer does not influence GPIO_ODR/GPIO_BSRR in any way. OTOH, GPIO_IDR reflects the actual state of the pin, regardless of how it's driven (unless set to Analog in GPIOx_MODER).

I don't use Cube.

JW

View solution in original post

6 REPLIES 6

Make sure the pin is actually connected as you suppose it to be. If it's a Nucleo or Disco board, check jumpers/solder bridges. As a test, set the given pin to Output and toggle it in GPIO_ODR, perhaps in debugger, to see the effect on the LED.

For timer operation, read out and check (or post) TIM and relevant GPIO registers content. Make sure GPIOx_MODER is set to AF and the proper AF is selected in GPIOx_AFR for given pin; and as Timer1 is an Advanced Timer, makes sure TIMx_BDTR.MOE is set.

Timer does not influence GPIO_ODR/GPIO_BSRR in any way. OTOH, GPIO_IDR reflects the actual state of the pin, regardless of how it's driven (unless set to Analog in GPIOx_MODER).

I don't use Cube.

JW

TDK
Guru

> I noticed during my step through in Keil that the IDR register for Port E will toggle bit 9, so the PWM must be effecting the pin state in some way

If IDR is changing, but you're not seeing any change on the scope, you're probably not measuring the actual pin.

With Period = Pulse, you're not going to get a waveform, you're going to get a DC value.

I guess this is actually 1% duty cycle, so you should see a waveform.

If you feel a post has answered your question, please click "Accept as Solution".

I’m a bit confused, why it would be a 1% duty cycle. I thought this configuration in the code would be equivalent to simply driving the pin high constantly, with a 100% duty cycle, since the pulse width would take up the entire counter period.

When CCRx=ARR, polarity flips. This happens when ARR=99, then it flips again when ARR rolls over to 0.
You want Pulse=100 or 0.
If you feel a post has answered your question, please click "Accept as Solution".

I see, thanks! I never knew that.

Turns out I actually had my logic analyzer/breadboard connected to Pin E11 rather than E9. What a fool I am. Thank you for the help, you were right that if IDR was toggling the pin state must have some observable output. I was just looking at the wrong pin!