Timer "Input Capture" ?

Post here first, or if you can't find a relevant section!
User avatar
RogerClark
Posts: 7683
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Timer "Input Capture" ?

Post by RogerClark » Thu Feb 08, 2018 11:06 pm

Interesting..

I think I can use this in my AC dimmer project

User avatar
RogerClark
Posts: 7683
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Timer "Input Capture" ?

Post by RogerClark » Fri Feb 09, 2018 10:00 pm

I'm trying to add this code to the core

However, there is one thing I don't understand.

Is only one of the GPIO's connected to each timer ?

The timer has its input set to

TIMER_CCMR_CCS_INPUT_TI1

But I don't see how the input GPIO pin is routed to this ??

Edit.

I now see

Code: Select all

#define RX1 PA0 //t2c1
I'll need to check the spec to see if this is the only pin that can be used for this input, or if its simply the default

User avatar
RogerClark
Posts: 7683
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Timer "Input Capture" ?

Post by RogerClark » Sat Feb 10, 2018 12:10 am

OK.

Just to answer my own question...

As far as I can see from

http://www.st.com/content/ccc/resource/ ... 161566.pdf

These are the timers which have an ETR pin

Timer1 PA12 or PE7 (remap)
Timer2 PA0 or PA15 (remap)
Timer3 PD2
Timer4 PE0

But for the Blue Pill and Maple mini etc (F103Cx) only Timer2 can be used if you are using the bootloader, because PA12 (Timer1) is one of the USB signal s.

The remapping of the ETR seems to be controlled by the register AFIO_MAPR (see section 9.4.2 of the reference manual, on page 183)

This has remapping for Timers 1, 2,3 and 4
Bit 12 TIM4_REMAP: TIM4 remapping
This bit is set and cleared by software. It controls the mapping of TIM4 channels 1 to 4 onto
the GPIO ports.
0: No remap (TIM4_CH1/PB6, TIM4_CH2/PB7, TIM4_CH3/PB8, TIM4_CH4/PB9)
1: Full remap (TIM4_CH1/PD12, TIM4_CH2/PD13, TIM4_CH3/PD14, TIM4_CH4/PD15)
Note: TIM4_ETR on PE0 is not re-mapped.

Bits 11:10 TIM3_REMAP[1:0]: TIM3 remapping
These bits are set and cleared by software. They control the mapping of TIM3 channels 1 to
4 on the GPIO ports.
00: No remap (CH1/PA6, CH2/PA7, CH3/PB0, CH4/PB1)
01: Not used
10: Partial remap (CH1/PB4, CH2/PB5, CH3/PB0, CH4/PB1)
11: Full remap (CH1/PC6, CH2/PC7, CH3/PC8, CH4/PC9)
Note: TIM3_ETR on PE0 is not re-mapped.

Bits 9:8 TIM2_REMAP[1:0]: TIM2 remapping
These bits are set and cleared by software. They control the mapping of TIM2 channels 1 to
4 and external trigger (ETR) on the GPIO ports.
00: No remap (CH1/ETR/PA0, CH2/PA1, CH3/PA2, CH4/PA3)
01: Partial remap (CH1/ETR/PA15, CH2/PB3, CH3/PA2, CH4/PA3)
10: Partial remap (CH1/ETR/PA0, CH2/PA1, CH3/PB10, CH4/PB11)
11: Full remap (CH1/ETR/PA15, CH2/PB3, CH3/PB10, CH4/PB11)


Bits 7:6 TIM1_REMAP[1:0]: TIM1 remapping
These bits are set and cleared by software. They control the mapping of TIM1 channels 1 to
4, 1N to 3N, external trigger (ETR) and Break input (BKIN) on the GPIO ports.
00: No remap (ETR/PA12, CH1/PA8, CH2/PA9, CH3/PA10, CH4/PA11, BKIN/PB12,
CH1N/PB13, CH2N/PB14, CH3N/PB15)
01: Partial remap (ETR/PA12, CH1/PA8, CH2/PA9, CH3/PA10, CH4/PA11, BKIN/PA6,
CH1N/PA7, CH2N/PB0, CH3N/PB1)
10: not used
11: Full remap (ETR/PE7, CH1/PE9, CH2/PE11, CH3/PE13, CH4/PE14, BKIN/PE15,
CH1N/PE8, CH2N/PE10, CH3N/PE12)

User avatar
RogerClark
Posts: 7683
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Timer "Input Capture" ?

Post by RogerClark » Sat Feb 10, 2018 1:22 am

OK...

The remaping can already be handled by

Code: Select all

afio_remap(    AFIO_REMAP_TIM2_PARTIAL_1);  //etc
AFIO_REMAP_TIM2_PARTIAL_1 = AFIO_MAPR_TIM2_REMAP_PA15_PB3_PA2_PA3,
/**
* Timer 2 partial remapping 2 (CH1 and ETR on PA0, CH2 on PA1,
* CH3 on PB10, CH4 on PB11) */

AFIO_REMAP_TIM2_PARTIAL_2 = AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11,
/** Timer 2 full remapping */

AFIO_REMAP_TIM2_FULL = AFIO_MAPR_TIM2_REMAP_FULL,
= AFIO_MAPR_TIM2_REMAP_PA15_PB3_PA2_PA3,
/**
* Timer 2 partial remapping 2 (CH1 and ETR on PA0, CH2 on PA1,
* CH3 on PB10, CH4 on PB11) */
AFIO_REMAP_TIM2_PARTIAL_2 = AFIO_MAPR_TIM2_REMAP_PA0_PA1_PB10_PB11,
/** Timer 2 full remapping */
AFIO_REMAP_TIM2_FULL = AFIO_MAPR_TIM2_REMAP_FULL,);
/* (CH1/ETR/PA15, CH2/PB3, CH3/PB10, CH4/PB11) */

User avatar
RogerClark
Posts: 7683
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Timer "Input Capture" ?

Post by RogerClark » Sat Feb 10, 2018 1:27 am

This does still leave the polarity.

I think this may need to be handled by a new gpio_xxxx function, as would reading the value from the timer

User avatar
RogerClark
Posts: 7683
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Timer "Input Capture" ?

Post by RogerClark » Sat Feb 10, 2018 2:39 am

Looks like Leaflab already wrote the function to get the value

Code: Select all

static inline uint16 timer_get_compare(timer_dev *dev, uint8 channel) {
    __io uint32 *ccr = &(dev->regs).gen->CCR1 + (channel - 1);
    return *ccr;
}
called by

Code: Select all

getCompare(1);

User avatar
RogerClark
Posts: 7683
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Timer "Input Capture" ?

Post by RogerClark » Sat Feb 10, 2018 3:50 am

OK

I've added this functionality to the Core

But. I still need to decide how to add input polarity selection

I've included an example in the Sensors section, as thats where the Hardware Timer Encoder example is

Grab the latest version of the repo and you can try the example

(Now on to what I really wanted which is the "One Pulse" feature ;-)

Code: Select all

/* Example of the Timer Input Capture mode
 *  
 * Thanks to @cesco on the stm32duino.com
 * 
 * This example uses Timer2. Other timers also support this mode, bnt on the F103C 
 * only Timer 2 has usable external trigger pins. PA0 and PA15
 * Because the only other usable pin on the F103C is one of the USB pins.
 * 
 * Upload to your favourite F103Cx 
 * Open the Serial plotter
 * Put your finger on either PA0 or PA15 (depenidng whether you USE the pin remapping)
 * 
 * Observe your local mains frequency in terms of pulse width time.
 *
 */

/* Timer2 external trigger  can be ether PA0 or PA15. 
 To use use afio_remap(FIO_REMAP_TIM2_PARTIAL_1)  or afio_remap(AFIO_REMAP_TIM2_FULL)
 Note. using afio_remap also changes the pins used by Timer2 CH1,CH2,CH3 amd CH4 
 * See page 184 of the STM32F10x Refernce manual (PDF downloadable from ST.com
 */

//#define USE_REMAP_PIN
#ifdef USE_REMAP_PIN
const int timer2ExternalTriggerPin = PA15;
#else
const int timer2ExternalTriggerPin = PA0;
#endif

volatile boolean hasCapture;
volatile uint16_t captureValue;
volatile uint16_t lastCaptureValue=0;
volatile uint16_t captureDifference=0;

void captureCallback(void) {

   hasCapture=true;
   captureValue = Timer2.getCompare(1);
   captureDifference = captureValue-lastCaptureValue;
   lastCaptureValue=captureValue;   
}

void setup() {
  
  pinMode(timer2ExternalTriggerPin,INPUT);

  #ifdef USE_REMAP_PIN
    afio_remap(AFIO_REMAP_TIM2_PARTIAL_1);
  #endif
  
  hasCapture = false;

  Timer2.setPrescaleFactor(72); // prescaler to count 72,000,000 / 72 counts per second. i.e count microseconds
  Timer2.setMode(TIMER_CH1, TIMER_INPUT_CAPTURE);
  Timer2.attachCompare1Interrupt(captureCallback);

}

void loop()  {

  // Printing inside the callback is not a good idea. 
  // Hence the capture callback sets a flag , which is detected here
  if (hasCapture)
  {
    Serial.println(captureDifference);
    hasCapture=false;
  }  
}


stevestrong
Posts: 2063
Joined: Mon Oct 19, 2015 12:06 am
Location: Munich, Germany
Contact:

Re: Timer "Input Capture" ?

Post by stevestrong » Sat Feb 10, 2018 10:44 pm

What exactly has the example sketch on purpose? To measure the high period of a pulse? Or the time between two input capture events?
Anyway, reading capture values within ISR is not the best method to get precise values.

User avatar
RogerClark
Posts: 7683
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: Timer "Input Capture" ?

Post by RogerClark » Sat Feb 10, 2018 10:52 pm

Steve

I just used the code provided by @Cesco

But I now see that it has problems
I think the config is wrong.
The counter seems to free run and the ISR gets called when the input pin changes.

Looking at the original code (from Leaflabs) they thought that there would be a pinMode() for INPUT_CAPTURE, but as you have pointed out on GitHub this only allows very limited functionality

So perhaps this is not the correct way to add this functionality, and instead perhaps the Hardware Timer class should have additional functions

e.g.

TimerX.setInputCaptureMode(args .....)

and also

TimerX.setOnePulseMode(args....)

This would then allow better configuration.

stevestrong
Posts: 2063
Joined: Mon Oct 19, 2015 12:06 am
Location: Munich, Germany
Contact:

Re: Timer "Input Capture" ?

Post by stevestrong » Sat Feb 10, 2018 11:07 pm

Roger, do you refer to this code example: viewtopic.php?f=3&t=2008&p=26987#p27037 ?
This is from @konczakp, not @cesco.

Anyway, you are right, it misses to set the timer in slave mode reset mode (SMS = b100) and to select the right trigger, so that the CCR1 register value is steady after the input signal trigger occurred.

See RM0008 rev.16, p. 383-384, chapter 15.3.6 PWM input mode:
For example, you can measure the period (in TIMx_CCR1 register) and the duty cycle (in TIMx_CCR2 register) of the PWM applied on TI1 using the following procedure (depending on CK_INT frequency and prescaler value):
• Select the active input for TIMx_CCR1: write the CC1S bits to 01 in the TIMx_CCMR1 register (TI1 selected).
• Select the active polarity for TI1FP1 (used both for capture in TIMx_CCR1 and counter clear): write the CC1P to ‘0’ (active on rising edge).
• Select the active input for TIMx_CCR2: write the CC2S bits to 10 in the TIMx_CCMR1 register (TI1 selected).
• Select the active polarity for TI1FP2 (used for capture in TIMx_CCR2): write the CC2P bit to ‘1’ (active on falling edge).
• Select the valid trigger input: write the TS bits to 101 in the TIMx_SMCR register (TI1FP1 selected).
• Configure the slave mode controller in reset mode: write the SMS bits to 100 in the TIMx_SMCR register.
• Enable the captures: write the CC1E and CC2E bits to ‘1 in the TIMx_CCER register.
Me, I am using duty cycle measuring in one of my projects according to this description.

The reference manual has too many examples (with many different options) to be all supported / implemented in the core.
I really cannot see how the HardwareTimer class should be changed to support them.
It would be nice if we would have one example sketch for all of them, even with direct register settings. But I think no one has the necessary time.

Post Reply