2013-01-22 07:53 AM
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
2013-01-23 02:36 AM
''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!
2013-01-23 08:48 AM
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.
2013-01-24 09:04 AM
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.
2013-01-24 09:30 AM
Also:
TIM_InternalClockConfig(PULSE_MEASUREMENT_TIM);