Skip to main content
XHuan.1
Associate
July 14, 2020
Question

Issue with resetting timer count in encoder mode with external interrupt (stm32f411)

  • July 14, 2020
  • 2 replies
  • 1211 views

So I am trying to use the encoder mode that's built into the timer to get accurate encoder step count, which have worked flawlessly. I tried to use PA0 as the external interrupt that detects the rising edge to the index pulse. However, when I set the Timer value inside the interrupt, the timer count gets stuck to the value I have set and doesn't count up or down anymore. If anyone have any idea what I have missed that would be amazing ( I have made sure to clear the interrupt before exiting)

interrupt:

void EXTI0_IRQHandler(void)
{
	USART1_write_string("here\n",5);
	if(TIM4->CR1 &= 0x10)
	{
	 TIM4->CNT = 7200;
	}
	else
	{
		TIM4->CNT = 0;
	}
	EXTI->PR = 0x1; //clear interrupt
}
 
 
 
 
 

Timer 4 setup for encoder:

void init_encoder(void)
{
	/* timer 4 channel 1 and channel 2 (PB6, PB7) for encoder */
	RCC->AHB1ENR |= 0x2; // enable port B
	RCC->APB1ENR |= 0x4; // enable timer 4
	
	GPIOB->MODER |= 0xA000; // set to alternate function for pin6 amd 7
	GPIOB->PUPDR |= 0x5000; // set to pull up resistor for pin 6 and 7
	GPIOB->AFR[0] |= 0x22000000; // set AFR to tim2-tim5
	
	TIM4->ARR = 0xFFFF; // set max value
	
	TIM4->CCMR1 |= TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0;
	TIM4->SMCR |= 0x3; // set to count both rising and falling edge of AB channels, with reset mode enabled
	TIM4->CR1 |= 0x1; // enable counter
	
	
	/* external interrupt, call encoder_reset() on rising edges */
	// PA0 //
	__disable_irq(); // disable iterrupt before configuring
	RCC->AHB1ENR |= 0x1; // enable port A
	RCC->APB2ENR |= 0x4000; // enable systemconfig clock
 GPIOA->PUPDR |= 0x1; // pull up for pin A0
	
	SYSCFG->EXTICR[0] |= 0x0; // EXIT0, Port A
	EXTI->IMR |= 0x1; // mask exti 0
	EXTI->RTSR |= 0x1; // set to rising edge
	NVIC_EnableIRQ(EXTI0_IRQn); // renaable exti0
	
	__enable_irq(); // renable interupt
}

while loop in main:

while(1)
	{
		 if (TIM4->CNT >= 7200)
			{
				TIM4->CNT = 0;
			}
			rotary_raw = TIM4->CNT;
			sprintf(send, "%d\n", rotary_raw);
			//get_dec_str (send, distance);
			USART1_write_string(send,7);
			delayms(10);
	}

PS: Solved it, I disabled the timer before changing the value and reeenable it afterward, that seems to prevent the values being stuck

PS2: If anyone have any other advice or suggestions for a more efficient encoder tracking I'm all ears, but this seems to work well enough for my use case.

This topic has been closed for replies.

2 replies

waclawek.jan
Super User
July 14, 2020

> if(TIM4->CR1 &= 0x10)

You surely meant

if(TIM4->CR1 & 0x10)

JW

XHuan.1
XHuan.1Author
Associate
July 14, 2020

oh wow totally missed that, yup that was the actual culprit.