2020-06-07 11:22 AM
Hi
I am currently trying to create a delay function on my STM32F407 discovery board using a free running timer (I used TIM6 for this purpose). I set my counter clock frequency as high as possible and my max counter value to 0xFFFF. Based on my calculations, I should get a delay of approx 4ms:
16MHz/1=16MHz counter clock frequency -> 1/16MHz = 62.5ns counter period.
62.5ns*0xFFFF = 62.5ns*65535=0.0040959375s = 0.004s=4ms.
I toggle an LED every time the counter has reached its max value of 0xFFFF. So in theory, it should be 4ms on, 4ms off. 8ms in total.
However, using a logic analyzer, I get a period of 45ms, so a factor of 5 higher. Do you have an idea what could cause this behavior? Thank you,
#include "stm32f4xx.h"
#define LCD_BOOTUP_MS 15
void funcTimerInit();
void delay_LCD(int delay);
void funcGPIOInit();
int main(void)
{
funcTimerInit();
funcGPIOInit();
for(;;)
{
delay_LCD(LCD_BOOTUP_MS);
}
}
void funcTimerInit()
{
// TIM6 setup
// Peripheral clock
RCC->APB1ENR |= (1<<4); // Enables APB1 bus to use Timer 6
// 2. Init timer
TIM6->CR1 |= (1<<0); // CEN: Enables counter
TIM6->CR1 &= ~(1<<1); // UDIS: Update event enabled
TIM6->CR1 |= (1<<2); // URS: Update request source enabled for overflow/underflow only
TIM6->CR1 &= ~(1<<3); // OPM: One Pulse Mode. Counter continues counting.
TIM6->DIER &= ~(1<<0); // UIE: Update interrupt disabled
TIM6->EGR |= (1<<0); // UG: Update generation. Re-initializes the counter and updates registers
TIM6->PSC = 0x0000; // Sets prescaler to 0. Timer clock is now 16MHz/(0+1)=16MHz -> 62.5ns
TIM6->ARR = 0xFFFF; // Counter goes up to 65535
}
void delay_LCD(int delay)
{
static uint8_t flag = 1;
if(delay==15) // ms
{
while((TIM6->CNT) < 0xFFFF)
{
// Do nothing
}
}
else
{
// Do something
}
if(flag)
{
// Turn LED on
GPIOD->ODR |= (1<<12); // Sets PD12
flag = 0;
}
else
{
// Turn LED off
GPIOD->ODR &= ~(1<<12); // Clears PD12
flag = 1;
}
}
void funcGPIOInit()
{
// Peripheral clock
RCC->AHB1ENR |= (1<<3); // Enables AHB1 to use GPIOD peripheral
// 2. Init GPIO
GPIOD->MODER |= (1<<24); // Sets GPIOD as Output
GPIOD->MODER &= ~(1<<25); // Sets GPIOD as Output (redundant because bit 25 is already 0 after reset)
GPIOD->OTYPER &= ~(1<<12); // Set PD12 as Push Pull
GPIOD->OSPEEDR &= ~(1<<24); // Sets speed on PD12 to low
GPIOD->OSPEEDR &= ~(1<<25); // Sets speed on PD12 to low
}
Solved! Go to Solution.
2020-06-07 11:40 AM
while((TIM6->CNT) < 0xFFFF)
{
// Do nothing
}
Since CNT goes from 0xFFFF to 0 in 1 tick, you may miss out on getting the exact value of 0xFFFF. Sounds like this is happening 5 times before you catch the actual value. One option would be to compare against 0xFFF0, so you at least have a larger span of ticks to capture. A better solution would be to use the timer in one shot mode and wait until it's done. Another would be to use SysTick for these types of measurements, or the debug timer.
2020-06-07 11:40 AM
while((TIM6->CNT) < 0xFFFF)
{
// Do nothing
}
Since CNT goes from 0xFFFF to 0 in 1 tick, you may miss out on getting the exact value of 0xFFFF. Sounds like this is happening 5 times before you catch the actual value. One option would be to compare against 0xFFF0, so you at least have a larger span of ticks to capture. A better solution would be to use the timer in one shot mode and wait until it's done. Another would be to use SysTick for these types of measurements, or the debug timer.
2020-06-07 12:17 PM
Thank you for your reply. One shot mode did the trick. Regarding SysTick, I didn't know about it until I read your comment. I checked the reference manual, but didn't find it there, until Google eventually told me to find it in CMSIS.
Thanks a lot.
Cheers,