K230 SDK IoT WiFi AiW4211LV10驱动开发指南#

1. 功能介绍#

AiW4211LV10是一款低功耗IoT WiFi芯片,我司采用该芯片平台设计了一款AiW4211LV10开发板,该开发板可插入K230 EVB板的TF卡插槽实现接入。K230 EVB加载AiW4211LV10驱动之后,可以生成wlan0无线网卡,实现网络数据通信。

2. 模块依赖#

硬件上依赖AiW4211LV10开发板,依赖K230 EVB开发板,K230 EVB为WiFi提供电源及中断检测连线。

软件上依赖于K230 SDIO主控驱动,依赖GPIO驱动的完备,需要emmc引导启动实现。

2.1 操作系统#

当前驱动支持linux 4.9、linux 4.17和linux 5.10.4

2.2 硬件环境#

K230 EVB开发板设置emmc启动,空出TF卡插槽用于AiW4211LV10开发板接入。

K230 EVB开发板飞线到AiW4211LV10开发板排针。连接关系如下:

表 2-1 飞线关系

Link1

Link2

Link3

Link4

Link5

K230排针

J5 PIN16 (5V)

J8 PIN9 (GPIO34)

WiFi排针

J6 PIN1 (5V)

J2 PIN3 (SDIO_INT_OUT)

J2 PIN4 (TX)

J2 PIN5 (RX)

J2 PIN6 (GND)

TTL-USB

RX

TX

GND

备注:TTL-USB与WiFi的连线主要是为了观察WiFi的固件输出,可以不连接

3. 模块配置#

3.1 设备树修改#

3.1.1 配置引脚function#

修改uboot设备树arch/riscv/dts/k230_evb.dts,配置K230 EVB IO52引脚功能为GPIO,方向为input:

&iomux {
pinctrl-names = "default";
pinctrl-0 = <&pins>;
pins: iomux_pins {
pinctrl-single,pins = <

......

(IO52) ( 0 <<SEL | 0<<SL | BANK_VOLTAGE_IO50_IO61<<MSC | 1<<IE | 0<<OE | 0<<PU | 1<<PD | 7<<DS | 0<<ST )
}
}

3.1.2 配置GPIO控制器#

修改linux设备树arch/riscv/boot/dts/kendryte/gpio_provider.dtsi,配置K230 EVB GPIO52控制器:

/ {

......

gpio52: gpio52@9140c000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "canaan,k230-apb-gpio";
reg = <0x0 0x9140c000 0x0 0x1000>;
interrupt-controller;
interrupt-parent = <&intc>;
#interrupt-cells = <2>;
interrupts = <84 IRQ_TYPE_EDGE_RISING>;

port52: gpio-controller@0 {
gpio-controller;
#gpio-cells = <2>;
nr-gpios = <1>;
reg-bank = <0>;
id = <52>;
};
};
};

3.1.3 配置SDHCI1参数#

修改linux设备树arch/riscv/boot/dts/kendryte/k230_evb.dtsi,配置对应sdio主控参数:

sdcard: sdhci1@91581000 {
compatible = "snps,dwcmshc-sdhci";
reg = <0x0 0x91581000 0x0 0x1000>;
interrupt-parent = <&intc>;
interrupts = <144>;
interrupt-names = "sdhci1irq";
clocks = <&dummy_sd>,<&dummy_sd>;
clock-names = "core", "bus";
max-frequency = <50000000>;
bus-width = <4>;
//cd-gpios = <>;
no-1-8-v;
cap-sd-highspeed;
sdhci,auto-cmd12;
status = "okay";
};

3.2 内核配置项#

通过内核配置将AiW4211LV10驱动编译为内核模块,并将必要的协议及驱动编入内核。

使能kprobes:

> General architecture-dependent options

|| [*] Kprobes

将cfg80211编入内核,注意需要选中 cfg80211 wireless extensions compatibility:

> Networking support > Wireless

│ --- Wireless │ │

│ │ <*> cfg80211 - wireless configuration API │ │

│ │ [ ] nl80211 testmode command │ │

│ │ [ ] enable developer warnings │ │

│ │ [ ] cfg80211 certification onus │ │

│ │ [*] enable powersave by default │ │

│ │ [ ] cfg80211 DebugFS entries │ │

│ │ [*] support CRDA │ │

│ │ [*] cfg80211 wireless extensions compatibility │ │

│ │ [ ] lib80211 debugging messages │ │

│ │ < > Generic IEEE 802.11 Networking Stack (mac80211)

将AiW4211LV10驱动编译成内核模块,注意需要选中 IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP):

> Device Drivers > Network device support > Wireless LAN

│ --- Wireless LAN │ │

│ │ [ ] mac80211-based legacy WDS support │ │

│ │ [ ] ADMtek devices │ │

│ │ [*] Aich devices │ │

│ │ <M> Aich AiW4211LV10 (SDIO) support │

│ │ [ ] Atheros/Qualcomm devices │ │

│ │ [ ] Atmel devices │ │

│ │ [ ] Broadcom devices │ │

│ │ [ ] Cisco devices │ │

│ │ [ ] Intel devices │ │

│ │ [*] Intersil devices │ │

│ │ <*> IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)

│ │ [ ] Support downloading firmware images with Host AP driver │ │

│ │ [ ] Marvell devices │ │

│ │ [ ] MediaTek devices │ │

│ │ [ ] Microchip devices

3.3 SDIO主控增加扫描接口#

AiW4211LV10驱动需要依据WiFi所接入的槽位发起SDIO扫描,因此特封装plat_sdio_rescan接口函数。修改drivers/mmc/host/sdhci-of-dwcmshc.c文件如下:

static unsigned int slot_index = 0;
static struct mmc_host \*__mmc__host[3] = {NULL};
int plat_sdio_rescan(int slot)
{
struct mmc_host \*mmc = \__mmc__host[slot];
if (mmc == NULL) {
pr_err("invalid mmc, please check the argument\\n");
return -EINVAL;
}

mmc_detect_change(mmc, 0);
return 0;
}

static int dwcmshc_probe(struct platform_device \*pdev)
{

......

priv->bus_clk = devm_clk_get(&pdev-\>dev, "bus");
if (!IS_ERR(priv->bus_clk))
clk_prepare_enable(priv->bus_clk);
__mmc__host[slot_index++] = host->mmc;
err = mmc_of_parse(host->mmc);
if (err)
goto err_clk;

......

}

4. 模块编译#

在SDK顶层执行make linux,随内核一同编译,ko临时存储在output/k230_evb_defconfig/little/linux/drivers/net/wireless/aich/aiw4211lv10/目录。

5. 模块启动#

5.1 WiFi固件#

在K230 SDK当中WiFi固件AiW4211L_demo_allinone.bin以二进制文件形式提供,如需源码请联系我们。

固件存储路径:k230_sdk/src/little/utils/firmware/AiW4211L_demo_allinone.bin

5.2 驱动加载#

在硬件环境配置完成后上电启动,执行以下指令即可实现驱动加载:

modprobe aiw4211lv10 或者 modprobe aiw4211lv10 mmc=1 gpio=52

当前驱动支持传入mmc主控编号及用于中断检测的gpio编号,可以实现较为灵活的硬件配置,如果不传参则分别使用代码中规定的默认值1和52。

驱动加载完成后,使用ifconfig -a指令可以看到已经生成了无线网卡wlan0。

5.3 网络配置#

启动配置工具server端并置于后台运行:iotwifi_link &

该工具的功能角色类似于wpa_supplicant。iotwifi_link首先会将wlan0 up起来,然后从WiFi设备侧同步mac地址及ip地址到host端。

运行配置工具client端,控制WiFi接入AP及设置其他参数:iotwifi_cli –config /etc/wifi.conf

运行配置工具client端,控制WiFi进入深睡模式:iotwifi_cli –dirsleep

/etc/wifi.conf是WiFi工作参数配置文件,以json格式编写,基本上是对wifi_config_t结构体的映射,具体可参考6.1.2章节。

6. API参考#

AiW4211LV10驱动加载后生成的无线网卡与一般WiFi网卡无异,因此网络通信功能无特殊API需要说明。

除基本的网络通信外,K230与WiFi还存在两个消息通信接口,需要重点说明。

6.1 config接口#

6.1.1 API#

int kd_wifi_config(wifi_config_t *config)

配置WiFi工作参数:

  • 配置目标AP的名称、密码、认证及加密方式

  • 配置WiFi休眠等级,苏醒周期以及可唤醒的gpio

  • 配置tcp keepalive时间参数等

6.1.2 数据结构#

6.1.2.1 wifi_config_t#
typedef struct {
unsigned int config_mask;
#define CFG_MASK_SLEEP (1 << 0)
#define CFG_MASK_CONNECT (1 << 1)
#define CFG_MASK_KEEPALIVE (1 << 2)
wifi_sleep_t sleep;
wifi_connect_t conn;
wifi_keepalive_t keepalive;
} wifi_config_t;

表 6-1 wifi_config_t结构体成员

成员

说明

config_mask

配置目标项掩码,使能或屏蔽目标项,例如全部配置则:config_mask = CFG_MASK_SLEEP|CFG_MASK_CONNECT|CFG_MASK_KEEPALIVE; CFG_MASK_SLEEP:配置休眠参数,CFG_MASK_CONNECT:配置AP连接参数,CFG_MASK_KEEPALIVE:配置tcp keepalive参数

sleep

休眠参数

conn

AP连接参数

keepalive

tcp keepalive参数

6.1.2.2 wifi_sleep_t#

typedef struct
{
unsigned int level;
#define WIFI_SLEEP_LIGHT 1
#define WIFI_SLEEP_DEEP 2
#define WIFI_SLEEP_ULTRA 3
unsigned int period;
union
{
/*
* gpioX_wake: 0---disable, 1---enable
*/
struct {
unsigned int gpio0_wake:1;
unsigned int gpio1_wake:1;
unsigned int gpio2_wake:1;
unsigned int gpio3_wake:1;
unsigned int gpio4_wake:1;
unsigned int gpio5_wake:1;
unsigned int gpio6_wake:1;
unsigned int gpio7_wake:1;
unsigned int gpio8_wake:1;
unsigned int gpio9_wake:1;
unsigned int gpio10_wake:1;
unsigned int gpio11_wake:1;
unsigned int gpio12_wake:1;
unsigned int gpio13_wake:1;
unsigned int gpio14_wake:1;
};
unsigned int wake_gpios;
};
} wifi_sleep_t;

表 6-2 wifi_sleep_t结构体成员

成员

说明

level

休眠等级 WIFI_SLEEP_LIGHT:浅睡 WIFI_SLEEP_DEEP:深睡,主要休眠模式 WIFI_SLEEP_ULTRA:超深睡,只有3/5/7/14号gpio可唤醒,目前不使用

period

苏醒周期,有效数值33~~4000ms。WiFi周期性从休眠态醒来,检测AP是否有发给自己的数据缓存

wake_gpios

enable或disable可唤醒WiFi的gpio(WiFi侧gpio)

6.1.2.3 wifi_connect_t#

typedef struct
{
char ssid[EXT_WIFI_MAX_SSID_LEN + 1];
ext_wifi_auth_mode auth;
char key[EXT_WIFI_MAX_KEY_LEN + 1];
unsigned char bssid[EXT_WIFI_MAC_LEN];
ext_wifi_pairwise pairwise;
} wifi_connect_t;

表 6-3 wifi_connect_t结构体成元

ssid

AP名称

auth

认证类型 EXT_WIFI_SECURITY_OPEN EXT_WIFI_SECURITY_WEP EXT_WIFI_SECURITY_WPA2PSK EXT_WIFI_SECURITY_WPAPSK_WPA2PSK_MIX EXT_WIFI_SECURITY_WPAPSK EXT_WIFI_SECURITY_WPA EXT_WIFI_SECURITY_WPA2 EXT_WIFI_SECURITY_SAE EXT_WIFI_SECURITY_WPA3_WPA2_PSK_MIX EXT_WIFI_SECURITY_UNKNOWN

Key

AP密码

bssid

AP bssid,一般为AP mac地址

pairwise

加密类型 EXT_WIFI_PARIWISE_UNKNOWN EXT_WIFI_PAIRWISE_AES EXT_WIFI_PAIRWISE_TKIP EXT_WIFI_PAIRWISE_TKIP_AES_MIX

6.1.2.4 wifi_keepalive_t#

typedef struct
{
unsigned char svrip[16];
unsigned short svrport;
unsigned short tcp_keepalive_time;
unsigned short tcp_keepalive_intvl;
unsigned short tcp_keepalive_probes;
unsigned short heartbeat_intvl;
unsigned short heartbeat_probes;
} wifi_keepalive_t;

表 6-4 wifi_keepalive_t结构体成员

svrip

server端ip地址

svrport

server端端口号

tcp_keepalive_time

TCP层keepalive心跳包常规发送周期,秒

tcp_keepalive_intvl

TCP层keepalive心跳包无回应之后新的发送周期,秒

tcp_keepalive_probes

TCP层keepalive心跳包无回应计数超过该阈值之后,判断TCP连接异常,断开重连

heartbeat_intvl

应用层心跳包发送周期,秒

heartbeat_probes

应用层心跳包无回应计数超过该阈值之后,判断socket连接异常,断开重连

6.2 sleep接口#

int kd_wifi_sleep(void)

控制WiFi进入休眠,休眠相关参数在config API当中设置。

7. 基本性能测试#

7.1 吞吐量测试#

在办公室环境使用iperf进行网络吞吐量测试,PC通过网线接入AP,K230 EVB通过AiW4211LV10接入同一AP,分别在两端启动iperf工具,交叉测试上行及下行吞吐量。

client:iperf -c xxx.xxx.xxx.xxx -i 2 -t 300

server:iperf -s -i 2

dual:iperf -c xxx.xxx.xxx.xxx -i 2 -t 300 -d

表 7-1 TCP吞吐量粗测数据

WiFi ROLE

Bandwidth(Mbits/sec)

client

12.2

server

20.3

client:iperf -c xxx.xxx.xxx.xxx -i 2 -t 300 -u -b 25M

server:iperf -s -i 2 -u

表 7-2 UDP吞吐量粗测数据

WiFi ROLE

Bandwidth(Mbits/sec)

Jitter(ms)

Lost/Total Datagrams

client

17.8

1.341

1571/455457 (0.34%)

server

21.0

1.064

1/534990 (0.00019%)

7.2 文件传输测试#

分别在PC与K230 EVB端架设nginx服务器,并分别使用wget拉取544MB大文件,并校验拉取文件的MD5值,测试150次无异常。