Skip to main content
DChan.2
Associate
May 25, 2020
Solved

When TIM4 is set to encoder mode, what is the minimum pulse width it can capture

  • May 25, 2020
  • 10 replies
  • 9797 views

I use to stm32f302 to measure the external encoder signal. There is no problem at low speed, but it will not work when the pulse width is reduced to about 11us. I want to know what is the limit pulse width (minimum) when TIM is set to encoder mode.

Pulse width as shown:0693W000001pP5lQAE.png

The initialization code is as:

void encoder_pin_init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_AHBPeriphClockCmd( RCC_AHBPeriph_GPIOB, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;	
	GPIO_Init( GPIOB, &GPIO_InitStructure );	
	
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_2);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_2);	
}
 
void encoder_timer_init(void)
{
	TIM_TimeBaseInitTypeDef 	TIM_TimeBaseStructure;
/* 	TIM_ICInitTypeDef 				TIM_ICInitStructure;
 */
	RCC_APB1PeriphClockCmd(	RCC_APB1Periph_TIM4, ENABLE );
	TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); 
 
	TIM_DeInit(TIM4);
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);		
	 
	TIM_TimeBaseStructure.TIM_Period =0xffffu;
	TIM_TimeBaseStructure.TIM_Prescaler =0u; 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0u;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);	 	
	
	TIM_EncoderInterfaceConfig( TIM4, 
								TIM_EncoderMode_TI1,
								TIM_ICPolarity_Rising, 
								TIM_ICPolarity_Rising );
	
/* 	TIM_ICStructInit(&TIM_ICInitStructure);
	TIM_ICInitStructure.TIM_ICFilter = 6;
	TIM_ICInit(TIM4, &TIM_ICInitStructure);
	
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
	TIM_ICInit(TIM4, &TIM_ICInitStructure); */
 
	TIM_Cmd(TIM4, ENABLE); 	
}

This topic has been closed for replies.
Best answer by berendi

So here is an improved version thanks to the comments by @Community member​ 

It counts the edges on TIM4_CH2, counting direction is determined by CH1 XOR CH3. Connect the direction signal to either CH1 or CH3, and pull down the other pin to GND. Leaving the unused timer input unconfigured, i.e. no pin assigned should work too, but this is not officially documented.

TIM4->CR2 = TIM_CR2_TI1S; // TIMx_CH1, CH2 and CH3 pins are connected to the TI1 input (XOR combination)
TIM4->SMCR = TIM_SMCR_SMS_1; // 0b0010: Encoder mode 2 - Counter counts up/down on TI2FP2 edge depending on TI1FP1 level.
TIM4->CCMR1 =
 (0b01 << TIM_CCMR1_CC1S_Pos) | // 0b01: CC1 channel is configured as input, IC1 is mapped on TI1
 (0b0010 << TIM_CCMR1_IC1F_Pos) | // 0b0010: fSAMPLING=***_INT, N=4
 (0b01 << TIM_CCMR1_CC2S_Pos) | // 0b01: CC2 channel is configured as input, IC2 is mapped on TI2
 (0b0011 << TIM_CCMR1_IC2F_Pos) | // 0b0011: fSAMPLING=***_INT, N=8
 0;
TIM4->CR1 = TIM_CR1_CEN; // enable counter

The timer is in encoder mode 2, counting the edges on TI2FP2, and using TI1FP1 (which is actually CH1^CH2^CH3) as the direction signal. Channels 1 and 2 are configured as inputs connected to TI1FP1 and TI2FP2 respectively. Look up the General-purpose timer block diagram in the reference manual if this makes little sense to you so far. There is a 4 cycles digital filter on TI1, and 8 cycles on TI2 to ensure that a transition on CH2 reaches TI1FP1 first.

0693W000001pXL8QAM.png

Let's suppose all inputs are initially low, then there is a rising edge on CH2. The input filter duration on TI1 is shorter, so the "opposite signal" is rising first, followed by TI2FP2 rising, resulting in the counter going up. Then there is a falling edge on CH2, "opposite signal" is already low when TI2FP2 is falling, causing the counter going up again. When CH1^CH3 is high, TI1 is the opposite of CH2, so the counter counts down on both the rising and the falling edge of CH2.

Some filtering is apparently necessary on TI1, the counter is sporadically changing when I remove the TI1 filter (IC1F) and change the direction repeatedly. It might be the result of my not too sophisticated test setup, which means touching dangling jumper wires to ground and using the internal pullups.

PS. direct link to this comment.

10 replies

TDK
Super User
May 25, 2020

Should work as long as edges are separated by at least one timer tick.

But a pulse on one of the encoder inputs won't change the counter. It'll increment on the rising edge and decrement on the falling (or the opposite depending on the other signal) so no net change after the pulse is done.

"If you feel a post has answered your question, please click ""Accept as Solution""."
DChan.2
DChan.2Author
Associate
May 26, 2020

Thanks Reply, I got understand, the stm32 only can decode the Quadrature signals, but can’t decode the Dir-Step signals.

TDK
Super User
May 26, 2020

The encoder is not designed to decode DIR/STEP signals as given to a stepper motor driver, if that's what you're trying to do.

"If you feel a post has answered your question, please click ""Accept as Solution""."
berendi
Principal
May 25, 2020

If you'd like to know what you are doing, read the TIM2/TIM3/TIM4 functional description chapter of the reference manual, up to and including PWM input mode.

 

You will be rewarded with a step-by-step description of what you need at the end.

Never mind, I've misunderstood the question

DChan.2
DChan.2Author
Associate
May 27, 2020

thank you reply

berendi
Principal
May 26, 2020

Looks like the encoder mode and the TI1^TI2^TI3 XOR feature (TIM_CR2_TI1S) can be abused to produce a dir/step encoder. It counts on CH2 pulses, CH1 XOR CH3 determines the direction, connect one of them to the actual direction signal, and pull the other one low.

TIM4->CR2 = TIM_CR2_TI1S;
TIM4->SMCR = TIM_SMCR_SMS_0;
TIM4->CCMR1 =
		TIM_CCMR1_CC1S_0 |
		TIM_CCMR1_IC1F_0 |
		TIM_CCMR1_IC1F_1 |
		TIM_CCMR1_CC2S_0 |
		TIM_CCMR1_IC2F_0 |
		TIM_CCMR1_IC2F_1;
TIM4->CR1 = TIM_CR1_CEN;

The timer is in encoder mode 1, actually counting the edges on TI1, and using TI2 as the direction signal. When CH1^CH3 is low and CH2 is rising, TI2 becomes high so the direction is downcounting on rising edge, the rising edge on TI1 decreases the counter by one. When CH2 is falling, TI2 becomes low so the direction is downcounting on falling edge, the falling edge on TI1 decreases the counter again. When CH1^CH3 is high, TI1 is the opposite of CH2, so the counter goes up on both edges.

It probably depends on some undocumented aspect of the hardware design, maybe the XOR logic delaying the edge on TI1. It doesn't work in encoder mode 2. It is also completely unreliable without some filtering on the timer input (IC1F and IC2F bits).

I have no STM32F3, so I have tested it on a STM32H743 which happened to sit on my desk, so it might work with your MCU, but there is no guarantee.

waclawek.jan
Super User
May 27, 2020

Interesting idea, but I'd expect the filters been set to two distinct values, to produce a defined phase shift...

Doesn't the direction change alone produce false counts in this scheme?

JW

berendi
Principal
May 27, 2020

> I'd expect the filters been set to two distinct values, to produce a defined phase shift...

Right, changing IC1F to 0b0010 (N=4) and leaving IC2F at 0b0011 (N=8) changed the direction and made it work with encoder mode 2 too.

> Doesn't the direction change alone produce false counts in this scheme?

Yes it does. But it affects only the least significant bit, which would be discarded anyway to get a pulse count, because it counts on both edges of the CH2 pulse.

waclawek.jan
Super User
May 27, 2020

>> Doesn't the direction change alone produce false counts in this scheme?

>>

> Yes it does. But it affects only the least significant bit, which would be discarded anyway to get a pulse count, because it counts on both edges of the CH2 pulse.

Okay, but counting on TI2FP2 (I don't know how the respective mode is called) should eliminate this problem, am I right?

Can you please post then the resulting "consolidated" code, so that we can use it in the future as a reference? Can you please use the binary constants and shifts for the non-single-bit bitfields, perhaps adding also comments?

It's a very smart trick, solving a problem which was brought up here several times - even if has the constraint given by the need for filtering and for CH3 to remain stationary - whih probably can be solved by simply not assigning TIM3 to any pin - ST might finally confirm this to be a guaranteed 0 as it behaves when tested. Thank you for posting and testing it.

Jan

berendi
berendiAnswer
Principal
May 27, 2020

So here is an improved version thanks to the comments by @Community member​ 

It counts the edges on TIM4_CH2, counting direction is determined by CH1 XOR CH3. Connect the direction signal to either CH1 or CH3, and pull down the other pin to GND. Leaving the unused timer input unconfigured, i.e. no pin assigned should work too, but this is not officially documented.

TIM4->CR2 = TIM_CR2_TI1S; // TIMx_CH1, CH2 and CH3 pins are connected to the TI1 input (XOR combination)
TIM4->SMCR = TIM_SMCR_SMS_1; // 0b0010: Encoder mode 2 - Counter counts up/down on TI2FP2 edge depending on TI1FP1 level.
TIM4->CCMR1 =
 (0b01 << TIM_CCMR1_CC1S_Pos) | // 0b01: CC1 channel is configured as input, IC1 is mapped on TI1
 (0b0010 << TIM_CCMR1_IC1F_Pos) | // 0b0010: fSAMPLING=***_INT, N=4
 (0b01 << TIM_CCMR1_CC2S_Pos) | // 0b01: CC2 channel is configured as input, IC2 is mapped on TI2
 (0b0011 << TIM_CCMR1_IC2F_Pos) | // 0b0011: fSAMPLING=***_INT, N=8
 0;
TIM4->CR1 = TIM_CR1_CEN; // enable counter

The timer is in encoder mode 2, counting the edges on TI2FP2, and using TI1FP1 (which is actually CH1^CH2^CH3) as the direction signal. Channels 1 and 2 are configured as inputs connected to TI1FP1 and TI2FP2 respectively. Look up the General-purpose timer block diagram in the reference manual if this makes little sense to you so far. There is a 4 cycles digital filter on TI1, and 8 cycles on TI2 to ensure that a transition on CH2 reaches TI1FP1 first.

0693W000001pXL8QAM.png

Let's suppose all inputs are initially low, then there is a rising edge on CH2. The input filter duration on TI1 is shorter, so the "opposite signal" is rising first, followed by TI2FP2 rising, resulting in the counter going up. Then there is a falling edge on CH2, "opposite signal" is already low when TI2FP2 is falling, causing the counter going up again. When CH1^CH3 is high, TI1 is the opposite of CH2, so the counter counts down on both the rising and the falling edge of CH2.

Some filtering is apparently necessary on TI1, the counter is sporadically changing when I remove the TI1 filter (IC1F) and change the direction repeatedly. It might be the result of my not too sophisticated test setup, which means touching dangling jumper wires to ground and using the internal pullups.

PS. direct link to this comment.

waclawek.jan
Super User
May 27, 2020

Thanks for the sophisticated testing, the detailed writeup and the link ;)

Jan

waclawek.jan
Super User
October 14, 2020

Can please the ST staff who made the comment hidden to public but making this thread resurface after half a year, please work towards public confirmation of the assertion needed to get this trick be reliable (i.e. that AF inputs unassigned in GPIO are reliably 0)?

JW

Laurent Ca...
Senior III
October 15, 2020

Dear @Community member​ 

From mid of September, I'm trying to improve the forum for all posts with the tag "STM32 Motor control".

To make them more readable for all users, each time a technical question seems solved, I indicate it. This is why this thread has moved this week.

And I will soon have finished analyzing all the existing messages with the "STM32 Motor control" tag.

On the other hand I do not see at all what a hidden message is, to my knowledge it does not exist and therefore it is not possible to make it visible.

Best regards

Laurent Ca...

waclawek.jan
Super User
October 15, 2020

Hi @Laurent Ca...​ ,

OK I see.

It would still be nice if ST could confirm that AF inputs unassigned in GPIO are reliably 0. This would make solutions to several - perhaps niche, but still existing - problems possible.

JW

Laurent Ca...
Senior III
October 15, 2020

Dear @Community member​ 

I am in charge of improving the dynamism of the "STM32 Motor control" tag community.

For such specific question do not hesitate to open a specific post with only the tag "STM32F3".

Best regards

Laurent Ca...

waclawek.jan
Super User
October 15, 2020

Hi @Laurent Ca...​ ,

This is not a 'F3-specific question, bot goes across the entire STM32 family; and in fact does relate to motor controls, too.

JW