本帖爲繼續爲大家分享實戰技能。
一、內聯函數Inline function:
內聯函數就是帶inline關鍵字修飾的函數,作用是將函數直接嵌入到調用此函數的代碼中,從而降低調用此函數所佔用的時間。
典型的像CMSIS軟件包,ST的LL庫都開始採用內聯的定義方式,這類函數特點是簡短,適合需要頻繁調用的場景。因爲這樣才能發揮內聯的優勢:
LL庫這裏用的關鍵字是__STATIC_INLINE,這個是ARM的CMSIS軟件包專門做的定義方式,對MDK,IAR和GCC都做了適配,通用。
二、內聯彙編Inline assembler:
內聯彙編可以將彙編程序指令直接插入到 C 或 C++ 函數中。通常,如果需要訪問在 C 中不可訪問的硬件資源或者編寫時間關鍵的代碼序列,使用內聯彙編非常方便。
內聯彙編程序類似 C 函數,也可以有形參和返回值。
這個的典型代表是CMSIS軟件包,由於要訪問一些內核寄存器,所以C裏面嵌入彙編再合適不過了。
cmsis_armcc.h :對應MDK AC5頭文件
cmsis_gcc.h : 對應各種基於GCC的編譯器頭文件
cmsis_clang.h : 對應MDK AC6頭文件
cmsis_iccarm.h : 對應IAR頭文件
比如我們常用的函數__set_MSP設置主堆棧指針,實現如下:
又比如32bit變量賦值的原子操作,由於要用到互斥指令ldrex和strex,通過內聯彙編,就可以方便的在各種編譯器裏實現:
三、內部函數Instruction Intrinsics
使用內聯彙編程序的一個限制是編譯器的各種優化對其可能不起作用,這裏時候就可以考慮改用內部指令。
內部函數看起來像一個普通的函數調用,但它實際上是編譯器識別的內置函數。內部函數編譯爲內聯代碼,作爲單個指令或作爲一小段指令序列,一般用雙下劃線 (__) 標記
針對內部函數,ARM的CMSIS軟件包也是做了一大批,主要分兩類:
1、一類是CPU使用的內部函數,部分截圖:
像NOP空週期指令,用到的地方很多。
需要硬件開平方指令,可以使用__sqrtf,開方操作僅需要12-14個時鐘週期。
需要調節字節順序,可以使用__REV, __REV16, __REVSH, __RBIT,這比我們用C來實現,方便太多了,而且速度快肯定,因爲是直接調用的M內核專用指令
又比如各種RTOS裏面最高優先級任務查找,調用指令CLZ(Count Leading Zeros)可以很快查找當前就緒的最高優先級任務(32個優先級)。
2、另一類是SIMD指令,這個在CMSIS-DSP庫裏面被大量應用,主要使用操作加速,下面是部分截圖:
四、嵌入式彙編:
現在xxxx.S啓動文件和各種RTOS的Port移植,都是採用的彙編文件(或者內聯彙編)實現。像RTOS裏面,做上下文切換得用匯編來做入棧和出棧處理。
不可否認,彙編用的比較溜,相比C有不錯的速度優勢。但是需要較深的彙編編程能力,這個時候可以多積累些好用的彙編代碼。特別是一些算法類的加速和中斷服務程序的快速執行。
比如uCOS做的CRC彙編,在需要軟件CRC場景下,實際測試比市面上的各種C實現CRC加速都要有優勢。
而且做成了C接口形式,大大方便大家使用,部分截圖:
五、總結:
剛開始階段可以先用ARM,各IC廠家和軟件廠商提供的各種玩法,用熟練了,慢慢積累形式自己的風格。
針對這幾種用法,ARM也做過一個簡單對比圖: