Search code examples
carmembeddedstm32f7

Measuring clock cycle count on cortex m7


I have been measuring clock cycle count on the cortex m4 and would now like to do it on the cortex m7. The board I use is STM32F746ZG.

For the m4 everything worked with:

volatile unsigned int *DWT_CYCCNT;
volatile unsigned int *DWT_CONTROL;
volatile unsigned int *SCB_DEMCR;

void reset_cnt(){
    DWT_CYCCNT   = (volatile unsigned int *)0xE0001004; //address of the register
    DWT_CONTROL  = (volatile unsigned int *)0xE0001000; //address of the register
    SCB_DEMCR    = (volatile unsigned int *)0xE000EDFC; //address of the register
    *SCB_DEMCR   = *SCB_DEMCR | 0x01000000;
    *DWT_CYCCNT  = 0; // reset the counter
    *DWT_CONTROL = 0; 
}

void start_cnt(){
    *DWT_CONTROL = *DWT_CONTROL | 0x00000001 ; // enable the counter
}

void stop_cnt(){
     *DWT_CONTROL = *DWT_CONTROL & 0xFFFFFFFE ; // disable the counter    
}

unsigned int getCycles(){
    return *DWT_CYCCNT;
}

The problem is that the DWT_CTRL register isn't changed when I run on the m7 and remains 0x40000000 instead of changing to 0x40000001 so the cycle count is always zero. From what I have read in other posts it seems like you need to set the FP_LAR register to 0xC5ACCE55 to be able to change DWT_CTRL.

I added these defines (have tried both FP_LAR_PTR addresses below):

#define FP_LAR_PTR ((volatile unsigned int *) 0xe0000fb0) //according to reference
//#define FP_LAR_PTR ((volatile unsigned int *) 0xe0002fb0) //according to guy on the internet
// Lock Status Register lock status bit
#define DWT_LSR_SLK_Pos                1
#define DWT_LSR_SLK_Msk                (1UL << DWT_LSR_SLK_Pos)
// Lock Status Register lock availability bit
#define DWT_LSR_SLI_Pos                0
#define DWT_LSR_SLI_Msk                (1UL << DWT_LSR_SLI_Pos)
// Lock Access key, common for all
#define DWT_LAR_KEY                    0xC5ACCE55

and this function:

void dwt_access_enable(unsigned int ena){
    volatile unsigned int *LSR;
    LSR = (volatile unsigned int *) 0xe0000fb4;
    uint32_t lsr = *LSR;;
    //printf("LSR: %.8X - SLI MASK: %.8X\n", lsr, DWT_LSR_SLI_Msk);

    if ((lsr & DWT_LSR_SLI_Msk) != 0) {
        if (ena) {
            //printf("LSR: %.8X - SLKMASK: %.8X\n", lsr, DWT_LSR_SLK_Msk);
            if ((lsr & DWT_LSR_SLK_Msk) != 0) {    //locked: access need unlock
                *FP_LAR_PTR = DWT_LAR_KEY;
                printf("FP_LAR directly after change: 0x%.8X\n", *FP_LAR_PTR);
            }
        } else {
            if ((lsr & DWT_LSR_SLK_Msk) == 0) {   //unlocked
                *FP_LAR_PTR = 0;
                 //printf("FP_LAR directly after change: 0x%.8X\n", *FP_LAR_PTR);
            }
        }
    }
}

When I call the uncommented print I get 0xC5ACCE55 but when I printed it after the return of the function I get 0x00000000 and I have no idea why. Am I on the right track or is this completely wrong?

Edit: I think it also would be good to mention that I have tried without all the extra code in the function and only tried to change the LAR register.

BR Gustav


Solution

  • Looking at the docs again, I'm now incredibly suspicious of a typo or copy-paste error in the ARM TRM. 0xe0000fb0 is given as the address of ITM_LAR, DWT_LAR and FP_LSR (and equivalently for *_LSR). Since all the other ITM registers are in page 0xe0000000, it looks an awful lot like whoever was responsible for that part of the Cortex-M7 documentation took the Cortex-M4 register definitions, added the new LAR and LSR to the ITM page, then copied them to the DWT and FPB pages updating the names but overlooking to update the addresses.

    I'd bet my dinner that you're unwittingly unlocking ITM_LAR (or the real FP_LAR), and DWT_LAR is actually at 0xe0001fb0.

    EDIT by dwelch

    Somebody owes somebody a dinner.

    hexstring(GET32(0xE0001FB4));
    hexstring(GET32(0xE0001000));
    hexstring(GET32(0xE0001004));
    hexstring(GET32(0xE0001004));
    
    PUT32(0xE000EDFC,0x01000000);
    
    hexstring(GET32(0xE0001FB4));
    hexstring(GET32(0xE0001000));
    hexstring(GET32(0xE0001004));
    hexstring(GET32(0xE0001004));
    
    PUT32(0xE0001000,0x40000001);
    
    hexstring(GET32(0xE0001FB4));
    hexstring(GET32(0xE0001000));
    hexstring(GET32(0xE0001004));
    hexstring(GET32(0xE0001004));
    
    PUT32(0xE0001FB0,0xC5ACCE55);
    PUT32(0xE0001000,0x40000001);
    
    hexstring(GET32(0xE0001FB4));
    hexstring(GET32(0xE0001000));
    hexstring(GET32(0xE0001004));
    hexstring(GET32(0xE0001004));
    

    output

    00000000
    00000000
    00000000
    00000000
    00000003
    40000000
    00000000
    00000000
    00000003
    40000000
    00000000
    00000000
    00000001
    40000001
    0000774F
    0000B311
    

    The table in the TRM is funny looking and as the other documentation shows you add the 0xFB0 and 0xFB4 to the base, the rest of the DWT for the Cortex-M7 is 0xE0001xxx and indeed it appears that the LAR and LSR are ate 0xE0001FB0 and 0xE0001FB4.