cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4discovery measuring a pulse duration

chrispadbury
Associate II
Posted on January 22, 2013 at 16:53

I am having some trouble setting up an external pulse duration measurement on a Timer. Ideally I'd like to capture the duration of just the first incidence of a pulse on the desired pin, but that could require the use of interrupts and or debouncing.

Here's the code for setting up the Timer (TIM5):

/** 
* 
* Uses Timer PULSE_MEASUREMENT_TIM (with RCC as PULSE_MEASUREMENT_TIM_RCC) 
* on pin PULSE_MEASUREMENT_PIN of PULSE_MEASUREMENT_PORT (with RCC as PULSE_MEASUREMENT_PORT_RCC). 
* Also uses PULSE_MEASUREMENT_PINSOURCE and GPIO_AF_PULSE_MEASUREMENT_TIM. 
* 
*/ 
uint32_t Pulse_Measurement_TIM_Config(void) { 
GPIO_InitTypeDef GPIO_InitStructure; 
NVIC_InitTypeDef NVIC_InitStructure; 
TIM_ICInitTypeDef TIM_ICInitStructure; 
/* PULSE_MEASUREMENT_TIM clock enable */ 
RCC_APB1PeriphClockCmd(PULSE_MEASUREMENT_TIM_RCC, ENABLE); 
/* PULSE_MEASUREMENT_PORT clock enable */ 
RCC_AHB1PeriphClockCmd(PULSE_MEASUREMENT_PORT_RCC, ENABLE); 
/* PULSE_MEASUREMENT_TIM channel2 configuration : PULSE_MEASUREMENT_PIN of PULSE_MEASUREMENT_PORT */ 
GPIO_InitStructure.GPIO_Pin = PULSE_MEASUREMENT_PIN; 
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; 
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; 
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //GPIO_PuPd_UP; 
GPIO_Init(PULSE_MEASUREMENT_PORT, &GPIO_InitStructure); 
/* Connect TIM pin to AF2 */ 
GPIO_PinAFConfig(PULSE_MEASUREMENT_PORT, PULSE_MEASUREMENT_PINSOURCE, PULSE_MEASUREMENT_GPIO_AF_TIM); 
/* Enable the TIM4 global Interrupt // 
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; 
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; 
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
NVIC_Init(&NVIC_InitStructure); 
*/ 
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; 
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_PWMIConfig(PULSE_MEASUREMENT_TIM, &TIM_ICInitStructure); 
/* Select the TIM4 Input Trigger: TI2FP2 */ 
TIM_SelectInputTrigger(PULSE_MEASUREMENT_TIM, TIM_TS_TI2FP2); 
/* Select the slave Mode: Reset Mode */ 
//TIM_SelectSlaveMode(PULSE_MEASUREMENT_TIM, TIM_SlaveMode_Reset); 
TIM_SelectSlaveMode(PULSE_MEASUREMENT_TIM, TIM_SlaveMode_Gated); 
TIM_SelectMasterSlaveMode(PULSE_MEASUREMENT_TIM, TIM_MasterSlaveMode_Enable); 
/* TIM enable counter */ 
TIM_Cmd(TIM4, ENABLE); 
return 0; 
}

Here is the sub-routine for querying the timer:

/** 
* 
* This function queries the counter value of PULSE_MEASUREMENT_TIM. Also checks that the timer isn't still counting. 
* 
* returns 
* positive integer : the number of us counted since last reset of the timer counter 
* -1 : timer counter still counting (error) 
* 
*/ 
uint32_t Query_Last_Pulse(void) { 
char return_message[23]; 
unsigned int divisor = 84; 
unsigned int counter_value; 
unsigned int number_of_us; 
/* read counter value */ 
counter_value = TIM_GetCounter(PULSE_MEASUREMENT_TIM); 
/* wait 8us */ 
Delay_US(8); 
/* check if counter value has changed */ 
if(counter_value == TIM_GetCounter(PULSE_MEASUREMENT_TIM)) { 
// it hasn't changed for return the number of microseconds; 
number_of_us = counter_value / divisor; 
} 
else { 
sprintf(return_message, ''%cERROR:_Still_Counting...%c'', FRAMING_BYTE, FRAMING_BYTE); // it hasn't stopped counting, error 
return -1; 
} 
return number_of_us; 
}

And finally here is the section of main code that defines the timer used etc and attempts to measure the duration of a pulse that happens between the two USERbutton presses:

#define PULSE_MEASUREMENT_TIM TIM5 
#define PULSE_MEASUREMENT_TIM_RCC RCC_APB1Periph_TIM5 
#define PULSE_MEASUREMENT_PIN GPIO_Pin_1 
#define PULSE_MEASUREMENT_PORT GPIOA 
#define PULSE_MEASUREMENT_PORT_RCC RCC_AHB1Periph_GPIOA 
#define PULSE_MEASUREMENT_PINSOURCE GPIO_PinSource7 
#define PULSE_MEASUREMENT_GPIO_AF_TIM GPIO_AF_TIM5 
#define PULSE_MEASUREMENT_OFFSET 0 
#define USER_BUTTON_PORT GPIOA 
#define USER_BUTTON_PIN GPIO_Pin_0 
#define USER_BUTTON_DEFAULT 0 
//........ 
/* Initialise PULSE_MEASUREMENT_TIM */ 
Pulse_Measurement_TIM_Config(); 
while(GPIO_ReadInputDataBit(USER_BUTTON_PORT, USER_BUTTON_PIN) == USER_BUTTON_DEFAULT); 
/* Reset PULSE_MEASUREMENT_TIM timer */ 
TIM_SetCounter(PULSE_MEASUREMENT_TIM, PULSE_MEASUREMENT_OFFSET); 
Delay_ms(1000); 
while(GPIO_ReadInputDataBit(USER_BUTTON_PORT, USER_BUTTON_PIN) == USER_BUTTON_DEFAULT); 
sprintf(UART_Buffer, ''Pulse(us)=%d\n'', Query_Last_Pulse()); 
Send_UART_Buffer(); 
//........

I always get ''Pulse(us)=0'', even when I define PULSE_MEASUREMENT_OFFSET as #stm32f4discovery #tim-pulse-capture-config #stm32-timer #pulse
4 REPLIES 4
chrispadbury
Associate II
Posted on January 23, 2013 at 11:36

''I always get ''Pulse(us)=0'', even when I define PULSE_MEASUREMENT_OFFSET as ''

Obvious mistake here as Query_Last_Pulse uses a divisor of 10 / 84 = 0. Changing PULSE_MEASUREMENT_OFFSET to a 840 results in ''Pulse(us)=10''.

#define PULSE_MEASUREMENT_OFFSET 840

Still doesn't count though!
chrispadbury
Associate II
Posted on January 23, 2013 at 17:48

Ok so it was two basic mistakes:

1. Wrong Pin Source definition for the AF mode config (7 came from changing from TIM4). Should be:

#define PULSE_MEASUREMENT_PINSOURCE GPIO_PinSource1

2. Enabled the wrong timer (TIM4) by not updating to PULSE_MEASUREMENT_TIM. Should be:

 /* TIM enable counter */ 
TIM_Cmd(PULSE_MEASUREMENT_TIM, ENABLE);

Now it works and I'm going to test its accuracy.
chrispadbury
Associate II
Posted on January 24, 2013 at 18:04

For safety's sake, worth adding the these lines to initialise the timebase correctly:

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure //add to top of sub-routine 
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); 
//TIM_TimeBaseStructure.TIM_Prescaler = 83; // Option: sets tick rate to 1MHz, value of 0 sets it to 84MHz 
TIM_TimeBaseInit(PULSE_MEASUREMENT_TIM, &TIM_TimeBaseStructure);

As not using interrupt, no need for the NVIC lines (hence commented out). All works nicely.
chrispadbury
Associate II
Posted on January 24, 2013 at 18:30

Also:

TIM_InternalClockConfig(PULSE_MEASUREMENT_TIM);