[英]Peripheral read vs RAM read + RAM write
我正在使用 IOs 調試關鍵代碼,我遇到了一個難題:
這兩個功能之間最快的是什么?
我的 CPU 在哪個 function 花費的時間會更少?
A:CPU讀取一個外設寄存器,寫入外設寄存器
void d_toggle_pin(void)
{
NRF_P1->OUT ^= 1 << Debug_Pin;
}
B:CPU讀一個RAM變量並寫外設寄存器+寫一個RAM變量
void d_toggle_pin(void)
{
static byte pin_state = 0;
if(pin_state)
{
NRF_P1->OUTCLR = 1U << Debug_Pin;
pin_state = 0;
}
else
{
NRF_P1->OUTSET = 1U << Debug_Pin;
pin_state = 1;
}
}
我正在使用 nrf52840(皮質 M4 CPU),但無論實現如何,答案都是一樣的
TL;DR:第一個版本表現更好。
性能方面的差異是微不足道的。 Cortex M3 及更高版本具有簡單的分支預測和流水線,但這不會對這里的這個簡單的小代碼產生太大影響。 當然,第二個版本在分支預測器上可能會稍微粗糙一些,因為它們是兩個獨立的內存映射寄存器,但差異可以忽略不計。
如果您堅持要比較它們,那么這里有一個 gcc ARM non-eabi -O3
的小基准,我在其中替換了寄存器名稱並將“調試引腳”設為硬編碼常量: https://godbolt.org/z/88vn1EqKj 。 該分支已被優化掉,但第一個版本的性能仍然稍好一些。
然而,您在這里的首要任務應該是功能性和可讀性。 這兩個函數都可以,但如果我要剖析它們......
XOR 版本的優點是 XOR 是一種切換位的慣用方式,因此它是可讀的。 您還可以保證代碼始終與實際寄存器值同步,以防萬一。
XOR 版本的缺點是,對硬件寄存器進行讀-修改-寫訪問有時會出現問題,因為它會引入副作用,並且在某些情況下還會導致重入問題。 因此,與其將寄存器值用作 XOR 的占位符,我認為您的其他版本單獨跟蹤端口並僅執行寫訪問就可以了。
其他注意事項:
1 <<...
在 C 中總是錯誤的。您幾乎可以肯定永遠不要移動 signed int
,它是 integer 常量1
的類型。 例如1 << 31
調用未定義的行為。 始終使用1u
。
為諸如設置/清除/切換 GPIO 引腳之類的非常基本的事情編寫包裝函數已經完成了數百次……並且沒有人設法編寫比這更容易閱讀的 function 包裝函數:
reg |= mask
(設置)reg &= ~mask
(清除)reg ^= mask;
(切換)這是慣用的、超快的、超可讀的 C 代碼,所有 C 程序員 100% 都可以輕松理解。 在查看了數百個失敗的、臃腫的 GPIO HAL 之后,我可以自信地說簡單 GPIO 的抽象可以而且只會導致臃腫。 我自己寫了很多這樣的東西,但總是出錯。
(對於帶有一堆路由寄存器、中斷處理、奇怪的狀態標志等的更復雜的 GPIO,那么一定要編寫一個 HAL 和一個驅動程序。但不是為了只做簡單的端口 I/O。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.