STM32 - How to enable DWT Cycle counter
Asked Answered
P

6

18

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.

E.G. :

//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: Before

After: After

Purposive answered 2/4, 2016 at 20:22 Comment(10)
" the values are not changed or the operations are skipped" - Why don't you find out before asking? And use the CMSIS headers. Don't define your own registers. Btw. The definitions will generate much more code, as you define the pointers as variables. (Don't even think ybout const qualifier, they will be still variables.)Litho
Well I've stepped through it and the operations look like they are occurring, but the values do not change for any memory location I want to edit. I have tried to find out without much avail so I figured the logical next step was to ask.Purposive
Should work according to this. Note that when you're using the debugger, the debugger will be using the DWT for its own purposes. So you can't really use the debugger with this code.Phreno
@user3386109: It depends on the debugger. OpenOCD does not use the counter and it works perfectly at least on STM32F4.Litho
@Olaf Yup, you're right, I should have said that the debugger may be using the DWT for its own purposes.Phreno
Just double checked, OpenOCD doesn't use it. But even without the debugger, the value is not changing. Any other ideas or things I could try to figure out what is going on?Purposive
@KenQueso: That is not exactly correct. OpenOCD very well does use the DWT module, e.g. for semi-hosting it uses an register to exchange data between host and target. It just does not use the cycle counters.Litho
@Olaf that is good to know. With the 32F4 have you ever had an issue with starting the DWT module?Purposive
@KenQueso: None at all. But I use the CMSIS header. Note your variables might get overridden by wrong code (and as I wrote) they increase code quite a bit.Litho
Ok, I had a look on how I did it in the F4 now. See my answer and please drop a comment at the answer(!) if it works for the F7, too. I'll edit then for other readers.Litho
O
10

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;
Onestep answered 20/5, 2016 at 11:45 Comment(2)
Any idea where is the documentation to explain this magic access word: DWT->LAR = 0xC5ACCE55?Axon
@GabrielStaples See ARMv7-M Architecture Reference Manual in section D1 it tells you that each CoreSight component has these special registers, one of which is a software lock. Then you have to look at ARM CoreSight Architecture Specification, in section B2.3.10 there is a description of LSR and LAR registers, along with the key.Disadvantage
L
9

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.

Litho answered 2/4, 2016 at 23:21 Comment(8)
I tried the above using the predefined definition headers but I still seem to be having the same issue where the values cannot be edited. The CoreDebug->DEMCR won't change either which is very strange. The only other thing I can think of is if FreeRTOS or LwIP use the CMSIS header, but if that was the case wouldn't I see the CYCCNT value increasing as the program ran?Purposive
@KenQueso: This is no reason to downvote my answer! Not sure what you mean with your comment, AFIK the IPs are identical in these aspects. What do you mean with "where the values cannot be edited"? It is completely unclear. And that is not related to FreeRTOS, etc. The headers can be used without any OS, just the proper compiler. Maybe you lack some basics using your toolchain. Provide a minimal reproducible example.Litho
I didn't downvote your answer, I don't even have enough points to vote on questions. Either way, I added a before and after image to the original post to try and clear up what is going onPurposive
Please see How to Ask. You are supposed to post text as text, neither as external links, nor images!Litho
I cleaned up the edit again. The images are watches at different points during runtime. I figured it'd be easier to see that then me typing it out.Purposive
I still don't see a MCVE. I'll leave my answer as-is for now. Get the headers working (still not clear what your comment meant). Sorry, this is no debugging service and I don't have the time to tutor you. RTFineM.Litho
I don't know how I can be more clear. I outlined my problem exactly and said specifically what it is. I'm not asking for a tutor. I am asking what could be cause the behavior I outlined clearly above.Purposive
Upvote for the recommendation to use the HAL headers over hardcoded addresses. Note: I tried this on an STM32F4, and it does not have/need the DWT->LAR as in other answers, just for someone using that processor. And: you might add #include stm32f417xx.h or similar to your code, for those who are not so much experienced.Adal
U
6

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 ;)

Unhandled answered 16/12, 2016 at 16:31 Comment(0)
E
1

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;
Euripus answered 25/3, 2022 at 15:22 Comment(0)
I
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
Inapplicable answered 21/6, 2018 at 6:49 Comment(0)
N
0

STM32H563xx Cortex M33 way (no software locks) using CMSIS:

// DWT and ITM blocks are enabled if TRCENA is 1
SET_BIT(DCB->DEMCR, DCB_DEMCR_TRCENA_Msk);

// Enable cycle counter
SET_BIT(DWT->CTRL, DWT_CTRL_CYCCNTENA_Msk);

ARM documentation --> DWT --> CYCCNT cycle counter and related timers

Nicker answered 26/4, 2024 at 13:41 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.