简体   繁体   中英

STM32 - How to enable DWT Cycle counter

I am using the STM32F7-Discovery board and have been stuck at trying to enable the DWT cycle counter. From what I've seen online this should suffice for enabling it:

CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL  |= 1;

However, whenever I run that code the values are not changed or the operations are skipped (I am not too sure what is happening).

I've tried making pointers to the addresses in memory and altering them directly with no avail either. Ex:

volatile uint32_t *DWT_CONTROL = (uint32_t *) 0xE0001000;
volatile uint32_t *DWT_CYCCNT = (uint32_t *) 0xE0001004;
volatile uint32_t *DEMCR = (uint32_t *) 0xE000EDFC;
*DEMCR = *DEMCR | 0x01000000;
*DWT_CYCCNT  = 0;
*DWT_CONTROL = *DWT_CONTROL | 1;

Currently, the only way I've gotten the is when stepping through with the debugger in Visual Studios (with VisualGDB), if I change the value of DWT->CTRL to the ON value the cycle counter begins. Aside from that though, I cannot seem to get the value to change in code.

Edit: What could be causing the behavior where these lines of code are not performing their tasks but also not crashing and continuing.

CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL  |= 1;

After running these lines of codes, all of the values at those memory locations stay the same and are not altered with the operations that were supposed to be performed.

EG :

//DWT_CTRL_CYCCNTENA_Msk = 1
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk 

Should result in the value of DWT->CTRL being 0x40000001 but it remains at its default value 0x40000000

The pictures below are an example of what is occurring during runtime.

Before : 前

After : 后

Maybe missing to unlock the dbg regs (DWT->LAR = 0xC5ACCE55): Sequence below solved pb for me :

      CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
      DWT->LAR = 0xC5ACCE55; 
      DWT->CYCCNT = 0;
      DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;

Not sure if that is identical on the STM32F7, but this is how to do it correctly using the CMSIS headers on a STM32F4 (should actually work on any Cortex-M3/4(/7?) which provides this module):

CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;

You have to enable the trace module, too. Caution the code is not interrupt-safe! In general, you should leave the counter just free running and take differences of snapshots for timing.

Just make sure your toolchain does not use interfere with your code. OpenOCD/gdb do not, not sure how about tools which provide a manual profiling funtionality.

As I already emphasised in the comments: Don't use some homebrew definitions for registers. ST (and ARM) provide CMSIS headers for the standard peripheral modules (DWT and CoreDebug are actually ARM IPs) which you should use. This includes not using magic numbers , but the defined constants/macros.

More information can be found in the "Architecture Reference Manual". Caution: there is also an "Architecture Application Level Reference Manual", which is not what you want.

You are doing everything right, except you are missing to unlock access to DWT register (as Howard pointed out). In your code it would be something like:

volatile uint32_t *DWT_CONTROL = (uint32_t *) 0xE0001000;
volatile uint32_t *DWT_CYCCNT = (uint32_t *) 0xE0001004;
volatile uint32_t *DEMCR = (uint32_t *) 0xE000EDFC;
volatile uint32_t *LAR  = (uint32_t *) 0xE0001FB0;   // <-- added lock access register

*DEMCR = *DEMCR | 0x01000000;     // enable trace
*LAR = 0xC5ACCE55;                // <-- added unlock access to DWT (ITM, etc.)registers 
*DWT_CYCCNT = 0;                  // clear DWT cycle counter
*DWT_CONTROL = *DWT_CONTROL | 1;  // enable DWT cycle counter

Note that, as stated in ARMv7-M Architecture Reference Manual, lock mechanism only applies to software access. DAP access is always allowed (that's why you could enable cycle counter using the debugger).

Please note that both STM32F7 documentation and ARM documentation have a typo and give 0xE0000FB0 as address of Lock Access register (see here ). Using provided CMSIS core registres definitions (core_cm7.h) would have avoided you this problem since they are correct, and of course would have been more efficient as Olaf stated ;)

I know I am a bit late but if anyone else looks how to properly setup DWT, you can look https://developer.arm.com/documentation/ddi0337/e/ch11s05s01
In my example using the stm32f1, it is sufficient for my needs to setup DWT as

DWT->CTRL = DWT_CTRL_CYCEVTENA_Msk | DWT_CTRL_CYCCNTENA_Msk;
DWT->CYCCNT = 0;

This worked for me:

//address of the register
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 *DWT_LAR      = (volatile unsigned int *)0xE0001FB0;     

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

...

*DWT_LAR = 0xC5ACCE55; // unlock (CM7)
*SCB_DEMCR |= 0x01000000;
*DWT_CYCCNT = 0; // reset the counter
*DWT_CONTROL |= 1 ; // enable the counter

...

x = *DWT_CYCCNT;

... code under test:

y = *DWT_CYCCNT;
x = (y - x); // Elapsed clock ticks, at SystemCoreClock

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM