在數字電源的研發過程中,純數字控制的閉環算法是個難點。要想達到預期的性能指標,一般要求控制環中的算法滿足下面的一些條件:
1.從被控量的采樣到完成占空比的計算和更新,這個過程的時間要盡可能的短。越少的時間越能提高控制環路的相位裕度,增加環路的穩定性。針對這個問題,microchip的dsp系列單片機有專用的硬件來解決。以dsp33ep128gs806舉例:
首先,為縮短ADC采樣的時間,該芯片內部有4個專用內核用來對被控量進行采樣,以最高速運行的dsp,adc的轉換時間能控制在200ns以內。在上篇文章中,用來采樣mos電流和輸入輸出電壓的ADC(AN0、AN1、AN2、AN3)都是專用內核。
其次,為減少進入ADC中斷時,寄存器壓棧和出棧的時間,引入context轉換的功能。筆者實測能比普通方式進入ADC中斷少300ns左右。
最后,為了快速解算環路中差分方程的解,引入帶飽和功能的40位累加器,在一個指令周期能完成累加,相乘,兩個參數的讀取,累加器回寫等指令。配合專用的累加器匯編指令,能加快運算速度。以筆者用的PID算法,在60MHz的工作頻率下,能在1.6us的時間內完成差分方程的求解和占空比的更新。
2.環路中的差分方程的參數有很多是用小數表示的。為了滿足控制的精度,并且還能有很快的運算速度,microchip的dsp33ep系列的dsp單片機沒有用浮點數表示小數,而是用定點數來表示。具體到累加器中的小數表示,就是用Q15的格式。
從上面提到的這些條件來看,筆者覺得,先將累加器是如何工作,如何進行小數乘法的計算這兩方面弄清楚是很有必要的。
dsp如何表示小數?dsp小數數據表示為二進制補碼數,其中最高位定義為符號位,小數點隱含于符號位之后。這種格式通常被 稱為1.15(或Q15)格式。其中1是用來表示數據的整數部分的位數,而15是用來表示小數部分的位數。1.15格式的dsp小數數據表示的范圍是:-1.0(0x8000)至0.999969482(0x7FFF)。可見,要把紙面中的小于1的小數轉換成dsp能識別的小數數據,應該用公式:,比如:
而32767的十六進制數為0x7FFF
那么0.1953125該如何表示?
6400的十六進制數為0x1900。
下面舉例說明累加器如何計算小數乘法:
- 純小數×整數:
0.1953125*2762=??
0.1953125--0.1953125*2^15=6400--0x1900
2762--0x0ACA
下圖是累加器ACCA計算乘法的過程:
將0x1900賦值給w4寄存器,0x0ACA賦值給w5寄存器。mac指令是用累加器A做w4×w5的運算,并將累加器的ACCAH部分保存在w6寄存器中,下圖是40位累加器寄存器的結構圖:
ACCA寄存器的結果是0x00021B7400,只保存0x021B到w6中,0x021B的十進制為539。
而,所以w6的結果就是w4×w5的最終結果。其實這個計算過程手動推導一下是這樣的:
而0x00010DBA00除就是右移15位,也就是0x021B,即為539。
那這個0x00010DBA00是怎么回事??其實累加器有兩種工作模式:小數模式和整數模式。當處于小數模式時,會把結果自動左移一位,而整數模式工作時,則不會進行位移。所以讀者可以嘗試將0x00010DBA00左移一位就是0x00021B7400,因此要把0x00021B7400右移16位才是乘法運算正確的結果。而w6寄存器中的數據0x021B正是0x00021B7400右移16位的結果。
那為何小數模式會把結果自動左移一位?小數都是用1.15格式,1.15×1.15=2.30,即小數乘法的結果是2.30格式,但是累加器的小數點固定在31位和30位之間,為了對齊結果,就變成了左移一位,成為1.31格式。
從上面的分析中,可以看到,對于累加器A來說,根本就沒有做小數的乘法,都是整數的乘法,小數點只存在于程序員的心里。
- 純小數乘純小數:
0.1953125*0.08428955078125=??
0.01953125--0.01953125*2^15=6400--0x1900
0.08428955078125--0.08428955078125*2^15=2762--0x0ACA
0.1953125*0.08428955078125=0.01646280288.......
考慮到小數取整時的誤差,可以看出,累加器的計算結果在一定精度上是對的!!
- 整數乘整數:(用累加器的整數模式)
6400*2762=17676800(十六進制0x00010DBA00)
這時的正確結果是保存在ACCxH和ACCxL兩個寄存器中,無法把結果保存在一個16位的寄存器中。
- 大于1的小數×整數:
以上都是對于純小數或純整數的乘法做的計算。那么對于大于1的小數該如何表示?大于1的小數無法表示成1.15的格式!
還是那句話,小數點只存于使用者的心里,累加器只會做整數的乘法!
舉例:
3.348*2762=9247.176
3.348是大于1的小數,且小于4(2^2),所以換算成dsp可以識別的小數就應該左移(15-2)位,即13位。
2762--0x0ACA
w6寄存器保存正確的結果0x241F--十進制為9247。
手動推導計算過程:
在計算完w4×w5的結果后,還要用sftac指令將累加器結果寄存器ACCA左移2位,最終保存在w6寄存器才是正確的結果。
在microchip官方提供的PID算法庫函數中,對于大于1的小數就是用這種方法來計算的,這在后面還會提到。
通過前面的幾個例子,可以看到dsp能夠處理任意小數的乘法運算。但是要注意結果飽和的問題。比如:
200.863*742=149040.346 > 32767,
這時再用上面的步驟,得到結果后,再左移位,將會引起累加器的飽和,這種情況就只能用整數模式,并且自己計算小數的位移,保存計算結果。
200.863<256(2^8)所以左移7位。即
742--十六進制0x02E6
可以看到累加器最終的計算結果為0x00012316D4,這時就不能再左移8位了,否則會導致累加器ACCA飽和
最終結果與正確的結果有一定的誤差,這是由于取整誤差造成的。
總結:
dsp的小數乘法,本質上就是整數乘法,當對于累加器的工作方式了解以后,有助于程序員選擇合適的計算模式。
通過上面的方法,dsp對所有整數和小數的乘法運算都可以很好的支持,明白這些之后,才能熟練應用smps_control_library函數庫,明白如何設定函數的參數。