cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F411CE hardware timer in encoder mode won't increment

TOG435
Associate II

I'm using a STM32F411CE on a blackpill dev board with a second connected as a BMP debugger.

I'm attempting to use the hardware timer quadrature encoder support and having absolutely no luck. I've followed the guidance in both the application note AN4013 (pg35) and the STM32F411CE Reference Manual (pg341) to set all the appropriate configuration registers and verified those registers are set with the debugger - but the TIMx->CNT never changes. I've also tried all of the general purpose timers (TIM2...TIM5) with no luck.

Relevant code for config registers (GPIOA/GPIOB/TIM2):

   RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
   LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_15, LL_GPIO_PULL_NO);
 
   RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
   LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_3, LL_GPIO_PULL_NO);
 
   RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
   TIM2->CCMR1 |= (TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0);
   TIM2->CCER &= ~(TIM_CCER_CC1P | TIM_CCER_CC2P);
   TIM2->SMCR |= TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1;
   TIM2->CR1 |= TIM_CR1_CEN;

Once run and as viewed through the debugger, the GPIOA/B ports are enabled, set to input, and without any pullup/pulldown. Likewise, the timer is set to the proper SMCR, CCMR1 modes and is enabled.

I also am able to view the GPIO input data register changing as I spin the encoder, and I have verified the encoder output on my oscilloscope. I'm also able to do a basic blinky without any troubles manipulating the ports directly to output modes, so I don't think there's anything wrong with the chip.

Everything looks great except that the counter never increments - please help! I feel like I've got to be missing something really obvious and simple here.

7 REPLIES 7

> GPIOA/B ports are enabled, set to input

They have to be set to AF in GPIO_MODER, and the appropriate AF number set in respective GPIO_AFR[].

If still in doubts, read out and post all the relevant registers content. And since you know how to program properly using registers, ditch Cube/LL, it's just an unnecessary intermediary.

JW

TOG435
Associate II

I started out writing directly to the registers but fell back to Cube/HAL/LL as I was trying to figure out what was going wrong.

This is my first time getting below the Arduino level of embedded really - how exactly do the Alt-Function things work? I'm having trouble parsing the datasheet into understanding of how I should know when to set AF in GPIO_MODER and what the settings of GPIO_AFR[] even mean - how do I know what function is what, and where, and what AFR should be?

I see the Alternate Functions and Additional Functions on the datasheet, but where should I be looking to know what bits should be set to connect, say, PA1 to TIM2_CH2 versus PA1 to TIM5_CH2?

The AF setting is a pin mux, associating a pin with a controlling peripheral

The setting is 4-bit allowing for up to 16 options.

PA1 would be GPIOA->AFR[0], bits 4 thru 7

0693W00000VOqO7QAL.jpgGPIOA->AFR[0] = (GPIOA->AFR[0] & 0xFFFFFF0F) | (1 << 4); // AF1 on Pin 1

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

>I started out writing directly to the registers but fell back to Cube/HAL/LL as I was trying to figure out what was going wrong.

This is normal, i do not do register level programming unless i need to really optimice something or if HAL is giving me a headache.

I am not an expert and at the end of the day i need to make things work in a reasonable time or i wont eat XD.

In the meantime i am slowly becoming more knowledgeable, and accomplishing real things at the same time.

>This is my first time getting below the Arduino level of embedded really

Youre choosing a very challening baptise

>how do I know what function is what, and where, and what AFR should be?

Yup , thats the magic of register level programming.

  1. Either you alread have vast experience so you use the datasheet only as a spell check/ reminder.
  2. Or you try to juice ST datasheets, thick as every other datasheet, full of erratas and wrong naming.

I personally do a mix of option two with a bit of reverse engineering ST examples (the ones coming inside the firmware package folder) and youtube videos.

About your original question, i have no clue sorry

we dont need to firmware by ourselves, lets talk

Oh, I see! So setting GPIOA->AFR[0] is the AFRLow and GPIOA->AFR[1] is the AFRHigh?

Thank you so much, your comment with the clarifications below from other folks was the one that got it working.

For anyone who googles this later, ChA and ChB of my encoder were connected to PA0 and PA1, and those port/pins were configured with AF01 to be TIM2_CH1 and TIM2_CH2 respectively. The code block is:

	RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;	// Enable RCC GPIOA
	GPIOA->MODER |= 0xA;					// Set PA0 and PA1 to MODER 0b10 for AF
	GPIOA->AFR[0] |= 0x11;					// Set PA0 and PA1 to AFR01 (TIM2_CH1 and TIM2_CH2)
 
	RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;						// Enable RCC TIM2
	TIM2->CCMR1 |= (TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0);	// set CC1S/CC2S to 0b1
	TIM2->CCER &= ~(TIM_CCER_CC1P | TIM_CCER_CC2P);			// set CC1P/CC2P to 0b0
	TIM2->SMCR |= TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1;			// set SMS to 0b011
	TIM2->CR1 |= TIM_CR1_CEN;								// Enable TIM2 operation

Register is 32-bit wide, or hold 8 pins settings (4-bit x 😎

AFR[0] covering Pin 0 thru 7

AFR[1] covering Pin 8 thru 15

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..