I'm using a STM32 for PAC (phase-angle control) of a mains load (cos phi > 0.95) and I'm unsure, how I should implement the firing of the pulses.

My first try was to use two timers and a EXTI pin, which measures the zero-crossing. When I detect a zero-crossing, I start a delay timer in one-shot mode and delay according my phase angle. After the delay (output compare trigger), I trigger an interrupt, where I deactivate the delay timer (such that I don't need to finish the period) and start a puls timer in single shot-mode, that gives a 100us puls.

**Concept**:
[![enter image description here][1]][1]

**Glitches**:
[![enter image description here][2]][2]

This works pretty good so far, but I have seen, that when I change the PAC angle several times, I sometimes get 2-3 mains period, that the delay timer does not trigger anymore. The timer is started correctly from the EXTI interrupt, but no delay timer interrupt is triggered. 

I also attached the important code, where the ZC Interrupt triggers the CM_POWER_ZC_Trigger() function, that starts the delay timer with TIMER_PAC_Single_Delay_Trigger(). The delay timer interrupt should then trigger HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim) (but it does not always), which starts then a again a puls.

Any ideas, how I can improve PAC? What I already tried is to use Timer3 (puls timer) in slave mode of Timer2 (delay timer) and then not use any interrupts, but I could not achieve proper functions with just one-puls mode. The thing is, that I cannot let the delay timer period constant at 10ms (50Hz), since it should also work for 60Hz and thats why I disable the timer after the output-compare interrupt.

**STM32 HAL Settings**:

 //PAC Delay Timer
 static void MX_TIM2_Init(void)
 {
 
 /* USER CODE BEGIN TIM2_Init 0 */
 
 /* USER CODE END TIM2_Init 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 = 31;
 htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
 htim2.Init.Period = 65535;
 htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
 htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
 if (HAL_TIM_OC_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_TIMING;
 sConfigOC.Pulse = 0;
 sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
 sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
 if (HAL_TIM_OC_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN TIM2_Init 2 */
 
 /* USER CODE END TIM2_Init 2 */

 }

 //PAC Puls Timer
 static void MX_TIM3_Init(void)
 {
 
 /* USER CODE BEGIN TIM3_Init 0 */
 
 /* USER CODE END TIM3_Init 0 */
 
 TIM_MasterConfigTypeDef sMasterConfig = {0};
 TIM_OC_InitTypeDef sConfigOC = {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 = 3199;
 htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
 htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
 if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
 {
 Error_Handler();
 }
 if (HAL_TIM_OnePulse_Init(&htim3, TIM_OPMODE_SINGLE) != HAL_OK)
 {
 Error_Handler();
 }
 sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
 sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
 if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
 {
 Error_Handler();
 }
 sConfigOC.OCMode = TIM_OCMODE_PWM2;
 sConfigOC.Pulse = 0;
 sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
 sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
 if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN TIM3_Init 2 */
 
 /* USER CODE END TIM3_Init 2 */
 HAL_TIM_MspPostInit(&htim3);
 
 }

 /****************************/
 /* Defines in Header file	*/
 /****************************/
 void TIMER_PAC_Single_Puls_Trigger()
 {
 	TIM3->CR1 &= ~TIM_CR1_CEN; //This re-enables the One-Shot Timer
 	TIM3->CR1 |= TIM_CR1_CEN;
 }
 
 /****************************/
 /* Defines in Header file	*/
 /****************************/
 void TIMER_PAC_Single_Delay_Trigger()
 {
 	TIM2->CR1 &= ~TIM_CR1_CEN; //This re-enables the One-Shot Timer
 	TIM2->CR1 |= TIM_CR1_CEN;
 }

 /********************/
 /* External defined	*/
 /********************/
 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
 {
 	if(GPIO_Pin == CM_ZC_PIN)
 	{
 		/************************/
 		/* Set a trigger puls	*/
 		/************************/
 		CM_POWER_ZC_Trigger();
 
 		/****************************************/
 		/* Update the cycle time from the ZC	*/
 		/****************************************/
 		cm_master.power.zc_cycle_time_us = Get_F_Main_Time_us();
 
 	}
 }
 
 /********************/
 /* External defined	*/
 /********************/
 void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
 {
 	if(htim->Instance == TIM2)
 	{
 		/************************************************/
 		/* Extremly important to stop the timer here	*/
 		/************************************************/
 		TIM2->CR1 &= ~TIM_CR1_CEN;
 		TIM2->CNT = 0;
 
 		/************/
 		/* Debug	*/
 		/************/
 		HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_14);
 
 		/****************/
 		/* Trigger Puls	*/
 		/****************/
 		TIMER_PAC_Single_Puls_Trigger();
 	}
 
 }

 /****************************/
 /* Defines in Header file	*/
 /****************************/
 void CM_POWER_ZC_Trigger()
 {
 	cm_master.power.zc_cnt++;
 	if(!cm_master.power.pac_enabled)
 	{
 		return;
 	}
 
 
 	/************************************************/
 	/* Trigger the delay according the PAC cycle	*/
 	/************************************************/
 #ifdef PAC_TRIGGER_ACTIVE
 	TIMER_PAC_Single_Delay_Trigger();
 #endif
 
 }

**Edit**: 
I tried now to use only Timer3 and start it over the EXTI interrupt and depicted above. The glitch is still here and I don't use any interrupt except the EXTI interrupt now and the EXTI interrupt comes reliable. So somehow I think the timer runs the full period of ARR = 65535 and is not stopped in some cases. How should I properly reset the timer in one-shot mode, that it won't glitch?


 [1]: https://i.sstatic.net/FCa2x.png
 [2]: https://i.sstatic.net/iMilT.png