How to get pin number based on known timer and known channel?

Post here all questions related to STM32 core if you can't find a relevant section!
Post Reply
User avatar
Bakisha
Posts: 139
Joined: Fri Dec 20, 2019 6:50 pm
Answers: 5
Contact:

How to get pin number based on known timer and known channel?

Post by Bakisha »

Hi, i need some help figuring how to determine pin number when i have already set what timer and what channel to use.
In my project i'm using one timer and 3 channels (one for interrupt, one for PWM2 and one for toggle) and i'm planning to use pins based on timer, not a timer based on pin. Main reason is because i use STM32F103C8, STM32F401CE, STM32F411CC and STM32F407VE boards for testing, and they have different timers on same pin name. Yes, i could use per board definitions, but i'm trying to avoid that.

Here is small sketch (original sketch is too large):

Code: Select all

uint32_t HSYNC_pin         ; // TIM2 CH3 // TIM5 CH3
uint32_t channel_HSYNC = 3 ; // TIM2 CH3 // TIM5 CH3             // PA2

#ifdef TIM1
HardwareTimer *MyTim =  new HardwareTimer(TIM1);
#else
HardwareTimer *MyTim =  new HardwareTimer(TIM2);
#endif

TIM_TypeDef * Instance = NULL; // Instance can be used for direct writing to timer's registers


void changeTimer(TIM_TypeDef * NEW_timer) {

  delete MyTim ;                                                                    // destroy previous instance
  HardwareTimer *MyTim = new HardwareTimer(NEW_timer);  // set new instance
  Instance = NEW_timer;

  // HSYNC_pin  = ?????

}

void setup() {

  changeTimer(TIM5); // TIM2 for STM32F103 // TIM5 for STM32F401CC

  uint32_t  TIMER_MHZ = ( MyTim->getTimerClkFreq()) / 1000000;

  MyTim->pause();
  MyTim->setPrescaleFactor(1); // count timers clock ticks
  MyTim->setMode(channel_HSYNC, TIMER_OUTPUT_COMPARE_PWM2,  HSYNC_pin);  // <--------- HSYNC pin?
  MyTim->setOverflow( TIMER_MHZ * 64, TICK_FORMAT); // first value
  MyTim->setCaptureCompare(channel_HSYNC, 4.70*TIMER_MHZ, TICK_COMPARE_FORMAT);
  MyTim->resume();
}

void loop() {
 
}
by Bakisha » Wed Jul 15, 2020 5:31 pm
I think i got it right this time. Tested on STM32F10C8 and STM32F401CE

Code: Select all

#ifdef TIM1
HardwareTimer *MyTim =  new HardwareTimer(TIM1);
#else
HardwareTimer *MyTim =  new HardwareTimer(TIM2);
#endif

TIM_TypeDef * Instance = NULL;

uint32_t changeTimerGetPin(TIM_TypeDef * NEW_timer, uint32_t NEW_channel) {

  bool finished = false;
  uint32_t pin_match = 0xffff;

  for (int k = 0; k < 256; k++) { // from PA_0 to PK_15
    if (!finished) {
      for (int i = 0; i < NUM_DIGITAL_PINS; i++) { // whatever order is in variant.h
        if (k == digitalPinToPinName(i) ) { // there is only 1 match per i loop
          if ((NEW_timer == (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(i), PinMap_PWM))) { // same as requested timer?
            if (NEW_channel == STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(i ), PinMap_PWM))) { // same as requested channel
              pin_match = i;
              finished = true; // only first match from PinMap_PWM is valid
            }
          }
        }
      }
    }
  }
  delete MyTim ;                                        // destroy previous instance
  HardwareTimer *MyTim = new HardwareTimer(NEW_timer);  // set new instance
  Instance = NEW_timer;

  return (pin_match) ;
}

void setup() {
  Serial.begin(9600);
  delay(1000);

  uint32_t  pin  = changeTimerGetPin(TIM2, 2); // change timer, get pin number based on timer and channel

  if (pin < 256) { // only if there is available pin on requested timer / channel

    Serial.print(  "requested pin found: " );
    Serial.print(pin);
    
    Serial.print(  " - P" );
    Serial.write(((digitalPinToPinName(pin) >> 4) & 0x0f)   + 65  );
    Serial.print(digitalPinToPinName(pin) & 0x0f);
    Serial.println("");
  }
  else {
    Serial.println(  "no pwm output on that timer/channel  " );
  }

}

void loop() {

}
Go to full post
User avatar
fpiSTM
Posts: 1738
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 91
Location: Le Mans
Contact:

Re: How to get pin number based on known timer and known channel?

Post by fpiSTM »

Hi,

you can use this if you use the same pin:

Code: Select all

  // Automatically retrieve TIM instance and channel associated to pin
  // This is used to be compatible with all STM32 series automatically.
  TIM_TypeDef *Instance = (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(pin), PinMap_PWM);
  uint32_t channel = STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(pin), PinMap_PWM));
About searching with timer and channel, you will have to implement one by yourself to search in the PinMap_PWM. You can refers to the libraries\SrcWrapper\src\stm32\pinmap.c file to see how access this.
User avatar
Bakisha
Posts: 139
Joined: Fri Dec 20, 2019 6:50 pm
Answers: 5
Contact:

Re: How to get pin number based on known timer and known channel?

Post by Bakisha »

I managed to get pin number by searching all pins for a match with timer and channel.
If someone is interested, here is a example sketch:

Code: Select all


uint32_t HSYNC_pin ;
uint32_t channel_HSYNC ;

#ifdef TIM1
HardwareTimer *MyTim =  new HardwareTimer(TIM1);
#else
HardwareTimer *MyTim =  new HardwareTimer(TIM2);
#endif

TIM_TypeDef * Instance = NULL;

uint32_t changeTimerGetPin(TIM_TypeDef * NEW_timer, uint32_t NEW_channel) {


  bool finished = false;

  uint32_t pin_match = 0xffff;

  for (int i = 0; i < 256; i++) {

    if (!finished) {
      if ((NEW_timer == (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(i), PinMap_PWM))) {
        if (NEW_channel == STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(i), PinMap_PWM))) {
          pin_match = i;
          finished = true;
        }
      }
    }
  }

  delete MyTim ;                                                                    // destroy previous instance
  HardwareTimer *MyTim = new HardwareTimer(NEW_timer);  // set new instance
  Instance = NEW_timer;

  return (pin_match) ;
}

void setup() {

  channel_HSYNC = 3 ;                                  // desired channel
  HSYNC_pin  = changeTimerGetPin(TIM5, channel_HSYNC); // get pin number based on timer and channel

  if (HSYNC_pin < 256) { // only if there is available pin on requested timer / channel


    uint32_t  TIMER_MHZ = ( MyTim->getTimerClkFreq()) / 1000000;

    MyTim->pause();
    MyTim->setPrescaleFactor(1); // count timers clock ticks
    MyTim->setMode(channel_HSYNC, TIMER_OUTPUT_COMPARE_PWM2,   HSYNC_pin);
    MyTim->setOverflow( TIMER_MHZ * 64, TICK_FORMAT); // first value
    MyTim->setCaptureCompare(channel_HSYNC, 4.70 * TIMER_MHZ, TICK_COMPARE_FORMAT);
    MyTim->resume();
  }

}

void loop() {

}
It's enough for me to implement it into my project, for boards that i have.
User avatar
fpiSTM
Posts: 1738
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 91
Location: Le Mans
Contact:

Re: How to get pin number based on known timer and known channel?

Post by fpiSTM »

Fine👍
ozcar
Posts: 143
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 5

Re: How to get pin number based on known timer and known channel?

Post by ozcar »

Bakisha wrote: Mon Jul 13, 2020 7:04 pm I managed to get pin number by searching all pins for a match with timer and channel.
Perhaps I do not understand exactly what you need to do, but....

How do you know that the first match you get for timer and channel is the one you want?
User avatar
Bakisha
Posts: 139
Joined: Fri Dec 20, 2019 6:50 pm
Answers: 5
Contact:

Re: How to get pin number based on known timer and known channel?

Post by Bakisha »

ozcar wrote: Tue Jul 14, 2020 3:09 am
Bakisha wrote: Mon Jul 13, 2020 7:04 pm I managed to get pin number by searching all pins for a match with timer and channel.
Perhaps I do not understand exactly what you need to do, but....

How do you know that the first match you get for timer and channel is the one you want?
Well, it should be only match because there is only one pin associated with certain channel. I did test the sketch with serial output, and it worked for various timers and channels.

As for purposes. Let's say i want write sketch/library that uses pin two pins for PWM output and plus interrupt, that have same period, so i only need one timer. But various variants have different timers on those pins. Some have (for example) TIM2, some have TIM5, some have mixed of both. So, i decided to not used fixed pins, but rather fixed timer number that will be passed as parameter, and PWM will be outputed on whatever pin is associated with that timer. Or return false if timer don't have 4 channels.

Function setMode for timer uses pin number as parameter, and i needed a way to calculate that pin number based on timer and channel.
ozcar
Posts: 143
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 5

Re: How to get pin number based on known timer and known channel?

Post by ozcar »

Bakisha wrote: Tue Jul 14, 2020 4:16 am Well, it should be only match because there is only one pin associated with certain channel. I did test the sketch with serial output, and it worked for various timers and channels.
So, if you comment out the “finished = true” you still get the same pin? If I try it on a F103 blue pill board just forcing it to look for say TIM2, channel 2, like this:

Code: Select all

if (!finished) {
  if ((TIM2 == (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(i), PinMap_PWM))) {
    if (2 == STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(i), PinMap_PWM))) {
      //pin_match = i;
      //finished = true;
      Serial.print("TIM2 channel 2 pin ");
      Serial.println(  digitalPinToPinName(i) );  
    }
  }
} 
It comes up with 19 and 1, which I think is right for PB_3 and PA_1 which are both candidates for TIM2, channel 2.

But then I have no use for this at this time, so if it works for you, I'm probably still confused.
User avatar
Bakisha
Posts: 139
Joined: Fri Dec 20, 2019 6:50 pm
Answers: 5
Contact:

Re: How to get pin number based on known timer and known channel?

Post by Bakisha »

ozcar wrote: Tue Jul 14, 2020 7:09 am
Bakisha wrote: Tue Jul 14, 2020 4:16 am Well, it should be only match because there is only one pin associated with certain channel. I did test the sketch with serial output, and it worked for various timers and channels.
So, if you comment out the “finished = true” you still get the same pin? If I try it on a F103 blue pill board just forcing it to look for say TIM2, channel 2, like this:

Code: Select all

if (!finished) {
  if ((TIM2 == (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(i), PinMap_PWM))) {
    if (2 == STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(i), PinMap_PWM))) {
      //pin_match = i;
      //finished = true;
      Serial.print("TIM2 channel 2 pin ");
      Serial.println(  digitalPinToPinName(i) );  
    }
  }
} 
It comes up with 19 and 1, which I think is right for PB_3 and PA_1 which are both candidates for TIM2, channel 2.

But then I have no use for this at this time, so if it works for you, I'm probably still confused.
Uf, it turns out that example sketch is not working as i planned. I am getting wrong results but i track that down to my wrong assumption pin names PA0, PA1, PA2... are using numbers 0,1,2... But i have idea how to solve it (after some dive into core file), i just need some time.

As for your question, yes, if i comment out !finished it will found a match of all alternate pins that can be used for TIM2 CH2. That is PA1 and PB3 defined in variant.h with numbers 21 and 6, or value of 1 and 19 when used digitalPinToPinName().

Maybe i'm overcomplicate things, i might end up just using pins PA8 and PA9 (same timer on all boards i have).
User avatar
Bakisha
Posts: 139
Joined: Fri Dec 20, 2019 6:50 pm
Answers: 5
Contact:

Re: How to get pin number based on known timer and known channel?

Post by Bakisha »

I think i got it right this time. Tested on STM32F10C8 and STM32F401CE

Code: Select all

#ifdef TIM1
HardwareTimer *MyTim =  new HardwareTimer(TIM1);
#else
HardwareTimer *MyTim =  new HardwareTimer(TIM2);
#endif

TIM_TypeDef * Instance = NULL;

uint32_t changeTimerGetPin(TIM_TypeDef * NEW_timer, uint32_t NEW_channel) {

  bool finished = false;
  uint32_t pin_match = 0xffff;

  for (int k = 0; k < 256; k++) { // from PA_0 to PK_15
    if (!finished) {
      for (int i = 0; i < NUM_DIGITAL_PINS; i++) { // whatever order is in variant.h
        if (k == digitalPinToPinName(i) ) { // there is only 1 match per i loop
          if ((NEW_timer == (TIM_TypeDef *)pinmap_peripheral(digitalPinToPinName(i), PinMap_PWM))) { // same as requested timer?
            if (NEW_channel == STM_PIN_CHANNEL(pinmap_function(digitalPinToPinName(i ), PinMap_PWM))) { // same as requested channel
              pin_match = i;
              finished = true; // only first match from PinMap_PWM is valid
            }
          }
        }
      }
    }
  }
  delete MyTim ;                                        // destroy previous instance
  HardwareTimer *MyTim = new HardwareTimer(NEW_timer);  // set new instance
  Instance = NEW_timer;

  return (pin_match) ;
}

void setup() {
  Serial.begin(9600);
  delay(1000);

  uint32_t  pin  = changeTimerGetPin(TIM2, 2); // change timer, get pin number based on timer and channel

  if (pin < 256) { // only if there is available pin on requested timer / channel

    Serial.print(  "requested pin found: " );
    Serial.print(pin);
    
    Serial.print(  " - P" );
    Serial.write(((digitalPinToPinName(pin) >> 4) & 0x0f)   + 65  );
    Serial.print(digitalPinToPinName(pin) & 0x0f);
    Serial.println("");
  }
  else {
    Serial.println(  "no pwm output on that timer/channel  " );
  }

}

void loop() {

}
Post Reply

Return to “General discussion”