Jump to content


Photo

Execution time - the easy way


  • Please log in to reply
6 replies to this topic

#1 Lyon

Lyon

    Level 2

  • Members
  • 193 posts

Posted 31 March 2014 - 08:40 AM

Hi,

Found on web several postings related to some available, but unused hardware on Cortex-Mx processors (unused on some platforms, available on others.

Adapted for TM4C as below:

#include "inc/hw_nvic.h"          /* for definition of NVIC_DBG_INT */ 
#include "inc/hw_memmap.h"        /* for definition of DWT_BASE */
#include "inc/hw_types.h"         /* for definition of HWREG */

#define DWT_O_CYCCNT 0x00000004
static  uint32_t     c_start, c_stop;

// declaration of an initialization function
void  EnableTiming(void);

// definition of that function
/******************************************************************************/
void EnableTiming(void){
   HWREG(NVIC_DBG_INT) |= 0x01000000;      /*enable TRCENA bit in NVIC_DBG_INT*/
   HWREG(DWT_BASE + DWT_O_CYCCNT) = 0;     /* reset the counter */
   HWREG(DWT_BASE) |= 0x01;                /* enable the counter */
   enabled = 1;
}
/******************************************************************************/

 // and then, in the code to be examined write these:
 EnableTiming();
 c_start = HWREG(DWT_BASE + DWT_O_CYCCNT); // at the beginning of the tested code
 // your code follows here
 c_stop = HWREG(DWT_BASE + DWT_O_CYCCNT);  // at the end of the tested code

 // then c_stop - c_start is the execution number of cycles for the code; 
 // just multiply with clock period to find out the execution time of the code.
 // At 80MHz, the 32 bit counter gives you a total time 2^32 x 12.5ns = ~53 seconds!
 
 // Another interesting function is this one 
 /**********************************************************/
 void TimingDelay(unsigned int tick)
 {
   unsigned int start, current;
   start = HWREG(DWT_BASE + DWT_O_CYCCNT);
   do {
	current = HWREG(DWT_BASE + DWT_O_CYCCNT);
   } while((current-start)<tick);
 }
/*********************************************************/

Enjoy!

L


  • bluehash, timotet, pabigot and 3 others like this

#2 pabigot

pabigot

    Level 3

  • Members
  • 503 posts


Posted 08 April 2014 - 05:28 PM

Excellent; thank you. For reference, here's a portable version using CMSIS, checked on Tiva and EFM32 processors. (You will need to include the CMSIS device header, e.g. TIVA.h for TM4C and em_device.h for EFM32. That's hidden in bspacm/core.h below.)

For reference, the necessary information is in the ARMv7-M Architecture Reference Manual; you have to register with ARM to download the PDF. See sections C1.6.5 for DEMCR and C1.8 for DWT.
 
/* BSPACM - demonstrate cycle counter interface
 *
 * Written in 2014 by Peter A. Bigot <http://pabigot.github.io/bspacm/>
 *
 * To the extent possible under law, the author(s) have dedicated all
 * copyright and related and neighboring rights to this software to
 * the public domain worldwide. This software is distributed without
 * any warranty.
 *
 * You should have received a copy of the CC0 Public Domain Dedication
 * along with this software. If not, see
 * <http://creativecommons.org/publicdomain/zero/1.0/>.
 */

#include <bspacm/core.h>
#include <stdio.h>

#define BSPACM_CORE_ENABLE_CYCCNT() do {              \
    if (! (DWT_CTRL_NOCYCCNT_Msk & DWT->CTRL)) {      \
      CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; \
      DWT->CYCCNT = 0;                                \
      DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;            \
    }                                                 \
  } while (0)

#define BSPACM_CORE_DISABLE_CYCCNT() do {              \
    if (! (DWT_CTRL_NOCYCCNT_Msk & DWT->CTRL)) {       \
      DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk;            \
      CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk; \
    }                                                  \
  } while (0)

#define BSPACM_CORE_CYCCNT() DWT->CYCCNT

#define BSPACM_CORE_DELAY_CYCLES(cycles_) do {  \
    uint32_t const delta = (cycles_);           \
    uint32_t const cc0 = DWT->CYCCNT;           \
    while ((DWT->CYCCNT - cc0) < delta) {       \
      /* spin */                                \
    }                                           \
  } while (0)

void main ()
{
  uint32_t cc0 = 0;
  BSPACM_CORE_ENABLE_INTERRUPT();

  printf("\n" __DATE__ " " __TIME__ "\n");
  printf("System clock %lu Hz\n", SystemCoreClock);
  if (DWT_CTRL_NOCYCCNT_Msk & DWT->CTRL) {
    printf("DWT does not support cycle counting\n");
    return;
  }
  BSPACM_CORE_ENABLE_CYCCNT();
  do {
    uint32_t cc1 = DWT->CYCCNT;
    uint32_t delta = cc1 - cc0;
    printf("Cycle counter %lu, delta %lu\n", cc1, delta);
    cc0 = cc1;
    BSPACM_CORE_DELAY_CYCLES(8000000U);
  } while (1);
}

  • bluehash and Lyon like this

#3 bluehash

bluehash

    Site Admin

  • Administrators
  • 6,429 posts

Posted 13 April 2014 - 04:26 PM

Sweetness! Thanks guys.


43oh - MSP430, TivaC, ARM-Sitara and C2000 Discussion, News, Projects and Hacks

 

 


#4 Mr.Cruz

Mr.Cruz

    Newbie

  • Members
  • Pip
  • 0 posts

Posted 30 April 2014 - 04:04 PM

Nice code dump! Just thought I'd add a few notes:

  • In the first implementation, if you make the functions inline, the compiler can optimize out the function jump, and you can get a slightly more accurate time measurement (pushing/popping registers to go to and from functions generally takes around 12 cycles if I recall)
  • CMSIS is interesting, and I have yet to get a chance to play with it. I think the CMSIS example will be more accurate due to the #define macros (no pushing/popping registers from the stack), but some cycles will be lost due to de-referencing. 

Nice code dumps!



#5 pabigot

pabigot

    Level 3

  • Members
  • 503 posts


Posted 30 April 2014 - 06:37 PM

  • CMSIS is interesting, and I have yet to get a chance to play with it. I think the CMSIS example will be more accurate due to the #define macros (no pushing/popping registers from the stack), but some cycles will be lost due to de-referencing. 
FWIW, DWT is a compile-time constant pointer, not a variable, so there's no double-dereference (the CYCCNT value is read directly from its register). This is true of all CMSIS pointers to mapped memory.
  • Mr.Cruz likes this

#6 Mr.Cruz

Mr.Cruz

    Newbie

  • Members
  • Pip
  • 0 posts

Posted 30 April 2014 - 06:43 PM

Ah! Wonderful!

I may look at CMSIS yet!



#7 krishnat

krishnat

    Noob Class

  • Members
  • 9 posts

Posted 06 February 2017 - 06:04 AM

Hi ,

which systemclock should I configure with ADC & timer module ( I am using both module in same code)..??

SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); freq = SysCtlClockGet(); // 80MHz
SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); freq = SysCtlClockGet(); // 50MHz
SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ); freq = SysCtlClockGet(); // 40MHz

If I dont write any of above, I get :: freq = SysCtlClockGet(); // 16MHz

My requirement is lowest execution time.
Should I configure to 80MHz..?? 

If I do so will both ADC and Timers will work fine..??
Is any extra configuration needed...?



Regards,
Krishnat






0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users