A Step-by-Step Guide to Integrating AX210NGW Wi-Fi 6E With OK3576-C Development Board

In the era of ubiquitous connectivity, wireless communication technology is an essential part of embedded systems. Wi-Fi modules, as a crucial link between devices and networks, require high performance and compatibility. Intel's AX210NGW Wi-Fi 6E module, a high-performance wireless network adapter, supports the latest Wi-Fi 6E standard and Bluetooth 5.3, offering excellent transmission speeds and compatibility, thus providing strong support for wireless connectivity in embedded systems.

A Step-by-Step Guide to Integrating AX210NGW Wi-Fi 6E With OK3576-C development board

AX210NGW Wi-Fi 6E Module

To meet the demand for high-performance embedded control applications, this article details how to adapt the AX210NGW Wi-Fi 6E module (hereinafter “the module”) on the Forlinx Embedded OK3576-C development board, enabling developers to quickly start and utilize its performance advantages.

Note: The Bluetooth function of the Wi-Fi module has not been adapted. This article only covers Wi-Fi adaptation.

A Step-by-Step Guide to Integrating AX210NGW Wi-Fi 6E With OK3576-C development board

OK3576-C Development Board Interface Diagram

First, Wi-Fi module should be connected to the Forlinx OK3576-C development board. The Wi-Fi module uses an M.2 Key A + E interface, while the OK3576-C board lacks this interface. An M.2 to PCIe dual-band wireless network card adapter can be used for conversion.

Go to the kernel directory to start configuration:

forlinx@ubuntu20:~/3576$ cd kernel-6.1/
forlinx@ubuntu20:~/3576/kernel-6.1$ make menuconfig ARCH=arm64

Select in the following order:

Location:
  -> Device Drivers
-> Network device support (NETDEVICES [=y])
      -> Wireless LAN (WLAN [=y])
        -> Intel devices (WLAN_VENDOR_INTEL [=y])
          -> Intel Wireless WiFi Next Gen AGN-Wireless-N/Advanced-N/Ultimate-N (iwlwifi)  (IWLWIFI [=m]) 
            -> Intel Wireless WiFi MVM Firmware support (IWLMVM [=m])

Start to compile:

forlinx@ubuntu20:~/3576/kernel-6.1$ export CROSS_COMPILE=/home/forlinx/3576/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-
forlinx@ubuntu20:~/3576/kernel-6.1$ export PATH=$PATH:/home/forlinx/3576/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/
forlinx@ubuntu20:~/3576/kernel-6.1$ make ARCH=arm64 rk3576-evb1-v10-linux.img

Finally, copy the compiled module to the OK3576-C development board. Here, copy the module to the/root directory. Enter the kernel source path:

(1) drivers/net/wireless/intel/iwlwifi/iwlwifi.ko

(2) drivers/net/wireless/intel/iwlwifi/mvm/iwlmvm.ko

In addition, copy the Wi-Fi firmware and STA scripts to the/root directory for backup.

root@rk3576-buildroot:/root# ls
firmware.zip  fltest_wifi.sh  iwlmvm.ko  iwlwifi.ko

STA scripts can refer to the following contents, such as creating scripts by yourself, and remember to add executable permissions.

#!/bin/sh
cnt1=`ps aux | grep hostapd | grep -v grep  | wc -l`
if [ "$cnt1" != "0" ];then
        killall hostapd > /dev/null
fi
ifconfig uap0 down
function usage()
{
    echo "Usage: -i-s-p"
    echo "eg: ./wifi.sh -i mlan0 -s bjforlinx -p 12345678 "
    echo "eg: ./wifi.sh -i mlan0 -s bjforlinx -p NONE "
    echo " -i : mlan0 or mlan1"
    echo " -s : wifi ssid"
    echo " -p : wifi password or NONE"
}
function parse_args()
{
    while true; do
        case "$1" in
            -i ) wifi=$2;echo wifi $wifi;shift 2 ;;
            -s ) ssid=$2;echo ssid $ssid;shift 2 ;;
            -p ) pasw=$2;echo pasw $pasw;shift 2 ;;
            -h ) usage; exit 1 ;;
            * ) break ;;
        esac
    done
}
if [ $# != 6 ]
then
    usage;
    exit 1;
fi
parse_args $@
if [ -e /etc/wpa_supplicant.conf ]
then
    rm /etc/wpa_supplicant.conf
fi
    echo \#PSK/TKIP >> /etc/wpa_supplicant.conf
        echo ctrl_interface=/var/run/wpa_supplicant >>/etc/wpa_supplicant.conf
        echo ctrl_interface_group=0 >>/etc/wpa_supplicant.conf
        echo update_config=1 >>/etc/wpa_supplicant.conf
        echo network={ >>/etc/wpa_supplicant.conf
    echo ssid=\"$ssid\" >>/etc/wpa_supplicant.conf
        echo scan_ssid=1 >>/etc/wpa_supplicant.conf
    if [ $pasw == NONE ]
        then
                echo key_mgmt=NONE >>/etc/wpa_supplicant.conf
        else
                echo psk=\"$pasw\" >>/etc/wpa_supplicant.conf
                echo key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE >>/etc/wpa_supplicant.conf
        #       echo group=CCMP TKIP WEP104 WEP40 >>/etc/wpa_supplicant.conf
        fi
    echo } >>/etc/wpa_supplicant.conf
ifconfig -a|grep mlan0 |grep -v grep  > /dev/null
if [ $? -eq 0 ]
then
        ifconfig mlan0 down > /dev/null
fi
ifconfig -a|grep mlan1 |grep -v grep  > /dev/null
if [ $? -eq 0 ]
then
        ifconfig mlan1 down > /dev/null
fi
ifconfig -a|grep eth0 |grep -v grep  > /dev/null
if [ $? -eq 0 ]
then
        ifconfig eth0 down > /dev/null
fi
ifconfig -a|grep eth1 |grep -v grep  > /dev/null
if [ $? -eq 0 ]
then
        ifconfig eth1 down > /dev/null
fi
ifconfig -a|grep usb0 |grep -v grep  > /dev/null
if [ $? -eq 0 ]
then
        ifconfig usb0 down > /dev/null
fi
ps -fe|grep wpa_supplicant |grep -v grep > /dev/null
if [ $? -eq 0 ]
then
        kill -9 $(pidof wpa_supplicant)
fi
sleep 1
ifconfig $wifi up > /dev/null 
sleep 1
(wpa_supplicant -Dnl80211,wext -i$wifi -c/etc/wpa_supplicant.conf  >/dev/null) &
echo "waiting..."
sleep 3
wpa_cli -i$wifi status |grep COMPLETED |grep -v grep >/dev/null
if [ $? -eq 0 ]
then
        dhcpcd -i $wifi
        echo "Finshed!" 
else
        echo "try to connect again..."
        sleep 3
        wpa_cli -i$wifi status |grep COMPLETED |grep -v grep >/dev/null
                if [ $? -eq 0 ]
                then
                        dhcpcd -i $wifi
                                echo "nameserver 114.114.114.114" > /etc/resolv.conf
                        echo "Finshed!"
                else
                        echo "************************************************"
                        echo "connect faild,please check the passward and ssid"
                        kill -9 $(pidof wpa_supplicant)
                        exit 1
                fi
fi

Next, the firmware needs to be deployed to the /lib/firmware path of the board.

root@rk3576-buildroot:/root# unzip firmware.zip -d /lib/
root@rk3576-buildroot:/root# ls /lib/firmware/iwlwifi-ty-a0-gf-a0*
/lib/firmware/iwlwifi-ty-a0-gf-a0-59.ucode
/lib/firmware/iwlwifi-ty-a0-gf-a0-66.ucode
/lib/firmware/iwlwifi-ty-a0-gf-a0-71.ucode
/lib/firmware/iwlwifi-ty-a0-gf-a0-72.ucode
/lib/firmware/iwlwifi-ty-a0-gf-a0-73.ucode
/lib/firmware/iwlwifi-ty-a0-gf-a0-74.ucode
/lib/firmware/iwlwifi-ty-a0-gf-a0-77.ucode
/lib/firmware/iwlwifi-ty-a0-gf-a0-78.ucode
/lib/firmware/iwlwifi-ty-a0-gf-a0-79.ucode
/lib/firmware/iwlwifi-ty-a0-gf-a0-81.ucode
/lib/firmware/iwlwifi-ty-a0-gf-a0-83.ucode
/lib/firmware/iwlwifi-ty-a0-gf-a0-84.ucode
/lib/firmware/iwlwifi-ty-a0-gf-a0-86.ucode
/lib/firmware/iwlwifi-ty-a0-gf-a0-89.ucode
/lib/firmware/iwlwifi-ty-a0-gf-a0.pnvm

Next, load the module:

root@rk3576-buildroot:/root# insmod iwlwifi.ko 
[ 1996.796387] Intel(R) Wireless WiFi driver for Linux
[ 1996.803930] iwlwifi 0000:01:00.0: api flags index 2 larger than supported by driver
[ 1996.804075] iwlwifi 0000:01:00.0: TLV_FW_FSEQ_VERSION: FSEQ Version: 0.0.2.36
[ 1996.806470] iwlwifi 0000:01:00.0: loaded firmware version 72.a764baac.0 ty-a0-gf-a0-72.ucode op_mode iwlmvm
root@rk3576-buildroot:/root# insmod iwlmvm.ko 
[ 2005.034727] iwlwifi 0000:01:00.0: Detected Intel(R) Wi-Fi 6 AX210 160MHz, REV=0x420
[ 2005.036391] thermal thermal_zone6: power_allocator: sustainable_power will be estimated
[ 2005.036966] thermal thermal_zone6: failed to read out thermal zone (-61)
[ 2005.212436] iwlwifi 0000:01:00.0: loaded PNVM version 35148b80
[ 2005.228063] iwlwifi 0000:01:00.0: Detected RF GF, rfid=0x10d000
[ 2005.299203] iwlwifi 0000:01:00.0: base HW address: 4c:49:6c:f0:99:7a
[ 2005.323434] iwlwifi 0000:01:00.0 wlp1s0: renamed from wlan0

If there is the above information, it indicates that the module has been loaded successfully, and the network card node information can be seen:

root@rk3576-buildroot:/root# ifconfig wlp1s0
wlp1s0    Link encap:Ethernet  HWaddr 4C:49:6C:F0:99:7A  
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

Let's start testing the STA mode:

root@rk3576-buildroot:/root# ./fltest_wifi.sh -i wlp1s0 -s forlinx-wlan -p fl03123102650
ifconfig: SIOCGIFFLAGS: No such device
wifi wlp1s0
ssid forlinx-wlan
pasw fl03123102650
[ 2242.183049] rk_gmac-dwmac 2a220000.ethernet eth0: FPE workqueue stop
waiting...
try to connect again...
[ 2247.876030] wlp1s0: authenticate with ee:b9:70:81:7d:88
[ 2247.883905] wlp1s0: send auth to ee:b9:70:81:7d:88 (try 1/3)
[ 2248.015556] wlp1s0: send auth to ee:b9:70:81:7d:88 (try 2/3)
[ 2248.119667] wlp1s0: send auth to ee:b9:70:81:7d:88 (try 3/3)
[ 2248.172500] wlp1s0: authenticated
[ 2248.175429] wlp1s0: associate with ee:b9:70:81:7d:88 (try 1/3)
[ 2248.183347] wlp1s0: RX AssocResp from ee:b9:70:81:7d:88 (capab=0x1931 status=0 aid=42)
[ 2248.192191] wlp1s0: associated
[ 2248.218419] IPv6: ADDRCONF(NETDEV_CHANGE): wlp1s0: link becomes ready
main: control_open: Connection refused
dhcpcd-10.0.4 starting
dev: loaded udev
DUID 00:01:00:01:c7:92:c8:aa:4c:49:6c:f0:99:7a
wlp1s0: connected to Access Point: forlinx-wlan
wlp1s0: IAID 6c:f0:99:7a
wlp1s0: soliciting an IPv6 router
wlp1s0: rebinding lease of 192.168.81.206
wlp1s0: NAK: from 192.168.80.1
wlp1s0: soliciting a DHCP lease
wlp1s0: offered 192.168.81.206 from 192.168.80.1
wlp1s0: probing address 192.168.81.206/23
wlp1s0: leased 192.168.81.206 for 28800 seconds
wlp1s0: adding route to 192.168.80.0/23
wlp1s0: adding default route via 192.168.80.1
forked to background, child pid 1185
dhcpcd_fork_cb: truncated read 0 (expected 4)
Finshed!

Test ping to the embedded official website of Forlinx to check whether the Internet can be accessed normally:

root@rk3576-buildroot:/root# ifconfig wlp1s0
wlp1s0    Link encap:Ethernet  HWaddr 4C:49:6C:F0:99:7A  
          inet addr:192.168.81.206  Bcast:192.168.81.255  Mask:255.255.254.0
          inet6 addr: fe80::4e49:6cff:fef0:997a/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1547 errors:0 dropped:93 overruns:0 frame:0
          TX packets:21 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:150462 (146.9 KiB)  TX bytes:3123 (3.0 KiB)
root@rk3576-buildroot:/root# ping www.forlinx.com     
PING s-526319.gotocdn.com (211.149.226.120) 56(84) bytes of data.
64 bytes from 211.149.226.120 (211.149.226.120): icmp_seq=1 ttl=54 time=45.9 ms
64 bytes from 211.149.226.120 (211.149.226.120): icmp_seq=2 ttl=54 time=40.1 ms
64 bytes from 211.149.226.120 (211.149.226.120): icmp_seq=3 ttl=54 time=39.8 ms
64 bytes from 211.149.226.120 (211.149.226.120): icmp_seq=4 ttl=54 time=40.8 ms
64 bytes from 211.149.226.120 (211.149.226.120): icmp_seq=5 ttl=54 time=40.5 ms
^C
--- s-526319.gotocdn.com ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4007ms
rtt min/avg/max/mdev = 39.813/41.401/45.867/2.257 m

Pinging the Forlinx official website confirms normal functionality, indicating successful STA mode configuration.

To enable AP mode, follow these steps: Next, let's look at how to configure AP mode.

The first step is to write the AP mode script. The script is placed in the/usr/bin/directory, and the file name is fltest _ hostapd. sh, which also needs to be configured with executable permissions.

#!/bin/sh
cnt=`ps aux | grep wpa_supplicant | grep -v grep  | wc -l`
if [ "${cnt}" != "0" ];then
        killall wpa_supplicant > /dev/null
fi
cnt1=`ps aux | grep hostapd | grep -v grep  | wc -l`
if [ "${cnt1}" != "0" ];then
        killall hostapd > /dev/null
fi
/etc/init.d/S80dnsmasq stop
echo 1 > /proc/sys/net/ipv4/ip_forward
#iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
sleep 1
ifconfig wlp1s0 192.168.2.1
hostapd /etc/hostapd-2.4g.conf &
#hostapd /etc/hostapd-5g.conf &
/etc/init.d/S80dnsmasq start

That's all for the fltest _ hostapd. sh script. In the fltest _ hostapd. sh script, the/etc/hostapd-2.4g.conf configuration file is also used, and the following is the configuration content of the file:

interface=wlp1s0
driver=nl80211
channel=9
hw_mode=g
auth_algs=1
ieee80211n=1
wpa=1
ssid=OK3576_WIFI_2.4G_AP   //AP mode wifi name
wpa_passphrase=12345678   //AP mode WiFi password
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP

Next, configure the dnsmasq. conf service.

root@rk3576-buildroot:/root# vi /etc/dnsmasq.conf
interface=wlp1s0
bind-interfaces
except-interface=lo
dhcp-range=192.168.2.100,192.168.2.254,12h
dhcp-option=3,192.168.2.1
dhcp-option=6,192.168.2.1

Some users might ask why udhcpd is used in other systems, while DNSmasq is chosen here. Here's a brief comparison of the two services:

(1)udhcpd  A DHCP server from the BusyBox toolkit. Assigns dynamic IP addresses, subnet masks, gateways, etc., to local network devices. Does not include DNS forwarding or other network services.

(2)DNSmasq  A lightweight DNS forwarder and DHCP server.

① Forwards DNS queries to upstream servers and caches results to improve response times.

② As a DHCP server, its functionality is similar to udhcpd (not repeated here).

Primarily used in small networks (e.g., home networks, small offices, routers) due to its ease of configuration and management. In contrast, udhcpd is better suited for embedded systems or resource-constrained environments.

After the introduction of extended knowledge, the AP mode is opened:

root@rk3576-buildroot:/root# fltest_hostapd.sh 
[ 6470.256308] wlp1s0: deauthenticating from ee:b9:70:81:7d:88 by local choice (Reason: 3=DEAUTH_LEAVING)
killall: hostapd: no process killed
Stopping dnsmasq: FAIL
Starting dnsmasq: OK
[ 6471.641533] IPv6: ADDRCONF(NETDEV_CHANGE): wlp1s0: link becomes ready
wlp1s0: interface state UNINITIALIZED->ENABLED
wlp1s0: AP-ENABLED 
root@rk3576-buildroot:/root# ifconfig wlp1s0
wlp1s0    Link encap:Ethernet  HWaddr 4C:49:6C:F0:99:7A  
          inet addr:192.168.2.1  Bcast:192.168.2.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:50382 errors:0 dropped:2982 overruns:0 frame:0
          TX packets:261 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:4291281 (4.0 MiB)  TX bytes:27170 (26.5 KiB)

The following is the hot spot to use mobile phone to connect to the embedded OK3576-C development board.

root@rk3576-buildroot:/root# ping 192.168.2.225
PING 192.168.2.225 (192.168.2.225) 56(84) bytes of data.
64 bytes from 192.168.2.225: icmp_seq=1 ttl=64 time=142 ms
64 bytes from 192.168.2.225: icmp_seq=2 ttl=64 time=60.1 ms
64 bytes from 192.168.2.225: icmp_seq=3 ttl=64 time=88.2 ms
64 bytes from 192.168.2.225: icmp_seq=4 ttl=64 time=110 ms
64 bytes from 192.168.2.225: icmp_seq=5 ttl=64 time=69.9 ms
^C
--- 192.168.2.225 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4004ms

At this point, the new AX210NGW Wi-Fi 6E module has been successfully adapted.

The adaptation approach for PCIe Wi-Fi modules is consistent. If other Wi-Fi modules are involved, this method can also serve as a reference for implementation.




Dear friends, we have created an exclusive embedded technical exchange group on Facebook, where our experts share the latest technological trends and practical skills. Join us and grow together!