目前收集到的 88W8686资料:
Mavell 88W8686 数据手册(Rev D,2007年4月).pdf (2647 K) 下载次数:1174
WM-G-MR-09_应用电路(环隆电气).pdf (180 K) 下载次数:434
SDIO(SPI)_WIFI_Linux驱动分析.pdf (1319 K) 下载次数:718
XG-182M Embedded WLAN Module.pdf (458 K) 下载次数:987
linux下的源代码:
GSPI-8686-LINUX26-BULVERDE-9.70.3.p20-26409.P42.rar (354 K) 下载次数:931
FwImage.rar (82 K) 下载次数:785
GSPI-8686-LINUX26-BULVERDE-9.70.3.p20-26409.P42.zip (949 K) 下载次数:324
AppNote-GSPI8686-MacRxOptiimization.pdf (317 K) 下载次数:319
BAT-GSPI-8686-BULVERDE26-9.70.3.p20-26409.P42_BAT4.4.pdf (48 K) 下载次数:248
GSPI-8686-LINUX26-BULVERDE-9.70.3.p20-26409.P42 - Release Notes.pdf (40 K) 下载次数:242
推荐一个讨论WIFI的好帖子:
http://bbs.21ic.com/icview-160285-7-1.html
======================================================================
现在WIFI热点很多、无线路由器已经白菜价格了,我也一直想在STM32平台低成本实现WIFI通信。上Linux,WINCE太复杂,开发环境和STM32的环境相比,不是一个数量级。要学的东西太多。 因此决定利用业余时间尝试下 STM32 裸机无系统 + WIFI 方案。不过现在对WLAN协议一无所知,不知道编译后的代码空间和RAM空间需求。先弄套源码试试再说。
2012-03-17 花了大约6个小时
1. 首先从WIFI芯片选型上,决定选择常用的比较容易购买的Marvell 88W8686芯片。考虑先购买成品SDIO (带SPI)接口的88W8686模块进行调试。
先移植SPI接口,再移植SDIO接口。 淘宝有SDIO接口的WIFI模块,插入STM32开发板的SD卡接口即可实现WIFI功能。硬件比较容易实现
。(如果成功,之前购买了安富莱STM32开发板的用户就可以通过购买SDIO接口的WIFI模块学习WIFI了)
2. 到网上收集了一些资料。有了些初步的了解
(1)88W8686 每次上电需要下载固件 (可以通过STM32的SPI接口或SDIO接口访问88W8686寄存器的方式下载固件,也可以控制88W8686从SPI接口引导自己加载固件)
两个二进制固件文件: helper_gspi.bin (3K)和gspi8686.bin (117K),共120K字节。这是Marvell官方提供的固件,没有源码的。不过我们也不需要研究其源码,只需要将其下载到88W8686内部即可。
88W8686有2个SPI接口,一个叫SPI (设备接口,可以连接串行Flash),一个叫G-SPI(主机接口,和STM32的SPI相连),STM32的命令通过G-SPI接口发送。
后期我们设计WIFI模块的时候,可能考虑加上一片SPI串行Flash存储固件,这样就可以通过发送简单的命令,让其自动从SPI Flash加载固件。这样做有2个好处:
(a)可以加快加载速度,按照最大50M的时钟访问SPI串行Flash。
(b)避免120K字节固件占用STM32有限的Flash空间。留出更多的空间做应用,同时大幅度降低调试下载时间。
(2) 实现的难点在于WLAN协议以及WLAN和TCP/IP协议栈的接口软件移植。底层SPI接口和SDIO接口读写寄存器应该是比较好实现的。
(3)移植方案:基于Linux的驱动源码,尽量不修改文件夹结构,也少改WLAN部分的源码,因为对WLAN协议不熟,修改了后可能导致很多问题,不便于比对查找问题。通过单独增加一个接口文件,重载Linux系统特有的函数,一些特定的宏也重新指定,保证编译通过。看懂所有的源代码是不可能的,那样太花时间。我的首要目的是创建一个MDK工程,将所有的源码文件加入工程,然后编译通过。调试是下一步事情。只要保证修改过的地方都有注释,确认不会影响整体流程,成功的可能性还是比较大的。
2. 阅读Linux下的88W8686驱动源码 (基于多任务系统,驱动程序框架,大量的设备、文件、链表等概念,确实有些复杂)
(1) 解压 GSPI-8686-LINUX26-BULVERDE-9.70.3.p20-26409.P42.zip
(2) 创建SourceInsight工程,方便浏览代码
(3) 找到了底层接口文件: if_gspi.c (通过GSPI访问88W8686寄存器的接口函数) 和 gspi_io.c (这是配置CPU的SPI接口以及DMA之类的)。 这个地方不用细看了,到时候移植代码的时候需要大改。具体编码的时候,可以先将函数内部全部注释掉,保证整个工程编译能够通过。
(4) 找主函数费了很多周折,不过SourceInsight很强大,一步步跟踪跳转,终于找到了。乱翻代码,无意中看到了 wlan_process_rx_command() 函数,从字面理解就是处理无线AP发过来的命令,于是顺藤摸瓜,看这个函数在哪里被调用。它被wlan_main.c 中的wlan_service_main_thread() 调用。打开这个函数一看,所有的收发命令都在这个函数处理。这个函数是一个线程函数,也就是和主任务同步运行的函数,是一个 for (;;) 死循环。如果要移植到裸机程序(无操作系统),则需要将for循环去掉,然后有主程序轮询调用或者有中断触发调用。
(5) wlan_service_main_thread() 函数只看了前面几行,有个结构体指针变量 wlan_adapter *Adapter = priv->adapter;顺便看了下 struct _wlan_adapter 这个结构体,成员变量超多,估计50个以上是有的,很多是缓冲区,加起来估计好几KB了。在这个地方只是指针引用,没有分配变量空间。肯定在某个地方申明了一个全局的结构变量,也不排除动态分配。很多函数之间的数据交换,都可以通过这个超大结构体指针互访。这是耗内存大户,需要特别关注。
这个函数里面用到 add_wait_queen() ,谷歌搜索了下,是把当前进程加入等待队列,等待事件唤醒。裸机程序没有任务等待队列,后面移植的时候可以直接去掉。
(6)继续向前追溯,wlan_service_main_thread() 这个函数被wlan_add_card(void *card)调用。字面理解是添加网卡设备的函数(典型的驱动编程思想)。
先大致看下它调用了哪些函数。
a) dev = alloc_etherdev(sizeof(wlan_private))); 分配以太网设备,不太理解,估计和Linux上层TCP/IP协议栈关联,这个地方以后肯定要替换掉。
b) priv->adapter = kmalloc(sizeof(wlan_adapter), GFP_KERNEL) 之前的猜测没错,它是通过动态分配内存的方式建立这个Adapter全局变量的。不过 kmalloc 函数标准c不支持,这个地方需要替换。
动态分配空间会占用堆空间,因此stm32初始化文件中的堆空间就要预留的足够大。
c)遇到 SET_MODULE_OWNER(dev); Sourceinsight没有显示跳转,看来是Linux编译器特有的关键字。google一下,SET_MODULE_OWNER(scull_fops)的实现(&scull_fops)-> owner = THIS_MODULE; 当时时展开替换掉即可。也可能对于裸机程序无用。到改代码的时候再说吧。
d)类似的还有 INIT_LIST_HEAD(&priv->adapter->CmdFreeQ); 宏函数。
Sourceinsight中没有加上彩色的宏和函数(也就是没有定义的),一般都是要修改的,因为在源码中没找到,那就是编译器特有的。 初略google了下,和链表有关。这个地方后期得花点时间更改了。
e) wlan_add_card这个函数懒得看了,估计很多语句得大动手术,到时再说吧。
(7) 继续向前追溯,
wlan_add_card
被 wlan_init_module调用. 函数很简单,注册了添加WLAN卡和卸载WLAN卡的函数。这和操作系统相关了。到此为止,我们不必再向前追溯了,因为裸机程序不需要这些概念。
因此,我们只要从 wlan_add_card()函数开始正式阅读代码即可。
int
wlan_init_module(void)
{
int ret = WLAN_STATUS_SUCCESS;
ENTER();
if (sbi_register(wlan_add_card, wlan_remove_card, NULL) == NULL) {
ret = WLAN_STATUS_FAILURE;
goto done;
}
done:
LEAVE();
return ret;
}