燒寫Flash後的DSP程式運行不正常的情況分析

來源:互聯網
上載者:User

這段時間一直在調試DSP6713的Flash燒寫,現在對Flash的燒寫也算心中了如。

那天,非常Happy的發現將閃爍LED燒寫到Flash成功了,然後,就以為一切都OK了……

那天,成功燒寫了一個300KB以上的程式,又認為,這次應該OK了……

那天,寫了個Timer中斷程式,燒寫到Flash,卻死機了……

那天,在RAM上運行很流暢的一個演算法(演算法中調用了CCS的atan函數),在燒寫到Flash後演算法卻死機了……

那天,我開始思考:是什麼情況導致RAM中跑得很Happy的程式燒寫到Flash就運行得如此的不堪——眾多的囧相。

“且行且珍惜”,珍惜這些次發現Bug的機會,因此,我要總結:在RAM中能正常運行,而燒寫到Flash後無法正常啟動並執行一些情況討論。

請檢查中斷向量表

中斷向量表包含了所有中斷的入口,在燒寫Flash的時候,有兩種方式可以保證中斷能正常工作。具體可參見TMS320C6713燒寫Flash的通用方法的第5小節。

請檢查程式中隱形記憶體錯誤

很多情況下,當出現數組越界時,在RAM中的程式都能正常運行,但在燒寫Flash後運行就會出現死機或程式跑飛的現象。

比如定義一個數組,

int x[5];

你使用x[5]=10這樣的語句在RAM程式中是某些時候能正確啟動並執行,在PC上應該也可以。但將這種程式燒寫到Flash之後運行,DSP果斷和你說拜拜!

因此,請謹慎地檢查程式碼中的數組越界和指標操作。在DSP程式中,堅決不使用C庫函數中的malloc函數。如果需要動態分配記憶體的操作,可以自己寫一個,或使用uCOS II或DSP/BIOS等嵌入式作業系統。

請盡量避免使用math.h中的三角及log等函數

也不知道是什麼原因,也可能是我對atan函數的使用方法不正確造成的吧。在我的一個最初的程式中,我是直接這樣計算atan(x)的,

float x,y;...y = atan(x); // x範圍為[0, 1.7]

在RAM中以及在PC中都多次測試過沒有任何問題。

燒寫Flash之後,也不是死機,但程式運行到atan這個函數的時候會卡上很長一段時間,再接著往下運行。

難道是math.h中的atan運算效率太低?但為什麼RAM中就能運行呢?這個還不清楚。

於是想了個招,在要使用三角函數和log等函數的地方都使用查表法替代庫函數,在精度要求高而儲存空間又有限的場合,可使用查表+插值的方式。

下面是改進方法計算atan,

/* table of determine ATAN(x) */const float atan_tb[] = {  // 精度(0.020)0.00, 1.15, 2.29, 3.43, 4.57, 5.71 , 6.84, 7.97, 9.09, 10.20,11.31, 12.41, 13.50, 14.57, 15.64, 16.70 , 17.74, 18.78, 19.80, 20.81,21.80, 22.78, 23.75, 24.70, 25.64, 26.57 , 27.47, 28.37, 29.25, 30.11,30.96, 31.80, 32.62, 33.42, 34.22, 34.99 , 35.75, 36.50, 37.23, 37.95,38.66, 39.35, 40.03, 40.70, 41.35, 41.99 , 42.61, 43.23, 43.83, 44.42,45.00, 45.57, 46.12, 46.67, 47.20, 47.73 , 48.24, 48.74, 49.24, 49.72,50.19, 50.66, 51.12, 51.56, 52.00, 52.43 , 52.85, 53.27, 53.67, 54.07,54.46, 54.85, 55.22, 55.59, 55.95, 56.31 , 56.66, 57.00, 57.34, 57.67,57.99, 58.31, 58.63, 58.93, 59.24, 59.53 , 59.83 };y = atan_tb[((uint16_t)(x*100)) >> 1];

建立atan的表可以藉助Matlab。在需要插值的場合,比如,上面atan_tb的精度為0.02,而我們希望在少數的一些場合下使atan在0.01的精度,如果以0.01建表將會使表的資料存放區量擴大1倍,這是我們可以在0.02精度表的基礎上再使用插值的方式。

比如,要計算atan(0.03),我們可以從表中查到atan(0.02)和atan(0.04),如果僅使用線性插值的話,則

atan(0.03) = (atan(0.02) + atan(0.04)) / 2
請檢查程式的邏輯

曾傻傻的寫過一個類似下面的程式,

uint8_t dir;  // 低3位進行了編碼,下面的switch進行解碼int dist_switch(int a, int b, int c){    int max_dist;    int min_dist;    int result = 0;    switch (dir) {    case 0x00: break;    case 0x01: max=a;min=b;break;    case 0x02: max=a;min=c;break;    case 0x03: max=b;min=a;break;    case 0x04: max=b;min=c;break;    case 0x05: max=c;min=a;break;    case 0x06: max=c;min=b;break;    case 0x07: break;    default: break;    }    result = max * 100 / (min + max);    return result;}

咋一看,沒有文法問題,switch的break語句也加上了。

問題出就出在:dir低三位進行了編碼,最大編碼個數應該是8。而因為實際中只用到6種情況,switch中對其它的兩種編碼都使用break,問題就出來了,如果我的dir=0x00會怎麼樣?switch語句當然沒問題,問題在下一條語句:

result = max * 100 / (min + max);

dir=0x00沒有對max和min進行任何的賦值,而且其它地方也沒有。因此max和min作為局部變數將會是一個隨機的值,這在RAM中是能夠運行通過的,但燒寫到Flash之後,這種局部變數的不確定性直接回導致Flash宕機。

因此,對於switch以及if...else...的邏輯問題,不能只關注它們所在範圍,請仔細檢查其上下文。

請特別關照一下程式中的除法運算

x=a/b中若b可能為0,這樣的程式燒寫到Flash會直接導致DSP死機的。如果可以的話,盡量將除法運算轉換為移位元運算。

比如,要計算y=x/0.02,一個號的轉換方式就是:

y=(uint32_t)(x*100)/2=((uint32_t)(x*100) >> 1);

還可以更好一點,將*100也使用移位替代,

uint32_t tmp_x = (uint32_t)x;y = ((tmp_x<<6) + (tmp_x<<5) + (tmp_x<<2)) >> 1;

這樣你就再也看不到除法運算了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.