Marvell 88W8686/88W8782/88W8801 WiFi模組驅動程式的編寫
本文以STM32F1系列的微控制器為例,詳細講解Marvell公司的88W8686/88W8782/88W8801 WiFi模組驅動程式的編寫。編寫程式時為了程式碼簡短起見,直接用暫存器操作,不使用STM32庫函式。IDE採用Keil uVision5。為了儲存下WiFi模組龐大的韌體,以及方便lwip的移植,請儘量採用較大SRAM和Flash容量的微控制器(如High-density或XL-density系列的),這裡筆者用的是STMF103RET6(引腳數64,SRAM容量64KB,Flash容量512KB)。因為Connectivity line系列的STM32F105/107微控制器沒有SDIO介面,所以請不要使用這兩種微控制器來測試。STM32F103C8T6容量太小,雖然Flash程式儲存空間有64KB,但SRAM執行記憶體只有20KB,不方便lwip協議棧的移植,所以最好也不要使用(當然這種情況改用uip協議棧也行,uip在SRAM容量才1KB的ATMega16微控制器上都能執行)。
88W8686已經是比較老的晶片了,其資料手冊(datasheet)的釋出時間是2007年2月20日。淘寶網上可以買到晶片組(Chip Set)為88W8686的WM-G-MR-09模組,價格比較貴,85元一個。其韌體(firmware)及Fedora Linux下的驅動程式可直接在Marvell的官方網站上下載到,壓縮包名稱為SD-8686-LINUX26-SYSKT-9.70.3.p24-26409.P45-GPL.zip,裡面有兩個韌體:helper_sd.bin和sd8686.bin,最後修改日期都是2008年2月29日。
賣家世訊電子提供了STM32103RET6驅動該網絡卡的程式。但該程式可靠性很差,程式碼既亂又複雜而且很難看懂,掃描熱點時經常出現problem fetching packet from firmware, rewhile的錯誤,連線熱點時有時候會出現認證失敗的錯誤type=0x888e!,一連線失敗就直接重啟微控制器,而且與WPA2-PSK認證有關的程式碼被封裝到了wap_wpa2_lib.lib檔案中,不開放原始碼。這也是筆者寫本教程的原因:自己編寫出高可靠性的驅動程式!
較新的88W8782和88W8801模組價格更便宜,大概20~30塊錢一個,支援建立AP模式的熱點,安卓手機可以不打補丁直接連線,但很多暫存器的地址和88W8686不一樣。其韌體和Linuxl驅動程式無法在Marvell的官方網站上下載到,但可在淘寶的賣家那裡獲得,還可以獲得資料手冊PDF文件。資料手冊的釋出時間分別為2011年4月6日和2013年8月19日。壓縮包的名稱分別為SD-UAPSTA-8782-FC13-MMC-14.69.12.p35-M2614336_B0-GPL_new.zip和SD-UAPSTA-8801-FC18-MMC-14.76.36.p61-C3X14090_B0-GPL.zip。每個模組只有一個韌體,分別是sd8782_uapsta.bin和sd8801_uapsta.bin,最後修改日期分別為2012年8月16日和2015年2月25日。
本文主要講解88W8686模組,同時也會順帶說明如何在88W8782/8801這兩款晶片上執行所寫的程式。
這些WiFi模組都是SD I/O卡,而我們平常在手機裡面插的記憶體卡屬於SD memory卡。SDIO card和SD memory card都可以用STM32微控制器的SDIO介面來操作,但它們所支援的命令不一樣。後者支援很多命令,比如復位命令CMD0、寫資料塊命令CMD24~25、讀資料塊命令CMD17~18等等。但前者就只支援CMD0、3、5、7、15、52、53這幾個命令,並且CMD0不是復位命令,而是從SDIO模式切換到SPI模式的命令。並且,兩者的初始化時序也不一樣。
其中,Part1_Physical_Layer_Simplified_Specification_Ver6.00是SD memory卡的文件,PartE1_SDIO_Simplified_Specification_Ver3.00是SDIO卡的文件。PartE7_Wireless_LAN_Simplified_Addendum_Ver1.10雖然是介紹SDIO WiFi卡的文件,但和本文所講的WiFi模組沒有任何關係,因此不必下載。
接下來,筆者將參考Part E1文件,講解SDIO WiFi卡的初始化方法。
工程的建立:在Keil中新建一個STM32F103RE的工程,並勾選上啟動程式碼CMSIS/CORE和Device/Startup:
如果要使用STM32的庫函式,則還需要勾選Device/StdPeriph Drivers中的專案(本文不使用庫函式,因此不必勾選):
工程建好後,Keil已經幫我們自動新增好了啟動檔案startup_stm32f10x_hd.s,其中hd是指high-density。
在其中建立main.c檔案,以及存放WiFi驅動程式的檔案WiFi.h和WiFi.c。
以下是88W8686 WiFi模組與STM32微控制器的連線。
SDIO_CLK接PC12,SDIO_CMD接PD2,資料線D0~D3接PC8~11。
在筆者所用的的開發板上,VCC3V3引腳不是直接連線到電源的,而是通過一個場效電晶體接到PB12上的。當開發板外接了5V的電源插頭,並且PB12為低電平時,WiFi模組才通電工作。下載程式時,PB12輸出高阻態,此時WiFi模組斷電。每次微控制器復位時,WiFi模組也就跟著自動復位。自己焊的板子可以用一個PNP三極體來代替場效電晶體Q1。
- RCC->AHBENR = RCC_AHBENR_SDIOEN;
- RCC->APB1ENR = RCC_APB1ENR_TIM6EN;
- RCC->APB2ENR = RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN| RCC_APB2ENR_USART1EN;
- GPIOA->CRH = 0x000004b0;
- GPIOB->CRH = 0x00030000; // PB12為WiFi模組電源開關, PB12=0時開啟WiFi模組
- GPIOC->CRH = 0x000bbbbb;
- GPIOD->CRL = 0x00000b00;
- USART1->BRR = 0x271;
- USART1->CR1 = USART_CR1_UE | USART_CR1_TE;
接下來配置PA~PD的I/O口。CRL負責Px0~Px7,CRH負責Px8~Px15。每個十六進位制數位配置一個埠,最低位為Px8或Px0,最高位為Px15或Px7。
對於USART1串列埠,傳送埠USART1_TX為PA9,設定為複用推輓輸出,速度為50MHz:b,接收埠USART1_RX為PA10,設定為浮空輸入:4。
PB12為外接的電源開關,最開始為高阻態,WiFi模組為斷電狀態。當設定CRH為3(推輓輸出,速度為50MHz)後,因為GPIOB->ODR為0,所以PB12輸出低電平,WiFi模組通電。
PC8~11為SDIO資料埠D0~D3,PC12為SDIO時鐘引腳,PD2為SDIO命令埠。這些都應該設定為複用推輓輸出50MHz,因此都設為b。
由STM32F103的參考手冊(Reference manual)的9.1.11 GPIO configurations for device peripherals中的表格可知,所有的SDIO引腳都應該設為複用推輓輸出。
推輓和開漏輸出的區別:推輓輸出可以輸出低電平(ODR=0)和高電平(ODR=1)。開漏輸出可以輸出低電平(ODR=0),但不能輸出高電平,當ODR=1時輸出高阻態,高阻態相當於斷開了埠與電源的連線。
GPIO_CRH/CRL配置方法(加粗的表示常用):
每1位16進位制數表示一個I/O埠。
1為10MHz推輓輸出(推輓輸出適合直接驅動)(複用為9)
2為2MHz推輓輸出(複用為a)
3為50MHz推輓輸出(複用為b)
5為10MHz開漏輸出(開漏輸出適合接三極體基極)(複用為d)
6為2MHz開漏輸出(複用為e)
7為50MHz開漏輸出(複用為f)
0為模擬輸入/輸出
4為浮空輸入
8為帶上/下拉電阻的輸入(ODR=0為下拉,1為上拉),上拉輸入表示IDR的預設值為1,下拉輸入表示IDR的預設值為0
當使用帶上下拉電阻的輸入模式時,該埠對應的ODR位的值就表示預設的輸入電平。當該埠懸空時,IDR=ODR。否則IDR就等於輸入的電平值。
一般情況下,PNP型三極體的發射極都是接的+5V,如果基極通過電阻接到微控制器的I/O口上並配置為開漏輸出,則當ODR=0時,三極體飽和導通,發射極與基極間的電壓為0.7V,基極電阻兩端的電壓為4.3V;當ODR=1時輸出高阻態,相當於基極直接懸空,三極體截止。所以開漏輸出特別適合接三極體的基極。如果配置為推輓輸出,那麼當ODR=1時,I/O口輸出的是3.3V的高電平,5V-3.3V=1.7V高於導通電壓0.7V,因此三極體還是導通的,且基極電阻兩端的電壓為1V。
所以,如果WiFi模組的電源上接的是PNP三極體,那麼只有將PB12配置為開漏輸出(7)後,才能通過ODR暫存器控制WiFi模組電源的通斷。
接著配置串列埠USART1,BRR為波特率。USART1是在APB2總線上的外設,該匯流排的時鐘為72MHz,也就是72000000Hz。欲設定的波特率為115200,72000000 ÷ 115200 = 625 = 0x271,因此,BRR=0x271。CR1為控制暫存器,UE表示啟動該外設,TE表示允許傳送。
為了在程式中使用printf函式向串列埠輸出資訊,需要引入stdio.h標頭檔案,然後實現fputc函式。printf函式使用的是C語言標準輸出流stdout,因此fp=stdout。ch為要輸出的每個字元。若輸出的是換行符\n,為了正確換行,需要先輸出一個回車符\r組成\r\n。向USART1的DR暫存器寫入資料前,必須先等待SR暫存器中的TXE位(傳送緩衝區空)變為1。寫入資料後,串列埠外設將自動傳送資料。最後函式必須返回ch的原有內容。
- #include <stdio.h>
- int fputc(int ch, FILE *fp)
- {
- if (fp == stdout)
- {
- if (ch == '\n')
- {
- while ((USART1->SR & USART_SR_TXE) == 0);
- USART1->DR = '\r';
- }
- while ((USART1->SR & USART_SR_TXE) == 0);
- USART1->DR = ch;
- }
- return ch;
- }
此外還需在專案屬性裡勾選上“Use MicroLIB”選項。
J-Link下載器配置:在Debug選項卡中選擇J-Link作為除錯工具,並在設定對話方塊裡勾選上Reset and Run複選框,以便下載完成後程式能自動開始執行。
STM32 SDIO外設的初始化
串列埠初始化完畢後便開始執行Card_Init函式:SDIO卡初始化函式。
- printf("Initialization begins...\n");
- SDIO->POWER = SDIO_POWER_PWRCTRL;
- SDIO->CLKCR = SDIO_CLKCR_CLKEN | 178; // 初始化時最高允許的頻率: 72MHz/(178+2)=400kHz
- delay(5); // 延時可防止CMD5重發
只有當該暫存器的第1~0位同時為1時才能啟動該外設。
在STM32F10x.h標頭檔案中,有如下的定義:
- /****************** Bit definition for SDIO_POWER register ******************/
- #define SDIO_POWER_PWRCTRL ((uint8_t)0x03) /*!< PWRCTRL[1:0] bits (Power supply control bits) */
- #define SDIO_POWER_PWRCTRL_0 ((uint8_t)0x01) /*!< Bit 0 */
- #define SDIO_POWER_PWRCTRL_1 ((uint8_t)0x02) /*!< Bit 1 */
接著配置SDIO_CLKCR暫存器。該暫存器的CLKEN位決定是否啟用時鐘引腳SDIO_CK,即是否向PC12引腳輸出時鐘訊號。CLKDIV為時鐘分頻係數。
PC12引腳上的頻率為:SDIO外設的頻率 ÷ (CLKDIV + 2)
因為SDIO是AHB總線上的外設,所以SDIO外設的頻率等於AHB匯流排的頻率(記為HCLK),為72MHz。
程式中配置的是CLKDIV=178,因此分頻後,在PC12引腳上輸出的時鐘頻率就是400kHz。這是SD卡在初始化時所允許的最高頻率。只有當SDIO總線上掛接的所有SD卡都初始化完畢了之後,這一頻率才允許提高。
然後呼叫delay函式延時5毫秒。延時的目的是上電後使器件做好準備,降低CMD5命令重發的可能性,但這不能完全防止CMD5重發。delay函式的實現如下:
- // 延時n毫秒
- void delay(uint16_t n)
- {
- TIM6->ARR = 10 * n - 1; // nms
- TIM6->PSC = 7199; // 72MHz/7200=10kHz
- TIM6->CR1 = TIM_CR1_URS | TIM_CR1_OPM; // UG不置位UIF, 非迴圈模式
- TIM6->EGR = TIM_EGR_UG; // 儲存設定
- TIM6->CR1 |= TIM_CR1_CEN; // 開始計時
- while ((TIM6->SR & TIM_SR_UIF) == 0); // 等待計時完畢
- TIM6->SR &= ~TIM_SR_UIF; // 清除溢位標誌
- }
CEN剛置位時,CNT=0。經過1/(10kHz)=0.1ms後,CNT從0跳變到1。經過4.9ms後,CNT從48跳變到49。經過5ms後,CNT剛好從49跳變到0。
SDIO卡的初始化流程見Part E1文件的圖3-2。首先以空引數(ARG=0)傳送一個CMD5命令,檢查有無迴應。若有迴應,則設定引數ARG後再次傳送CMD5,檢查迴應中的MP(Memory Present)位後決定之後的流程。
在STM32 SDIO外設中,使用SDIO_CMD暫存器傳送命令,使用SDIO_ARG暫存器設定命令引數。
在SDIO_CMD暫存器中,CMDINDEX決定命令號,CPSMEN=1時傳送命令(該位不會自動清零,只要寫完暫存器後該位為1,就傳送命令)。WAITRESP=00時不等待迴應,WAITRESP=01時等待48位的短迴應,WAITRESP=11時等待136位的的長迴應。迴應的內容儲存在RESP1~4暫存器中。
- /* 傳送CMD5: IO_SEND_OP_COND */
- SDIO->CMD = SDIO_CMD_CPSMEN | SDIO_CMD_WAITRESP_0 | 5;
- while (SDIO->STA & SDIO_STA_CMDACT);
- Card_CheckCommand(); // 為了保險起見還是要檢查一下是否要重發命令
- if (SDIO->STA & SDIO_STA_CMDREND)
- {
- SDIO->ICR = SDIO_ICR_CMDRENDC;
- Card_ShowShortResponse();
- }
- // 檢查命令是否收到了迴應, 若沒收到則重發命令
- void Card_CheckCommand(void)
- {
- while (SDIO->STA & SDIO_STA_CTIMEOUT)
- {
- SDIO->ICR = SDIO_ICR_CTIMEOUTC; // 清除標誌
- SDIO->CMD = SDIO->CMD; // 重發
- printf("Timeout! Resend CMD%d\n", SDIO->CMD & SDIO_CMD_CMDINDEX);
- while (SDIO->STA & SDIO_STA_CMDACT);
-
相關推薦
Marvell 88W8686/88W8782/88W8801 WiFi模組驅動程式的編寫
本文以STM32F1系列的微控制器為例,詳細講解Marvell公司的88W8686/88W8782/88W8801 WiFi模組驅動程式的編寫。編寫程式時為了程式碼簡短起見,直接用暫存器操作,不使用STM32庫函式。IDE採用Keil uVision5。為了儲存下
【程式】STM32F407VE微控制器驅動Marvell 88W8801 WiFi模組的程式(20181010版)
本程式所用的微控制器型號為:STM32F407VE PD14埠為復位引腳(PDN),請務必連線! 晶振用的是8MHz,請注意檢查自己的開發板,看看晶振是不是8MHz。如果是25MHz,請修改system_stm32f4xx.c檔案! 程式支援連線無密碼的熱點以及WEP、
【程式】Marvell 88W8782/88W8801 WiFi模組的韌體下載程式碼
本程式所用的微控制器型號為:STM32F103VEPB12接WiFi模組的復位引腳(RST),上電時RST=0先復位,然後RST=1開始工作。所用的WiFi模組為:88W8801。雖然綠色的板子上面寫的是88W8782,但實際上中間的黑色晶片用的是88W8801。【sd880
【程式】Marvell 88W8801 WiFi模組連線路由器,並使用lwip2.0.3建立http伺服器(20180807版)
本程式所用的微控制器型號為:STM32F103ZE 可以用STM32F103RE或STM32F103RD,但是STM32F103RC不行! PB12埠為復位引腳(PDN),請務必連線! 晶振用的是8MHz,請注意檢查自己的開發板,看看晶振是不是8MHz。如果是12MHz,請修
用一個例項來理解驅動程式編寫流程 (自用)
#include <linux/module.h> #include <linux/kernel.h> #include <asm/io.h> #include <linux/miscdevice.h> #include <linu
Linux驅動程式編寫&&應用程式對她的呼叫
Linux驅動程式的開發,我相信這是很多致力於嵌入式學習的騷年的終極夢想,不管是技術含量,還是薪金待遇,她都一一完美的體現了出來!當然,crk_13也一樣!不過,越是誘人的東西往往也越是可望而不可即,或許大家都對驅動開發的難度之大,要求之高有所耳聞!以我個人
STM32驅動Marvell 88W8686 WiFi模組程式碼說明(20180129版)
一、概述88W8686是Marvell公司2007年推出的一款SDIO Wi-Fi晶片,使用簡單的SPI或SDIO協議就可以與微控制器連線起來,操作方便,具有建立無密碼或帶有WEP密碼的Ad-Hoc熱點的功能,以及連線無密碼或帶有WEP、WPA/WPA2密碼的路由器的功能。不過有一點要注意,安卓手機預設是不能
88w8686 wifi模組的linux裝置驅動的測試
執行指令碼檔案wifisetup.sh來掃描並連線wifi熱點“cctest”,併為無線網絡卡分配IP地址192.168.43.25。如下所示。(注意,應事先把wifi_driver\FwImage目錄下的韌體程式helper_gspi.bin和gspi8686.bin放在
linux 核心模組程式設計之LED驅動程式(六)
我使用的是tiny6410的核心板,板子如下,淘寶可以買到 為了不與板子上的任何驅動發生IO衝突,我使用CON1那一排沒用到的IO口,引腳如下 LED1 LED2 LED3 LED4
wifi驅動的理解(4)——usb介面在wifi模組中的角色
轉載請註明出處:http://blog.csdn.net/Righthek 謝謝! 還有1天就到2017年了,回顧整個2016年至此,都沒發表過一篇技
wifi驅動的理解(3)——usb介面在wifi模組中的角色
轉載請註明出處:http://blog.csdn.net/Righthek 謝謝! 上一篇文章已經提到USB介面在wifi模組中的最重要兩個函式是usb_
wifi驅動的理解(2)——usb介面在wifi模組中的角色
轉載請註明出處:http://blog.csdn.net/Righthek 謝謝! 上一篇文章我們已經通過三條線索簡單地描述了wifi驅動的框架,現在我們開始深入到每條線索中。首先我們從USB裝置這條線
[Linux驅動煉成記] 06-博通WIFI模組AP6212配置
Buildroot 配置 Kernel -> wifi modle -> AP6212 Kernel -> wifi modle -> wifi fw local path (wifi韌體路徑) 相關安裝包主要是: buildroot/
13-編寫WIFI模組連線MQTT程式,和除錯助手測試通訊
直接上程式吧 local SubscribeTopic = "wifi/user".."/"..clientid PublishTopic = "wifi/device".."/"..clientid local UsartReceiveData=""; lo
wifi模組rtl8723b的驅動移植
一、前言 在除錯wifi驅動的時候會遇到很多坑,相信每個除錯驅動的工程師都深有體會吧。wifi驅動涉及到linux和android兩個大層面,任意一個環節出錯都有可能導致wifi驅動不能正常工作,現在我總結一下我在移植wifi驅動的時候所遇到的坑。 1.sdio
Tcar:智慧車之基於rtl8188eu驅動的wifi模組
2、WIFI模組 2.1 WIFI模組的驅動程式 http://www.realtek.com.tw https://github.com/lwfinger/rtl8188eu // wifi_hostapd_dnsmasq.rar/rtl81
STM32 超聲波測距模組HCSR-04 驅動程式
超聲波測距原理見:超聲波測距原理 超聲波測距模組:HC-SR04 採用定時器及外部中斷方式 /*******************************************************************************
如何解決 Windows 7 中安裝印表機驅動程式時,出現錯誤資訊"找不到指定模組"或"XXX.dll 檔案丟失"
文章簡介 在Windows7中安裝驅動程式時,出現錯誤資訊“找不到指定模組”或“XXX.dll 檔案丟失”,您可以參考本文的步驟嘗試解決問題 應用軟體執行時一般都是優先從自己的安裝目錄中呼叫所需的模組(.dll)檔案,如沒有所需檔案再到 Windows\System
基於ARM的模組方式驅動程式
基於ARM的模組方式驅動程式 作者:毛蘢瑋 / Saint 掘金:https://juejin.im/user/5aa1f89b6fb9a028bb18966a 微博:https://weibo.com/5458277467/profile?topnav=1&wvr=6&a
Linux 下wifi 驅動開發(二)—— WiFi模組淺析
一、什麼是wifi 模組 百度百科上這樣定義: Wi-Fi模組又名串列埠Wi-Fi模組,屬於物聯網傳輸層,功能是將串列埠或TTL電平轉為符合Wi-Fi無線網路通訊標準的嵌入式模組,內建無線網路協議IEEE802.11b.g.n協議棧以及TCP