Skip to main content
piotrek700
Associate
May 17, 2013
Question

STM32F4 Timer External Pulse counting

  • May 17, 2013
  • 35 replies
  • 7516 views
Posted on May 18, 2013 at 00:23

Since 4 day I'm trying write code which will be able to count external pulses. I tried to use encoder mode but i supposed that this work only with 2 quadrature encoders. I have only one pulse signal and i have no idea how to do it. Could you help me or show examples how to count external pulses using timer?

#counter #timer #off-topic #pulce
This topic has been closed for replies.

35 replies

Tesla DeLorean
Guru
April 6, 2015
Posted on April 06, 2015 at 20:02

I cannot figure out why i do not get the external pulse values print in my USART. please help.

I'm not using that library, inconsistent TIM3 and TIM4 references, but nothing that's obviously fatal. So what can you tell about what's happening via the debugger, and oscilloscope?

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
vimukthi_0123
Visitor II
April 7, 2015
Posted on April 07, 2015 at 17:39

hi clive1. thank you for responding. i have done a stupid mistake. have not called the TIM4_Configuration(); inside the ''main''. after i get values. 

my external signal is a frequency varying from around 30 to 200Hz for different motor speeds. its coming from my motor controller. i need the frequency value to then get the speed and use the speed to control my motor. 

now i get the frequency but for a particular motor speed frequency is not constant. it gives varying values on my usart. i cannot figure out the problem in my code. please help. thank you in advance.

float x;

int CaptureNumber = 0;

float counter;

float Time;

float freq;

void TIM4_Configuration(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;

TIM_ICInitTypeDef TIM_ICInitStructure;

  /* GPIOC clock enable */

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

 

  /* TIM4 clock enable */

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);

  

  /* GPIOA Configuration: TIM4 CH1 (PD12) */

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // Input/Output controlled by peripheral

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // Button to ground expectation

  GPIO_Init(GPIOD, &GPIO_InitStructure);

 

    /* Connect TIM4 pins to AF */

  GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIM4);

  

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);

//   //Time initialization

  TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //Control with dead zone.

  TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;  //Counter direction

  TIM_TimeBaseInitStructure.TIM_Prescaler = 84-1;   //Timer clock = sysclock /(TIM_Prescaler+1) = 2M

  TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;

  TIM_TimeBaseInitStructure.TIM_Period = 0xFFFF;

//Period = (TIM counter clock / TIM output clock) - 1 = 40Hz 

  TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);

  TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;

  TIM_ICInitStructure.TIM_ICFilter = 0;

  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;

  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;

  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;

  TIM_ICInit(TIM4,&TIM_ICInitStructure);

  TIM_Cmd(TIM4,ENABLE);

}

int main()

{

char str[120];

SystemInit();

TM_DELAY_Init();

/* Initialize USART, TX: PB6 */

TM_USART_Init(USART1, TM_USART_PinsPack_2, 9600);

TIM4_Configuration();

while (1) {

/* Every 500ms */

if (TM_DELAY_Time() >= 500) {

/* Reset time */

TM_DELAY_SetTime(0);

if(TIM_GetFlagStatus(TIM4,TIM_FLAG_CC1)==SET)

{

TIM_ClearFlag(TIM4,TIM_FLAG_CC1);

if(CaptureNumber == 0)

{

counter = TIM_GetCapture1(TIM4);  //The first capture

CaptureNumber = 1;

}

else if(CaptureNumber == 1)  //Treatment of second capture

{

if(TIM_GetFlagStatus(TIM4,TIM_FLAG_Update) != SET)//Treatment of two capture no overflow occurs

{

Time = TIM_GetCapture1(TIM4);

Time = Time - counter;

}

else

{

TIM_ClearFlag(TIM4,TIM_FLAG_Update);   //The update event

Time = 0xFFFF - counter + TIM_GetCapture1(TIM4)+1;  //If the calculation mode update events

}

CaptureNumber = 0;

if(Time!=0)

{

freq= 2000000/Time;  //Calculation of frequency

}

freq = freq;  //To avoid the freq variable is compiler optimization.

}

}

sprintf(str, ''freq\n- %f\r\n'', freq);

/* Show to usart */

TM_USART_Puts(USART1, str);

}

}

}

hchaychi
Visitor II
May 8, 2015
Posted on May 08, 2015 at 12:37

Hi clive1

is it possible i use ch4 for external clock input ? and if yes how ?

Regards

Tesla DeLorean
Guru
May 8, 2015
Posted on May 08, 2015 at 19:20

No, you need to refer to the Timer Block Diagram in the Reference Manual

You can use an TIMx_ETR pins, internal sources (ITRx from other timers), TI1FP1 (CH1 side), TI2FP2 (CH2 side), TI1F_ED

You could perhaps use an EXTI interrupt for low bandwidth applications

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
hchaychi
Visitor II
May 11, 2015
Posted on May 11, 2015 at 08:43

Hi Clive1

Thank you very much

patrob680
Visitor II
October 15, 2015
Posted on October 15, 2015 at 04:13

Hi all,

I am a beginner in this arena. If I use TIM5 (32-bit) CH1(PA.0) of STML1 to count external pulses in 10ms period (10ms active count, 10ms interval, again 10ms active), How to configure interrupt routine? Please educate me in this regard.

I've followed the earlier posts and started like this:

#include ''stm32l1xx.h''

#include ''misc.h''

#include ''stm32l1xx.h''

#include ''stm32l1xx_gpio.h''

#include ''stm32l1xx_rcc.h''

#include ''stm32l1xx_tim.h''

# define sample 20  

int count[sample];

int i;

int main(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

TIM_ICInitTypeDef   TIM_ICInitStructure;

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

/* TIM5 clock enable */

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);

/* GPIOA clock enable */

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

   /*  TIM5 channel 1 pin (PA.0) configuration */

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

   GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;

   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;

   GPIO_Init(GPIOA, &GPIO_InitStructure);

   GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_TIM5);

   /* TIM5 configuration: Input Capture mode  */

   TIM_TimeBaseStructure.TIM_Period = 0xF9FF;

// To generate interrupt in .01s (Count 64000-1)

   TIM_TimeBaseStructure.TIM_Prescaler = 4;      // 32MHz/(4+1) = 6.4MHz

   TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;

   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

   TIM_TimeBaseInit(TIM5, & TIM_TimeBaseStructure);

   TIM_ICInitStructure.TIM_Channel     = TIM_Channel_1;

   TIM_ICInitStructure.TIM_ICPolarity  = TIM_ICPolarity_Rising;

   TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;

   TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;

   TIM_ICInitStructure.TIM_ICFilter = 0x0;

   TIM_ICInit(TIM5, &TIM_ICInitStructure);

        /* TIM enable counter */

   TIM_Cmd(TIM5, ENABLE);

   /* Enable the TIM5 global Interrupt */

   NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;

   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

   NVIC_Init(&NVIC_InitStructure);

 /* Enable the CC1 Interrupt Request */

   TIM_ITConfig(TIM5, TIM_IT_CC1, ENABLE);

   while (1)

   {    

   // How to read total ticks in 10ms window and put sleep for another 10ms ?

  

  count[i] = TIM5->CNT;

  i++;

   }

}

Tesla DeLorean
Guru
October 15, 2015
Posted on October 15, 2015 at 07:00

Honestly this seems off-topic, can we not do that.

The TIM5_IRQHandler() would have to read consecutive captures of CNT stored in TIM5->CCR1, and do a delta computation between the two, of ticks at the timebase frequency. Using a 0-63999 count is going to make the math unduly complicated. If you just go with the maximal mode (Period = 0xFFFFFFFF), deltaticks = b - a; Where deltaticks, a, b are all uint32_t

In some situations PWM Input mode might be more helpful for period/duty, a single interrupt, and the timebase is automatically reset.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
patrob680
Visitor II
October 26, 2015
Posted on October 26, 2015 at 04:36

Sorry, I misunderstood my requirements. I need to count pulses for consecutive 10ms period. Can I use RTC auto-wakeup interrupt to store TIM5-> CNT value after 10ms, reset CNT and re-count after 10ms? In that case, do I still need to configure TIM5 time-base interrupt?

Also, to store in a SD card text file (using FATFS), how to design a storage format for comma separated count values. I request some guidelines or

an example link, if available

.
patrob680
Visitor II
October 26, 2015
Posted on October 26, 2015 at 13:43

Or to store in a .csv log file.

Tesla DeLorean
Guru
October 26, 2015
Posted on October 26, 2015 at 15:59

I'd probably put one timer in External Count mode, and use a second one to DMA sample the TIMx->CNT with the 10ms periodicity, have a 200 sample buffer with HT/TC interrupts, process 100 elements by doing a delta computation on one vs the next capture and build an output list. This would decimate processor activity to once a second.

Have a foreground task take the processed data and have it write it to you FatFs implementation using an SD Card interfacing with SDIO or SPI depending on what's available on your hardware. You'd want to flush or close periodically. It would be somewhat similar to the ADC to SD Card example I posted for the STM32F4 Disco.

How many samples would be on a comma delimited line? Assume you can't do so endlessly. You're just printing ASCII data to a file, you could format it any way you think is suitable, and that you can process.

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