cancel
Showing results for 
Search instead for 
Did you mean: 

timer not sending the correct number of pulses

JustSomeGuy
Associate III

Hi all,

I am trying to send x number of 100 ms pulses (50 ms on, 50 ms off) with a PWM in one-pulse mode. when I wired the output to a pulse-counting device, I noticed that it is picking up 10x less pulses than is programmed. I believe there is an issue with how I programmed the timer, but could not figure it out for the life of me. Any ideas on what might be causing this issue? I am using a B-L072Z-LRWAN1. here are the relevant blocks of code.

Main loop. the variable pulsesToSend is being received by another LoRa board, and that part works no issue. it is getting the correct number there:

  while(HAL_TIM_OnePulse_Start_IT(&htim2, TIM_CHANNEL_1) == HAL_BUSY);

  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  if((pulsesToSend>0) && pulseComplete) //execute if there are pulses to send AND the PWM cycle is finished
	  {
		  __HAL_TIM_SET_COUNTER(&htim2, 0);
		  __HAL_TIM_ENABLE(&htim2);
		  pulseComplete = false;
		  pulsesToSend--;
		  pulsesSent++;
	  }
  }

the callback function:

//this function keeps track of the number of pulses sent.
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
	  if(htim->Instance == TIM2) pulseComplete = true;
}

Timer set-up:

static void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 63;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 49999;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_OnePulse_Init(&htim2, TIM_OPMODE_SINGLE) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM2;
  sConfigOC.Pulse = 25000;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */
  setPeriod = htim2.Init.Period;
  /* USER CODE END TIM2_Init 2 */
  HAL_TIM_MspPostInit(&htim2);

}

 

6 REPLIES 6

I don't Cube, but you probably should use HAL_TIM_PeriodElapsedCallback() rather than HAL_TIM_PWM_PulseFinishedCallback() to allow for both the ON and OFF periods.

JW

I tried that, but that interrupt callback never gets triggered. This is the last part I'm hung up on; which callback function works with PWM in one-pulse? currently I am using HAL_TIM_PWM_PulseFinishedCallback() which seems to get called twice; once when CNT >= CCR1, and once when CNT == ARR. Is this correct? How can I add a check in the interrupt callback to toggle a flag only during a rollover event and not a CNT >= CCR1 event? I tried this in the callback function:

if((htim->Instance  == TIM2) && (htim->Instance->CNT == 0)) 

but the CNT register seems to keep going once the interrupt is triggered, so it's never 0 during the callback. Is there a specific flag bit in the htim struct that would tell me if the interrupt was triggered by a rollover?

> currently I am using HAL_TIM_PWM_PulseFinishedCallback() which seems to get called twice; once when CNT >= CCR1, and once when CNT == ARR. Is this correct?

You don't seem to check, which channel caused the interrupt/callback. Can't this be interrupt from some other channel, i.e. when CNT == CCRx, where CCRx = 0 (because they were never set)? Try checking htim->Channel if it is set to HAL_TIM_ACTIVE_CHANNEL_1 or some other value.

> Is there a specific flag bit in the htim struct that would tell me if the interrupt was triggered by a rollover?

I don't know about htim struct, but TIMx_SR contains the flags indicating what caused the interrupt, "rollover" is called "update", the flag is TIMx_SR.UF. But Cube/HAL already read those flags and might have also cleared them by the time the callback is called. OTOH, the HAL_TIM_PWM_PulseFinishedCallback() callback is not supposed to be called upon Update, only upon Compare events; Update should result in HAL_TIM_PeriodElapsedCallback(). If it is not called, that probably means that it's not enabled (TIMx_DIER.UIE).

---

As I've said, I don't use Cube.

Would you use registers, this would be a no-question. Cube does things for you - e.g. enables interrupts - but then it does it in the way the Cube authors deemed appropriate. If it does not fit your application, you will fight it and spend some time, maybe comparable what you've spared by using Cube.

Sorry, I can't help you with Cube-specific questions.

JW

No worries at all, your answers still point me in the right direction. Thank you!

BarryWhit
Senior III

@JustSomeGuy , "what callback gets called" is a common question with the HAL and the answer is sometimes surprising. My advice would be to read the code for `HAL_TIM_IRQHandler`, and possibly step through it with a debugger. You will find the section that  deals with your event of interest and you will see exactly which callback is called and how the HAL code picks it. Also double check your "NVIC" peripheral config in CubeMX/IDE, and make sure you don't need to enable anything. But If you're getting any timer interrupt, that's probably configured correctly already.

- If a post has answered your question, please acknowledge the help you received by clicking "Accept as Solution".
- Once you've solved your issue, please consider posting a summary of any additional details you've learned. Your new knowledge may help others in the future.

Thank you! I will do that.