cancel
Showing results for 
Search instead for 
Did you mean: 

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

XHuan.1
Associate II

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.

2 REPLIES 2

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

You surely meant

if(TIM4->CR1 & 0x10)

JW

XHuan.1
Associate II

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