Search code examples
timerstm32halpwmstm32cubeide

How do I fix my code to make an LED blink on an STM32 Nucleo Board in sync with 1sec, 50% duty cycle PWM?


My board is the NUCLEO-H743ZI2

I configured TIM4,CH2 as PWM such that TIM4 output should be HI for half a second and LO for half a second. Here is the block.ioc clock and pin configuration enter image description here enter image description here enter image description here

I auto generated the code and tried to add my own to toggle the LED with the H/L of PWM. What I want to do is this:

if(timer_4 == HIGH) LED_state = !LED_state

Here is the actual code:

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_ETH_Init();
  MX_USART3_UART_Init();
  MX_USB_OTG_FS_PCD_Init();
  MX_DAC1_Init();
  MX_TIM3_Init();
  MX_TIM4_Init();
  /* USER CODE BEGIN 2 */

  HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_2);
  uint16_t timer_init_val = __HAL_TIM_GET_COUNTER(&htim4);
  uint16_t timer_poll;

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

      timer_poll = __HAL_TIM_GET_COUNTER(&htim4);
      if(timer_poll - timer_init_val >= 500) {
          HAL_GPIO_TogglePin(GPIOB,LD1_Pin);
      }



    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

I know that this most likely does not work. In fact. I was confused because replacing the >=500 with <=100 actually made it seem like it was working..but the LED just blinks at seemingly random intervals. I have tried to test if !timer{..} (timer reached 0) to toggle the LED but none of my methods have seemed to work.

Am I misunderstanding something about timers? Is there something super obvious I am missing? It does not seem like it would be difficult to blink an LED with a 1sec PWM


Solution

  • What you have written does the following:

    1. for 500 counts of the timer do nothing
    2. after that turn the LED repeatedly on and off (faster than the eye can see) until the timer wraps
    3. when the timer wraps (65.536 seconds?) goto (1).

    You can't really do this with GPIO_TogglePin because you will call it many many times during the same value of the counter.

    Try something like:

    if (((timer_poll - timer_init_val) % 1000) < 500)
    {
        HAL_GPIO_WritePin(GPIOB, LD1_Pin, 0);
    }
    else
    {
        HAL_GPIO_WritePin(GPIOB, LD1_Pin, 1);
    }
    

    But this still isn't completely clean when the timer wraps. To sort that out you can adjust the period of the timer to be a multiple of the period of your sequence.