开发环境:
RT-Thread版本:4.0.3
操作系统:Windows10
Keil版本:V5.30
RT-Thread Studio版本:2.0.1
开发板MCU:STM32F746ZGT6U(NUCLEO-F746ZG开发板)

前面是通过以太网进行网络连接,本文将讲解Wifi联网。

4.1 RW007联网

4.1.1 RW007简介

RW007 是由上海睿赛德电子科技有限公司开发的高速 WiFi 模块,模块基于 Realtek RTL8710BN(Ameba Z 系列) WIFI SOC,使用 SPI/UART 与主机通信 ,支持 IEEE 802.11b/g/n 网络、 WEP/WPA/WPA2 加密方式和 STA 和 AP 模式。

主要特性

1.Cortex-M4 高性能 MCU
2.可自由选择的 AT SPI 双模式,工作模式可由主机配置
3.SPI 时钟高达 30Mbps,UART 波特率高达 6Mbps。
4.SPI 模式下有效以太网带宽高达上传 1MBytes/s,下载 1MBytes/s
5.内置 Bootloader,支持固件升级、安全固件功能。
6.支持快速连接、airkiss 配网
7.支持存储多达 5 条连接信息

4.1.2 RW007硬件电路

RW007与MCU的电路连接示意图如下:

RW007与MCU具体IO连线如下:

从上图可以看出WiFi的接口是SPI。

STM32引脚名 封装管脚序号 功能
PA5 5 BOOT0/CLK
PA6 6 MISO
PB5 7 MOSI
PD14 62 BOOT1/CS
PD15 63 INT/BUSY
PF12 252 RESET

值得注意的是,PA7已近被以太网占用了,因此需要修改电路。

这里需要将SB122连接,将SB121断开。

4.1.3 RW007相关配置

1.配置 SPI

进行配置 SPI1,并生成代码,保存退出即可 。

2.配置 RW007 软件包

RT-Thread 通过软件包的形式,对 RW007 模块提供配套驱动支持,系统默认选项不包含软件包,用户需手动开启:

RT-Thread online packages —> 、IoT - internet of things —>、Wi-Fi —>,勾选 rw007: SPI WIFI rw007 driver —> 选项

接着进一步设置软件包参数,完成 SPI 总线和 IO 的配置,更改总线设备名称 RW007 BUS NAME 为 spi1。

当然啦,这里需要根据自己的板子来决定使用哪个SPI。还需要配置 SPI 控制 IO。

3.开启 WiFi 框架

RW007 驱动使用了 WLAN 相关的接口,按以下选项路径打开 WiFi 框架:
组件 —>设备驱动程序 —>使用 Wi-Fi 框架:

保存即可配置完成。

值得注意的是,LWIP默认已经勾选,但不一定是最新版本。可以在组件中的进行修改。

4.1.4 WiFi联网测试

一切完成后,编译,下载,打开终端。

这里通过wifi命令来联网。

先对周围的无线网络进行扫描,如果你知道Wii信息可以跳过该步骤:

wifi scan

连接网络:

wifi join ssid passwd

联网成功后会显示IP,接下来可以使用下WiFi相关的的其他命令。

有WiFi信息不代表联网成功,接下来ping下IP。

ping ip/域名

【问题】RW007 初始化失败

【问题分析】由于RW007的软件版本默认选择的是1.1.1,不是最新版本,固件和应用软件不匹配。

【解决办法】选择与固件匹配的软件版本即可。

4.1.5 WiFi联网总结

关于WiFi的底层驱动已经封装了,这部分内容也很多,主要是协议栈内容多,但是大体的流程和其他驱动一样的。

驱动的入口是wifi_spi_device_init函数,主要要RW007硬件使能。然后跳转到rt_hw_wifi_init函数中。

int wifi_spi_device_init(void)
{char sn_version[32];GPIO_TypeDef *cs_gpiox;uint16_t cs_pin;cs_gpiox = (GPIO_TypeDef *)((rt_base_t)GPIOA + (rt_base_t)(RW007_CS_PIN / 16) * 0x0400UL);cs_pin = (uint16_t)(1 << RW007_CS_PIN % 16);rw007_gpio_init();rt_hw_spi_device_attach(RW007_SPI_BUS_NAME, "wspi", cs_gpiox, cs_pin);rt_hw_wifi_init("wspi");rt_wlan_set_mode(RT_WLAN_DEVICE_STA_NAME, RT_WLAN_STATION);rt_wlan_set_mode(RT_WLAN_DEVICE_AP_NAME, RT_WLAN_AP);rw007_sn_get(sn_version);rt_kprintf("\nrw007  sn: [%s]\n", sn_version);rw007_version_get(sn_version);rt_kprintf("rw007 ver: [%s]\n\n", sn_version);return 0;
}
INIT_APP_EXPORT(wifi_spi_device_init);rt_err_t rt_hw_wifi_init(const char *spi_device_name)
{static struct rt_wlan_device wlan_sta, wlan_ap;rt_err_t ret;wifi_sta.wlan = &wlan_sta;wifi_sta.hspi = &rw007_spi;wifi_ap.wlan = &wlan_ap;wifi_ap.hspi = &rw007_spi;/* align and struct size check. */RT_ASSERT((SPI_MAX_DATA_LEN & 0x03) == 0);memset(&rw007_spi, 0, sizeof(struct rw007_spi));rw007_spi.spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);if (rw007_spi.spi_device == RT_NULL){LOG_E("spi device %s not found!\r", spi_device_name);return -RT_ENOSYS;}/* config spi */{struct rt_spi_configuration cfg;cfg.data_width = 8;cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0. */cfg.max_hz = RW007_SPI_MAX_HZ;             /* 15M 007 max 30M */rt_spi_configure(rw007_spi.spi_device, &cfg);}/* init spi send mempool */rt_mp_init(&rw007_spi.spi_tx_mp,"spi_tx",&rw007_spi.spi_tx_mempool[0],sizeof(rw007_spi.spi_tx_mempool),sizeof(struct spi_data_packet));/* init spi send mailbox */rt_mb_init(&rw007_spi.spi_tx_mb,"spi_tx",&rw007_spi.spi_tx_mb_pool[0],SPI_TX_POOL_SIZE,RT_IPC_FLAG_PRIO);/* init spi recv mempool */rt_mp_init(&rw007_spi.spi_rx_mp,"spi_rx",&rw007_spi.spi_rx_mempool[0],sizeof(rw007_spi.spi_rx_mempool),sizeof(struct spi_data_packet));/* init spi recv mailbox */rt_mb_init(&rw007_spi.spi_rx_mb,"spi_rx",&rw007_spi.spi_rx_mb_pool[0],SPI_RX_POOL_SIZE,RT_IPC_FLAG_PRIO);/* init spi data notify event */rt_event_init(&spi_wifi_data_event, "wifi", RT_IPC_FLAG_FIFO);rw007_spi.rw007_cmd_event = rt_event_create("wifi_cmd", RT_IPC_FLAG_FIFO);/* register wlan device for ap */ret = rt_wlan_dev_register(&wlan_ap, RT_WLAN_DEVICE_AP_NAME, &ops, 0, &wifi_ap);if (ret != RT_EOK){return ret;}/* register wlan device for sta */ret = rt_wlan_dev_register(&wlan_sta, RT_WLAN_DEVICE_STA_NAME, &ops, 0, &wifi_sta);if (ret != RT_EOK){return ret;}{rt_thread_t tid;/* Create package parse thread */tid = rt_thread_create("wifi_handle",wifi_data_process_thread_entry,&rw007_spi,2048,8,20);if(!tid){return -RT_ERROR;}rt_thread_startup(tid);/* Create wifi transfer thread */tid = rt_thread_create("wifi_xfer",spi_wifi_data_thread_entry,RT_NULL,2048,9,20);if(!tid){return -RT_ERROR;}rt_thread_startup(tid);}spi_wifi_hw_init();return RT_EOK;
}

rt_hw_wifi_init负责创建WIFI数据处理线程,函数如下:

rt_err_t rt_hw_wifi_init(const char *spi_device_name)
{static struct rt_wlan_device wlan_sta, wlan_ap;rt_err_t ret;wifi_sta.wlan = &wlan_sta;wifi_sta.hspi = &rw007_spi;wifi_ap.wlan = &wlan_ap;wifi_ap.hspi = &rw007_spi;/* align and struct size check. */RT_ASSERT((SPI_MAX_DATA_LEN & 0x03) == 0);memset(&rw007_spi, 0, sizeof(struct rw007_spi));rw007_spi.spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);if (rw007_spi.spi_device == RT_NULL){LOG_E("spi device %s not found!\r", spi_device_name);return -RT_ENOSYS;}/* config spi */{struct rt_spi_configuration cfg;cfg.data_width = 8;cfg.mode = RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0. */cfg.max_hz = RW007_SPI_MAX_HZ;             /* 15M 007 max 30M */rt_spi_configure(rw007_spi.spi_device, &cfg);}/* init spi send mempool */rt_mp_init(&rw007_spi.spi_tx_mp,"spi_tx",&rw007_spi.spi_tx_mempool[0],sizeof(rw007_spi.spi_tx_mempool),sizeof(struct spi_data_packet));/* init spi send mailbox */rt_mb_init(&rw007_spi.spi_tx_mb,"spi_tx",&rw007_spi.spi_tx_mb_pool[0],SPI_TX_POOL_SIZE,RT_IPC_FLAG_PRIO);/* init spi recv mempool */rt_mp_init(&rw007_spi.spi_rx_mp,"spi_rx",&rw007_spi.spi_rx_mempool[0],sizeof(rw007_spi.spi_rx_mempool),sizeof(struct spi_data_packet));/* init spi recv mailbox */rt_mb_init(&rw007_spi.spi_rx_mb,"spi_rx",&rw007_spi.spi_rx_mb_pool[0],SPI_RX_POOL_SIZE,RT_IPC_FLAG_PRIO);/* init spi data notify event */rt_event_init(&spi_wifi_data_event, "wifi", RT_IPC_FLAG_FIFO);rw007_spi.rw007_cmd_event = rt_event_create("wifi_cmd", RT_IPC_FLAG_FIFO);/* register wlan device for ap */ret = rt_wlan_dev_register(&wlan_ap, RT_WLAN_DEVICE_AP_NAME, &ops, 0, &wifi_ap);if (ret != RT_EOK){return ret;}/* register wlan device for sta */ret = rt_wlan_dev_register(&wlan_sta, RT_WLAN_DEVICE_STA_NAME, &ops, 0, &wifi_sta);if (ret != RT_EOK){return ret;}{rt_thread_t tid;/* Create package parse thread */tid = rt_thread_create("wifi_handle",wifi_data_process_thread_entry,&rw007_spi,2048,8,20);if(!tid){return -RT_ERROR;}rt_thread_startup(tid);/* Create wifi transfer thread */tid = rt_thread_create("wifi_xfer",spi_wifi_data_thread_entry,RT_NULL,2048,9,20);if(!tid){return -RT_ERROR;}rt_thread_startup(tid);}spi_wifi_hw_init();return RT_EOK;
}

后面就是进行WIFI 的连接断开,扫描等操作。

关于WiFi的更多信息,请参看官方手册:

WiFi

好了,WiFi就移植成功了。

4.2双网卡手动切换实现

到目前,板子就有两块网卡。既然有了双网络,必然就会有网络切换,可类比我们的笔记本,可接以太网和WiFi,当WiFi信号不好就使用以太网,当以太网断了,就自动切换到WiFi。ART-Pi也是一样的。
RT-Thread提供了网卡管理和控制的网路组件netdev 网卡。netdev 组件主要作用是解决设备多网卡连接时网络连接问题,用于统一管理各个网卡信息与网络连接状态,并且提供统一的网卡调试命令接口。

Netdev官网地址

关于Netdev的原理和API请参看官方手册。笔者这里给出网卡切换的代码。
如下示例,导出命令用于切换默认网卡:

#include <arpa/inet.h>
#include <netdev.h>       /* 当需要网卡操作是,需要包含这两个头文件 */static int netdev_set_default_test(int argc, char **argv)
{struct netdev *netdev = RT_NULL;if (argc != 2){rt_kprintf("netdev_set_default [netdev_name]   --set default network interface device.\n");return -1;}/* 通过网卡名称获取网卡对象,名称可以通过 ifconfig 命令查看 */netdev = netdev_get_by_name(argv[1]);if (netdev == RT_NULL){rt_kprintf("not find network interface device name(%s).\n", argv[1]);return -1;}/* 设置默认网卡对象 */netdev_set_default(netdev);rt_kprintf("set default network interface device(%s) success.\n", argv[1]);return 0;
}
#ifdef FINSH_USING_MSH
#include <finsh.h>
/* 导出命令到 FinSH 控制台 */
MSH_CMD_EXPORT_ALIAS(netdev_set_default_test, netdev_set_default, set default network interface device);
#endif /* FINSH_USING_MSH */

重点代码就两句,一句是netdev_get_by_name获取网卡,另外一句是netdev_set_default设置获取的网卡作为默认网卡。这两句在后面也会使用。

接下来编译下载。

连接网线,打印信息如下:

接下来查看网络连接状态:

可以看到默认使用的是以太网。接着看看是否连网。

说明网络是正常的。

我们通过netdev_set_status_test命令切换网络。

可以看到网络切换到WiFi,只是WiFi没有连接而已。

关于WiFi配置有两种方式,不清楚的请参看笔者以前的文章。

Wifi的移植使用

4.3双网卡自动切换

在netdev.c文件中static void netdev_auto_change_default(struct netdev *netdev)这个函数进行了默认网卡的设置。

当然,要想实现这个功能,需要配置如下选项,可使能默认网卡自动切换功能:

多网卡模式下,如果开启默认网卡自动切换功能,当前默认网卡状态改变为 down 或 link_down 时,默认网卡会切换到网卡列表中第一个状态为 up 和 link_up 的网卡。这样可以使一个网卡断开后快速切换到另一个可用网卡,简化用户应用层网卡切换操作。如果未开启该功能,则不会自动切换默认网卡。

但是这个自动切换是由缺陷的,默认板子是使用以太网,不管网线插上与断开与否,当没有插网线时,尽管连接了WiFi,还是不会自动切换,需要手动切换,当WiFi连接后,默认也不会切换到以太网。

我们根据实际应用需求,我们知道:

1.默认使用以太网,如果断开以太网,当连接WiFi后,会自动切换到WiFi,WiFi可通过蓝牙配置,并且记录在Flash中,以便下次使用;
2.如果连接了WiFi,再插上网线,则会自动切换到以太网。
因此需要修改两处代码:

第一处:增加WiFi联网自动切换到WiFi

这是在rt_wlan_event_dispatch函数中,当WiFi连接后,就切换到WiFi。

第二处:增加以太网联网自动切换到以太网

这是在phy_linkchange()函数中添加的,当以太网插上后,就切换到以太网。

好了,最后的编译下载即可。

如果想要记住WiFi账号密码,需要开启easyflash,关于该部分内容请参看笔者博文。

WIFI移植



代码获取方法

1.长按下面二维码,关注公众号[嵌入式实验楼]
2.在公众号回复关键词[LWIP]获取资料



欢迎访问我的网站

BruceOu的哔哩哔哩
BruceOu的主页
BruceOu的博客
BruceOu的CSDN博客
BruceOu的简书
BruceOu的知乎

《嵌入式 - Lwip开发指南》第4章 移植LWIP(基于RT-Thead系统-以太网+Wifi)相关推荐

  1. 【正点原子FPGA连载】第六章Petalinux设计流程实战摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

    1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=692450874670 3)全套实验源码+手册+视频下载地址: h ...

  2. 【正点原子FPGA连载】第十六章Petalinux设计流程实战摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

    1)实验平台:正点原子MPSoC开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=692450874670 3)全套实验源码+手册+视频下载地址: h ...

  3. 北京迅为i.mx6ull终结者开发板使用手册+嵌入式Linux开发指南+裸机手册下载地址

    i.MX6ULL终结者三大手册,加速学习和开发速度,一秒化无形! <嵌入式Linux开发指南>+<开发板使用手册>+<裸机使用手册> 详细手册点击链接下载:http ...

  4. i.MX8MM嵌入式linux开发指南+全覆盖开发资料

    01教程主题 根据多年工作经验总结框架学习法,先掌握整体的开发流程,然后再逐一击破,综合大量工作中的实战案例,在实践中检验理论知识,强化所学知识点,从而掌握Linux的核心技术. 02教学方式 教程由 ...

  5. 基于 Linux 和 MiniGUI 的嵌入式系统软件开发指南(一)(转)

    自 MiniGUI 从 1998 年底推出以来,越来越多的人开始选择 MiniGUI 在 Linux 上开发实时嵌入式系统.为了帮助嵌入式软件开发人员使用 MiniGUI编写出更好的应用程序,我们将撰 ...

  6. 基于 Linux 和 MiniGUI 的嵌入式系统软件开发指南题八——MiniGUI 和其他嵌入式 Linux 上的图形及图形用户界面系统

    简介: 为了让读者对嵌入式 Linux 当中能够使用的图形及图形用户界面有个较为全面的认识,本文将为读者介绍一些嵌入式 Linux 系统中常见的图形及图形用户界面系统,并作为<基于 Linux ...

  7. 基于 Linux 和 MiniGUI 的嵌入式系统软件开发指南

    内容: 1 Linux 图形领域的基础设施 2 Linux 图形领域的高级函数库 3 面向嵌入式Linux 系统的图形用户界面 4 小结 关于作者 相关内容: 主题一:选择MiniGUI-Thread ...

  8. 基于 Linux 和 MiniGUI 的嵌入式系统软件开发指南(八)

    基于 Linux 和 MiniGUI 的嵌入式系统软件开发指南(八) MiniGUI 和其他嵌入式 Linux 上的图形及图形用户界面系统 魏永明 (ymwei@minigui.org) 自由撰稿人 ...

  9. 10001.基于Linux和MiniGUI的嵌入式系统软件开发指南(转载)

    1 Linux 图形领域的基础设施 2 Linux 图形领域的高级函数库 3 面向嵌入式Linux 系统的图形用户界面 4 小结 关于作者 相关内容: 主题一:选择MiniGUI-Threads 或者 ...

  10. Knockout应用开发指南 第六章:加载或保存JSON数据

    原文:Knockout应用开发指南 第六章:加载或保存JSON数据 加载或保存JSON数据 Knockout可以实现很复杂的客户端交互,但是几乎所有的web应用程序都要和服务器端交换数据(至少为了本地 ...

最新文章

  1. 字符串转换整数 (atoi)
  2. Kaggle Tabular Playground Series - Jan 2022 的baseline和日期特征处理
  3. 5G产业发展最新进展深度解析(144页PPT)
  4. python flask 上传文件到服务器
  5. 怎么用python做表格-零基础小白怎么用Python做表格?
  6. zabbix3.4搭建钉钉报警
  7. 华为敏捷 DevOps 实践:产品经理如何开好敏捷回顾会议
  8. 论坛高级签名_2020行走的酒窖首届中国(华北)定制白酒高峰论坛在天津盘山举行...
  9. mongodb 事务_MongoDB 事务 — 基础入门篇
  10. CentOS 8安装JFrog Artifactory社区版解决方案
  11. android窗口速度条,android 改变ViewPager切换页面时的速度
  12. 写代码爬取了某 Hub 资源,只为撸这个鉴黄平台!
  13. [0715]Jsoi Test elevator
  14. hosts文件中同一个域名两个IP的解析顺序
  15. nutch爬虫原来是这样操作的!
  16. 计算机审计初级难度,到现在你还不知道注会各科通过率 就真的out啦
  17. 泛微云桥e-Bridge任意文件读取
  18. win10关闭自动更新
  19. 【转】Android Hook框架Xposed详解
  20. php微信支付分取消订单,PHP实现微信支付和退款

热门文章

  1. 人工智能赋能于企业?来自英特尔的几点建议
  2. 梆梆安全:做以结果为导向的安全服务商
  3. vs2015编译基于obs-studio的阿里巴巴直播工具tblive
  4. 他狂骗五千万美元消失17年...却被一个纪录片导演锲而不舍的追到了镜头前!...
  5. 第一部分-实时爬取WeiBo热搜
  6. 博应用测评软件ofo小黄车和摩拜单车哪个更好骑
  7. STM32:OLED显示屏代码
  8. unity3d新手笔记
  9. Notepad++ 删除关键词所在行
  10. 人工智能起源| 阿兰·图灵的《计算机器与智能》