cancel
Showing results for 
Search instead for 
Did you mean: 

TIM 15 uSeconds

botmail242
Associate II
Posted on June 27, 2016 at 19:58

I have and EXTI fire when the signal goes high and I want to check the signal 15 microseconds after the interrupt. I'm using a TIM but it doesn't work. I'm using an STM32F4 Discovery MCU

#include ''stm32f4xx_hal.h''
#include <
string.h
>
#include <
stdlib.h
>
#include ''stm32f4xx_hal_tim.h''
#include ''stm32f4xx_hal_tim_ex.h''
void enable_exti(void);
void enable_tim(void);
void EXTI2_IRQHandler(void);
void SysTick_Handler(void);
void stopwatch(int uSecs);
TIM_HandleTypeDef tim_init;
int usec = 0;
int curr_sec = 0;
// Note: defined HAL_TIM_MODULE_ENABLED in stm32f4xx_hal_tim_ex.c
// defined HAL_TIM_MODULE_ENABLED in stm32f4xx_hal_conf.h
// clock runs at 16,000,000 Hz
int
main(void){
// setup TIM
HAL_TIM_Base_MspInit(&tim_init); // initialize the TIM basic
enable_tim();
// setup EXTI
enable_exti();
// configure clock to 16MHz (check with HAL_RCC_GetSysClockFreq())
SysTick_Config(HAL_RCC_GetHCLKFreq());
while(1);
}
void
HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if(htim->Instance == TIM2){
if(curr_sec == usec){
HAL_TIM_Base_Stop(&tim_init); // stop the timer it has been 15 useconds
// print the level of the signal to the console
curr_sec = 0;
}
else
curr_sec++;
}
}
/*
* Used to start a timer that will fire an interrupt at num microseconds. The
* interrupt is configured in the HAL_TIM_PeriodElapsedCallback() function.
*/
void
stopwatch(int num){
curr_sec = 0;
usec = num;
HAL_TIM_Base_Start(&tim_init); // starts the timer
}
void
SysTick_Handler(void){
HAL_IncTick();
}
/*
* Configures pin PB02 as the SDQ wire.
*/
void
enable_exti(void){
GPIO_InitTypeDef GPIO_InitStruct;
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin PB2 */
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_NVIC_SetPriority(EXTI2_IRQn, 0x1, 0);
HAL_NVIC_EnableIRQ(EXTI2_IRQn);
}
/*
* Configures the timer to pin PA3.
*/
void
enable_tim(void){
tim_init.Instance = TIM2;
tim_init.Init.CounterMode = TIM_COUNTERMODE_UP;
tim_init.Init.Prescaler = 16 - 1; // 1,000,000 Hz -> 1/1,000,000 seconds
tim_init.Init.Period = 0;
tim_init.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // for now...
//tim_init.Init.RepetitionCounter = 0;
__TIM2_CLK_ENABLE(); // pin PA3
// configure the GPIO PA3
__GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0); //Enable the peripheral IRQ
HAL_NVIC_EnableIRQ(TIM2_IRQn);
HAL_TIM_Base_Init(&tim_init);
//HAL_TIM_Base_Start_IT(&tim_init); //Start the timer
}
void
TIM2_IRQHandler(void) {
HAL_TIM_IRQHandler(&tim_init);
}
void
EXTI2_IRQHandler(void){
stopwatch(15); // function that starts the timer and checks signal after 15 useconds
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2);
}

5 REPLIES 5
botmail242
Associate II
Posted on June 27, 2016 at 20:02

The TIM should increment curr_sec every 1 usecond. When curr_sec is equal to the usec variable, 15 useconds has elapsed and the signal is read and printed to the terminal.

Posted on June 27, 2016 at 20:07

Not sure that's something I'd do with an interrupt.

Interrupting at 1 MHz isn't going to fly, you'll want to think how you can get hardware to capture the signal edge, and delayed sample of another signal.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
botmail242
Associate II
Posted on June 27, 2016 at 20:37

What about a looping delay (because that would work)? Something like...

void delay( uint32_t time ) {
// runs at 16MHz
while( usec) {
usec--;
}
}

How would I get a semi accurate delay function? It doesn't have to be extremely precise.
Posted on June 27, 2016 at 21:18

Review the use of DWT_CYCCNT, is should allow you to get sub-microsecond, either as a method of constraining the loop, or benchmarking one with the correct iterations. The latter can be problematic from a compiler optimization, and interrupted perspective.

You could also look at using a TIM in a free running mode.

Alternatively you could use a TIM with one channel doing input capture to time stamp your original event, and then using that along with the CNT value of the timer currently to acquire the event 15us down the time line.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
botmail242
Associate II
Posted on June 28, 2016 at 20:44

Thanks for the great ideas. I'm posting this in case anyone in the future stumbles upon this thread. I ended up making busy loops and measuring how long they took with a timer. I found that every 10 iterations of a loop takes approx 25 uS (for my board). I didn't need it to be extremely accurate so this worked.

void
delay(int usec){
unsigned int time;
char time_str[32];
__HAL_TIM_SetCounter(&tim_init, 0);
int iters = 10 * (usec / 25);
int x;
for(x=0; x<iters; x++);
time = (unsigned int)__HAL_TIM_GetCounter(&tim_init);
sprintf( time_str, ''%u'', time); // convert uint to str
HAL_UART_Transmit(&uart_init, (uint8_t*)time_str, (uint16_t)strlen(time_str), 100);
HAL_UART_Transmit(&uart_init, (uint8_t*)''
'', (uint16_t)strlen(''
''), 100);
}