cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L timebetween pulses

k_
Associate II
Posted on September 06, 2013 at 15:35

Hello,

I'm trying to measure time between two pulses on a pin. Time between pulses is in 10 - 100 uS range so I can't use millis function. What I'm trying to do is use TIM2 CNT register. Since my APB2 clock is runnig at 32MHz I should get a resolution of about  0.03 uS. 

The problem is that when I try to debug the CNT register is always at 0x0000 value :(

I use this code to initialize timer:

void Enable_Timer()

{

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

TIM_InitStructure.TIM_Period = 0xFFFFFFFF;

TIM_InitStructure.TIM_Prescaler = 0x0000;

TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;

TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM2, &TIM_InitStructure);

TIM_Cmd(TIM2, ENABLE);

}

And this to read the CNT value:

tt= TIM_GetCounter(TIM2);

EDIT:

I am using STM32L152 board

#timer #discovery #stm32l #tim
10 REPLIES 10
Posted on September 06, 2013 at 15:59

The counters at all 16-bit as I recall, otherwise looks reasonable, so I'd question the context.

To measure pulses on a timer channel, you'd want to look at Input Capture mode.
Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
k_
Associate II
Posted on September 09, 2013 at 15:47

Tried input capture mode, but can't start the timers.

My Code:

GPIO pin initialization

/* Enable GPIOA clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
/* Enable SYSCFG clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB, GPIO_Pin_10, GPIO_AF_TIM2);

Enable Timer 2 and Interrupt on timer update:

void Enable_Timer()
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_InitStructure.TIM_Period = 0xFFFFFFFF;
TIM_InitStructure.TIM_Prescaler = 0x0000;
TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1
TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_InitStructure);
TIM_Cmd(TIM2, ENABLE);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
TIM_ICInitStructure.TIM_ICFilter = 0x00;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
}

Timer interrupt:

void TIM2_IRQhandler()
{
if (TIM2->SR & TIM_IT_CC2)
{ /* capture timer */
TIM2->SR = ~TIM_FLAG_CC2;
if(CaptureNumber == 0)
{
/* Get the Input Capture value */
IC2ReadValue1 = TIM2->CCR2;
CaptureNumber = 1;
}
else if(CaptureNumber == 1)
{
/* Get the Input Capture value */
IC2ReadValue2 = TIM2->CCR2;
/* Capture computation */
if (IC2ReadValue2 > IC2ReadValue1)
{
Capture = (IC2ReadValue2 - IC2ReadValue1);
}
else
{
Capture = ((IC2ReadValue2 + 0x10000) - IC2ReadValue1);
}
IC2ReadValue1 = IC2ReadValue2;
}
}
}

Still the Capture value doesn't change. Ant timer register value is always zero. I just can't figure out why it is not working.

Posted on September 09, 2013 at 17:57

GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_TIM2);

TIM_ITConfig(TIM2, TIM_IT_CC2, ENABLE);
Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
k_
Associate II
Posted on September 10, 2013 at 12:27

Will I see timers running in debug window?

Posted on September 10, 2013 at 17:12

Dunno, the code is insufficiently complete for me to quickly test, and I don't know what tool chain/debugger you have.

Personally, I'd array the samples and break-point, and then look at the array, should be apparent if it's functional, or the measurements are within scope. Alternatively you could print results periodically to the USART.
Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
k_
Associate II
Posted on September 11, 2013 at 15:26

I have the timer running. But now I can't get an interrupt to measure pulse width on PB

If I set interrupt flag by software I get correct timer values. But I can't make a hardware interrupt. I think the problem is somewhere in void Enable_Timer() function, but I just can't find it :(

I'm using Keil. Here's the full code:

#include ''stm32l1xx.h''
#include ''stdio.h''
#include ''string.h''
#include ''math.h''
int Capture;
int CaptureNumber; 
int IC2ReadValue1;
int IC2ReadValue2;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
TIM_TimeBaseInitTypeDef TIM_InitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
//*****************************************************
//Enable system clocks for input configuration
//*****************************************************
void Enable_Clocks()
{
/* Enable GPIOA clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
/* Enable GPIOA clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
/* Enable SYSCFG clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
}
//******************************************************
//******************************************************
//TIM2 interrupt
//******************************************************
void TIM2_IRQhandler()
{
GPIO_ResetBits(GPIOB, GPIO_Pin_11);
if (TIM2->SR & TIM_IT_CC2)
{
TIM2->SR = ~TIM_FLAG_CC2;
if(CaptureNumber == 0)
{
/* Get the Input Capture value */
IC2ReadValue1 = TIM2->CCR2;
CaptureNumber = 1;
}
else if(CaptureNumber == 1)
{
/* Get the Input Capture value */
IC2ReadValue2 = TIM2->CCR2;
/* Capture computation */
if (IC2ReadValue2 > IC2ReadValue1)
{
Capture = (IC2ReadValue2 - IC2ReadValue1);
}
else
{
Capture = ((IC2ReadValue2 + 0x10000) - IC2ReadValue1);
}
IC2ReadValue1 = IC2ReadValue2;
}
}
}
//******************************************************
//******************************************************
//Enable APB pin 10 for timer interrupt input
//******************************************************
void Enable_APB()
{
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure); 
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_TIM2);
}
//******************************************************
//******************************************************
//Enable TIM2 timer 
//******************************************************
void Enable_Timer()
{
TIM_InitStructure.TIM_Period = 0xFFFF;
TIM_InitStructure.TIM_Prescaler = 32;
TIM_InitStructure.TIM_ClockDivision = 0;
TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_InitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICFilter = 0;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_TRC;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM2->SMCR = 0x00000074;
TIM_SelectInputTrigger(TIM2, TIM_TS_ETRF);
TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
TIM_Cmd(TIM2, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
}
//******************************************************
//******************************************************
//Main function calls all other functions when needed
//******************************************************
int main(void)
{
Enable_Clocks();
Enable_APB();
Enable_Timer();
/* Infinite loop */
while(1)
{
}
}
//******************************************************

Posted on September 11, 2013 at 16:00

I'm confused,

You enable a bunch of clocks, USART2 twice, SYSCFG not at all. Things that aren't used and inconsistent with the comments.

You use PB10, which as I recall is TIM2_CH3, you then make a bunch of reference to CH1 when configuring the TIM and interrupt, and then your interrupt code makes references to CH2

For a time base of 1 MHz from a 32 MHz core, then 32-1 for the prescaler
Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on September 11, 2013 at 16:24

Try this, it a blind build but is at least internally consistent.

#include ''stm32l1xx.h''
#include ''stdio.h''
#include ''string.h''
#include ''math.h''
volatile int Capture; // Changed under interrupt
volatile int CaptureCount = 0;
//*****************************************************
//Enable system clocks for input configuration
//*****************************************************
void Enable_Clocks()
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
}
//******************************************************
//******************************************************
//TIM2 interrupt
//******************************************************
void TIM2_IRQhandler()
{
static int CaptureNumber = 0;
static int IC3ReadValue1; // Retained
int IC3ReadValue2; // Transient
if (CaptureCount++ & 1) // Toggle PB11
GPIO_SetBits(GPIOB, GPIO_Pin_11);
else
GPIO_ResetBits(GPIOB, GPIO_Pin_11);
if (TIM2->SR & TIM_IT_CC3)
{
TIM2->SR = ~TIM_FLAG_CC3;
if(CaptureNumber == 0)
{
/* Get the Input Capture value */
IC3ReadValue1 = TIM2->CCR3;
CaptureNumber = 1;
}
else if(CaptureNumber == 1)
{
/* Get the Input Capture value */
IC3ReadValue2 = TIM2->CCR3;
/* Capture computation */
Capture = (IC3ReadValue2 - IC3ReadValue1) & 0xFFFF; // 16-bit masking
IC3ReadValue1 = IC3ReadValue2;
}
}
}
//******************************************************
//******************************************************
//Enable APB pin 10 for timer interrupt input
//******************************************************
void Enable_APB()
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure); 
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_TIM2); // PB10 TIM2_CH3
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_Init(GPIOB, &GPIO_InitStructure); 
GPIO_SetBits(GPIOB, GPIO_Pin_11);
}
//******************************************************
//******************************************************
//Enable TIM2 timer
//******************************************************
void Enable_Timer()
{
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_InitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
// Configure NVIC first
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_InitStructure.TIM_Period = 0xFFFF; // Maximal
TIM_InitStructure.TIM_Prescaler = 32 - 1; // 1 MHz from 32 MHz
TIM_InitStructure.TIM_ClockDivision = 0;
TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_InitStructure);
TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; // From the Pin
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling; // Measuring period on fall edges
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
TIM_ITConfig(TIM2, TIM_IT_CC3, ENABLE);
TIM_ClearITPendingBit(TIM2, TIM_IT_CC3);
TIM_Cmd(TIM2, ENABLE);
}
//******************************************************
//******************************************************
//Main function calls all other functions when needed
//******************************************************
int main(void)
{
Enable_Clocks();
Enable_APB();
Enable_Timer();
/* Infinite loop */
while(1)
{
}
}
//******************************************************

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
k_
Associate II
Posted on September 12, 2013 at 07:31

Thanks, you're the best. 

I couldn't find any information regards to PB10 channel in reference manual. Where did you find it?