Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
SPI
wlan
先楫HPM_RISCV
【先楫HPM6750测评】RT-Thread WiFi联网和SPI驱动
发布于 2022-06-14 20:05:25 浏览:2516
订阅该版
[tocm] # 【先楫HPM6750测评】RT-Thread SPI驱动和WiFi联网 ## 一、创建RT-Thread项目 开始本篇实验前,需要搭建RT-Thread开发环境,具体可以参考:http://bbs.eeworld.com.cn/thread-1205739-1-1.html 使用RT-Thread Studio创建名为hpm_net_test的项目: ![create_project.png](https://oss-club.rt-thread.org/uploads/20220614/c96ea3551b1bcfae02d151b9d27310a6.png "create_project.png") ## 二、为项目添加RW007支持 ### 2.1 打开RT-Thread Settings 项目创建成功后,打开项目的RT-Thread Settings界面: ![rtt_settings.png](https://oss-club.rt-thread.org/uploads/20220614/2267da988cba980028bc8ff7da13a878.png.webp "rtt_settings.png") 可以看到,默认情况下常见的项目SPI驱动框架已经打开了。 BSP中的SPI1驱动也已经打开了: ![hpm_bsp_spi_config.png](https://oss-club.rt-thread.org/uploads/20220614/8800cca2237908696cff34151cb2ced9.png "hpm_bsp_spi_config.png") ### 2.2 添加RW007软件包 在RT-Thread Settings界面,点击通过“添加软件包”按钮,会弹出RT-Thread Package Center界面: ![rtt_pkg_center.png](https://oss-club.rt-thread.org/uploads/20220614/8e172c3444f4bb2ca1c576dc22d91e7c.png.webp "rtt_pkg_center.png") 在中间的搜索框种输入RW007,回车,可以找到RW007驱动程序软件包: ![rtt_pkg_rw007_found.png](https://oss-club.rt-thread.org/uploads/20220614/dc89d74003e3eabe04a896a0f8cde838.png.webp "rtt_pkg_rw007_found.png") 点击界面“添加”按钮,即可将RW007软件包添加到当前项目的包配置中了,此时软件包并没有真正下载下来。点完添加按钮后,界面回到了RT-Thread Settings,此时按Ctrl+S保存,则会开始下载。下载过程中,控制台子窗口中可以看到一些日志输出: ![rtt_down_pkg.png](https://oss-club.rt-thread.org/uploads/20220614/5c8e8e4935ad6cf2070da2ebfe5f782b.png "rtt_down_pkg.png") 稍等片刻,可以看到控制台中间有“RW007 v2.0.1 is downloaded successfully.”输出。此时rw007软件包已经成功下载到当前项目中了,具体代码位于packages子目录下: ![rtt_pkg_ready.png](https://oss-club.rt-thread.org/uploads/20220614/fc91ff71fea6ecb7945b71f3d1f41a68.png "rtt_pkg_ready.png") ### 2.3 配置RW007驱动 在RT-Thread Settings界面,中将鼠标移动到RW007组件上,会弹出悬浮菜单: ![rtt_config_rw007.png](https://oss-club.rt-thread.org/uploads/20220614/5a8a07151ef43b122b6f622edd036868.png "rtt_config_rw007.png") 点击悬浮菜单中的“配置项”,即可进入RW007软件包的配置界面: ![rw007_config.png](https://oss-club.rt-thread.org/uploads/20220614/d442c9533bfd758c43dacc479bde8d80.png "rw007_config.png") 可以看到,默认有一个RW007 for stm32的配置,就是说RW007默认包含了STM32的驱动。 这里我们需要修改的就是这个example driver port配置项,点击下拉菜单改为不使用示例驱动: ![rw007_disable_stm32_driver.png](https://oss-club.rt-thread.org/uploads/20220614/d54d448a28d29815736c89834e6b810d.png "rw007_disable_stm32_driver.png") 选中后,记得Ctrl+S保存配置。 ### 2.4 编译、烧录、运行项目 在RT-Thread Studio中Ctrl+B或按“锤子”按钮,即可开始编译项目。编译完成后,可以看到控制台输出了RAM和Flash占用: ![rw007_build_finish.png](https://oss-club.rt-thread.org/uploads/20220614/446e35dcda136a4b5bfe71e6bfd7db55.png "rw007_build_finish.png") 此时,将开发板连接到PC,并使用串口助手或者其他终端工具,连接到新增的串口上。 再到RT-Thread Studio中,使用“下载”按钮或Ctrl+Alt+D即可进行烧录(或者直接进行调试也可以)。 烧录完成后,可以看到串口终端上有输出: ![rtt_boot_log.png](https://oss-club.rt-thread.org/uploads/20220614/3f704011fae1566ff87f2d64e1b8e593.png "rtt_boot_log.png") 可以看到,输出了RT-Thread版本信息和RW007模组的序列号以及固件版本信息。这里能够看到RW007模组的固件版本信息,其实HPM6750芯片和RW007模组之间可以已经正常通信了。 ## 三、WiFi测试 接下来,我们进行一些简单的WiFi测试。 添加RW007组件后,默认会打开RT-Thread的WiFi驱动框架,而RT-Thread的WiFi驱动框架中同时带有一个测试命令——wifi(对就是这么直接)。 我们可以在RT-Thread的finsh交互环境中使用help查看当前已有哪些命令: ![rtt_help_print.png](https://oss-club.rt-thread.org/uploads/20220614/093658ccb9b083b5c74f2ab60a2bd36f.png "rtt_help_print.png") 可以看到有一个wifi命令。 接下来我们查看wifi命令的使用方式: ![rtt_wifi_help.png](https://oss-club.rt-thread.org/uploads/20220614/9982ecf4dc4cf7621c0272dd04e1ce54.png "rtt_wifi_help.png") ### 3.1 扫描测试 尝试扫描周围的WiFi热点: ![rtt_wifi_scan.png](https://oss-club.rt-thread.org/uploads/20220614/e5ecb981945f98d06d41a55de76b2aa7.png "rtt_wifi_scan.png") 可以看到,成功扫描到了周围的WiFi热点。 ### 3.2 连接测试 尝试连接其中的一个热点: ![rtt_wifi_join.png](https://oss-club.rt-thread.org/uploads/20220614/147c72a872ae1500a7cdaad50d2aefa2.png "rtt_wifi_join.png") 然而,不幸的是,发生异常了。 不过,从这里的几个warning打印信息可以看到,应该是因为tcpip线程栈溢出导致的。 ### 3.3 调大tcpip线程栈大小 接下来,我们通过RT-Thread Settings修改tcpip线程栈的大小。 同样,首先打开RTT Settings界面,鼠标指针放到LwIP组件图标上: ![rtt_lwip_config.png](https://oss-club.rt-thread.org/uploads/20220614/155845daffffc70aab707555709b5e01.png.webp "rtt_lwip_config.png") 打开配置项,找到**RT_LWIP_TCPTHREAD_STACKSIZE**配置项,并将其修改为4096: ![rtt_lwip_tcpip_thread_stack_size.png](https://oss-club.rt-thread.org/uploads/20220614/5892fe002e5aafdba9b53047a895d1c0.png "rtt_lwip_tcpip_thread_stack_size.png") 界面下方可以看到这个LwIP线程栈大小的配置项名称为**RT_LWIP_TCPTHREAD_STACKSIZE。**至于这里为什么要改这个配置项,没有在RT-Thread用过LwIP的同学可能会疑惑。其实,这里可以根据线程名“tcpip”,一路搜索代码,首先可以找到创建名为tcpip线程的代码位置,然后可以找到线程栈大小参数的来源。这里是搜索结果: ![rtt_grep_tcpip.png](https://oss-club.rt-thread.org/uploads/20220614/a934d84ed15e2be873beeaf59041179d.png.webp "rtt_grep_tcpip.png") ![rtt_grep_tcpip_thread_name.png](https://oss-club.rt-thread.org/uploads/20220614/3574a8f2312ad6e3a3803fa02a939743.png.webp "rtt_grep_tcpip_thread_name.png") ![rtt_grep_tcpip_thread_stack_size.png](https://oss-club.rt-thread.org/uploads/20220614/f3e75933e747608f53310eeec607ba2e.png.webp "rtt_grep_tcpip_thread_stack_size.png") PS:因为默认使用的是lwip 2.0.3版本,所以这里只搜索了lwip-2.0.3的代码。 ### 3.4 重新测试 配置修改完成后,Ctrl+S保存,重新编译项目、烧录、运行,这次能够成功连接WiFi热点了: ![rtt_wifi_join_ok.png](https://oss-club.rt-thread.org/uploads/20220614/a310e5599843c6cd2ac2ed363aefdd7f.png "rtt_wifi_join_ok.png") 可以看到,已经成功通过DHCP从热点获取到IP地址了。 ## 四、网络测试 ### 4.1 RT-Thread网络组件 前面提到,添加了RW007软件包后,会开启RT-Thread的WiFi驱动框架;同时,也会开启系统中网络协议相关的组件,主要包括套接字抽象层(SAL)、网络接口层、轻量级TCP/IP堆栈(LwIP),如下图所示。 ![rtt_network_comps.png](https://oss-club.rt-thread.org/uploads/20220614/7364e7fc13fbd4f356378097cbd780a9.png.webp "rtt_network_comps.png") 其中,LwIP的默认版本用的是v2.0.3,也可以切换为其他版本(RT-Thread系统中同时提供了LwIP的好几个版本可供选择)。 ### 4.2 RT-Thread网络组件相关的命令 RT-Thread系统网络相关组件打开后,将会向finsh中注册几个命令用于测试,具体包括:ifconfig、ping、netstat、dns等,可以在help的输出中找到: ![rtt_help_out.png](https://oss-club.rt-thread.org/uploads/20220614/060e4dfa10d63745cd801a7adc1d7447.png "rtt_help_out.png") ### 4.3 ping测试 有IP地址了,[我们可以用ping命令测试一下能不能访问baidu.com](http://xn--pingbaidu-y75nzdya60zja8h609gefcpt8hpu4bd46ax63cba6544d6oa189r.com): ![rtt_ping_baidu.png](https://oss-club.rt-thread.org/uploads/20220614/5b3465a279b9dfde830af9e5ad758e02.png "rtt_ping_baidu.png") 可以看到,能够成功ping通baidu.com了。 使用baidu.com的域名能够访问,说明DNS整个流程都是OK的,同时网路协议也是没问题的。 ## 五、网络带宽测试 ### 5.1 添加netutils软件包 RT-Thread的netutils组件中提供了iperf命令,可以用于测试网络带宽; 和前面类似的方法,为项目添加netutils组件: ![rtt_add_netutils.png](https://oss-club.rt-thread.org/uploads/20220614/89b3585551ff72f0384cd717a695d286.png.webp "rtt_add_netutils.png") 打开“配置项”后,打开iperf的配置项: ![rtt_netutils_config_iperf.png](https://oss-club.rt-thread.org/uploads/20220614/640ca664bb6900306a74114fe8c2e194.png "rtt_netutils_config_iperf.png") 修改配置后,Ctrl+S保存。 重新编译、烧录、运行项目,help的输出可以看到多了iperf命令。 ### 5.2 iperf命令参数 在RT-Thread的finsh中运行iperf,默认输出帮助信息: ![rtt_iperf_help.png](https://oss-club.rt-thread.org/uploads/20220614/1c3b8488a4fe25945a4e47f2ffbeb8d2.png.webp "rtt_iperf_help.png") 可以看到iperf的命令参数使用方法。 **需要注意:** 1. RT-Thread的iperf命令实现中,对参数的顺序由要求,如果使用过程中发现参数报错,需要查看源码定位原因; 2. RT-Thread的iperf不支持持续时间选项,一般是先启动,后通过stop选项停止的方式控制测试时长; ### 5.3 PC端的iperf PC端的iperf可以到iperf项目官网下载:https://iperf.fr/iperf-download.php 我使用的mobaxterm,里面自带了iperf命令,所以就不单独下载了: ![moba_iperf_help.png](https://oss-club.rt-thread.org/uploads/20220614/1299975f646e63bdbd05d33fffbe7a10.png "moba_iperf_help.png") ### 5.4 进行iperf测试 进行iperf测试之前,需要注意: 1. 最好用PC创建热点,用无线路由器也行,但是需要确保信号强度足够; 2. 确保开发板和PC直接的距离不要太远,否则WiFi信号较弱,测试的结果可能会偏小; 3. 最好在WiFi热点较少的环境下进行测试,否则测出的结果数据也会偏小; 下面进行测试,测试步骤如下: 1. 在PC上,创建热点,例如名为rtt,密码为12345678 2. 在PC上,启动iperf服务端:iperf -s -p 5678 3. 在PC上,使用ipconfig/ifconfig命令查看热点的IP地址,例如我在Win10上创建的热点,IP地址是:192.168.137.1 4. 在开发板上,连接PC启动热点:wifi join rtt 12345678 5. 在开发板上,查看IP地址是否已成功分配:ifconfig,另外,可以通过ping命令测试开发板和PC直接IP是否可达 6. 在开发板上,启动iperf客户端:iperf -c 192.168.137.1 -p 5678 - 启动后,可以通过ps命令查看正在运行的线程 7. 一段时间后,在开发板上,停止iperf客户端:iperf --stop 8. 开发板上iperf停止后,PC端应该可以看到iperf的输出; 开发板上整个过程的输出如下: ![rtt_iperf_test_output.png](https://oss-club.rt-thread.org/uploads/20220614/40b17ba370b148daa62c6112020745c0.png "rtt_iperf_test_output.png") PC端输出: ![iperf_output.png](https://oss-club.rt-thread.org/uploads/20220614/804a63de92dacf79505a53264eea93cb.png "iperf_output.png") 可以看到带宽为7.45Mbps ### 5.5 iperf测试小结 实际上,影响WiFi带宽测试结果数据的因素很多。我们这里,其中,起决定性的的主要由以下几个方面: 1. RW007模组本身支持的最高WiFi传输速率; 2. RW007模组的SPI接口支持的最高工作频率; 3. HPM6750 SPI接口最高支持的工作频率; 4. 热点(PC或路由器)的WiFi最高传输速率; 5. 各种环境因素,例如开发板和PC直接的距离、环境是否有其他热点干扰等等; ## 六、业务代码——socket测试 前面的ping测试、iperf测试使用的是系统已有组件或软件包。除此之外,也可以通过socket连接网络。这里以一个简单的使用socket获取baidu首页为例(直接使用web_client软件包也可以实现该功能): ```c #include
#include
#include
#include
#define DEFAULT_HOST "example.com" #define DEFAULT_PORT 80 #define CONTENT_LENGTH "Content-Length:" #define HEADER_END_MARK "\\r\\n\\r\\n" uint32_t get_host_addr(const char *host) { uint32_t dest = 0; struct hostent *he; he = gethostbyname(host); if (he && he->h_addr_list && he->h_addr_list[0]) { dest = ((struct in_addr *)(he->h_addr_list[0]))->s_addr; } return dest; } #define close(fd) closesocket(fd) int fetch(int argc, char* argv[]) { char* host = DEFAULT_HOST; int port = DEFAULT_PORT; int sockfd = -1; int retval = 0; int recved = 0; int content_start = 0; int content_length = 0; struct sockaddr_in server_addr = {0}; static char request[256]; static char response[4096]; if (argc > 1) host = argv[1]; if (argc > 2) port = atoi(argv[2]); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { rt_kprintf("create socket failed!\\n"); return -1; } rt_kprintf("create socket success!\\n"); rt_memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); server_addr.sin_addr.s_addr = get_host_addr(host); // IP转为 “点分十进制” 格式 inet_ntop(AF_INET, &server_addr.sin_addr, response, sizeof(response)); rt_kprintf("server IP: %s\\n", response); rt_kprintf("connect to server...\\n"); retval = connect(sockfd, (const struct sockaddr *)&server_addr, sizeof(server_addr)); if (retval < 0) { rt_kprintf("connect failed!\\n"); close(sockfd); return -1; } rt_snprintf(request, sizeof(request), "GET / HTTP/1.1\\r\\n" "Host: %s\\r\\n" "User-Agent: curl/7.81.0\\r\\n" "Accept: */*\\r\\n" "\\r\\n", host); rt_kprintf("send request...\\n"); retval = send(sockfd, request, rt_strlen(request), 0); if (retval < 0) { rt_kprintf("send failed!\\n"); close(sockfd); return -1; } rt_kprintf("%d bytes sent\\n", retval); rt_kprintf("recv response...\\n"); recved = 0; while ((retval = recv(sockfd, &response[recved], sizeof(response) - recved, 0)) > 0) { if (content_length == 0) { char* content_length_pos = rt_strstr(response, CONTENT_LENGTH); if (content_length_pos) { content_length = atoi(content_length_pos + rt_strlen(CONTENT_LENGTH)); rt_kprintf("found %s %d!\\n", CONTENT_LENGTH, content_length); } } if (content_start == 0) { char* header_end = rt_strstr(response, HEADER_END_MARK); if (header_end) { content_start = header_end + rt_strlen(HEADER_END_MARK) - response; rt_kprintf("content_start: %d\\n", content_start); } } recved += retval; rt_kprintf("recved: %d %d %d\\n", recved, content_start, content_length); if (content_length && content_start && recved - content_start >= content_length) { rt_kprintf("fully recved!\\n"); break; } } response[recved] = '\\0'; rt_kprintf("==== Response Header ====:\\n"); for (int i = 0; i < content_start; i++) { rt_kprintf("%c", response[i]); } rt_kprintf("==== Response Content ====:\\n"); for (int i = content_start; i < recved; i++) { rt_kprintf("%c", response[i]); } if (retval < 0) { rt_kprintf("recv failed!\\n"); close(sockfd); return -1; } shutdown(sockfd, SHUT_RDWR); close(sockfd); return 0; } MSH_CMD_EXPORT(fetch, "fetch home page of a site"); ``` 这是一段使用裸socket实现的简单HTTP客户端,依次进行了请求发送、回复接收和回复解析的过程,测试结果: ![fetch_www.baidu.com.png](https://oss-club.rt-thread.org/uploads/20220614/0598af6d8ab40e29ae5fada4ed806eeb.png "fetch_www.baidu.com.png") ## 七、原理简介 以上操作,我们没有任何底层驱动相关代码,就实现了通过HPM6750EVKMINI开发板的RW007 WiFi模组实现联网功能。这是因为我们基于RT-Thread的项目中,从底到上已经有了: - HPM6750EVKIMNI BSP中包含了SPI驱动(libraries/drivers/drv_spi.c文件); - 默认打开了spi1的编译配置; - HPM6750EVKIMNI BSP中包含了网卡初始化代码(board/rw007_port.c文件); - 向系统注册了启动时自动执行的wifi_spi_device_init函数; - wifi_spi_device_init函数内部会调用rw007软件包中的rt_hw_wifi_init函数; - RW007软件包,包含RW007模组的驱动代码; - 底层使用SPI驱动实现主控和RW007模组之间的通讯; - 上层向RT-Thread系统注册WLAN设备(rt_hw_wifi_init函数内部会调用rt_wlan_dev_register函数); - RT-Thread的WiFi(也叫WLAN)驱动框架; - 对下连接具体的 WIFI 驱动,控制 WIFI 的连接断开,扫描等操作。 - 对上承载不同的应用,为应用提供 WIFI 控制,事件,数据导流等操作,为上层提供统一的 WIFI 控制接口。 - RT-Thread的Socket抽象层(SAL),统一集中不同的socket实现; - RT-Thread的TCP/IP协议栈(LwIP),具体的TCP/IP协议实现; 本篇就到这里了,感谢你的阅读,下次再见。
3
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
xusiwei1236
https://blog.csdn.net/xusiwei1236
文章
11
回答
33
被采纳
4
关注TA
发私信
相关文章
1
BBB的SPI驱动
2
求个SPI上挂两个或多个设备的使用例子
3
SPI设备有个bug
4
spi flash 的fatfs使用一段时间后读写文件出现故障
5
SPI驱动
6
请教rt_spi_configure函数理解
7
SPI FLASH挂载的问题
8
SPI-FLASH 文件系统 SPIFFS
9
求助一个完整的 spi flash 驱动
10
关于同时使用文件系统与SPI FLASH的问题
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
a1012112796
20
个答案
3
次被采纳
张世争
12
个答案
3
次被采纳
踩姑娘的小蘑菇
7
个答案
3
次被采纳
用户名由3_15位
13
个答案
2
次被采纳
rv666
9
个答案
2
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
RTT_逍遥
1
篇文章
7
次点赞
大龄码农
1
篇文章
5
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部