作者:allen_zhan [前言] 在前文"關于 FREESCALE 的 DEMO 中 PSOR與PCOR 操作的常見錯誤 "中, 我們討論了 kinetis L series 的 Sample 中容易出現的, 關于 PSOR 的常見錯誤, 我們分析, 這種錯誤, 大致可能與未曾熟讀 RM 有關. 在之后對 kinetis L series 的 samples 繼續短暫的了解過程中, 我們發現參考例程其他的較明顯的錯誤, 或者說不足疏漏之處. 因其常常表現為 uController 的新生容易發生的錯誤, 故我想稱其為"初學者錯誤", 或者說是"初學者不足". [例程] 讓我們引 Blinky sample 中的, 開啟 Interrupt 的例程作為例子, 如下圖例1: [圖例1: Blinky sample 中的使能例程] 這個例程, 讓我們覺得不能沉默以對. 因為, 作為 Freescale 官方例程, 可能類似的代碼會被我們國內的初學者諸君, 作為效仿的對象. 從而產生錯誤的引導效果, 不利于我們工程師的自我完善和提升. [可能的疏漏或錯誤] 這里我們想主要指出, 這段短短的例程中可能出現的 4 個不足: (1) 首先, 這個 (irq%32) 浪費代碼空間并影響效率. -- 其本質原因, 可能存在著邏輯上混淆不清. (2) 其次, IRQ的值域為: [0, 31]. 而該 code sample 卻允許對 32 的計算. -- 其本質原因, 應該是未作越界(邊界)檢查. 并未仔細閱讀 Register bit field定義. (3) 第三, 對 irq=31 時的可能情況, 也就是 (1<<31) 的情況, 毫無敏感. -- 這里毫無敏感的意思, 大致反應為: (a) 對有符號數與無符號數區別不敏感, (b) 對左移操作不敏感. (4) 第四, 正如同我們在 PSOR 中分析到的 |= 錯誤, 在這段簡單的例程中, 仍然存在 ICPR 在 bit 被 write 0時無任何影響, ISER 在 bit 被 write 0 時無任何影響. 都應該改為 =. [討論(1<<31)的特例] 讓我們用例子來討論這個 (1<<31): (1) 首先, IAR 中定義的常量, 都是有符號的 int 類型. 這個前提為大家公認, 但是我沒有找到出處``` 麻煩讀到此處的同行, 能給我一個出處鏈接, 或者是 IAR help documentation 中的說明. 蟹蟹. (2) 有符號數 1, 在左移 31 bit 后, 將導致符號位被置1, 也就是計算得到一個負整數. 如果我們只看這里 NVIC_ICPR |= 1 << 31; 似乎沒有影響到最終邏輯結果. 但是, 其真實原因是, 該負整數被強制轉化為 unsigned int 的結果, 也即是最終正確的 0x80000000. 但這并不表示, coder 清楚這個結果是由強制轉換產生, 從這段代碼本身, 我們合理判斷該 coder 將分不清下面代碼的執行結果, 也就是容易犯一些"初學者錯誤". 比方說: 我懷疑該 coder 會毫無自覺寫出下面的代碼: if( (1<<31) > 1 ) { do what he wants; } 顯然我們知道, 這片代碼永遠不能為真, 去執行 what he want to do. (3) 根據圖例2, 我們對 (1<<31) 進行詳論: [圖例2: Allen 隨手編碼給出3個例子討論 (1<<31) ] 我們把3個例子的結果, 都有注釋, 可以見到: (a) (1<<31) 的值, 不是正數 0x80000000, 而是負數 -2147483648. (b) (1u<<31) 的值, 才是 0x80000000. (c) 條件比較語句, 首先是兩邊轉化為同類型才能比較. 由于無符號數優先級高于 int, 故 (1<<31) 被強制轉化為 unsigned int, 也就是 0x80000000, 用于比較, 導致和 sample1 的結果截然不同. 上面3個例子, 清楚表明了 (1<<31) 的值為何(如果我有任何錯誤請告訴我). [我們修改的代碼] 因此, Allen 嘗試修改這個例程如下, 見圖例3: [圖例3: 被修改后的例程] [結論] 我們通過對一個 enable interrupt 例程的修改, 討論了 firmware programmer 可能容易犯的問題, 主要有: (1) 不能熟讀 datasheet, 了解 register 的具體用法. (2) 代碼邏輯混亂. (3) 忽視邊界檢查. (4) 對有符號和無符號數區別不夠重視. (5) 不了解左移時牽涉符號位的特例. (6) 不清楚在條件比較時強制轉換現象. 上述問題, 一般多見于 uController 的初級選手. 作為公司新晉員工, 或者任何致力于 MCU code 實現 application 的新進同行們, 可以將上述錯誤作為范例保存而自省. 另外, 我們說不定應謹慎檢閱各種 Freescale 給出的 kinetis L series 的參考 samples, 反復測試, 可能避免出貨后造成不可預料之損失. |