[Solved] Set alternate function for quadrature encoder pins.

Post here all questions related to STM32 core if you can't find a relevant section!
Post Reply
jsuijs
Posts: 5
Joined: Tue Dec 22, 2020 1:36 pm

[Solved] Set alternate function for quadrature encoder pins.

Post by jsuijs »

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
Last edited by jsuijs on Thu Dec 24, 2020 8:28 am, edited 1 time in total.
User avatar
fpiSTM
Posts: 1738
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 91
Location: Le Mans
Contact:

Re: Set alternate function.

Post by fpiSTM »

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.

Code: Select all

   LL_GPIO_SetAFPin_8_15(port, ll_pin, afnum);
   LL_GPIO_SetAFPin_0_7(port, ll_pin, afnum);
jsuijs
Posts: 5
Joined: Tue Dec 22, 2020 1:36 pm

Re: Set alternate function.

Post by jsuijs »

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

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);
}
jsuijs
Posts: 5
Joined: Tue Dec 22, 2020 1:36 pm

Re: Set alternate function.

Post by jsuijs »

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
User avatar
fpiSTM
Posts: 1738
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 91
Location: Le Mans
Contact:

Re: Set alternate function.

Post by fpiSTM »

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
jsuijs
Posts: 5
Joined: Tue Dec 22, 2020 1:36 pm

Re: Set alternate function.

Post by jsuijs »

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);
}
jsuijs
Posts: 5
Joined: Tue Dec 22, 2020 1:36 pm

Re: Set alternate function.

Post by jsuijs »

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

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);
}
AndrewBCN
Posts: 105
Joined: Sun Apr 25, 2021 3:50 pm
Answers: 1
Location: Strasbourg, France

Re: [Solved] Set alternate function for quadrature encoder pins.

Post by AndrewBCN »

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
razvitm
Posts: 38
Joined: Sat Apr 11, 2020 12:35 pm

Re: Set alternate function.

Post by razvitm »

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);
}
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
User avatar
fpiSTM
Posts: 1738
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 91
Location: Le Mans
Contact:

Re: Set alternate function.

Post by fpiSTM »

razvitm 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
See my answer here: viewtopic.php?p=9640#p9640
Post Reply

Return to “General discussion”