2016-09-19 01:54 AM
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 outputvoid 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 configvoid 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 µsvoid 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 setDELAY_TIME to 12, the generated delay ist about 420 ns!
I do not understand what am i missing out.Thanks for advice! :)2016-09-19 09:16 AM
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.
2016-09-21 02:38 AM
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?2016-09-21 08:44 AM
If it does the math in the uint16t number space the fact it wraps will be handled by the subtraction.
ie 0x0004 - 0xFFFC = 82016-09-22 03:15 AM
Thanks again! You are right.
But i have one more idea. What if i use timer in one/pulse mode? Like that://Timer 7 configvoid 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 µsvoid 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 :)2016-09-22 07:13 AM
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.
2016-09-23 12:35 AM
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!