小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

CC3000驅動移植中的幾個陷阱

 細寒 2014-04-12

1. 文檔中的一個小錯誤

CC3000驅動移植中的幾個大坑 - 月下獨酌 - The Bloom of Youth
wlan_ioctl_get_scan_results 函數(shù)用于返回WLAN掃描的結果,每調用一次返回一個結果。返回的數(shù)據結構在文檔中給出,但是這里文檔寫錯了。。。Result entry前的56bytes應該是42bytes,而每次的結果總有有4+4+42=50(bytes)。把下面的結果加起來,也會發(fā)現(xiàn)各項的和是42 而不是56. 這本來只是手冊上的一個筆誤,但在編程時,大家通常會使用一個結構體來接收返回的數(shù)據,如果這個字節(jié)數(shù)不對的話,就會影響內存對齊,從而導致返回的結果錯誤。這里,我使用的結構體定義如下:
  1. typedef struct _wlan_full_scan_results_args_t 
  2.     /* 
  3.         4 Bytes: number of networks found 
  4.         4 Bytes: The status of the scan: 0 - agged results, 1 - results valid, 2 - no results 
  5.         { 
  6.             1 bit isValid - is result valid or not 
  7.             7 bits rssi - RSSI value; 
  8.         } 
  9.         { 
  10.             2 bits: securityMode - security mode of the AP: 0 - Open, 1 - WEP, 2 WPA, 3 WPA2 
  11.             6 bits: SSID name length 
  12.         } 
  13.         2 bytes: the time at which the entry has entered into scans result table 
  14.         32 bytes: SSID name 
  15.         6 bytes: BSSID 
  16.     */ 
  17.     uint32_t ap_count; 
  18.     uint32_t ap_state; 
  19.     uint32_t ap_vaild    : 1; 
  20.     uint32_t ap_rssi     : 7; 
  21.     uint32_t ap_security : 2; 
  22.     uint32_t ap_ssidlen  : 6; 
  23.     uint16_t ap_time; 
  24.     char     ap_ssid[32]; 
  25.     uint8_t  ap_bssid[6]; 
  26.     uint8_t  reserved[2]; //for memory align 
  27. } wlan_scan_result; 
另外,這個函數(shù)讀到最后一條結果時,再讀會返回一個長度為0的結果,即前四個字節(jié)(number of networks found)為零,然后再讀才會讀出下一次掃描的結果。這一點手冊上并沒有指出,是我們在編程實踐中自己發(fā)現(xiàn)的。

 

2. SpiPause - SpiResume與WlanInterruptDisable - WlanInterruptEnable的實現(xiàn)
如 果前面一條是一個小坑的話,這一條絕對是一個大坑。目前為止,我見過的CC3000的驅動實現(xiàn)中,不論是開源的、產品正在開發(fā)而尚未開源的實現(xiàn),除了官方 的例程以外,還沒有人將這兩組函數(shù)寫對。甚至有人能通過降低SPI速率、修改IO中斷方式等等辦法,使得整個程序得以正常運行,將錯誤帶到了產品中。只要 有人說:“我的CC3000驅動有點問題,調了很久都不行。。?!敝惖脑?,不用等他說完,就可以猜想他是把這兩組函數(shù)寫錯了。
這兩組函數(shù)非常容易錯,錯了又非常難以發(fā)現(xiàn)。這兩組函數(shù)的實現(xiàn)已經成為了CC3000驅動移植的主要障礙。其主要原因如下:
(1)是官方的Porting Guide沒有明確指出這兩組函數(shù)的區(qū)別。很多人則想當然地認為這兩組函數(shù)是一樣的。甚至是一組中調用另一組。再看官方的實現(xiàn),又有點不知所云,所以就忽略了這個問題。
(2) 忽略這個問題后,CC3000模塊可以正常初始化,還可以正常掃描WiFi熱點,有人還能正常進行Smart config,甚至有人還能正常打開socket并使用UDP協(xié)議發(fā)送數(shù)據!開發(fā)者根據CC3000驅動自下而上分層的架構來看,看到SPI已經可以進行 正常通信,從而直接在心理上排除了SPI驅動實現(xiàn)有誤的可能性,錯誤查來查去還是在原地兜圈子。
(3)由于這兩組函數(shù)實現(xiàn)有誤導致的錯誤幾乎成了一個人品問題,在不同速度MCU上的錯誤實現(xiàn)會導致不同的錯誤現(xiàn)象,以至于大家的描述不統(tǒng)一,很難從現(xiàn)象判斷到底是哪兒錯了,即使在網上根據錯誤現(xiàn)象搜索或者發(fā)帖求助,也很難得到有針對性的答案。
為什么這兩組函數(shù)寫錯了,會有這么神奇的問題呢?答案就是,這里的錯誤會導致程序的“競態(tài)問題”,類似于數(shù)字電路基礎中的“競爭冒險”。SPI速率、AP的品質和信號強度、IO口翻轉速度、延時的誤差等無關緊要的問題,都可能讓競態(tài)問題出現(xiàn)不同的現(xiàn)象。因此,出現(xiàn)的錯誤現(xiàn)象千奇百怪,貌似跟人品有關就不難解釋了。說了這么多,下面就來解釋一下這兩組函數(shù)到底有什么區(qū)別:
WlanInterruptDisable的作用是關閉IO口的外部中斷,也就是IRQ的下降沿中斷。關閉以后,IRQ下降沿的中斷將被丟棄,在調用WlanInterruptEnable時,會重新使能中斷,之后發(fā)生在該IO上的外部中斷又再次可以響應。而中斷被禁用期間,發(fā)生的中斷都被丟棄,永遠不再響應。這個函數(shù)一般人都寫對了。
SpiPauseSpi函數(shù)是暫時掛起IO口外部中斷,也就是IRQ下降沿中斷,如果在SpiPauseSpi調用之后,IRQ線上再有下降沿,該中斷將一直保持Pending狀態(tài),暫時不調用中斷服務程序,該中斷必須在調用SpiResumeSpi被重新響應,而不能被丟棄。這里,很多很多很多人,都,寫錯了。。。
       這種中斷的響應方式比較特殊,像STM32就沒有在標準驅動庫中實現(xiàn)相應的API,而必須通過操作寄存器的方式來手工實現(xiàn)。相應寄存器的定義,既不在芯 片Datasheet里,也不在那份大家熟知的STM32F1系列Reference Manual(RM0008)里,而是在很多STM32開發(fā)者都沒有聽說過的一份文檔PM0056——STM32F10xxx/20xxx/21xxx/L1xxxx Cortex-M3 programming manual里。有很多MCU,甚至包括TI的MSP430,在硬件上根本就不支持這種響應方式,因此只能用一些猥瑣的方法來實現(xiàn)。MSP430該函數(shù)的代碼居然是向一個配置為輸入的IO口寫數(shù)據,足以讓不熟悉MSP430的開發(fā)者撓頭了。
STM32F103上的實現(xiàn)如下
  1. void SpiPauseSpi(void) 
  2. //    if(IRQ_INT_CHANNEL >= 0 && IRQ_INT_CHANNEL <= 31) 
  3. //    { 
  4. //        //NVIC->ICER[0] = (1 << IRQ_INT_CHANNEL); 
  5. //    } 
  6. //    else if(IRQ_INT_CHANNEL >= 32 && IRQ_INT_CHANNEL <= 63) 
  7. //    { 
  8.     NVIC->ICER[1] = (1 << (IRQ_INT_CHANNEL - 32)); 
  9. //    } 
  10. //    else if(IRQ_INT_CHANNEL >= 64 && IRQ_INT_CHANNEL <= 67) 
  11. //    { 
  12. //        //NVIC->ICER[2] = (1 << (IRQ_INT_CHANNEL - 64)); 
  13. //    } 
  14. //    else 
  15. //    { 
  16. //        while(1); //Should not be here. Macro IRQ_INT_CHANNEL might be invalid. 
  17. //    } 
  18.  
  19. void SpiResumeSpi(void) 
  20. //    if(IRQ_INT_CHANNEL >= 0 && IRQ_INT_CHANNEL <= 31) 
  21. //    { 
  22. //        //NVIC->ISER[0] = (1 << IRQ_INT_CHANNEL); 
  23. //    } 
  24. //    else if(IRQ_INT_CHANNEL >= 32 && IRQ_INT_CHANNEL <= 63) 
  25. //    { 
  26.     NVIC->ISER[1] = (1 << (IRQ_INT_CHANNEL - 32)); 
  27. //    } 
  28. //    else if(IRQ_INT_CHANNEL >= 64 && IRQ_INT_CHANNEL <= 67) 
  29. //    { 
  30. //        //NVIC->ISER[2] = (1 << (IRQ_INT_CHANNEL - 64)); 
  31. //    } 
  32. //    else 
  33. //    { 
  34. //        while(1); //Should not be here. Macro IRQ_INT_CHANNEL might be invalid. 
  35. //    } 
另外一組的實現(xiàn)是
  1. void WlanInterruptEnable() 
  2.     EXTI_ClearITPendingBit(IRQ_INT_LINE); 
  3.     EXTI_InitTypeDef exti; 
  4.     exti.EXTI_Line = IRQ_INT_LINE; 
  5.     exti.EXTI_Mode = EXTI_Mode_Interrupt; 
  6.     exti.EXTI_Trigger = EXTI_Trigger_Falling; 
  7.     exti.EXTI_LineCmd = ENABLE; 
  8.     EXTI_Init(&exti); 
  9.  
  10. void WlanInterruptDisable() 
  11.     EXTI_ClearITPendingBit(IRQ_INT_LINE); 
  12.     EXTI_InitTypeDef exti; 
  13.     exti.EXTI_Line = IRQ_INT_LINE; 
  14.     exti.EXTI_Mode = EXTI_Mode_Interrupt; 
  15.     exti.EXTI_Trigger = EXTI_Trigger_Falling; 
  16.     exti.EXTI_LineCmd = DISABLE; 
  17.     EXTI_Init(&exti); 
3. TI提供的CC3000 Host Driver假設char類型是無符號的
這個問題可能很多人都不會遇到,因為在嵌入式開發(fā)中char通常都是無符號的,基本所有的用于嵌入式平臺的編譯器默認情況下都會這樣設定。而我則比較習慣PC上有符號的char,所以我手賤給GCC加了一個編譯參數(shù)-fsigned-char......
TI 的Host Driver就比較扯淡,它假設char是無符號的,并且在char有符號時就會因符號位在強制轉換中的行為不同而出錯。這個問題不容易排查,因為需要跟 蹤到TI實現(xiàn)的Host Driver里,而大家通常都會假設這個實現(xiàn)是沒錯的,能跟進去就是一種勇氣了……我當時遇到這個問題時,不知道是哪兒的錯誤,就在很多回調函數(shù)中添加了 串口打印的語句,通過串口輸出,觀察各個函數(shù)被調用的情況,結合現(xiàn)象,再加以大膽的猜想,才解決了這個問題。
4. 供電
CC3000驅動移植中的幾個大坑 - 月下獨酌 - The Bloom of Youth
這 個是一個硬件問題,一個不應該犯的錯誤。目前大家用的最多的CC3000模塊還是Jorjin的WG1300,而Jorjin的文檔中并未給出該模塊工作 時所需的電流。在一些追求體積最小化的應用中,大家也普遍使用了SOT23-5封裝的小型LDO,這類LDO的電流通常只有100mA左右。一個單片機才 幾十毫安的電流,一個WiFi又能大到哪里去呢?
看 看德州儀器官方WiFi模塊(TI的WiFi模塊封裝尺寸和引腳定義與WG1300完全相同,本人咨詢Jorjin總代理后得知TI的官方模塊正是由 Jorjin設計并制造的,與WG1300相比在硬件上也是完全一樣的,只是外殼上的字不同而已) 的文檔后,不禁大吃一驚!發(fā)送電流峰值275mA,接收峰值103mA,合起來有接近400mA的峰值電流!正是因為如此,我120mA的LDO被瞬間秒 殺,電壓從3.3V拉到了2.6V……我居然還不知道!因為STM32可以在2.6V下正常工作,我的還是在各種加斷點、各種單步跟蹤,完全沒有意識到模 塊已經因電壓過低死機了。。??戳艘幌耂parkcore的電路圖,發(fā)現(xiàn)它用的LDO型號是MIC5219,一個SOT23-5封裝,500mA的 LDO,哈哈~
另外還有一個不算是坑,或者說只是一個小坑~就是security.h文件最后少了一段代碼,在用C++編譯時可能導致編譯出錯,并且把錯誤報到別的文件里,讓人很困惑。。。缺少的代碼如下,大家一看就懂了~
#ifdef __cplusplus
}
#endif

    本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多