cancel
Showing results for 
Search instead for 
Did you mean: 

Failed attempt on using 2 Timers to Toggle GPIO.

Oahme.1
Associate III

Hello , 
I have initialized two timers , Timer3 and Timer9. Im using Timer9 with 137uS period , setting my gpio pin high , starting Tim3 Interrupt with 54uS period for now .When Tim3 Interrupt occurs I simply reset my gpio pin.My problem is that I should have a high pwm for 54uS and 137uS pwm in reset state.I have thoroughly checked individual timers to just toggle single gpio in 1 single interrupt , both give me a stable 137uS pwm and 54uS pwm . But as i use two different gpio's to set and reset my gpio. I get irregular pwm that has values randomly changing. My pwm will have a constant 137uS low and a variable high pwm state which is Max 122uS for now as I said its just fixed 54uS so I also did not enable autoload preload .This is the first time I'm doing it this way.

My Code :

Timer Setting : 

void MX_TIM3_Init(void)
{

  /* USER CODE BEGIN TIM3_Init 0 */

  /* USER CODE END TIM3_Init 0 */

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

  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 0;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 4700;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM3_Init 2 */

  //HAL_TIM_Base_Start_IT(&htim3);
  /* USER CODE END TIM3_Init 2 */

}
/* TIM9 init function */
void MX_TIM9_Init(void)
{

  /* USER CODE BEGIN TIM9_Init 0 */

  /* USER CODE END TIM9_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};

  /* USER CODE BEGIN TIM9_Init 1 */

  /* USER CODE END TIM9_Init 1 */
  htim9.Instance = TIM9;
  htim9.Init.Prescaler = 0;
  htim9.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim9.Init.Period = 11508;
  htim9.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim9.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim9) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim9, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM9_Init 2 */
  HAL_TIM_Base_Start_IT(&htim9);
  /* USER CODE END TIM9_Init 2 */

}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspInit 0 */

  /* USER CODE END TIM3_MspInit 0 */
    /* TIM3 clock enable */
    __HAL_RCC_TIM3_CLK_ENABLE();

    /* TIM3 interrupt Init */
    HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM3_IRQn);
  /* USER CODE BEGIN TIM3_MspInit 1 */

  /* USER CODE END TIM3_MspInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM9)
  {
  /* USER CODE BEGIN TIM9_MspInit 0 */

  /* USER CODE END TIM9_MspInit 0 */
    /* TIM9 clock enable */
    __HAL_RCC_TIM9_CLK_ENABLE();

    /* TIM9 interrupt Init */
    HAL_NVIC_SetPriority(TIM1_BRK_TIM9_IRQn,0, 0);
    HAL_NVIC_EnableIRQ(TIM1_BRK_TIM9_IRQn);
  /* USER CODE BEGIN TIM9_MspInit 1 */

  /* USER CODE END TIM9_MspInit 1 */
  }
}

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspDeInit 0 */

  /* USER CODE END TIM3_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM3_CLK_DISABLE();

    /* TIM3 interrupt Deinit */
    HAL_NVIC_DisableIRQ(TIM3_IRQn);
  /* USER CODE BEGIN TIM3_MspDeInit 1 */

  /* USER CODE END TIM3_MspDeInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM9)
  {
  /* USER CODE BEGIN TIM9_MspDeInit 0 */

  /* USER CODE END TIM9_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM9_CLK_DISABLE();

    /* TIM9 interrupt Deinit */
    HAL_NVIC_DisableIRQ(TIM1_BRK_TIM9_IRQn);
  /* USER CODE BEGIN TIM9_MspDeInit 1 */

  /* USER CODE END TIM9_MspDeInit 1 */
  }
}

 

Interrupt Callback function : 

volatile bool temp = true;
volatile bool Flag = true;

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{

	if(htim->Instance == TIM3)
			{
			if(temp)
				{

					temp= false;
				}
				//HAL_TIM_Base_Start_IT(&htim9);
			//__HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE);

			if(Flag)
			{
				HAL_GPIO_WritePin(GPIOA, weld_Pin,GPIO_PIN_RESET);

				Flag = false;
				__NOP();
			}

			}

	if(htim->Instance == TIM9)
			{

			if(temp)
			{

				temp= false;
				//HAL_TIM_Base_Init(&htim3);
				HAL_TIM_Base_Start_IT(&htim3);
			}

			//HAL_GPIO_TogglePin(GPIOA,weld_Pin);
			Flag = true;
			HAL_GPIO_WritePin(GPIOA, weld_Pin,GPIO_PIN_SET);
			__NOP();

			}
}

 

Initially I got overconfident and defined the whole structure program which is much complicated hoping this will definitely work , but unfortunately I had to go back to the basics because I was not getting the desired  Timer results.

I will add 2 photos which depict what I want and what I'm actually getting .

Any Help would be great . @Tesla DeLorean @TDK  ,Can you help in this matter ? 

Thanks.

Actual Picture

PWM Actual.jpeg

 

Original Idea

PWM_Orginal.png

 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

Using a single timer channel and feeding ARR with an array via DMA will be the best (lowest cpu cost, highest accuracy) solution here.

Using interrupts will always add delay, but you could use them. Why use two timers? Use a single timer and update the ARR value on the period elapsed interrupt callback.

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

View solution in original post

14 REPLIES 14
TDK
Guru

Using a single timer channel and feeding ARR with an array via DMA will be the best (lowest cpu cost, highest accuracy) solution here.

Using interrupts will always add delay, but you could use them. Why use two timers? Use a single timer and update the ARR value on the period elapsed interrupt callback.

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

Thanks @TDK  for replying , For now all I did was reinitialize the counter for both timers to zero in Tim9 and fortunately everythings working fine , dont know what happens when Im using ARR to increase period value.

You asked ,why use two timers?, As you can see I'm not just increasing my PWM period , But actually I'm going from 150Hz frequency to 50Hz. I really don't know other way that'll get my Job done, If you have suggestions Your more then welcome to help Sir. Also I've designed the PCB so basically I've allotted GPIO's as My PWM Source, But Could this using DMA ? How can I keep a constant 137uS period and just change the ON Time of PWM ? That would be really interesting to know , using DMA to do variable pwm is possible but that just changes the duty cycle. Do you understand what I'm saying @TDK  ? 

Oahme.1
Associate III

Looking at the picture in my previous reply can you tell me how its possible ?

> I'm not just increasing my PWM period , But actually I'm going from 150Hz frequency to 50Hz.

 

That just means that you have to change both ARR and CCRx. You want them both be preloaded. And if you insist on using interrupts instead of TIM_CHx pin, then interrupt on both Update and CCx event.

> Also I've designed the PCB so basically I've allotted GPIO's as My PWM Source

Which STM32? Which pin?

 

JW

Oahme.1
Associate III

Thanks @waclawek.jan  for replying ,I'll try this and get back ,But my pins will be a problem , I'll have to do something about it ,if it works with compare capture . MCU is stm32f401CxU6 , Pin is PB12,PB13 for CH1 and CH2 respectively.

> Do you understand what I'm saying @TDK  ? 

Not really. Your "original idea" pic shows a constant 7.3 kHz. My reply had a typo. I meant to suggest changing only CCR1, not ARR. But you can change ARR as well to change the frequency, as JW mentions.

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

Yes your right , I'm doing it the other way now , Firstly I tried using Compare Capture Mode but upon using SetCompare in the interrupt I'm unable to change the Duty Cycle. No Matter what the pulse value is it just outputs a constant 7.3kHz.I left that for now and am using PWM Mode. I'll show the settings I've done to achieve .It does work correctly ,but it seems that when using a lookup table to go through 22 values in the array , some duty cycle PWM is not what it should be , probably missing out on some settings I believe ? Thank you @TDK and @waclawek.jan for your replies .This a very simple implementation that should work, but I'm getting different pulses ,also lastly it seems that the last  value before null terminating character isn't being outputted .

Code_1.PNG

 

Code_2.PNG

 

Code_3.PNG

 

PWM_MODE_1.PNG

 

PWM_MODE_3.PNG

 

Code_4.PNG

 

Oahme.1
Associate III

I have one problem , How do I toggle my gpio on two different events , compare capture and timer update flag ?

once when 137uS interrupts I set my gpio pin and once when compare capture event occurs I gpio pin low   

It seems that the logic given below isn't working for Update Interrupt Flag: 

 

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{

	if((htim->Instance->SR &  TIM_FLAG_UPDATE  ) ==  TIM_FLAG_UPDATE )
	{
		__NOP();
		HAL_GPIO_WritePin(GPIOA,Weld_Pin,GPIO_PIN_SET);
		//__HAL_TIM_CLEAR_FLAG(&htim1,TIM_FLAG_UPDATE);
		//__HAL_TIM_CLEAR_IT(&htim1,TIM_FLAG_UPDATE);
	}


	if((htim->Instance->SR & TIM_FLAG_CC1  ) == TIM_EVENTSOURCE_CC1)
	{

	//	HAL_GPIO_WritePin(GPIOA,Weld_Pin,GPIO_PIN_RESET);
	if(sq==22)
	{
		sq=0;

		HAL_TIM_Base_Stop_IT(&htim1);
		HAL_TIM_PWM_Stop_IT(&htim1, TIM_CHANNEL_1);
		Flag = false;

	}

	if(Flag)
	{

		__HAL_TIM_SET_COUNTER(&htim1,0);
		__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,weldx_calculated[sq++]);

	}
}

}

 

Could this be because in the Interrupt Handler IRQ This is already reset in software ,after that the PeriodElaspedCallback is executed, I'm leaving the code snippet below where they reset Update Interrupt Flag : 

 /* TIM Update event */
  if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET)
  {
    if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) != RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
#if (USE_HAL_TIM_REGISTER_CALLBACKS == 1)
      htim->PeriodElapsedCallback(htim);
#else
      HAL_TIM_PeriodElapsedCallback(htim);
#endif /* USE_HAL_TIM_REGISTER_CALLBACKS */
    }
  }

 

HAL_TIM_PeriodElapsedCallback() is specifically for Update interrupts. CC interrupts have some other callback; I don't use Cube/HAL so I don't care.

I also recommend not to use Cube/HAL if you want to achieve any reasonable timing/precision.

JW