在Cortex M7上测量时钟周期计数

10
我一直在测量Cortex M4的时钟周期计数,现在想在Cortex M7上执行相同的操作。 我使用的开发板是STM32F746ZG。
对于M4,可以使用以下内容:
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;
}

问题在于当我在m7上运行时,DWT_CTRL寄存器没有改变,仍然是0x40000000,而不是改变为0x40000001,因此循环计数始终为零。根据我在其他帖子中阅读的内容,似乎需要设置FP_LAR寄存器为0xC5ACCE55才能更改DWT_CTRL。
我添加了以下定义(尝试过以下两个FP_LAR_PTR地址):
#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

还有这个函数:

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

当我调用未注释的打印语句时,我得到了0xC5ACCE55,但当我在函数返回后打印它时,我得到了0x00000000,我不知道为什么。我是在正确的轨道上还是完全错误了?
编辑:我认为也应该提到,我已经尝试过在函数中去掉所有额外的代码,只尝试更改LAR寄存器。
敬礼, Gustav

1
根据Cortex-M7 TRM,DWT_LAR是一个只写寄存器。 - Notlikethat
到目前为止,当我读取0xE0001000时,我得到了0x00000000,但是当我读取0xE00FF004时,我确实得到了0xFFF02003。 - old_timer
表11-1显示了DWT寄存器。根据处理器的实现,其中一些寄存器可能不存在。任何配置为不存在的寄存器都将读取为零。 - old_timer
尝试在DWT控制寄存器中设置低位(包括周期计数启用位),但读回时为零。那么它真的写入了DWT控制寄存器吗? - old_timer
不,它并不会,这就是我试图描述的问题的影响。我需要能够改变DWT_CTRL中的位0。我将尝试下面Notlikethat的回答,然后再汇报结果 :) - G. Johnsson
显示剩余8条评论
2个回答

6
重新查看文档后,我非常怀疑ARM TRM中存在拼写错误或复制粘贴错误。ITM_LAR、DWT_LAR和FP_LSR(以及*_LSR的等效物)的地址都给出为0xe0000fb0。由于所有其他ITM寄存器都在页面0xe0000000中,这看起来非常像负责Cortex-M7文档的人员采用了Cortex-M4寄存器定义,将新的LAR和LSR添加到ITM页面,然后将它们复制到DWT和FPB页面并更新名称,但忽略了更新地址。
我敢打赌你无意中解锁了ITM_LAR(或真正的FP_LAR),而DWT_LAR实际上位于0xe0001fb0。
dwelch进行了编辑。
有人欠有人一顿晚餐。
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));

输出

00000000
00000000
00000000
00000000
00000003
40000000
00000000
00000000
00000003
40000000
00000000
00000000
00000001
40000001
0000774F
0000B311
TRM (Technical Reference Manual)中的表格看起来很奇怪,而其他文档显示您需要将0xFB0和0xFB4添加到基础地址上,对于Cortex-M7的其余DWT,其地址为0xE0001xxx,看起来LAR和LSR确实位于0xE0001FB0和0xE0001FB4。

好的,星期一我回来后一定会尝试,并且再与您联系。我还在其他地方看到过一个错误的参考,但他建议使用0xe0002fb0,不过我尝试了并没有成功。 - G. Johnsson
是的,e0002fb0看起来是FPB单元对应的锁定。正如我所暗示的那样。似乎中间的那个人是唯一一个没有被任何人尝试过的人。 - Notlikethat
是的,我想我应该将代码中的FP_LAR_PTR更改为DWT_LAR_PTR,在研究时我有些困惑 :) - G. Johnsson
@Notlikethat 我修改了你的答案,而不是添加我的答案。这是你的发现,我只是在比原帖作者早几天进行了实验。请根据您自己的喜好重新编辑(或完全删除我的修改,随便你)。 - old_timer
0xe0001fb0 对我也起作用了!现在唯一的问题是它实际上显示了比M4更多的时钟周期执行DFT和FFT操作,但那是另一个问题 :) - G. Johnsson

4
我建议不要在CMSIS已定义的寄存器定义上创建自己的寄存器定义 - 这样需要确保文档和您的解释都正确。 在这种情况下,似乎文档确实不正确,但是CMSIS标头是正确的。 验证CMSIS标头的正确性比验证文档正确性要容易得多,因此我每次都会信任CMSIS。
我不确定寄存器FP_LAR可能指的是什么,但是您的地址分配引用了ITM_LAR,但更可能的是您想使用Cortex-M4缺少的DWT_LAR。
尽管我建议信任它,但是CMSIS 4.00省略了DWT_LSR / SWT_LAR的掩码定义,但我认为它们与相应的ITM掩码相同。
还要注意,LAR是一个只写寄存器 - 任何尝试读取它的操作都没有意义。
使用CMSIS的代码如下:
#include "core_cm7.h"  // Applies to all Cortex-M7

void reset_cnt()
{
    CoreDebug->DEMCR |= 0x01000000;
    DWT->CYCCNT = 0; // reset the counter
    DWT->CTRL = 0; 
}

void start_cnt()
{
    DWT->CTRL |= 0x00000001 ; // enable the counter
}

void stop_cnt()
{
     DWT->CTRL &= 0xFFFFFFFE ; // disable the counter    
}

unsigned int getCycles()
{
    return DWT->CYCCNT ;
}

// Not defined in CMSIS 4.00 headers - check if defined
// to allow for possible correction in later versions
#if !defined DWT_LSR_Present_Msk 
    #define DWT_LSR_Present_Msk ITM_LSR_Present_Msk
#endif
#if !defined DWT_LSR_Access_Msk 
    #define DWT_LSR_Access_Msk ITM_LSR_Access_Msk
#endif
#define DWT_LAR_KEY 0xC5ACCE55

void dwt_access_enable( unsigned ena )
{
    uint32_t lsr = DWT->LSR;;

    if( (lsr & DWT_LSR_Present_Msk) != 0 ) 
    {
        if( ena ) 
        {
            if ((lsr & DWT_LSR_Access_Msk) != 0) //locked: access need unlock
            {    
                DWT->LAR = DWT_LAR_KEY;
            }
        } 
        else 
        {
            if ((lsr & DWT_LSR_Access_Msk) == 0) //unlocked
            {   
                DWT->LAR = 0;
            }
        }
    }
}

你假设CMSIS是正确的,这和假设文档是正确的一样好/坏。有人使用某些资源编写了CMSIS头文件。对于公司来说,明智的做法是拥有一个信息数据库,并从中生成文档地址和头文件。我敢打赌这是例外而不是规则。CMSIS有它自己的包袱,也许在怀疑时可以从中复制粘贴,但不要认为它比文档更正确。 - old_timer
同样,如果没有人阅读文档,那么文档该如何修复?我已经向 ARM 提交了一张工单,看看会有什么结果,但至少有人已经被通知了。 - old_timer
@dwelch:我并不是假设什么;我只是说CMSIS可以通过自动化单元测试和验证来进行修改,而文档则不能。即使CMSIS与文档相匹配,它也不会比用户从文档中实现的代码更糟糕 - 为什么要重新发明轮子呢?此外,core_cmX对整个CMSIS至关重要,并被数千个项目使用 - 许多开发人员可能没有阅读文档到那个细节级别。在CMSIS和DWT_LAR/LSR与文档(和ITM)不同的情况下,这更有可能。 - Clifford
@dwelch:你仍然需要阅读文档才能知道寄存器的作用和工作原理,CMSIS不会告诉你这些。在这种情况下,使用CMSIS肯定可以避免问题。如果我使用CMSIS并发现问题,我会以相同的方式(反向)交叉检查文档,但从CMSIS开始会更省力。 - Clifford
@Clifford,FWIW,FP_LAR是CoreSight LAR的一部分,用于Flash Patch/Breakpoint Unit(实际上并不支持它主要命名的那个东西,很奇怪...) - Notlikethat
@Notlikethat: 哦!FP = FlashPatch(不是浮点数)。但在这种情况下,似乎更有可能是 DWT_LAR/LSR。FP_LAR/LSR 的文档也不正确。 FPB 在 CMSIS core_cm7.h 中未定义 - 我希望它对调试器更有用,而不是直接从代码进行访问 - 而且它并非在所有 CM7 设备上都实现。 - Clifford

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接