Particularly useful DWT counter in Cortex-M

Material source: https://blog.csdn.net/booksyhay/article/details/109028712

Finishing: Technology Makes Dreams Greater | Li Xiaoyao

DWT Tracking Component

The Definitive Guide to Cortex-M3:

16.2 TRACE COMPONENTS: DWT

The rest of the DWT counters are typically used for profiling the application codes. They can beprogrammed to emit events (in the form of trace packets) when the counter overflows. One typicalapplication is to use the CYCCNT register to count the number of clock cycles required for a specifictask, for benchmarking purposes.

16.2 Tracking Components: Data Watchpoints and Tracking (DWT)

There are remaining counters in the DWT, which are typically used for "profiling" of program code. They can be programmed to emit an event (in the form of a trace packet) when the counter overflows. Most typically, the CYCCNT register is used to measure the number of cycles it takes to execute a certain task, which can also be used for time-based purposes (it can be used to count CPU usage in the operating system).

DWT in Cortex-M

There is a peripheral in Cortex-M called DWT(Data Watchpoint and Trace), which is used for system debugging and tracking.

It has a 32-bit register called CYCCNT, which is an up counter that records the number of core clocks running. When the core clock jumps, the counter is incremented by 1. The precision is very high. If the core clock is 72M, the precision It is 1/72M = 14ns, and the running time of the program is at the microsecond level, so the accuracy of 14ns is far from enough.

The longest recording time is: 59.65s. The calculation method is 2 to the 32nd power/72000000.

When CYCCNT overflows, it will be cleared to 0 and start counting up again.

Instructions

To implement the delay function, a total of three registers are involved: DEMCR, DWT_CTRL, and DWT_CYCCNT, which are used to enable the DWT function, enable CYCCNT, and obtain the system clock count value.

DEMCR

To enable the DWT peripheral, it needs to be controlled by bit 24 of the other kernel debugging register DEMCR, and write 1 to enable it (mark the key point, take an exam!!). The address of DEMCR is 0xE000 EDFC

About DWT_CYCCNT

Clear 0 before enabling the DWT_CYCCNT register. Let's take a look at the base address of DWT_CYCCNT. From the ARM-Cortex-M manual, we can see that its base address is 0xE000 1004, the reset default value is 0, and its type is readable and writable. We go to the address 0xE000 1004 Writing 0 will clear DWT_CYCCNT to 0.

About CYCCNTENA

CYCCNTENA Enable the CYCCNT counter. If not enabled, the counter does not count and no event is generated for PS sampling or CYCCNTENA. In normal use, the debugger must initialize the CYCCNT counter to 0. It is the first bit of the DWT control register, Write 1 to enable, then enable the CYCCNT counter, otherwise the CYCCNT counter will not work.

[https://developer.arm.com/documentation/ddi0337/e/system-debug/dwt/summary-and-description-of-the-dwt-registers?lang=en]

In summary

CYCCNT steps that want to use DWT:

  1. First enable the DWT peripheral, which is controlled by bit 24 of the other core debug register DEMCR, write 1 to enable
  2. Clear to 0 before enabling the CYCCNT register.
  3. Enable the CYCCNT register, which is controlled by DWT's CYCCNTENA, that is, bit 0 of the DWT control register, and write 1 to enable

Register definition:

//0xE000EDFC DEMCR RW Debug Exception and Monitor Control Register.  
//Enable the function bit of the DWT module
#define DEMCR           ( *(unsigned int *)0xE000EDFC )  
#define TRCENA ( 0x01 << 24) // DWT enable bit of DEMCR  
  
//0xE0001000 DWT_CTRL RW The Debug Watchpoint and Trace (DWT) unit  
//Enable CYCCNT counter to start counting
#define DWT_CTRL        ( *(unsigned int *)0xE0001000 )  
#define CYCCNTENA ( 0x01 << 0 ) // SYCCNT enable bit of DWT
 
//0xE0001004 DWT_CYCCNT RW Cycle Count register,   
//Internal value of CYCCNT counter (32-bit unsigned)
#define DWT_CYCCNT ( *(unsigned int *)0xE0001004) //Display or set the cycle count value of the processor  
copy

Usage example:

vvolatile unsigned int *DWT_CYCCNT  ;
volatile unsigned int *DWT_CONTROL ;
volatile unsigned int *SCB_DEMCR   ;
 
void reset_timer(){
    DWT_CYCCNT   = (int *)0xE0001004; //address of the register
    DWT_CONTROL  = (int *)0xE0001000; //address of the register
    SCB_DEMCR    = (int *)0xE000EDFC; //address of the register
    *SCB_DEMCR   = *SCB_DEMCR | 0x01000000;
    *DWT_CYCCNT  = 0; // reset the counter
    *DWT_CONTROL = 0; 
}
 
void start_timer(){
    *DWT_CONTROL = *DWT_CONTROL | 1 ; // enable the counter
}
 
void stop_timer(){
    *DWT_CONTROL = *DWT_CONTROL | 0 ; // disable the counter    
}
 
unsigned int getCycles(){
    return *DWT_CYCCNT;
}
 
main(){
    ....
    reset_timer(); //reset timer
    start_timer(); //start timer
    //Code to profile
    ...
    myFunction();
    ...
    stop_timer(); //stop timer
    numCycles = getCycles(); //read number of cycles 
    ...
}
copy

Example 2:

#define start_timer()    *((volatile uint32_t*)0xE0001000) = 0x40000001  // Enable CYCCNT register
#define stop_timer()   *((volatile uint32_t*)0xE0001000) = 0x40000000  // Disable CYCCNT register
#define get_timer()   *((volatile uint32_t*)0xE0001004)               // Get value from CYCCNT register
 
/***********
* How to use:
*       uint32_t it1, it2;      // start and stop flag                                            
        start_timer();          // start the timer.
        it1 = get_timer();      // store current cycle-count in a local
        // do something
        it2 = get_timer() - it1;    // Derive the cycle-count difference
        stop_timer();               // If timer is not needed any more, stop
print_int(it2);                 // Display the difference
****/
copy

Example 3:

#define  DWT_CR      *(uint32_t *)0xE0001000
 
#define  DWT_CYCCNT  *(uint32_t *)0xE0001004
 
#define  DEM_CR      *(uint32_t *)0xE000EDFC
 
#define  DEM_CR_TRCENA                  (1 << 24)
 
#define  DWT_CR_CYCCNTENA                (1 <<  0)
 
/* initialization timestamp */
 
void CPU_TS_TmrInit(void)
 
{
 
        /* Enable DWT peripherals */
        DEM_CR |= (uint32_t)DEM_CR_TRCENA;               
 
        /* DWT CYCCNT Register count is cleared to 0 */
        DWT_CYCCNT = (uint32_t)0u;
       
 
        /* Enable Cortex-M3 DWT CYCCNT register */
        DWT_CR |= (uint32_t)DWT_CR_CYCCNTENA;
 
}
 
uint32_t OS_TS_GET(void)
{       
 
        return ((uint32_t)DWT_CYCCNT);
 
}
copy

Copyright statement: This article comes from the Internet, conveying knowledge for free, and the copyright belongs to the original author. If it involves copyright issues, please contact me to delete it.

‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧ END ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

Tags: Cyber Security Single-Chip Microcomputer https

Posted by unknown101 on Thu, 22 Dec 2022 08:48:42 +0530