17

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

Anton Krug
  • 1,555
  • 2
  • 19
  • 32
KenQueso
  • 191
  • 1
  • 1
  • 6
  • " 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.) – too honest for this site Apr 02 '16 at 20:34
  • 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. – KenQueso Apr 02 '16 at 20:39
  • Should work according to [this](http://stackoverflow.com/questions/13379220/generating-nanosecond-delay-in-c-on-stm32). 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. – user3386109 Apr 02 '16 at 20:41
  • @user3386109: It depends on the debugger. OpenOCD does not use the counter and it works perfectly at least on STM32F4. – too honest for this site Apr 02 '16 at 21:19
  • @Olaf Yup, you're right, I should have said that the debugger ***may*** be using the DWT for its own purposes. – user3386109 Apr 02 '16 at 21:22
  • 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? – KenQueso Apr 02 '16 at 21:30
  • @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. – too honest for this site Apr 02 '16 at 21:32
  • @Olaf that is good to know. With the 32F4 have you ever had an issue with starting the DWT module? – KenQueso Apr 02 '16 at 23:00
  • @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. – too honest for this site Apr 02 '16 at 23:16
  • 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. – too honest for this site Apr 02 '16 at 23:30

5 Answers5

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;
  • Any idea where is the documentation to explain this magic access word: `DWT->LAR = 0xC5ACCE55`? – Gabriel Staples Nov 28 '18 at 22:19
  • @GabrielStaples See [ARMv7-M Architecture Reference Manual](https://developer.arm.com/documentation/ddi0403/latest/) 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](https://developer.arm.com/documentation/ihi0029/e/), in section B2.3.10 there is a description of LSR and LAR registers, along with the key. – Enbyted Nov 20 '20 at 13:52
7

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.

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
  • 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? – KenQueso Apr 03 '16 at 15:39
  • 1
    @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 [mcve]. – too honest for this site Apr 03 '16 at 15:43
  • 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 on – KenQueso Apr 03 '16 at 16:06
  • Please see [ask]. You are supposed to post text as text, neither as external links, nor images! – too honest for this site Apr 03 '16 at 16:09
  • 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. – KenQueso Apr 03 '16 at 16:24
  • 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. – too honest for this site Apr 03 '16 at 16:33
  • 4
    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. – KenQueso Apr 03 '16 at 16:35
5

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

Community
  • 1
  • 1
paolok17
  • 51
  • 1
  • 1
0

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

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
sɐunıɔןɐqɐp
  • 3,332
  • 15
  • 36
  • 40