[Solved] Set alternate function for quadrature encoder pins.
[Solved] Set alternate function for quadrature encoder pins.
Hi,
I'm using timers to decode a quadrature signal but have trouble getting this running on an stmf4 with stm32 core.
In detail: PB6/PB7 on timer4 and PA0/PA1 on timer2, on a 'Black F407VE'.
I do have this running on the same hardware, using CMSIS files, mostly dated 2011. However, I'd like to switch to the stm32-core to avoid all the low-level stuff on each project.
Afaik there is no support for TIM_ENCODERMODE_TI12 in the core, so what I did on an STM32F103C8 was setup the timers HAL_TIM_Encoder_Init & HAL_TIM_Encoder_Start. And initialize the gpio using stm32-core with pinMode(MAQUEENPLUS_PIN_ENCODER_L_A, INPUT_PULLUP);
And this works as expected.
But, moving this to the stm23f407 doesn't produce any result. I suspect this may have to do with the alternate function setting, which is required. But I don't see how to set / change that.
So my basic question is how to setup these timers using stm32-core functions as much as possible, avoiding cmsis-call when possible.
Any help will be appreciated!
Joep
I'm using timers to decode a quadrature signal but have trouble getting this running on an stmf4 with stm32 core.
In detail: PB6/PB7 on timer4 and PA0/PA1 on timer2, on a 'Black F407VE'.
I do have this running on the same hardware, using CMSIS files, mostly dated 2011. However, I'd like to switch to the stm32-core to avoid all the low-level stuff on each project.
Afaik there is no support for TIM_ENCODERMODE_TI12 in the core, so what I did on an STM32F103C8 was setup the timers HAL_TIM_Encoder_Init & HAL_TIM_Encoder_Start. And initialize the gpio using stm32-core with pinMode(MAQUEENPLUS_PIN_ENCODER_L_A, INPUT_PULLUP);
And this works as expected.
But, moving this to the stm23f407 doesn't produce any result. I suspect this may have to do with the alternate function setting, which is required. But I don't see how to set / change that.
So my basic question is how to setup these timers using stm32-core functions as much as possible, avoiding cmsis-call when possible.
Any help will be appreciated!
Joep
Last edited by jsuijs on Thu Dec 24, 2020 8:28 am, edited 1 time in total.
Re: Set alternate function.
Right encoder is not supported.
It is working on F1 because the AF is not the same on this series compare to other.
You have to manually set the correct AF for each GPIO pins used using LL or HAL which is not managed by pinMode as it stands for pure GPIO config Input/output, PU/PD.
It is working on F1 because the AF is not the same on this series compare to other.
You have to manually set the correct AF for each GPIO pins used using LL or HAL which is not managed by pinMode as it stands for pure GPIO config Input/output, PU/PD.
Code: Select all
LL_GPIO_SetAFPin_8_15(port, ll_pin, afnum);
LL_GPIO_SetAFPin_0_7(port, ll_pin, afnum);
Re: Set alternate function.
Hi,
Thank you for your reply. Unfortunately this hasn't solved it yet. Spent the whole day on this and running out of ideas
.
Below is the current program, have tried many variants but timers stay at zero.
Any suggestions?
Joep
Thank you for your reply. Unfortunately this hasn't solved it yet. Spent the whole day on this and running out of ideas

Below is the current program, have tried many variants but timers stay at zero.
Any suggestions?
Joep
Code: Select all
HardwareSerial Serial(PA3, PA2);
void setup() {
Serial.begin(115200);
Serial.println("Hello Stm32Duino world!");
EncoderInit();
}
void loop() {
Serial.print(LL_TIM_GetCounter(TIM4));
Serial.print(' ');
Serial.println(LL_TIM_GetCounter(TIM2));
delay(1000);
}
void EncoderInit()
{
pinMode(PD12, INPUT_PULLUP); // TIM4
pinMode(PD13, INPUT_PULLUP); // TIM4
pinMode(PA15, INPUT_PULLUP); // TIM2
pinMode(PB3, INPUT_PULLUP); // TIM2
LL_GPIO_SetAFPin_8_15(GPIOD, GPIO_PIN_12, GPIO_AF2_TIM4);
LL_GPIO_SetAFPin_8_15(GPIOD, GPIO_PIN_13, GPIO_AF2_TIM4);
LL_GPIO_SetAFPin_8_15(GPIOA, GPIO_PIN_15, GPIO_AF1_TIM2);
LL_GPIO_SetAFPin_0_7(GPIOB, GPIO_PIN_3, GPIO_AF1_TIM2);
// RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM4, ENABLE);
// RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM2, ENABLE);
TIM_HandleTypeDef Encoder_Handle;
TIM_Encoder_InitTypeDef sEncoderConfig;
Encoder_Handle.Init.Period = 65535;
Encoder_Handle.Init.Prescaler = 0;
Encoder_Handle.Init.ClockDivision = 0;
Encoder_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
Encoder_Handle.Init.RepetitionCounter = 0;
Encoder_Handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
sEncoderConfig.EncoderMode = TIM_ENCODERMODE_TI12;
sEncoderConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
sEncoderConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
sEncoderConfig.IC1Prescaler = TIM_ICPSC_DIV1;
sEncoderConfig.IC1Filter = 0;
sEncoderConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
sEncoderConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
sEncoderConfig.IC2Prescaler = TIM_ICPSC_DIV1;
sEncoderConfig.IC2Filter = 0;
Encoder_Handle.Instance = TIM4;
if(HAL_TIM_Encoder_Init(&Encoder_Handle, &sEncoderConfig) != HAL_OK) Serial.println("Init error of TIM4\n");
HAL_TIM_Encoder_Start(&Encoder_Handle, TIM_CHANNEL_ALL);
Encoder_Handle.Instance = TIM2;
if(HAL_TIM_Encoder_Init(&Encoder_Handle, &sEncoderConfig) != HAL_OK) Serial.println("Init error of TIM2\n");
HAL_TIM_Encoder_Start(&Encoder_Handle, TIM_CHANNEL_ALL);
}
Re: Set alternate function.
Hi,
I'm almost there, it works but it needs quite some cleanup.
On of the issues was LL_GPIO_SetAFPin_8_15() and LL_GPIO_SetAFPin_0_7() do set the AFR-register, but do not activate the AF-mode in the MODER register. Is there a function or macro to set these bits, except HAL_GPIO_Init()?
Regards,
Joep
I'm almost there, it works but it needs quite some cleanup.
On of the issues was LL_GPIO_SetAFPin_8_15() and LL_GPIO_SetAFPin_0_7() do set the AFR-register, but do not activate the AF-mode in the MODER register. Is there a function or macro to set these bits, except HAL_GPIO_Init()?
Regards,
Joep
Re: Set alternate function.
Yes you can use LL_GPIO_SetPinMode.
You can refers to this function to see which LL are used: https://github.com/stm32duino/Arduino_C ... nmap.c#L62
You can refers to this function to see which LL are used: https://github.com/stm32duino/Arduino_C ... nmap.c#L62
Re: Set alternate function.
Hi,
Yes, that's what I needed
I combined your two answers and some research into arduino->stm pins into a function to switch a pin to an Alternate function.
It works as a charm now, thanks again.
Joep
Yes, that's what I needed

I combined your two answers and some research into arduino->stm pins into a function to switch a pin to an Alternate function.
It works as a charm now, thanks again.
Joep
Code: Select all
//-----------------------------------------------------------------------------
// pinModeAF - configure Arduino pin for given alternate-function
//-----------------------------------------------------------------------------
// Alternate values: see LL_GPIO_SetAFPin_8_15()
// example call: pinModeAF(PD12, GPIO_AF2_TIM4);
//-----------------------------------------------------------------------------
void pinModeAF(int ulPin, uint32_t Alternate)
{
int pn = digitalPinToPinName(ulPin);
if (STM_PIN(pn) < 8) {
LL_GPIO_SetAFPin_0_7( get_GPIO_Port(STM_PORT(pn)), STM_LL_GPIO_PIN(pn), Alternate);
} else {
LL_GPIO_SetAFPin_8_15(get_GPIO_Port(STM_PORT(pn)), STM_LL_GPIO_PIN(pn), Alternate);
}
LL_GPIO_SetPinMode(get_GPIO_Port(STM_PORT(pn)), STM_LL_GPIO_PIN(pn), LL_GPIO_MODE_ALTERNATE);
}
Re: Set alternate function.
Hi,
To finalize this, below the working version of the quadrature encoder setup on TIM4 and TIM2. Difference is TimerClock and AlternateFucnction are enabled.
Hope one day this will be useful for someone.
Joep
To finalize this, below the working version of the quadrature encoder setup on TIM4 and TIM2. Difference is TimerClock and AlternateFucnction are enabled.
Hope one day this will be useful for someone.
Joep
Code: Select all
HardwareSerial Serial(PA3, PA2);
void setup() {
Serial.begin(115200);
Serial.println("Hello Stm32Duino world!");
EncoderInit();
}
void loop() {
Serial.print(LL_TIM_GetCounter(TIM4));
Serial.print(' ');
Serial.println(LL_TIM_GetCounter(TIM2));
delay(1000);
}
//-----------------------------------------------------------------------------
// pinModeAF - configure Arduino pin for given alternate-function
//-----------------------------------------------------------------------------
// Alternate values: see LL_GPIO_SetAFPin_8_15()
// example call: pinModeAF(PD12, GPIO_AF2_TIM4);
//-----------------------------------------------------------------------------
void pinModeAF(int ulPin, uint32_t Alternate)
{
int pn = digitalPinToPinName(ulPin);
if (STM_PIN(pn) < 8) {
LL_GPIO_SetAFPin_0_7( get_GPIO_Port(STM_PORT(pn)), STM_LL_GPIO_PIN(pn), Alternate);
} else {
LL_GPIO_SetAFPin_8_15(get_GPIO_Port(STM_PORT(pn)), STM_LL_GPIO_PIN(pn), Alternate);
}
LL_GPIO_SetPinMode(get_GPIO_Port(STM_PORT(pn)), STM_LL_GPIO_PIN(pn), LL_GPIO_MODE_ALTERNATE);
}
void EncoderInit(void)
{
// use standaard Arduino function for basic setup
pinMode(PD12, INPUT_PULLUP); // TIM4
pinMode(PD13, INPUT_PULLUP); // TIM4
pinMode(PA15, INPUT_PULLUP); // TIM2
pinMode(PB3 , INPUT_PULLUP); // TIM2
// use custom function to switch to AlternateFuction.
pinModeAF(PD12, GPIO_AF2_TIM4);
pinModeAF(PD13, GPIO_AF2_TIM4);
pinModeAF(PA15, GPIO_AF1_TIM2);
pinModeAF(PB3 , GPIO_AF1_TIM2);
TIM_HandleTypeDef Encoder_Handle;
TIM_Encoder_InitTypeDef sEncoderConfig;
Encoder_Handle.Init.Period = 65535;
Encoder_Handle.Init.Prescaler = 0;
Encoder_Handle.Init.ClockDivision = 0;
Encoder_Handle.Init.CounterMode = TIM_COUNTERMODE_UP;
Encoder_Handle.Init.RepetitionCounter = 0;
Encoder_Handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
sEncoderConfig.EncoderMode = TIM_ENCODERMODE_TI12;
sEncoderConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
sEncoderConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
sEncoderConfig.IC1Prescaler = TIM_ICPSC_DIV1;
sEncoderConfig.IC1Filter = 0;
sEncoderConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
sEncoderConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
sEncoderConfig.IC2Prescaler = TIM_ICPSC_DIV1;
sEncoderConfig.IC2Filter = 0;
Encoder_Handle.Instance = TIM4;
enableTimerClock(&Encoder_Handle);
if(HAL_TIM_Encoder_Init(&Encoder_Handle, &sEncoderConfig) != HAL_OK) Serial.println("Init error of TIM4");
HAL_TIM_Encoder_Start(&Encoder_Handle, TIM_CHANNEL_ALL);
Encoder_Handle.Instance = TIM2;
enableTimerClock(&Encoder_Handle);
if(HAL_TIM_Encoder_Init(&Encoder_Handle, &sEncoderConfig) != HAL_OK) Serial.println("Init error of TIM2");
HAL_TIM_Encoder_Start(&Encoder_Handle, TIM_CHANNEL_ALL);
}
Re: [Solved] Set alternate function for quadrature encoder pins.
Thank you very much for posting your code. I used the elegant function you wrote to setup pins in alternate function mode in my project, as I posted here:
viewtopic.php?f=41&t=1030
viewtopic.php?f=41&t=1030
Re: Set alternate function.
Does not compile on latest core, did the new core version break compatibility i wonder:jsuijs wrote: Thu Dec 24, 2020 7:55 am Hi,
Yes, that's what I needed
I combined your two answers and some research into arduino->stm pins into a function to switch a pin to an Alternate function.
It works as a charm now, thanks again.
Joep
Code: Select all
//----------------------------------------------------------------------------- // pinModeAF - configure Arduino pin for given alternate-function //----------------------------------------------------------------------------- // Alternate values: see LL_GPIO_SetAFPin_8_15() // example call: pinModeAF(PD12, GPIO_AF2_TIM4); //----------------------------------------------------------------------------- void pinModeAF(int ulPin, uint32_t Alternate) { int pn = digitalPinToPinName(ulPin); if (STM_PIN(pn) < 8) { LL_GPIO_SetAFPin_0_7( get_GPIO_Port(STM_PORT(pn)), STM_LL_GPIO_PIN(pn), Alternate); } else { LL_GPIO_SetAFPin_8_15(get_GPIO_Port(STM_PORT(pn)), STM_LL_GPIO_PIN(pn), Alternate); } LL_GPIO_SetPinMode(get_GPIO_Port(STM_PORT(pn)), STM_LL_GPIO_PIN(pn), LL_GPIO_MODE_ALTERNATE); }
src\main.cpp: In function 'void pinModeAF(int, uint32_t)':
src\main.cpp:48:7: error: 'LL_GPIO_SetAFPin_0_7' was not declared in this scope; did you mean 'LL_GPIO_SetPinPull'?
48 | LL_GPIO_SetAFPin_0_7( get_GPIO_Port(STM_PORT(pn)), STM_LL_GPIO_PIN(pn), Alternate);
| ^~~~~~~~~~~~~~~~~~~~
| LL_GPIO_SetPinPull
src\main.cpp:50:7: error: 'LL_GPIO_SetAFPin_8_15' was not declared in this scope; did you mean 'LL_GPIO_SetPinPull'?
50 | LL_GPIO_SetAFPin_8_15(get_GPIO_Port(STM_PORT(pn)), STM_LL_GPIO_PIN(pn), Alternate);
| ^~~~~~~~~~~~~~~~~~~~~
| LL_GPIO_SetPinPull
Re: Set alternate function.
See my answer here: viewtopic.php?p=9640#p9640razvitm wrote: Wed Mar 16, 2022 12:25 pm Does not compile on latest core, did the new core version break compatibility i wonder:
src\main.cpp: In function 'void pinModeAF(int, uint32_t)':
src\main.cpp:48:7: error: 'LL_GPIO_SetAFPin_0_7' was not declared in this scope; did you mean 'LL_GPIO_SetPinPull'?
48 | LL_GPIO_SetAFPin_0_7( get_GPIO_Port(STM_PORT(pn)), STM_LL_GPIO_PIN(pn), Alternate);
| ^~~~~~~~~~~~~~~~~~~~
| LL_GPIO_SetPinPull
src\main.cpp:50:7: error: 'LL_GPIO_SetAFPin_8_15' was not declared in this scope; did you mean 'LL_GPIO_SetPinPull'?
50 | LL_GPIO_SetAFPin_8_15(get_GPIO_Port(STM_PORT(pn)), STM_LL_GPIO_PIN(pn), Alternate);
| ^~~~~~~~~~~~~~~~~~~~~
| LL_GPIO_SetPinPull