極品的C語言錯誤


 
     今天在測試硬件通信模塊時候發現一個奇怪的問題,發送數據和接收數據進行比較復制時候頻繁數據錯誤。

     測試流程如下:發送一個字節和接收一個字節,進行比較,當返回數據和發送數據不相等的時候,錯誤計數器累加。
     數據收發抽象如下:
     uint16 i = 0;
     uint16 j = 0;
     uint32 error_num = 0;
 
     XX_send_data(i++);
     j = XX_rece_data();    
     if(i != (j + 1)) {
          error_num++;
     }
 
     這段代碼按照理論上來說,只要發送數據i和接收數據一樣,那錯誤計數器應該不會出錯,但是實際上出錯了,最開始懷疑是由於FPGA硬件模塊數據發送和接收時序有問題,但是多次大批量功能仿真以及時序仿真都沒問題。
     這下我就開始懷疑這段短小的C程序是否工作正常,因此,
     在error_num++這句話這里打斷點,查看每次出錯數據都是i=0,j=65535的時候出錯,為什么會全部出錯在這里呢?
     百思不得其解,后來詢問資深工程師飛哥,飛哥一看就看出問題出現在哪里了,讓我汗顏呀!!~~
     原來錯誤是這樣發生的:(程序運行在32位處理器)
     這段程序從表面上看是沒有任何問題的,但是細致分析就會發現,當i=65535發送數據,發送完成后執行i++,i此時變為0,j調用接收函數后,返回值正確也是65535,但是,那看來問題就出現在if(i != (j+1))這里了。
     原來, j+1 這種算術運算的運算值是默認存到32寄存器中,因此j+1運算結果為32位數據,因此,當j=65535時候,(j+1)實則為65536,(0 != 65536),因此產生不匹配。錯誤碼自加。
     有很多種方法消除這種錯誤,修改代碼如下即可解決問題。
     uint16 i = 0;
     uint16 j = 0;
     uint32 error_num = 0;
 
     XX_send_data(i++);
     j = XX_rece_data();    
     if(i !=( uint16 ) (j + 1)) {
          error_num++;
     }
     終於找到問題了,看來以后寫代碼還得仔細了,吸取教訓。
 
   // 看了回復,發現很多人都以純軟件的方式來理解這段代碼,但是嵌入式C語言里面一定要詳細和處理器行為結合起來,以下添加詳細解釋
  這張截圖為這段代碼對應的匯編代碼,詳細閱讀這段匯編代碼即可找出問題所在。
  
  第一句匯編代碼ldhu r3,-10(fp)  意思為從內存或者cache中加載一個半字,並且擴展成無符號類型,這句話就是把變量i加載到寄存器R3中,R3為32位寄存器,這時候雖然變量i為uint16但是比較的時候還是變成了32位
  第二句匯編代碼ldhu r2,-12(fp)  同上一句話一樣,這里是加載變量j到寄存器R2中
  第三句匯編代碼addi r2,r2,1    /* 問題所在*/  這句話就是執行的j+1,可見結果是保存在r2中,r2為32位寬的寄存器,所以當i=0,j=65535時,j+1 = 65536並未溢出,而是直接賦值給r2,此時r2即為65536,r3為0
  最后一句匯編代碼 beq r3,r2,0x800258<main+92>這句話是比較r3和r2的值,如果相等就跳轉到0x800258<main+92>這個地址執行程序。如果不相等就直接運行下一句語句,也就是error_num++
 
  從上面的分析看出,嵌入式行業一定要對處理器非常熟悉,出現些稀奇古怪的問題,才能最終找到問題所在。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM