Table of Contents
1 談談 ARM Cortex-M4F 上的 DSP 功能
1 前言
從 ARM2 在 1986 年問世以來, ARM 的處理器一向以省電性聞名, 之後到了智慧型手持裝置的時代, 省電性更是非常迫切的需求, 到了 2005 年, 有 98% 的手機上面至少有一顆 ARM 的處理器。1 專精於數位訊號處理的工程師, 除了傳統的數位訊號處理器以外, 勢必要了解一下這樣的趨勢, 以及如何在自己的專案中評估使用 ARM 處理器的可能性, 本文將會針對與中低階 DSP 較為類似的 ARM Cortex-M4F 上的 DSP 功能來討論。
2 ARM Cortex-M4F 功能簡介
ARM Cortex-M4F 是 ARM Cortex-M 系列的處理器裡面功能最為強大的一個, 而 Cortex-M 系列的 M 是指 microcontroller, 下表列舉了部分的 Cortex-M 系列處理器的比較, 可以看出 Cortex-M4F 在指令集上有硬體乘法、硬體除法、飽和運算、數位訊號處理延伸指令以及浮點運算。
ARM Cortex-M 系列指令集支援2
ARM Cortex-M | Thumb | Thumb-2 | 硬體乘法器 | 硬體除法器 | 飽和運算 | DSP 延伸功能 | 浮點 | ARM 架構 | 核心架構 |
---|---|---|---|---|---|---|---|---|---|
Cortex-M3 | 完整 | 完整 | 單一時脈 | 有 | 有 | 無 | 無 | ARMv7-M | Harvard |
Cortex-M4 | 完整 | 完整 | 單一時脈 | 有 | 有 | 有 | 選項 | ARMv7E-M | Harvard |
另外, Cortex-M4F 還有以下特點是數位訊號處理器程式設計師會注意的:
- 沒有快取記憶體
- 沒有記憶體管理單元(MMU)
- 記憶體保護單元(MPU) 是選項功能
- 中斷處理延遲最長 12 個時脈
在擁有 DSP 能力的處理器中, 有幾個分類:
- 數位訊號處理器(Digital Signal Processor)
- 數位訊號控制器(Digital Signal Controller)
第一種就是一般印象中的數位訊號處理器, 其特點就是架構完全針對數位訊號處理而優化, 是真正能夠持續的以單一時脈執行乘積累加運算, 亦即乘積累加所需的運算元會在下一個時脈就已經載入並執行運算, 而不用等待運算元從記憶體載入的時間, 發揮極致的運算能力, 但是設計複雜度比較高, 一般來說省電性不如微處理器或微控制器。這種有 TI TMS320C67x 定點與浮點 DSP 系列與很早期的 Motorola(現為 Freescale) DSP56300(這是 Steve Jobs 出走 Apple 時創立的 NeXT 公司在他們的工作站使用的 DSP56001 的下一代產品線, 是特殊的 24-bit DSP)。大部分的 DSP 只支援定點運算, 因為同樣的面積與功耗, 定點運算能夠提供更高的運算能力, 而且以訊號處理的應用而言, 不需要浮點數這麼高的動態範圍。當然, 浮點 DSP 還是有其優勢, 尤其是在一些必須縮短開發時間的應用上, 浮點數能力使得程式設計師不需要耗費太多精神與時間處理定點數運算。
第二種就是把微控制器整合數位訊號處理能力而成, 以傳統的微控制器為主, 擁有豐富的周邊支援與輸出入腳位。ARM Cortex-M4F 屬於這一個分類, 並且因為 ARM 架構被廣泛的支援, 使得 ARM Cortex-M4F 擁有豐富的工具可以應用。以 STMicroelectronics 公司的 STM32F 系列來說, 其 10ku 報價在 2 至 10 美元之間, 往下與 16-bit MCU 重疊, 往上與入門級 DSP 重疊。
3 DSP 運算的核心: 乘積累加(Multiply-and-Accumulate)
我們常常看到支援數位訊號處理能力的處理器都會強調其乘積累加(MAC, or Multiply-and-ACcumulate) 的能力, 這是因為在數位訊號處理演算法上, 大量的使用 MAC 運算。
不管是有限響應濾波器:
\begin{equation} y[n] = \sum_{k=0}^{N-1} h[k]x[n-k] \end{equation}或是無限響應濾波器:
\begin{equation} y[n] = b_0 x[n] + b_1 x[n-1] + b_2 x[n-2] + a_1 y[n-1] + a_2 y[n-2] \end{equation}還是快速傅利葉轉換中很重要的 butterfly 運算:
\begin{eqnarray} Y[k_1] & = & X[k_1] + X[k_2] \\ Y[k_2] & = & (X[k_1] - X[k_2])e^{-j\omega} \end{eqnarray}這些都非常仰賴乘積累加的運算。
ARM Cortex-M4F 與乘法或乘積累加有關的指令集如下表2:
運算 | 指令意義 | 指令列表 |
---|---|---|
16 * 16 = 32 | Signed Multiply (SMUL) | SMULBB, SMULBT, SMULTB, SMULTT |
16 * 16 + 32 = 32 | Signed Multiply and Accumulate (SMLA) | SMLABB, SMLABT, SMLATB, SMLATT |
16 * 16 + 64 = 64 | 16-bit Signed Multiply with 64-bit Accumulate (SMLAL) | SMLALBB, SMLALBT, SMLALTB, SLMALTT |
16 * 32 = 32 | 16-bit by 32-bit signed multiply returning 32 MSB, i.e. word (SMULW) | SMULWB, SMULWT |
(16*32) + 32 = 32 | Q setting 16-bit by 32-bit signed multiply with 32-bit accumulate (SMLAW) | SMLAWB, SMLAWT |
(16*16) + (16*16) = 32 | Q setting sum of dual 16-bit signed multiply (SMU-AD) | SMUAD, SMUADX |
(16*16) - (16*16) = 32 | Dual 16-bit signed multiply returning difference (SMU-SD) | SMUSD, SMUSDX |
(16*16) + (16*16) + 32 = 32 | Q setting dual 16-bit signed multiply with single 32-bit accumulator (SMLAD) | SMLAD, SMLADX |
(16*16) - (16*16) + 32 = 32 | Q setting dual 16-bit signed multiply subtract with 32-bit accumulate (SMLSD) | SMLSD, SMLSDX |
(16*16) + (16*16) + 64 = 64 | Dual 16-bit signed multiply with single 64-bit accumulator (SMLALD) | SMLALD, SMLALDX |
(16*16) - (16*16) + 64 = 64 | Q setting dual 16-bit signed multiply subtract with 64-bit accumulate (SMLSLD) | SMLSLD, SMLSLDX |
32 * 32 = 32 | Multiply | MUL |
32 + (32 * 32) = 32 | Multiply accumulate | MLA |
32 - (32 * 32) = 32 | Multiply subtract | MLS |
32 * 32 = 64 | Long signed/unsigned multiply | SMULL, UMULL |
(32 * 32) + 64 = 64 | Long signed/unsgiend accumulate | SMLAL, UMLAL |
(32 * 32) + 32 + 32 = 64 | 32-bit unsigned multiply with double 32-bit accumulation yielding 64-bit result | UMAAL |
32 + (32 * 32) = 32 MSB | 32-bit multiply with 32-most-significant-bit accumulate | SMMLA, SMMLAR |
32 - (32 * 32) = 32 MSB | 32-bit multiply with 32-most-significant-bit subtract | SMMLS, SMMLSR |
(32 * 32) = 32 MSB | 32-bit multiply returning 32-most-significant-bits | SMMUL, SMMULR |
以上都是定點運算3, 並且每一個指令都能夠在一個時脈執行完畢, 或許你會問:「我只想寫 C 語言, 而且已經有函式庫, 為什麼還需要了解指令集呢?」如果你不碰數位訊號處理應用, 或許可以不用了解這一顆處理器的指令集, 但就像作業系統的程式設計師必須要了解處理器關於作業系統的指令集一樣, 數位訊號處理工程師必須在了解所有 DSP 指令集後, 想盡辦法像國稅局一樣榨乾這顆處理器, 一滴都不能剩。尤其是函式庫提供的定點運算都只有 Q31 與 Q15 的選擇, 如果你有其他特殊的需求, 就得自己寫數位訊號處理程式碼。在 C 語言的優化過程中, 使用指令集的 intrisincs 是不可避免的。
ARM Cortex-M4F 也有符合 IEEE-754 規範的浮點運算單元, 而單精確浮點數在訊號處理演算法上扮演很重要的角色, 下表列舉了單精確浮點數的運算與時脈數:
單精度浮點運算 | 指令 | 執行時脈 |
---|---|---|
加/減 | VADD.F32, VSUB.F32 | 1 |
乘法 | VMUL.F32 | 3 |
乘積累加 | VMLA.F32, VMLS.F32, VNMLA.F32, VNMLS.F32 | 3 |
Fused MAC | VFMA.F32, VFMS.F32, VFNMA.F32, VFNMS.F32 | 3 |
平方根 | VSQRT.F32 | 14 |
除法 | VDIV.F32 | 14 |
可以看出浮點數的乘法比較花時間, ARM Cortex-M4F 有提供 fused MAC 指令以增加精確度。
接下來, 我們來看實際上拿 ARM Cortex-M4F 寫數位訊號處理程式的時候的效能, 以下是一般標準的 FIR 濾波器的程式碼:
void fir(q31_t *in, q31_t *out, q31_t *coeffs, int *state, int numTaps, int blkSize) { int sample; int k; q63_t sum; /* Q2.62 in 64-bit acccumulator */ int idx = *state; for (sample=0; sample<blkSize; sample++) { state[idx++] = in[sample]; sum = 0; for (k = 0; k < numTaps; k++) { sum += (q63_t) coeffs[k] * state[idx]; /* 1. Fetch coefficient and sample. 2. Perform MAC */ idx--; /* Pointer update for circular addressing */ if (idx < 0) { idx = numTaps - 1; } } out[sample] = (q31_t) (sum >> 31u); // Convert Q2.62 to Q1.31 } *state = idx; }
參考更早之前的 FIR 濾波器運算式:4
\begin{equation} y[n] = \sum_{k=0}^{N-1} h[k]x[n-k] \end{equation}h[k] 就是 coeffs[k], x[n-k] 就是 state[idx], numTaps 就是 N, out[sample] 則是 y[n].
在最內側的迴圈中包含了:
- 載入係數與輸入取樣
- 執行乘積累加運算
- 循環定址的指標更新
在現代 DSP5 中, 上述運算可以在一個或兩個時脈內執行完畢, 如:
do x0,FirLoop mac x1,y1,a x:(r0)+,x1 y:(r4)+,y1 FirLoop
這個迴圈指令是 zero overhead loop, 而且只需一個時脈指令就能完成上述三項最內側迴圈需要完成的事項。這是數位訊號處理器的能力, 而且也需要使用組合語言來優化, 那我們來看 ARM Cortex-M4F 用 C 語言能夠達到的速度:
動作 | 時脈數 |
---|---|
載入 coeffs[k] | 2 |
載入 state[idx] | 1 |
乘積累加 | 1 |
idx-- | 1 |
循環定址 | 4 |
迴圈 overhead | 3 |
總共 | 12 |
從上述表格中可以看出, 即便 ARM Cortex-M4F 這類數位訊號控制器擁有一個時脈就可以完成的乘積累加指令, 加上其他額外的執行成本, 就增加到 12 個時脈才能完成一個乘積累加。有一些 C 語言優化的方式:
- Circular addressing alternatives
- Loop unrolling
- Caching of intermediate variables
- Extensive use of SIMD and intrinsincs(還是用上指令集)
如果用上這些, 並且輸入以及係數是 16-bit 的情況下, 是可以達到平均每個乘積累加 1.625 個時脈的程度。6如果需要的精確度是 32-bit 的情況下, 可能會需要更多時脈, 但已經與數位訊號處理器差距不算遠了, 當然若與同樣擁有 SIMD 能力的數位訊號處理器並且優化相比, 還是差上一大截, 但是搭配 ARM 廣泛的周邊與軟體資源, 這樣的效能已經很吸引人。
在數位訊號處理程式上, ARM 提供了 CMSIS(Cortex Microcontroller Software Interface Standard) DSP 函式庫, 在實際開發時只需要呼叫這些函數即可, 但要善用這個函式庫, 還是需要對於數位訊號處理基本概念有認識才行。
另外, 在使用 ARM Cortex-M4F 的累加器的時候, 需要注意的是, 累加器不會自動作飽和動作, 因此做定點運算的時候, 必需自行預留累加的空間, 或是先將數值預先縮小以避免溢位。
4 結語
從 ARM7 問世開始, ARM 這間公司展現的企圖就是除了 32-bit microprocessor 以外, 還要開始蠶食 8-bit/16-bit MCU 的市場, 經過了一陣子的努力之後, 繼續推出了 ARM Cortex-M 系列展現強烈的企圖心, 如今採用的公司漸漸增多, 侵蝕了部分 16-bit MCU 的市場, MCU 程式設計師必須要看清這個趨勢, 學習 ARM 系列架構來接受這個潮流變化。Cortex-M 系列最高接的 Cortex-M4F 提供了數位訊號處理能力, 成為數位訊號控制器, 在省電性主導的地方, 與 16-bit DSP 相比互有優劣, 但 Cortex-M4F 提供了 32-bit 浮點運算, 讓開發時間能夠縮短, 千萬不可小看 ARM 在數位訊號控制器上的未來性。本文只討論了 ARM Cortex-M4F 的 DSP 能力以及在新的 DSP 專案中使用 ARM Cortex-M4F 的可能性, 筆者將在後續的文章中陸陸續續介紹如何使用 Cortex-M4F 來做實際的數位訊號處理應用。
Footnotes:
Tom Krazit, ARMed for the living room, http://news.cnet.com/ARMed-for-the-living-room/2100-1006_3-6056729.html
ARM® Cortex™-M4 Processor Technical Reference Manual Revision r0p1, http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0439d/index.html
有關於定點數 Q format 可以參考我之前寫的「定點數表示法」, http://alberthuang314.blogspot.tw/2012/08/blog-post.html
有關於 FIR 有限響應濾波器的概念可以參考我之前寫的「淺談動平均濾波器」, http://alberthuang314.blogspot.tw/2012/08/blog-post_24.html
這還是 Motorola DSP56300 的組合語言, 是將近二十年前的產品。
Kishore Dasari, Designing with the Cortex-M4, https://www.arm.com/files/pdf/DSPConceptsM4Presentation.pdf