cancel
Showing results for 
Search instead for 
Did you mean: 

Timer Input Capture duty cycle calculation is sometimes complementary

EmbeddedPepe
Associate III

Hi!

I have two PWM signals coming into two MCU pins, that are two TIM4 channels. Channel 1 and Channel 2.

 

I initialized both Channel 1 and Channel 2 to input capture mode on Both Edges and enabled the Capture/Compare Interrupt (Not in slave master mode but free running)

 

I capture the value for 3 times and save it into an array and then proceed to calculate the full period as 3rd value minus the first one and the high period as 2nd value minus the first one.

 

The duty calculation is correct but sometimes instead of getting the correct duty cycle ( ex.70%) I get the complementary: 100% - 70% = 30%

 

Channel 1 Configuration:

RCC_ClocksTypeDef __RCC_CLOCK;

	myPWMInputCtor(me);

	RCC_GetClocksFreq(&__RCC_CLOCK);
	me->clock = __RCC_CLOCK.PCLK1_Frequency * 2; //APB1

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

	me->GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	me->GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	me->GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	me->GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	me->GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

	GPIO_Init(GPIOD, &me->GPIO_InitStructure);

	GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIM4);

	TIM4_IRQHandler_ptf = TIM4_IRQ_PWM;
	me->NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
	me->NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	me->NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	me->NVIC_InitStructure.NVIC_IRQChannelCmd = 1;
	NVIC_Init(&me->NVIC_InitStructure);

	me->TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
	me->TIM_TimeBaseStructure.TIM_Prescaler = 840 - 1;
	me->TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
	me->TIM_TimeBaseStructure.TIM_ClockDivision= TIM_CKD_DIV1;
	me->TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;

	TIM_TimeBaseInit(TIM4, &me->TIM_TimeBaseStructure);

	me->TIM_CH1_ICInitStructure.TIM_Channel 		= TIM_Channel_1;
	me->TIM_CH1_ICInitStructure.TIM_ICPolarity 		= TIM_ICPolarity_BothEdge;
	me->TIM_CH1_ICInitStructure.TIM_ICSelection 	= TIM_ICSelection_DirectTI;
	me->TIM_CH1_ICInitStructure.TIM_ICPrescaler 	= TIM_ICPSC_DIV1;
	me->TIM_CH1_ICInitStructure.TIM_ICFilter 		= 0x0;

	TIM_ICInit(TIM4, &me->TIM_CH1_ICInitStructure);
	TIM_SelectInputTrigger(TIM4, TIM_TS_TI1FP1);
                                          // Select the slave Mode: Reset Mod

                            // Enable the CC1 and the update Interrupt Request
	TIM_ITConfig(TIM4, TIM_IT_CC1, ENABLE);

	TIM_ClearFlag(TIM4, TIM_FLAG_Update);
	TIM_Cmd(TIM4, ENABLE);

 

Channel 2 Configuration:

RCC_ClocksTypeDef __RCC_CLOCK;

	myPWMInputCtor(me);

	RCC_GetClocksFreq(&__RCC_CLOCK);
	me->clock = __RCC_CLOCK.PCLK1_Frequency * 2; //APB1

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

	me->GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
	me->GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	me->GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	me->GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	me->GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

	GPIO_Init(GPIOD, &me->GPIO_InitStructure);

	GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_TIM4);

	TIM4_IRQHandler_ptf = TIM4_IRQ_PWM;
	me->NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
	me->NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	me->NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	me->NVIC_InitStructure.NVIC_IRQChannelCmd = 1;
	NVIC_Init(&me->NVIC_InitStructure);

	me->TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
	me->TIM_TimeBaseStructure.TIM_Prescaler = 840 - 1;
	me->TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
	me->TIM_TimeBaseStructure.TIM_ClockDivision= TIM_CKD_DIV1;
	me->TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;

	TIM_TimeBaseInit(TIM4, &me->TIM_TimeBaseStructure);

	me->TIM_CH2_ICInitStructure.TIM_Channel 		= TIM_Channel_2;
	me->TIM_CH2_ICInitStructure.TIM_ICPolarity 		= TIM_ICPolarity_BothEdge;
	me->TIM_CH2_ICInitStructure.TIM_ICSelection 	= TIM_ICSelection_DirectTI;
	me->TIM_CH2_ICInitStructure.TIM_ICPrescaler 	= TIM_ICPSC_DIV1;
	me->TIM_CH2_ICInitStructure.TIM_ICFilter 		= 0x0;

	TIM_ICInit(TIM4, &me->TIM_CH2_ICInitStructure);

	                                  // Select the TIM8 Input Trigger: TI1FP1
	TIM_SelectInputTrigger(TIM4, TIM_TS_TI2FP2);
                                          // Select the slave Mode: Reset Mode
	//TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Reset);


	TIM_ITConfig(TIM4, TIM_IT_CC2, ENABLE);

	TIM_ClearFlag(TIM4, TIM_FLAG_Update);
	TIM_Cmd(TIM4, ENABLE);

 

duty cycle calculation:

if (TIM_GetITStatus(TIM4, TIM_IT_CC1) != RESET) {
			tmyPWMInput *pPWM4_1 = &myCTRL.myHW.myPortDCfg.myPWM4_1; //PIN12
			                  // Clear TIM8 Capture Compare1 interrupt pending bit
			TIM_ClearITPendingBit(TIM4, TIM_IT_CC1);
			if ( i != 3 ) ch1[i++] = TIM4->CCR1;
			else if (i == 3) {
				uint8_t j;

				uint32_t full_period = ch1[2] - ch1[0];
				uint32_t high_period = (ch1[1] - ch1[0]);
				pPWM4_1->HighPeriod = high_period;
				pPWM4_1->FullPeriod = full_period;

				myPWMCalc(pPWM4_1);
				i = 0;
			}



	}
	if (TIM_GetITStatus(TIM4, TIM_IT_CC2) != RESET) {
			tmyPWMInput *pPWM4_2 = &myCTRL.myHW.myPortDCfg.myPWM4_2; //PIN13
			                  // Clear TIM8 Capture Compare1 interrupt pending bit
			TIM_ClearITPendingBit(TIM4, TIM_IT_CC2);
			if ( z != 3 ) ch2[z++] = TIM4->CCR2;
			else if ( z == 3 ) {

				uint32_t full_period = ch2[2] - ch2[0];
				uint32_t high_period = (ch2[1] - ch2[0]);
				pPWM4_2->HighPeriod = high_period;
				pPWM4_2->FullPeriod = full_period;

				myPWMCalc(pPWM4_2);
				z = 0;
			}

	}

 

Any idea on how to workaround this? or why it does this?

7 REPLIES 7
KnarfB
Principal III

If you capture on both edges, the timer may hit a rising or a falling edge first what explains your observations. If timing is not too fast, you may query the signal level in the interrupt handler and adjust your interpretation of the time stamps accordingly.

Are the two PWMs coherent with one edge in common or independent? In the first case, combined input PWM capture may help, in the second case, I would use anohter pair of combined channels.

hth

KnarfB

 

 

I'm sorry, could you explain further what can I do to workaround it? 

"you may query the signal level in the interrupt handler and adjust your interpretation of the time stamps accordingly."

 

Unfortunately I can only use these two channels.

The GPIO IDR register of a PWM pin should hold the current pin level, even if the pin is configured to alternate function mode for the timer. So, if your handler is fast enough, you can query IDR whether the first capture hit a rising or a falling edge.

hth

KnarfB 

What do you think about about setting channel to rising, reading the captured value, setting the channel to falling, getting a capture and set it again to rising to get the final capture and calculate all the variables?

TDK
Guru

If your signals are slow, say up to maybe 10 kHz, you can do what you propose. If they're very fast, you will miss edges and it will be difficult to know which edge is rising and which is falling, which is ultimately the cause of the error here.

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

This could also work. Double check that you can switch the settings on-the-fly and that the re-config works in time. 

hth

KnarfB 

 

The method you're referring to is a common technique used in embedded systems for capturing time intervals or pulses accurately. By configuring a hardware timer or input capture unit to trigger on rising and falling edges of a signal, you can capture timestamps corresponding to these events. This approach is efficient because it utilizes hardware features rather than relying on software polling, which can be less accurate and consume more processing power. After capturing the necessary timestamps (typically at the rising edge, falling edge, and another rising edge), you can compute variables such as pulse width, period, or frequency based on these timestamps. It's an effective method for real-time applications requiring precise timing measurements.