0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

测量ARM Cortex-M MCU上的代码执行时间

星星科技指导员 来源:嵌入式计算设计 作者:Jean Labrosse 2022-06-08 16:50 次阅读

在许多实时应用程序中,CPU 可以在不到 5% 的代码中花费 95%(或更多)的时间。电机控制、发动机控制、无线通信和许多其他对时间敏感的应用就是这种情况。这些嵌入式系统通常是用 C 语言编写的,并且开发人员经常被迫手动优化代码,可能会恢复为汇编语言,以满足紧迫的期限。测量部分代码的实际执行时间可以帮助您找到代码中的热点。本文将展示如何轻松测量和显示实时基于 Cortex-M 的 MCU 上的代码执行时间。

测量代码的执行时间

有很多方法可以测量代码执行时间。作为一名嵌入式工程师,我经常使用一个或多个数字输出和示波器。您只需在执行要监视的代码之前将其中一个输出设置为高电平,然后再将输出设置为低电平。当然,在您执行此操作之前还有相当多的设置工作:找到一个或多个空闲输出,确保它们易于探测,将端口配置为输出,编写代码,编译,设置范围等等。 收到信号后,您可能需要对其进行一段时间的监控以查看最小值和最大值。数字存储示波器使这个过程更容易,但还有其他方法比这更容易。

测量执行时间的另一种方法是使用具有跟踪功能的调试探针。您只需运行代码、查看跟踪、计算增量时间(通常是手动)并将 CPU 周期转换为微秒。不幸的是,跟踪为您提供了一个执行实例,您可能需要进一步查看跟踪捕获以找到最坏情况下的执行时间。这可能是一个乏味的过程。

Cortex-M 周期计数器

大多数基于 Cortex-M 的处理器上的 CoreSight 调试端口都包含一个 32 位自由运行计数器,用于计算 CPU 时钟周期。该计数器是调试监视和跟踪 (DWT) 模块的一部分,可轻松用于测量代码的执行时间。以下代码是启用和初始化这个非常有用的功能所需的全部内容。

#define ARM_CM_DEMCR (*(uint32_t *)0xE000EDFC)

#define ARM_CM_DWT_CTRL (*(uint32_t *)0xE0001000)

#define ARM_CM_DWT_CYCCNT (*(uint32_t *)0xE0001004)

if (ARM_CM_DWT_CTRL != 0) { // 看看

DWTDEMCR是否可用 ARM = 1 《《 24; // 设置位 24

ARM_CM_DWT_CYCCNT = 0;

ARM_CM_DWT_CTRL |= 1 《《 0; // 设置位 0

}

使用 DWT 循环计数器测量代码执行时间

您可以通过读取该段之前和之后的循环计数器的值来测量和计算代码段的执行时间,如下所示。当然,这意味着您必须检测您的代码,但您会得到一个非常准确的值。

uint32_t 开始;

uint32_t 停止;

uint32_t 增量;

开始 = ARM_CM_DWT_CYCCNT;

// 测量

停止的代码 = ARM_CM_DWT_CYCCNT;

delta = 停止 - 开始;

因为我们使用的是无符号数学,所以 delta 表示测量代码的实际执行时间(以 CPU 时钟周期为单位),即即使 stop 小于 start。

当然,在测量开始和停止读数之间括起来的代码的执行时间时可能会发生中断,因此每次执行此序列时很可能会有不同的值。在这种情况下,您可能希望在测量期间禁用中断以删除该伪影,如下所示,但要了解禁用中断是暂时的,并且仅包含在测量中。话虽如此,包含中断的工件可能会很有用,因为它们会影响代码的截止日期。

禁用中断;

开始 = ARM_CM_DWT_CYCCNT;

// 测量

停止的代码 = ARM_CM_DWT_CYCCNT;

启用中断;

delta = 停止 - 开始;

如果被测量的代码包含条件语句、循环或任何可能导致变化的东西,那么获得的值可能不代表最坏情况下的执行时间。要纠正这个问题,您可以简单地添加一个峰值检测器,如下所示。当然,在进行任何测量之前,需要声明 max 并将其初始化为最小值(即 0)。

开始 = ARM_CM_DWT_CYCCNT;

// 测量

停止的代码 = ARM_CM_DWT_CYCCNT;

delta = 停止 - 开始;

if (max 《 delta) {

max = delta;

}

同样,了解最短执行时间也可能很有趣且有用。在进行任何测量之前,只需声明 min 并将其初始化为最大可能值(即 0xFFFFFFFF)。这是新代码:

开始 = ARM_CM_DWT_CYCCNT;

// 测量

停止的代码 = ARM_CM_DWT_CYCCNT;

delta = 停止 - 开始;

if (max 《 delta) {

max = delta;

}

if (min 》 delta) {

min = delta;

}

执行时间还取决于 CPU 是否配备高速缓存,就像某些 Cortex-M4 处理器和 Cortex-M7 一样。如果您的系统使用指令或数据缓存,则同一段代码的多次测量可能会不一致。您可能会考虑禁用缓存以测量最坏的情况。

为了显示这些值,大多数调试器允许您实时显示这些变量值。如果是这种情况,则需要在全局范围内声明显示的变量以保留其值并允许实时监控。此外,不幸的是,这些值代表 CPU 时钟周期,并且大多数调试器都不够复杂,无法缩放变量以用于显示目的。假设 CPU 时钟速度为 16 MHz,显示 70.19 微秒比显示 1123 个周期要方便得多。实际上有一种更好的方法来显示实时变量,它还提供了缩放值的能力,因此您可以以更易读的形式查看它们。我将很快解释如何做到这一点。

经过时间模块

您当然可以将代码片段添加到您的应用程序中,或者您可以使用我编写的一个简单模块(包含在本文中)。与 elapsed_time.h 模块一起出现在下方的“elapsed_time.c”模块仅包含 4 个函数。

要使用:

只需#include

在使用 elapsed_time.c 中定义的其他函数之前调用 elapsed_time_init()。

通过设置 ELAPSED_TIME_MAX_SECTIONS 定义经过时间测量结构的最大数量。这对应于您要使用停止/启动代码包装的不同代码片段的数量。

调用 elapsed_time_start() 并将您要监视的代码片段的索引传递给它(即 0 。. ELAPSED_TIME_MAX_SECTIONS-1)。

调用 elapsed_time_stop() 并将您在 elapsed_time_start() 调用中使用的索引传递给它。

如果您的调试器允许您实时监控变量(即在目标运行时),您可以显示 elapsed_time_tbl[] 并查看您使用的相应索引的 ELAPSED_TIME 结构。

重复执行第 4 步到第 6 步,并让您的代码处于最坏和最好的情况下,以便 ELAPSED_TIME 结构的 .min 和 .max 字段很好地表示您正在测量的代码片段的执行时间。

您会注意到(请参阅 elapsed_time.c)我在测量期间没有禁用中断,因为可能涉及 ISR,您可能想知道这如何影响感知的执行时间。

void main (void)

{

// 一些代码

elapsed_time_init(); // 初始化模块

// 一些代码

}

void MyCode (void)

{

// 这里的一些代码

elapsed_time_start(0); // 开始测量代码片段 #0

// 正在测量的代码

elapsed_time_stop(0); // 停止和

// 一些其他代码

}

当然,最小和最大执行时间取决于您进行测量的频率以及代码是否分别受制于其最佳和最差条件。

elapsed_time_tbl[] 中的字段可以使用 Silicon Labs 的 Micrium uC/Probe 显示。事实上,uC/Probe 可以显示每个字段并缩放每个值,以便可以将 CPU 时钟周期转换为微秒,这更加友好。与大多数 Cortex-M MCU 内置的 CoreSight 调试端口连接时,uC/Probe 不需要对您的代码进行任何检测。

附带说明一下,不需要显示起始字段,因为它仅用于记录测量开始时 DWT 循环计数器的值。但是,开始字段可用于显示活动。换句话说,当您看到此值发生变化时,您就会知道正在进行测量。

使用 uC/Probe 的示例显示

我将 elapsed_time.c 模块与 uC/Probe 结合使用,并测量了四个代码片段的执行时间。

图 1 显示了使用 IAR 的 LiveWatch(左)和 uC/Probe 的 Tree View 控件(右)的原始形式的值。请注意,屏幕截图是在不同时间拍摄的。elapsed_time_tbl[] 是一个数组,用于存储不同代码片段的测量值。

图 1,IAR 和 uC/Probe 的树形视图控件。

您还可以将最小/最大/当前值分配给仪表和数字指示器,如图 2 所示。在这里,这些值以微秒为单位显示,因为我应用了 0.0125 的缩放因子,CPU 以 80 MHz 运行。我还决定只显示最大执行时间。左侧的按钮用于重置统计信息,从而强制重新计算最小值和最大值。

【图2 | 使用 uC/Probe 的仪表之一显示最大执行时间。]

uC/Probe 非常强大的功能之一是能够与 Microsoft 的 Excel 交互,从而在电子表格上显示值(实时),如图 3 所示。

【图3 | 使用 Excel 显示实时数据。]

概括

作为嵌入式开发人员,我们有很多工具可以用来测试和验证我们的设计。我已经演示了使用 Cortex-M 处理器的众多功能之一是多么容易,即 DWT 循环计数器。

Micrium 的 uC/Probe 提供了许多功能,允许您使用仪表、仪表、数字指示器、Excel 界面或图形/绘图来监控应用程序中的许多变量。凭借其内置的示波器功能,一旦满足触发条件,您还可以捕获多达七个附加变量的值。

随意使用或改进 elapsed_time.* 模块。不要犹豫,向我发送反馈。我考虑添加的另一个功能是在最大执行时间超过阈值时调用的回调函数。如果您想在这种情况发生时立即收到通知(打开 LED、发出警报等),这可能很有用。事实上,您甚至可以设置一个断点,以防您想查看是什么条件导致超过阈值。

审核编辑:郭婷

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 处理器
    +关注

    关注

    68

    文章

    19286

    浏览量

    229809
  • led
    led
    +关注

    关注

    242

    文章

    23277

    浏览量

    660844
  • 计数器
    +关注

    关注

    32

    文章

    2256

    浏览量

    94561
收藏 人收藏

    评论

    相关推荐

    如何使用Ozone分析Cortex-M异常

    Ozone可以帮助用户快速分析和查找导致CPU故障的软件bug。本文解释如何使用Ozone的调试功能,深入了解Cortex-M架构的这些错误。
    的头像 发表于 11-29 11:14 713次阅读
    如何使用Ozone分析<b class='flag-5'>Cortex-M</b>异常

    MAX32675C超低功耗Arm® Cortex®-M4F MCU

    检测(SEC-DED),确保为要求苛刻的应用提供超可靠的代码执行。 *附件:MAX32675C超低功耗Arm® Cortex®-M4F
    的头像 发表于 11-28 11:50 383次阅读
    MAX32675C超低功耗<b class='flag-5'>Arm</b>® <b class='flag-5'>Cortex</b>®-<b class='flag-5'>M</b>4F <b class='flag-5'>MCU</b>

    【RA-Eco-RA2E1-48PIN-V1.0开发板试用】原创测量代码行时间

    应用在所有Cortex-M处理器,不限内核版本。 加入keil工程 添加文件目录 在hal_entry()里面添加如下函数代码 while里面实现流水灯,同时测量流水灯
    发表于 11-06 15:32

    深度探讨:无人机干扰器干扰执行时间的关键影响因素

    随着无人机技术的广泛应用,无人机干扰器作为防御和管控无人机的重要工具,其在军事、民用及公共安全等领域发挥着重要作用。然而,无人机干扰器的干扰执行时间直接决定了其有效性和实用性。本文将深入探讨无人机干扰器干扰执行时间的影响因素,并对这些因素进行详细解析。
    的头像 发表于 05-29 09:27 545次阅读

    请问stm32cubeIDE仿真怎么看程序执行时间

    就想keil仿真那样,可以时刻监视程序执行时间,cubeide怎么在仿真debug时,监视程序时间呢?
    发表于 04-02 07:47

    Cortex-M85内核单片机如何快速上手

    2022年4月,Arm推出了全新的MCU级内核Cortex-M85。截止目前(2024年2月),Cortex-M85是最新、最强的Cortex-M
    发表于 02-29 09:35 745次阅读
    <b class='flag-5'>Cortex-M</b>85内核单片机如何快速上手

    ARM®Cortex®-M23 32位MCU数据表

    电子发烧友网站提供《ARM®Cortex®-M23 32位MCU数据表.pdf》资料免费下载
    发表于 02-22 14:32 0次下载
    <b class='flag-5'>ARM</b>®<b class='flag-5'>Cortex</b>®-<b class='flag-5'>M</b>23 32位<b class='flag-5'>MCU</b>数据表

    如何计算AURIX微控制器指令执行时间

    对于 AURIX TC38x,在数据表中,最大 CPU 频率为 300MHz,如下所示- 因此,在此频率下,每条指令的执行时间将为:1/300 MHz = 3.33 ns。 这种理解正确吗? 否则,如何计算每条指令的执行时间或 MIPS。 这里的动机是计算特定应用的
    发表于 01-23 08:08

    如何使用STM模块测量函数的执行时间

    我想问你如何使用 STM 模块测量函数的执行时间。 是否有可能通过BSP.H库的now () 函数为两个类型为ifx_tickTimer的变量(分别为起始变量和停止变量分配分笔数)来通过BSP默认
    发表于 01-22 06:38

    基于KEIL软件的C语言编程,如何计算一段程序的执行时间呢?

    如题,一段程序执行时间怎样确定,假如是把每条语句的执行时间累加,那么每条语句的时间如何确定???有别的方法可以确定执行时间
    发表于 01-18 06:10

    Arm®Cortex®-M4 32位MCU GD32F303xx数据手册

    电子发烧友网站提供《Arm®Cortex®-M4 32位MCU GD32F303xx数据手册.pdf》资料免费下载
    发表于 01-14 09:49 8次下载
    <b class='flag-5'>Arm</b>®<b class='flag-5'>Cortex</b>®-<b class='flag-5'>M</b>4 32位<b class='flag-5'>MCU</b> GD32F303xx数据手册

    HOLTEK新推出HT32F67742 Arm® Cortex®-M0+蓝牙5.2低功耗MCU

    Holtek新推出通过BQB(Bluetooth Qualification Body)认证Bluetooth 5.2 Arm Cortex-M0+低功耗蓝牙(Bluetooth Low Energy, BLE) MCU,HT3
    的头像 发表于 01-08 15:23 803次阅读

    GD32H757xx系列Arm Cortex-M7 MCU数据手册

    电子发烧友网站提供《GD32H757xx系列Arm Cortex-M7 MCU数据手册.pdf》资料免费下载
    发表于 01-03 10:47 1次下载
    GD32H757xx系列<b class='flag-5'>Arm</b> <b class='flag-5'>Cortex-M</b>7 <b class='flag-5'>MCU</b>数据手册

    GD32H759xx系列Arm Cortex-M7 MCU数据手册

    电子发烧友网站提供《GD32H759xx系列Arm Cortex-M7 MCU数据手册.pdf》资料免费下载
    发表于 01-03 10:45 6次下载
    GD32H759xx系列<b class='flag-5'>Arm</b> <b class='flag-5'>Cortex-M</b>7 <b class='flag-5'>MCU</b>数据手册

    GD32H737xx系列Arm Cortex-M7 MCU数据手册

    电子发烧友网站提供《GD32H737xx系列Arm Cortex-M7 MCU数据手册.pdf》资料免费下载
    发表于 01-03 10:42 5次下载
    GD32H737xx系列<b class='flag-5'>Arm</b> <b class='flag-5'>Cortex-M</b>7 <b class='flag-5'>MCU</b>数据手册