在許多實(shí)時(shí)應(yīng)用程序中,CPU 可以在不到 5% 的代碼中花費(fèi) 95%(或更多)的時(shí)間。電機(jī)控制、發(fā)動(dòng)機(jī)控制、無線通信和許多其他對(duì)時(shí)間敏感的應(yīng)用就是這種情況。這些嵌入式系統(tǒng)通常是用 C 語言編寫的,并且開發(fā)人員經(jīng)常被迫手動(dòng)優(yōu)化代碼,可能會(huì)恢復(fù)為匯編語言,以滿足緊迫的期限。測量部分代碼的實(shí)際執(zhí)行時(shí)間可以幫助您找到代碼中的熱點(diǎn)。本文將展示如何輕松測量和顯示實(shí)時(shí)基于 Cortex-M 的 MCU 上的代碼執(zhí)行時(shí)間。
測量代碼的執(zhí)行時(shí)間
有很多方法可以測量代碼執(zhí)行時(shí)間。作為一名嵌入式工程師,我經(jīng)常使用一個(gè)或多個(gè)數(shù)字輸出和示波器。您只需在執(zhí)行要監(jiān)視的代碼之前將其中一個(gè)輸出設(shè)置為高電平,然后再將輸出設(shè)置為低電平。當(dāng)然,在您執(zhí)行此操作之前還有相當(dāng)多的設(shè)置工作:找到一個(gè)或多個(gè)空閑輸出,確保它們易于探測,將端口配置為輸出,編寫代碼,編譯,設(shè)置范圍等等。 收到信號(hào)后,您可能需要對(duì)其進(jìn)行一段時(shí)間的監(jiān)控以查看最小值和最大值。數(shù)字存儲(chǔ)示波器使這個(gè)過程更容易,但還有其他方法比這更容易。
測量執(zhí)行時(shí)間的另一種方法是使用具有跟蹤功能的調(diào)試探針。您只需運(yùn)行代碼、查看跟蹤、計(jì)算增量時(shí)間(通常是手動(dòng))并將 CPU 周期轉(zhuǎn)換為微秒。不幸的是,跟蹤為您提供了一個(gè)執(zhí)行實(shí)例,您可能需要進(jìn)一步查看跟蹤捕獲以找到最壞情況下的執(zhí)行時(shí)間。這可能是一個(gè)乏味的過程。
Cortex-M 周期計(jì)數(shù)器
大多數(shù)基于 Cortex-M 的處理器上的 CoreSight 調(diào)試端口都包含一個(gè) 32 位自由運(yùn)行計(jì)數(shù)器,用于計(jì)算 CPU 時(shí)鐘周期。該計(jì)數(shù)器是調(diào)試監(jiān)視和跟蹤 (DWT) 模塊的一部分,可輕松用于測量代碼的執(zhí)行時(shí)間。以下代碼是啟用和初始化這個(gè)非常有用的功能所需的全部內(nèi)容。
#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; // 設(shè)置位 24
ARM_CM_DWT_CYCCNT = 0;
ARM_CM_DWT_CTRL |= 1 《《 0; // 設(shè)置位 0
}
使用 DWT 循環(huán)計(jì)數(shù)器測量代碼執(zhí)行時(shí)間
您可以通過讀取該段之前和之后的循環(huán)計(jì)數(shù)器的值來測量和計(jì)算代碼段的執(zhí)行時(shí)間,如下所示。當(dāng)然,這意味著您必須檢測您的代碼,但您會(huì)得到一個(gè)非常準(zhǔn)確的值。
uint32_t 開始;
uint32_t 停止;
uint32_t 增量;
開始 = ARM_CM_DWT_CYCCNT;
// 測量
停止的代碼 = ARM_CM_DWT_CYCCNT;
delta = 停止 - 開始;
因?yàn)槲覀兪褂玫氖菬o符號(hào)數(shù)學(xué),所以 delta 表示測量代碼的實(shí)際執(zhí)行時(shí)間(以 CPU 時(shí)鐘周期為單位),即即使 stop 小于 start。
當(dāng)然,在測量開始和停止讀數(shù)之間括起來的代碼的執(zhí)行時(shí)間時(shí)可能會(huì)發(fā)生中斷,因此每次執(zhí)行此序列時(shí)很可能會(huì)有不同的值。在這種情況下,您可能希望在測量期間禁用中斷以刪除該偽影,如下所示,但要了解禁用中斷是暫時(shí)的,并且僅包含在測量中。話雖如此,包含中斷的工件可能會(huì)很有用,因?yàn)樗鼈儠?huì)影響代碼的截止日期。
禁用中斷;
開始 = ARM_CM_DWT_CYCCNT;
// 測量
停止的代碼 = ARM_CM_DWT_CYCCNT;
啟用中斷;
delta = 停止 - 開始;
如果被測量的代碼包含條件語句、循環(huán)或任何可能導(dǎo)致變化的東西,那么獲得的值可能不代表最壞情況下的執(zhí)行時(shí)間。要糾正這個(gè)問題,您可以簡單地添加一個(gè)峰值檢測器,如下所示。當(dāng)然,在進(jìn)行任何測量之前,需要聲明 max 并將其初始化為最小值(即 0)。
開始 = ARM_CM_DWT_CYCCNT;
// 測量
停止的代碼 = ARM_CM_DWT_CYCCNT;
delta = 停止 - 開始;
if (max 《 delta) {
max = delta;
}
同樣,了解最短執(zhí)行時(shí)間也可能很有趣且有用。在進(jìn)行任何測量之前,只需聲明 min 并將其初始化為最大可能值(即 0xFFFFFFFF)。這是新代碼:
開始 = ARM_CM_DWT_CYCCNT;
// 測量
停止的代碼 = ARM_CM_DWT_CYCCNT;
delta = 停止 - 開始;
if (max 《 delta) {
max = delta;
}
if (min 》 delta) {
min = delta;
}
執(zhí)行時(shí)間還取決于 CPU 是否配備高速緩存,就像某些 Cortex-M4 處理器和 Cortex-M7 一樣。如果您的系統(tǒng)使用指令或數(shù)據(jù)緩存,則同一段代碼的多次測量可能會(huì)不一致。您可能會(huì)考慮禁用緩存以測量最壞的情況。
為了顯示這些值,大多數(shù)調(diào)試器允許您實(shí)時(shí)顯示這些變量值。如果是這種情況,則需要在全局范圍內(nèi)聲明顯示的變量以保留其值并允許實(shí)時(shí)監(jiān)控。此外,不幸的是,這些值代表 CPU 時(shí)鐘周期,并且大多數(shù)調(diào)試器都不夠復(fù)雜,無法縮放變量以用于顯示目的。假設(shè) CPU 時(shí)鐘速度為 16 MHz,顯示 70.19 微秒比顯示 1123 個(gè)周期要方便得多。實(shí)際上有一種更好的方法來顯示實(shí)時(shí)變量,它還提供了縮放值的能力,因此您可以以更易讀的形式查看它們。我將很快解釋如何做到這一點(diǎn)。
經(jīng)過時(shí)間模塊
您當(dāng)然可以將代碼片段添加到您的應(yīng)用程序中,或者您可以使用我編寫的一個(gè)簡單模塊(包含在本文中)。與 elapsed_time.h 模塊一起出現(xiàn)在下方的“elapsed_time.c”模塊僅包含 4 個(gè)函數(shù)。
要使用:
只需#include
在使用 elapsed_time.c 中定義的其他函數(shù)之前調(diào)用 elapsed_time_init()。
通過設(shè)置 ELAPSED_TIME_MAX_SECTIONS 定義經(jīng)過時(shí)間測量結(jié)構(gòu)的最大數(shù)量。這對(duì)應(yīng)于您要使用停止/啟動(dòng)代碼包裝的不同代碼片段的數(shù)量。
調(diào)用 elapsed_time_start() 并將您要監(jiān)視的代碼片段的索引傳遞給它(即 0 。. ELAPSED_TIME_MAX_SECTIONS-1)。
調(diào)用 elapsed_time_stop() 并將您在 elapsed_time_start() 調(diào)用中使用的索引傳遞給它。
如果您的調(diào)試器允許您實(shí)時(shí)監(jiān)控變量(即在目標(biāo)運(yùn)行時(shí)),您可以顯示 elapsed_time_tbl[] 并查看您使用的相應(yīng)索引的 ELAPSED_TIME 結(jié)構(gòu)。
重復(fù)執(zhí)行第 4 步到第 6 步,并讓您的代碼處于最壞和最好的情況下,以便 ELAPSED_TIME 結(jié)構(gòu)的 .min 和 .max 字段很好地表示您正在測量的代碼片段的執(zhí)行時(shí)間。
您會(huì)注意到(請(qǐng)參閱 elapsed_time.c)我在測量期間沒有禁用中斷,因?yàn)榭赡苌婕?ISR,您可能想知道這如何影響感知的執(zhí)行時(shí)間。
void main (void)
{
// 一些代碼
elapsed_time_init(); // 初始化模塊
// 一些代碼
}
void MyCode (void)
{
// 這里的一些代碼
elapsed_time_start(0); // 開始測量代碼片段 #0
// 正在測量的代碼
elapsed_time_stop(0); // 停止和
// 一些其他代碼
}
當(dāng)然,最小和最大執(zhí)行時(shí)間取決于您進(jìn)行測量的頻率以及代碼是否分別受制于其最佳和最差條件。
elapsed_time_tbl[] 中的字段可以使用 Silicon Labs 的 Micrium uC/Probe 顯示。事實(shí)上,uC/Probe 可以顯示每個(gè)字段并縮放每個(gè)值,以便可以將 CPU 時(shí)鐘周期轉(zhuǎn)換為微秒,這更加友好。與大多數(shù) Cortex-M MCU 內(nèi)置的 CoreSight 調(diào)試端口連接時(shí),uC/Probe 不需要對(duì)您的代碼進(jìn)行任何檢測。
附帶說明一下,不需要顯示起始字段,因?yàn)樗鼉H用于記錄測量開始時(shí) DWT 循環(huán)計(jì)數(shù)器的值。但是,開始字段可用于顯示活動(dòng)。換句話說,當(dāng)您看到此值發(fā)生變化時(shí),您就會(huì)知道正在進(jìn)行測量。
使用 uC/Probe 的示例顯示
我將 elapsed_time.c 模塊與 uC/Probe 結(jié)合使用,并測量了四個(gè)代碼片段的執(zhí)行時(shí)間。
圖 1 顯示了使用 IAR 的 LiveWatch(左)和 uC/Probe 的 Tree View 控件(右)的原始形式的值。請(qǐng)注意,屏幕截圖是在不同時(shí)間拍攝的。elapsed_time_tbl[] 是一個(gè)數(shù)組,用于存儲(chǔ)不同代碼片段的測量值。


圖 1,IAR 和 uC/Probe 的樹形視圖控件。
您還可以將最小/最大/當(dāng)前值分配給儀表和數(shù)字指示器,如圖 2 所示。在這里,這些值以微秒為單位顯示,因?yàn)槲覒?yīng)用了 0.0125 的縮放因子,CPU 以 80 MHz 運(yùn)行。我還決定只顯示最大執(zhí)行時(shí)間。左側(cè)的按鈕用于重置統(tǒng)計(jì)信息,從而強(qiáng)制重新計(jì)算最小值和最大值。

【圖2 | 使用 uC/Probe 的儀表之一顯示最大執(zhí)行時(shí)間。]
uC/Probe 非常強(qiáng)大的功能之一是能夠與 Microsoft 的 Excel 交互,從而在電子表格上顯示值(實(shí)時(shí)),如圖 3 所示。

【圖3 | 使用 Excel 顯示實(shí)時(shí)數(shù)據(jù)。]
概括
作為嵌入式開發(fā)人員,我們有很多工具可以用來測試和驗(yàn)證我們的設(shè)計(jì)。我已經(jīng)演示了使用 Cortex-M 處理器的眾多功能之一是多么容易,即 DWT 循環(huán)計(jì)數(shù)器。
Micrium 的 uC/Probe 提供了許多功能,允許您使用儀表、儀表、數(shù)字指示器、Excel 界面或圖形/繪圖來監(jiān)控應(yīng)用程序中的許多變量。憑借其內(nèi)置的示波器功能,一旦滿足觸發(fā)條件,您還可以捕獲多達(dá)七個(gè)附加變量的值。
隨意使用或改進(jìn) elapsed_time.* 模塊。不要猶豫,向我發(fā)送反饋。我考慮添加的另一個(gè)功能是在最大執(zhí)行時(shí)間超過閾值時(shí)調(diào)用的回調(diào)函數(shù)。如果您想在這種情況發(fā)生時(shí)立即收到通知(打開 LED、發(fā)出警報(bào)等),這可能很有用。事實(shí)上,您甚至可以設(shè)置一個(gè)斷點(diǎn),以防您想查看是什么條件導(dǎo)致超過閾值。
審核編輯:郭婷
-
處理器
+關(guān)注
關(guān)注
68文章
20255瀏覽量
252309 -
led
+關(guān)注
關(guān)注
243文章
24596瀏覽量
690880 -
計(jì)數(shù)器
+關(guān)注
關(guān)注
32文章
2316瀏覽量
98188
發(fā)布評(píng)論請(qǐng)先 登錄
最小化ARM Cortex-M CPU功耗的方法與技巧分享
探索MCXA345/346:混合信號(hào)Arm Cortex - M33 MCU的卓越性能與應(yīng)用潛力
探秘NXP MCXE315/316/317/31B:5V Arm Cortex M7 MCU的卓越性能與應(yīng)用潛力
探秘MCXE315/316/317/31B:5V強(qiáng)勁Arm Cortex M7 MCU的卓越性能
Cortex-M產(chǎn)品的特色
Cortex-M內(nèi)核中的精確延時(shí)的方法
Cortex-M級(jí)別的轉(zhuǎn)換
MSPM0G1507 80MHz Arm? Cortex-M0?+ MCU技術(shù)手冊(cè)
【RA-Eco-RA6M4開發(fā)板評(píng)測】使用ULINK2開發(fā)瑞薩MCU
Analog Devices Inc. MAX32675C超低功耗Arm? Cortex?-M4F MCU數(shù)據(jù)手冊(cè)
PPEC新品發(fā)布丨圖形化編程數(shù)字電源專用 ARM Cortex-M4 MCU
MSPM0G1505 80MHz Arm? Cortex-M0?+ MCU數(shù)據(jù)手冊(cè)
MSPM0G3106 80MHz Arm? Cortex-M0?+ MCU數(shù)據(jù)手冊(cè)
MSPM0C1103 24MHz Arm? Cortex-M0?+ MCU數(shù)據(jù)手冊(cè)
測量ARM Cortex-M MCU上的代碼執(zhí)行時(shí)間
評(píng)論