嵌入式Linux&Android开发-WiFi&BT SDIO调试

目录

 

一、基本概念

WiFi

STA 模式 和 AP 模式

SDIO(Secure Digital I/O)

SDIO-WiFi 模块

二、项目中WiFi说明

三、rockchip WiFi启动流程简介

WiFi应用部分 wpa_supplicant

四、RK WiFi驱动移植流程

4.1 BSP已支持WiFi

4.2 BSP未支持WiFi

五、排查流程

5.1 检查DTS

5.2 排查DTS对应的GPIO设置

5.3检查电压电平

5.4 检查时钟

5.5 尝试单线模式

5.6 检查模块能否处于工作状态

5.7 确认Android层是否能够打开

5.8 其他问题

六、常用调试shell指令


一、基本概念

WiFi

WiFi英文全称是 WIreless-FIdelity,英文简称WiFi。

STA 模式 和 AP 模式

Sta模式: Station, 类似于无线终端,sta本身并不接受无线的接入,它可以连接到AP,一般无线网卡即工作在该模式。

AP模式: Access Point,提供无线接入服务,允许其它无线设备接入,提供数据访问,一般的无线路由/网桥工作在该模式下。AP和AP之间允许相互连接。

SDIO(Secure Digital I/O)

SDIO协议是由SD卡的协议演化升级而来的,很多地方保留了SD卡的读写协议,同时SDIO协议又在SD卡协议之上添加了CMD52和CMD53命令。

现在SDIO卡比较常见:

  • Wi-Fi card(无线网络卡)
  • CMOS sensor card(照相模块)
  • GPS card
  • GSM/GPRS modem card
  • Bluetooth card
  • Radio/TV card

SDIO-WiFi 模块

SDIO 接口的 WiFi,首先,它是一个 SDIO卡 设备,然后具备了 WiFi 的功能,所以 SDIO 接口的 WiFi 驱动就是在 WiFi 驱动外面套上了一个 SDIO 驱动 的外壳。

SDIO 驱动部分代码结构如下

drivers/mmc 下有 mmc卡、sd卡、sdio 卡驱动。

SDIO驱动仍然符合设备驱动的分层与分离思想。

设备驱动层(WiFi 设备): 
| 
核心层(向上向下提供接口) 
| 
主机驱动层(实现 SDIO 驱动)

二、项目中WiFi说明

在嵌入式开发中,WiFi在SOC中有两种存在方式:

一种是集成在SOC当中,芯片代表有MTK和高通的芯片,因为这两家芯片厂商的通讯技术都比较厉害所以一般都会在他们自己的SOC中添加WiFi的模块,从而降低成本和降低板子的面积。

另一种是应用处理器加WiFi模组的方式,常用的通讯接口有为SDIO、USB、PCIE,其中SDIO、USB最为常用。

常用的WiFi芯片厂商有NXP、瑞昱(Realtek)、博通Broadcom、MTK等,然后一些模组厂商会使用这些公司的芯片来做一下WiFi模组,常见的模组厂商有海华、高盛达等等,模组厂商会调制好一些WiFi的芯片射频参数,写入模组当中,从而降低直接使用芯片的难度,如果直接使用芯片在生产的时候需要调试WiFi的射频参数。所以使用模组的好处是降低生产成本,因为要调制射频参数需要买仪器,坏处是会增加使用成本模组一般都会比芯片贵上1块钱左右(量多的时候)。

为了降低成本,现在很多芯片都是集成了WiFi和蓝牙功能的二合一芯片,也就是一款模组同时支持WiFi和蓝牙功能。

所以我们不只看到有WiFi使用的SDIO接口还有用于蓝牙WiFi通讯的UART接口,还有PCM接口。我们播放歌曲的时候音乐的数据的传输使用的是UART接口,如果是蓝牙通话的时候使用的是PCM接口。所以我们可以在WiFi和蓝牙二合一的芯片上看到3种接口,其中SDIO是WiFi的,UART和PCM是蓝牙的。

嵌入式Linux&Android开发-WiFi&BT SDIO调试_第1张图片

三、rockchip WiFi启动流程简介

  • 开机对 WiFi 模块上电,并自动进行扫描 sdio 操作。
  • 系统启动打开 WiFi 操作时,分别对系统 sys/bus/sdio(sdio WiFi)sys/bus/pic (pcie WiFi )文件系统下的 uevent 进行读取。
  • 获取到 WiFi 芯片 vid pid 加载相应的 WiFi ko 驱动。
  • 识别到 WiFi 类型后加载不同的参数启动 WiFi。

WiFi应用部分 wpa_supplicant

wpa_supplicant是一个开源软件,在Android平台wpa_supplicant被谷歌修改并加入到了Android系统,在linux平台主要就是使用wpa_supplicant的原生版本。wpa_supplicant的作用就是向上对接用户的WiFi配网支持、配置参数支持,向下对接WiFi驱动和WiFi芯片通讯的桥梁。

四、RK WiFi驱动移植流程

4.1 BSP已支持WiFi

可通过芯片手册查看BSP支持WiFi模组列表,也可以通过kernel Config查看

输cd kernel入 make menuconfig,然后选择 Device Drivers --->Network device

suppor--->Wireless LAN,即可看到参与编译的 WiFi 驱动。

嵌入式Linux&Android开发-WiFi&BT SDIO调试_第2张图片

 RK 平台上所有的 WiFi 模块驱动都是放到内核 kernel/drivers/net/wireless/rockchip_wlan 目录,一般移植新的 WiFi 驱动,需要在 kernel/drivers/net/wireless 目录添加相应的 WiFi 模块的 Kconfig 和Makefile。

4.2 BSP未支持WiFi

WiFi驱动放到kernel里面

将供应商提供rtl8821CU WiFi驱动复制到kernel/drivers/net/wireless/rockchip_wlan/这个目录下面,同时修改当前目录下的Kconfig文件和Makefile文件。

Kconfig

source "drivers/net/wireless/rockchip_wlan/rtl8189es/Kconfig"
source "drivers/net/wireless/rockchip_wlan/rtl8189fs/Kconfig"
source "drivers/net/wireless/rockchip_wlan/rtl8723bs/Kconfig"
source "drivers/net/wireless/rockchip_wlan/rtl8723bu/Kconfig"
source "drivers/net/wireless/rockchip_wlan/rtl8723cs/Kconfig"
source "drivers/net/wireless/rockchip_wlan/rtl8723ds/Kconfig"
source "drivers/net/wireless/rockchip_wlan/rtl8723du/Kconfig"
source "drivers/net/wireless/rockchip_wlan/rtl8822be/Kconfig"
source "drivers/net/wireless/rockchip_wlan/mvl88w8977/Kconfig"
xxxxxx 添加新WiFi驱动Kconfig

 Makefile

obj-$(CONFIG_RTL8723BS) += rtl8723bs/ 
obj-$(CONFIG_RTL8723BU) += rtl8723bu/ 
obj-$(CONFIG_RTL8723CS)        += rtl8723cs/ 
obj-$(CONFIG_RTL8723DS) += rtl8723ds/ 
obj-$(CONFIG_RTL8822BE)        += rtl8822be/ 
obj-$(CONFIG_RTL8723DU) += rtl8723du/
xxxxx 添加新WiFi编译信息

 根据原厂要求修改驱动内部makefile

修改rtl8822cs/makefile:
   CONFIG_PLATFORM_I386_PC=n
   CONFIG_PLATFORM_ARM_RK3188=y

有一些模块需要修改入口函数的,可以具体咨询RK&芯片厂家

修改wpa_supplicant的适配器部分

hardware/libhardware_legacy/wifi/rk_wifi_ctrl.c

static WiFi_device supported_WiFi_devices[] = {
        {"RTL8188EU",        "0bda:8179"},
        {"RTL8188EU",        "0bda:0179"},
        {"RTL8723DU",        "0bda:d723"},
        {"RTL8723BU",        "0bda:b720"},
        {"RTL8723BS",        "024c:b723"},
        {"RTL8822BS",        "024c:b822"},
        {"RTL8723CS",        "024c:b703"},
        {"RTL8723DS",        "024c:d723"},
        {"RTL8188FU",        "0bda:f179"},
        {"RTL8822BU",        "0bda:b82c"},
        {"RTL8189ES",        "024c:8179"},
        {"RTL8189FS",        "024c:f179"},
        {"RTL8192DU",        "0bda:8194"},
        {"RTL8812AU",        "0bda:8812"},
        XXXXXX添加新WiFi信息
        {"MTK7601U" ,   "148f:7601"},
        {"SSV6051",        "3030:3030"},
        {"ESP8089",        "6666:1111"},
        {"AP6354",        "02d0:4354"},
        {"AP6330",        "02d0:4330"},
        {"AP6356S",        "02d0:4356"},
        {"AP6335",        "02d0:4335"},
        {"AP6255",      "02d0:a9bf"},
        {"RTL8822BE",        "10ec:b822"},
};

wifi.c

WiFi_ko_file_name module_list[] = 
{ 
        {"RTL8723DU", RTL8723DU_DRIVER_MODULE_PATH, RTL8723DU_DRIVER_MODULE_ARG}, 
        {"RTL8723BU", RTL8723BU_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        {"RTL8188EU", RTL8188EU_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        {"RTL8192DU", RTL8192DU_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        {"RTL8822BU", RTL8822BU_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        {"RTL8822BS", RTL8822BS_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        {"RTL8188FU", RTL8188FU_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        {"RTL8189ES", RTL8189ES_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        {"RTL8723BS", RTL8723BS_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        {"RTL8723CS", RTL8723CS_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        {"RTL8723DS", RTL8723DS_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        {"RTL8812AU", RTL8812AU_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        XXXX 添加新WiFi信息
        {"RTL8189FS", RTL8189FS_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        {"RTL8822BE", RTL8822BE_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        {"MTK7601U",  MT7601_DRIVER_MODULE_PATH,    UNKKOWN_DRIVER_MODULE_ARG}, 
        {"SSV6051",     SSV6051_DRIVER_MODULE_PATH, SSV6051_DRIVER_MODULE_ARG}, 
        {"ESP8089",     ESP8089_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        {"AP6335",          BCM_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        {"AP6330",          BCM_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        {"AP6354",          BCM_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        {"AP6356S",         BCM_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        {"AP6255",          BCM_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        {"APXXX",           BCM_DRIVER_MODULE_PATH, UNKKOWN_DRIVER_MODULE_ARG}, 
        {"UNKNOW",       DRIVER_MODULE_PATH_UNKNOW, UNKKOWN_DRIVER_MODULE_ARG} 
 
};

修改dts

        //SDIO配置
        &sdio0 {
                clock-frequency = <100000000>; /*时钟修改的地方 如果SDIO读写识别,可调整时钟*/
                clock-freq-min-max = <200000 100000000>; /*时钟修改的地方*/
                supports-sdio; /*支持SDIO功能*/
                bus-width = <4>; /*4线模式,调试可改为1线测试*/
                disable-wp;
                cap-sd-highspeed; /*highspeed的SDIO外设*/
                cap-sdio-irq; /*SDIO中断*/
                keep-power-in-suspend; /*睡眠不断电*/
                mmc-pwrseq = <&sdio_pwrseq>; /*电源控制*/
                non-removable;
                num-slots = <1>;
                pinctrl-names = "default";
                pinctrl-0 = <&sdio0_bus4 &sdio0_cmd &sdio0_clk>;
                sd-uhs-sdr104; /* SDIO3.0 模式*/
                status = "okay";
        };
        //SDIO 外设的电源控制
        sdio_pwrseq: sdio-pwrseq {
                compatible = "mmc-pwrseq-simple";
                clocks = <&rk808 1>; /*提供32.768 LPO*/
                clock-names = "ext_clock"; /*外部时钟源*/
                pinctrl-names = "default";
                pinctrl-0 = <&WiFi_enable_h>;
                reset-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>; /* GPIO0_B2 */
        };
        //Wlan配置
        wireless-wlan {
                compatible = "wlan-platdata";
                rockchip,grf = <&grf>;
                WiFi_chip_type = "ap6255";
                sdio_vref = <1800>;
                //控制WiFi中断的GPIO
                WiFi,host_wake_irq = <&gpio0 3 GPIO_ACTIVE_HIGH>; /* GPIO0_a3 */
                status = "okay";
        };
        //bluetooth配置
        wireless-bluetooth {
                compatible = "bluetooth-platdata";
                clocks = <&rk808 1>;
                clock-names = "ext_clock";
                //WiFi-bt-power-toggle;
                uart_rts_gpios = <&gpio2 19 GPIO_ACTIVE_LOW>; /* GPIO2_C3 */
                //对应串口
                pinctrl-names = "default", "rts_gpio";
                pinctrl-0 = <&uart0_rts>;
                pinctrl-1 = <&uart0_gpios>;
                //对应引脚
                BT,reset_gpio    = <&gpio0 9 GPIO_ACTIVE_HIGH>; /* GPIO0_B1 */
                BT,wake_gpio     = <&gpio2 26 GPIO_ACTIVE_HIGH>; /* GPIO2_D2 */
                BT,wake_host_irq = <&gpio0 4 GPIO_ACTIVE_HIGH>; /* GPIO0_A4 */
                status = "okay";
        };

make menuconfig选择驱动

重新编译,生成新驱动.ko文件

烧录

全部工作完成后,就可以烧录全部的img,烧录完成后等待开机,然后在Android界面设置选项WiFi设置那里可以搜索到WiFi信号,然后就可以像正常的使用Android手机一样使用WiFi上网了。

SDIO WiFi注册成功会有如下Log:

mmc1: new ultra high speed SDR104 SDIO card at address 0001

查看sys/bus/sdio/devices也能看到设备,如果没有说明硬件有异常

$ ls sys/bus/sdio/devices/                  
mmc1:0001:1 mmc1:0001:2 mmc1:0001:3

五、排查流程

5.1 检查DTS

关注时钟、IO、WiFi_chip_type

5.2 排查DTS对应的GPIO设置

确定复用引脚已配置、方向配置、测试高低电平

使用io命令shell
io -4 -w 0xFF77e008 0x0fff0000
sysfs使用echo命令shell
echo xxx > /sys/class/gpio/export
echo out > /sys/class/gpio/gpioxxx/direction
echo 0 > /sys/class/gpio/gpioxxx/value
echo 1 > /sys/class/gpio/gpioxxx/value
使用debugfs查看

5.3检查电压电平

电源电压,VDDIO、VBAT的电压,WiFi_REG_ON上电及复位控制信号

电源控制:

echo 0 > /sys/class/rkWiFi/power //对WiFi模块掉电 
echo 1 > /sys/class/rkWiFi/power //对WiFi模块上电 
echo 1 > /sys/class/rkWiFi/driver //命令会调用模块的驱动的初始化操作,初始化成功后看到wlan0 节点;

如果执行上面命令对模块进行上下电,而实际测量对应管脚不受控,可以通过io 命令读取对应的寄存器,确认是否写入,如果正确写入但是实际测量不受控请检查硬件部分;

对于sdio接口的模块,执行” echo 1 > /sys/class/rkWiFi/driver”命令 ,正常情况下 sdio_clk 和sdio_cmd 能够测量到相关波形,内核打印上能够看到如下打印,如果没有测量到波形也没有看到如下打印,根据配置文档检查是否正确配置sdio;

WL_REG_ON 主要用于上电,休眠的时候,请保持该GPIO上电,否则会丢失WiFi内部的状态,导致WiFi唤醒失败;

WL_HOST_WAKE 主要用于WiFi设备有数据的时候,唤醒CPU,进入中断,关于中断流程上面已经说过。

5.4 检查时钟

32.768K的LPO, 37.4M晶振主时钟,SDIO_CLK、SDIO_CMD 的波形

同时测量执行echo 1 > /sys/class/rkWiFi/driver 时 外部晶体是否有起振,如果扫描时没有起振检查下硬件;同时建议测量外部晶体频偏,频偏比较大情况下,会出现能扫描到模块但是初始化失败;除检查晶振外,正基系列还需要外部32k,测量32k的峰峰值(峰峰值>=0.7*VDDIO && 峰峰值 <= 1*VDDIO);【注:频偏和峰峰值一定要测量检查,频偏过大峰峰值不对会影响WiFi(扫描连接热点)和蓝牙(扫描连接设备))】

5.5 尝试单线模式

如果降低clk依然不行,考虑使用sdio单线模式方法如下

&sdio {
...
bus-width = <1>;

使用 sdio 单线模式。如果单线模式可以而使用4线模式不行,检查硬件上sdio_data0~sdio_data3 四根线的线序是否弄错;

如果降低clk,使用单线模式均不可以检查下是否是使用最新的sdk代码和最新的WiFi驱动(ftp服务器上有相关patch);

上述检查均无结果,check 图纸 是否周围器件有贴错器件;

5.6 检查模块能否处于工作状态

netcfg wlan0 up 或busybox ifconfig wlan0 up //执行完成后检查 wlan0 是否处于up状态;如果没有处于up状态;做如下检查确认

1 确认相关固件是否存在(正基系列,通过看内核日志可以看到),固件不存在考虑到ftp下载固件;此时如果还报其他错误从两个方面排查1 上电时序,2检查sdio部分走线;

2 尝试使用原始最新的sdk代码做测试;(有客户出现过,上层做了相关修改导致WiFi初始化成功,但是执行netcfg wlan0 up 报告无法识别 ioctl 命令等奇怪错误,原生sdk生成的sysytem.img 没有问题)

执行iwlist wlan0 scanning ,测试扫描热点是否正常(3368平台下执行iwlist 命令有问题,忽略此步骤)

5.7 确认Android层是否能够打开

述检查各个步骤可以工作,而通过上层settings界面打开失败;以下几个方面排查

1 dts中的WiFi_type配置是否正确;cat /sys/class/rkWiFi/chip 确认 下 打印的结果和你的模块是否匹配

2 确认 wpa_supplicant 相关服务是否生成,libhardware_leacy 启动的wpa服务是否正确;

3 抓取logcat 日志上传readmine

5.8 其他问题

无法连接热点
1.无法连接热点,正基系列模块检查确认晶振频偏和32k峰峰值; 
rtl模块考虑驱动配置是否正确,是否匹配; 
2.检查确认p2p wlan0 的mac地址是否一致如果检查是否有调用rockchip_WiFi_mac_addr读取mac地址,如果有考虑直接在该函数中return -1; 
3.检查确认是否有做RF指标测试以及天线匹配测试 
4.上述检查没有问题,做如下测试 (首先用给手机连接所测试的热点做确认) 
1 连接无加密热点 2 连接加密热点 测试能否连接成功,并记录对应的logcat 日志与内核日志(开机到打开WiFi以及连接热点的整个过程)
softap 无法打开(正基系列的)
1.查看打开热点时的内核日志,确认下 下载固件是否正确 ,正基系列的模块 softap 下载的固件一般是带ap后缀结尾的; 
2.固件下载没有问题 ,考虑使用原始的sdk代码做测试
P2P 问题
P2p 无法打开:确认是否有p2p节点,有p2p节点的检查确认mac地址是否与wlan0 一样,如果一样按照热点问题中的step 2 处理; 
第一次开机能够打开,重启后无法打开:考虑检查上电时序,目前遇到都是rtl的模块出现过,问题在于chipen 脚不受控,建议做成受控,在重启时对chipen脚下电;可以通过如下方法实现net/rfkill-wlan.c中的rfkill_wlan_driver 中增加shutdown函数 在该函数中对chip_en 下电;
休眠唤醒出现WiFi无法打开: 
1 对比检查休眠唤醒前后 sdio 的iomux 是否发生变更 
2 对比 休眠前后以及休眠中 WiFi的外围供电是否发生变更
吞吐率问题
1. pcb检查,一定要让模块原厂检查确认 pcb是否存在问题
2. RF指标确认是否ok
3. 天线是否做过匹配
4. Sdio 接口的可以考虑 提到sdio的clk 启用sdio3.0【前提 平台支持 sdio3.0 ,模块支持sdio3.0】

六、常用调试shell指令

  • 打开和关闭WiFi
打开WiFi指令
svc WiFi enable
关闭WiFi指令
svc WiFi disable
查看wpa_supplicant是不是已经起来了
ps | grep WiFi 
  • 打开和关闭蓝牙BT:

关闭:adb shell settings put global bluetooth_on 0
打开:adb shell settings put global bluetooth_on 1
查询:adb shell settings get global bluetooth_on
  • 查询蓝牙开启状态:
adb shell settings get global bluetooth_on
=》0: 未开启  1: 已开启
  • 获取mac地址:
方法1:
adb shell settings get secure bluetooth_address
=》如:00:00:00:00:00:01

你可能感兴趣的:(嵌入式Linux,Android入门教程,linux,android,arm,驱动开发)