cancel
Showing results for 
Search instead for 
Did you mean: 

configure a general purpose TIMx (x=2,3,4) same as Systick on STM32F103B

slimbahri
Associate II
Posted on March 12, 2010 at 10:33

configure a general purpose TIMx (x=2,3,4) same as Systick on STM32F103B

14 REPLIES 14
lowpowermcu
Associate II
Posted on May 17, 2011 at 13:43

Hi Slim,

What does mean  ''we shouldn't use systick timer in user functions because that affects running accuracy'' ?

Regards,

low power

slimbahri
Associate II
Posted on May 17, 2011 at 13:43

Hi low power,

considering the aim of the project, I'm working on stm32F103B, to develop a benchmark tool (IAR systems IDE), so, if i would use often ''SysTick_GetCounter()'' in source code, that will produce software and hardware jitter (Sw: many system calls, Hw: PLL jitter), so i'll introduce another timer with the same configuration as systick. please, i need the configuration code of  this general purpose Timer.

Thanks in advance.

Slim

lowpowermcu
Associate II
Posted on May 17, 2011 at 13:43

Hi Slim,

As you can see in figure ''clock tree'' in datasheet, you should configure the APB1 prescaler so you have HCLK (core clock) = TIMxClk (timer clock)

then you have to enable the timer counter.

Regards,

be happy, don't worry

Posted on May 17, 2011 at 13:43

Pretty sure you are not going to see PLL jitter at this level. Things like synchronization, bus arbitration, interrupts, DMA and flash line cacher are going to impede absolute repeatability of measurements. The clock drift of the HSI is quite substantial.

The bigger problem is with quantization issues due to the granularity of the counters. You probably need to time multiple loops, and also wait on the counter to transition immediately before starting the test.

Personally I would use the Cortex's cycle counter to benchmark code. It's about as fine grained as you can get, but is still in the 10s on nanoseconds for granularity. Cycles are probably a better unit of measurement, time implies you know the clock frequency accurately.

-Clive
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on May 17, 2011 at 13:43

This code is also pretty awful, a lot of integer divides stealing precision. Consider if portTICK_RATE_MS is 3 or 4

val_tim_1=TIM_GetCounter(TIM3); 

for (i=0;i<=99;i++)

vTaskDelay( 10 / portTICK_RATE_MS ); // Delay 10 ms 

}

val_tim_2= TIM_GetCounter(TIM3); 

val_tim_2=((val_tim_2- val_tim_1)/100);

Try

double deltatime;

val_tim_1=TIM_GetCounter(TIM3); 

vTaskDelay( (10 * 100) / portTICK_RATE_MS ); // Delay 10 ms * 100

val_tim_2= TIM_GetCounter(TIM3); 

deltatime = ((double)(val_tim_2- val_tim_1) / 100.0);

It will give you a much better idea of the accuracy of vTaskDelay()

-Clive

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
slimbahri
Associate II
Posted on May 17, 2011 at 13:43

thanks a lot Clive1,

I'll do it, and tansmit you the results!!

Regards,

Slim

Posted on May 17, 2011 at 13:43

Here's some stuff I've pulled together with the cycle counter that I use to benchmark and optimize code on an STM32. This is like using RDTSC on x86.

a) Do enough work that the timing will be useful, ie call overhead, and interrupt handling.

b) Time empty calls if the call overhead is significant, or you want to remove it from estimates.

c) Time multi-iterations, either use an average (general real world), or minimum (best case execution).

d) Pick a suitable number of iterations. If something is complex you might only need to do it ten times, to get useful/repeatable numbers. Take care not to overrun the counters.

e) Mimic expected utilization for optimization. For example performing a CRC on 128K of data, trying to shave a few cycles.

-Clive

// Using the trace unit within the STM32, a method more generally suggested by Joseph Yiu

//  that works nicely on the STM32. For more course testing you could use a 1 ms SystemTick

//  variable, this might also help on longer tests to catch situations were the cycle

//  counter wraps.

unsigned int cyc[2];

// From http://forums.arm.com/index.php?showtopic=13949

volatile unsigned int *DWT_CYCCNT     = (volatile unsigned int *)0xE0001004; //address of the register

volatile unsigned int *DWT_CONTROL    = (volatile unsigned int *)0xE0001000; //address of the register

volatile unsigned int *SCB_DEMCR     = (volatile unsigned int *)0xE000EDFC; //address of the register

// Set up once

*SCB_DEMCR = *SCB_DEMCR | 0x01000000;

*DWT_CYCCNT = 0; // reset the counter

*DWT_CONTROL = *DWT_CONTROL | 1 ; // enable the counter

// Use macros around test code

#define STOPWATCH_START { cyc[0] = *DWT_CYCCNT; }

#define STOPWATCH_STOP { cyc[1] = *DWT_CYCCNT; cyc[1] = cyc[1] - cyc[0]; }

STOPWATCH_START

 TestFunction();

STOPWATCH_STOP

printf(''TestFunction() %d Cycles\n'',cyc[1]);

void EmptyFunction(void)

{

}

STOPWATCH_START

for(i=0; i<1000; i++)

  EmptyFunction();

STOPWATCH_STOP

printf(''1000x EmptyFunction() %d Cycles\n'',cyc[1]);

empty = cyc[1];

STOPWATCH_START

for(i=0; i<1000; i++)

  TestFunction();

STOPWATCH_STOP

printf(''1000x TestFunction() %lf Cycles (Core average)\n'',(couble)(cyc[1] - empty) / 1000.0);

quick = 0x7FFFFFFF;

for(i=0; i<1000; i++)

{

  STOPWATCH_START

  TestFunction();

  STOPWATCH_STOP

  if (quick > cyc[1]) quick = cyc[1];

}

printf(''TestFunction() %d Cycles (Best Case including call)\n'',quick);

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
slimbahri
Associate II
Posted on May 17, 2011 at 13:43

Hi clive, 

with the method you suggested, we should using J-TRACE isn't it ? I have only J-LINK; with the firmware of ST v3. 2; I have configured a timer as follow (check the configuration please)

#ifdef TIM_METHOD

/* clcok config: HCLK = SYSCLK  */

RCC_HCLKConfig(RCC_SYSCLK_Div1);

/* clcok config: PCLK1 = HCLK/2  */

RCC_PCLK1Config(RCC_HCLK_Div2);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);

/* TIM4config */

/* Initialise data. */

TIM_DeInit( TIM4 );

TIM_TimeBaseStructure.TIM_Period = 0xffff;

TIM_TimeBaseStructure.TIM_Prescaler = 15;

TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure );

//TIM_ARRPreloadConfig( TIM4, ENABLE);

        TIM4->EGR |= 0x01;

#else

/* GPIO config */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init( GPIOB, &GPIO_InitStructure );

#endif /* TIM_METHOD */

for (i=0;i<=99;i++)

{

  TIM4-> SR =0x0;

  TIM4->CR1 |= 0x0001;

  //GPIOB->BSRR = GPIO_Pin_9;

  vTaskDelay( 10 / portTICK_RATE_MS ); // Delay 10 ms 

  TIM4->CR1 &= 0x0000;

  TIM4->CNT = 0;

  //GPIOB->BRR = GPIO_Pin_9;//MeasuredDelay = TIM4->CNT;

  vTaskDelay( 1000 / portTICK_RATE_MS ); // Delay 10 ms 

}

with this configuration and referring to clock tree in the datasheet of STM32 (pescalar = 16 = 15+1 and F= 72Mhz), the CNT register contains (+/-) AFC8 = 45000 (10), how can i convert it to display on LCD 10 ms or 10000 µs (in linear formula 

proportionately 

to CNT register and prescalar?)

regards,

Slim

slimbahri
Associate II
Posted on May 17, 2011 at 13:43

I have implemented this source code to benchmark the jitter of 10 ms delay:

/* clcok config: HCLK = SYSCLK  */

RCC_HCLKConfig(RCC_SYSCLK_Div1);

/* clcok config: PCLK1 = HCLK/2  */

RCC_PCLK1Config(RCC_HCLK_Div2);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);

/* TIM4config */

/* Initialise data. */

TIM_DeInit( TIM4 );

TIM_TimeBaseStructure.TIM_Period = 0xffff;

TIM_TimeBaseStructure.TIM_Prescaler = 15;/*  

 Prescalar 16 = 15+1  */

TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure );

//TIM_ARRPreloadConfig( TIM4, ENABLE);

        TIM4->EGR |= 0x01;

for (i=0;i<=99;i++)

{

  TIM4-> SR =0x0;

  TIM4->CR1 |= 0x0001;

  //GPIOB->BSRR = GPIO_Pin_9;

  vTaskDelay( 10 / portTICK_RATE_MS ); // Delay 10 ms 

  TIM4->CR1 &= 0x0000;

  TIM4->CNT = 0;

  

}

with this configuration and referring to clock tree in the datasheet of STM32 (pescalar = 16 = 15+1 and F= 72Mhz), the CNT register contains (+/-) AFC8 = 45000 (10), how can i convert it to display on LCD 10 ms or 10000 µs (in linear formula 

proportionately 

to CNT register and prescalar?)

whereas, I have done this operations manually to know the granularity of the timer value to display after:  

Using 72 Mhz on STM32  ---> T= 1.38 e(-8) 

TIMx ->CNT :  0xFFFF---> 65535 

65535 * 1.38 e(-8) = 0. 91 ms 

CNT:  0xFFFF---> 65535 ---> 0.91 ms Prescalar  0

   

   1.82 ms Prescalar  2                            

                            ....

                            7.28 ms Prescalar  8

      14.56 ms Prascalar  16

                           

7.28 <10 ms< 14.28    Prescalar 16 = 15+1

How to display this please (with a generic formula)?

Reagards, 

Slim