cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F407VG Basic Timer 6 Magic value

dimf_91
Associate II
Posted on September 19, 2016 at 10:54

Hello! I use a basic timer 6 to make a simple delay. Here is my code:

#define DELAY_TIME       10

#define PB2_ON()         GPIOB->BSRRL = GPIO_Pin_2

#define PB2_OFF()        GPIOB->BSRRH = GPIO_Pin_2

//Config PortB_Pin2 as output

void PortB_Init(void)

{

   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);

   GPIO_InitTypeDef PortB_Pin2_init;

   PortB_Pin2_init.GPIO_Mode = GPIO_Mode_OUT;

   PortB_Pin2_init.GPIO_Pin = GPIO_Pin_2;

   PortB_Pin2_init.GPIO_Speed = GPIO_Speed_100MHz;

   PortB_Pin2_init.GPIO_OType = GPIO_OType_PP;

   PortB_Pin2_init.GPIO_PuPd = GPIO_PuPd_NOPULL;

   GPIO_Init(GPIOB, &PortB_Pin2_init);

}

//Timer 6 config

void Timer6_Init(void)

{

   RCC->APB1ENR |= RCC_APB1Periph_TIM6; // Enable Timer 6 clock

   TIM6->PSC = 83;  // Clock frequency: 1MHz

   TIM6->ARR = 0xFFFF; // Auto-reload register value  

                       // After reaching this value appears Update Interrupt and Counter Register will be reset 

   TIM6->CR1 |= TIM_CR1_CEN; //TIM6 Enable

}

//Delay-func. Count µs

void ddelay_micros(uint16_t delay_time)

{

   TIM6->CNT = 0;

   while (TIM6->CNT != delay_time) ;

   return;

}

void main(void)

{

   SystemInit();  

   PortB_Init();

   Timer6_Init();

   RCC_ClocksTypeDef RCC_Clocks;

   RCC_GetClocksFreq(&RCC_Clocks);

    while(1)

    {

       PB2_ON();

       ddelay_micros(DELAY_TIME);

       PB2_OFF();

       ddelay_micros(DELAY_TIME);

    }

}

It works pretty well, the achieved delay is about 10,6 µs.

With DELAY_TIME values: 15, 20, 1000 i obtain the correct time intervals.

But! If i set 

DELAY_TIME to 12, the generated delay ist about 420 ns!

I do not understand what am i missing out.

Thanks for advice! :)

 
6 REPLIES 6
Posted on September 19, 2016 at 18:16

I wouldn't keep resetting the counter, it is not thread safe, and the exact match is also a bear-trap. Pull a local copy of the entry value, and compare against that until enough time has passed. Should be good to 65ms

//Delay-func. Count µs
void ddelay_micros(uint16_t delay_time)
{
uint16_t start = TIM6->CNT;
while ((TIM6->CNT - start) < delay_time);
return;
}

Not sure why your code fails, perhaps it's a tool/optimization issue, TIM6->CNT should be volatile.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
dimf_91
Associate II
Posted on September 21, 2016 at 11:38

Thanks for your help clive1!

But i have one question more.

If i use your code, and it will so happen, that i go into these delay_function and the value of TIM_CNT register is 65534. So i'll become a wrong time delay.

What can i do to prevent it, if you mean that resetting the timer counter like ''TIM_CNT = 0'' is not such a good idea?

Posted on September 21, 2016 at 17:44

If it does the math in the uint16t number space the fact it wraps will be handled by the subtraction.

ie 0x0004 - 0xFFFC = 8

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
dimf_91
Associate II
Posted on September 22, 2016 at 12:15

Thanks again! You are right. 

But i have one more idea. What if i use timer in one/pulse mode? Like that:

//Timer 7 config

void Timer7_Init(void)

{

   RCC->APB1ENR |= RCC_APB1Periph_TIM7; // Enable Timer 7 clock

   TIM7->PSC = 83;  // Clock frequency: 1MHz

   TIM7->CR1 |= TIM_CR1_OPM; // Enable One-Pulse Mode

}

//Delay-func. Count µs

void ddelay_micros(uint16_t delay_time)

{

   TIM7

->SR = 0; //clear UIF Flag

   TIM7

->ARR = delay_time -1; // -1 clock cycle due to CEN set delay

   TIM7->CR1 |= TIM7_CR1_CEN; //Timer7 Enable

   while (!(TIM7

->SR & TIM_SR_UIF

)); // wait till UIF is set

   return;

}

What do you think about this idea?

With such implemantation i have an error about 0.5 µs from the disered delay and if i let pin toggle with these delay_func() i can see a very-very little phase jitter.

Thank you for your time and help :)  

Posted on September 22, 2016 at 16:13

Like I said, I prefer code that is thread/interrupt safe. The core has a 32-bit free-running counter, DWT_CYCCNT that clocks at the processor speed, depending on the core it has sub 10ns granularity.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
dimf_91
Associate II
Posted on September 23, 2016 at 09:35

Hello clive1!

I do not have a lot of experience in the µc programming, but what is the difference between using a free-runnig counter DWT and a basic timer such a Timers 6/7? Except their resolution and clock frequency?

Thank you!