一、创建rt-thread项目
开始本篇实验前,需要搭建rt-thread开发环境,具体可以参考:“快来看!先楫芯与rt-thread碰出火花了”
使用rt-thread studio创建名为hpm_net_test的项目:
二、为项目添加rw007支持
2.1 打开rt-thread settings
项目创建成功后,打开项目的rt-thread settings界面:
可以看到,默认情况下spi驱动框架已经打开了。
bsp中的spi1驱动也已经打开了:
2.2 添加rw007软件包
在rt-thread settings界面,通过点击“添加软件包”按钮,会弹出rt-thread package center界面:
在中间的搜索框中输入rw007,回车,可以找到rw007驱动程序软件包:
点击界面“添加”按钮,即可将rw007软件包添加到当前项目的包配置中了,此时软件包并没有真正下载下来。点完添加按钮后,界面回到了rt-thread settings,此时按ctrl+s保存,则会开始下载。下载过程中,控制台子窗口中可以看到一些日志输出:
稍等片刻,可以看到控制台中间有“rw007 v2.0.1 is downloaded successfully.”输出。此时rw007软件包已经成功下载到当前项目中了,具体代码位于packages子目录下:
2.3 配置rw007驱动
在rt-thread settings界面,将鼠标移动到rw007组件上,会弹出悬浮菜单:
点击悬浮菜单中的“配置项”,即可进入rw007软件包的配置界面:
可以看到,默认有一个rw007 for stm32的配置,就是说rw007默认包含了stm32的驱动。
这里我们需要修改的就是这个example driver port配置项,点击下拉菜单改为不使用示例驱动:
选中后,记得ctrl+s保存配置。
2.4 编译、烧录、运行项目
在rt-thread studio中按ctrl+b快捷键或点击“锤子”图标,即可开始编译项目。编译完成后,可以看到控制台输出了ram和flash占用:
此时,将开发板连接到pc,并使用串口助手或者其他终端工具,连接到新增的串口上。
再到rt-thread studio中,按ctrl+alt+d快捷键或点击“下载”图标即可进行烧录(或者直接进行调试也可以)。
烧录完成后,可以看到串口终端上有输出:
可以看到,输出了rt-thread版本信息和rw007模组的序列号以及固件版本信息。这里能够看到rw007模组的固件版本信息,其实hpm6750芯片和rw007模组之间已经可以正常通信了。
三、wifi测试
接下来,我们进行一些简单的wifi测试。
添加rw007组件后,默认会打开rt-thread的wifi驱动框架,而rt-thread的wifi驱动框架中同时带有一个测试命令——wifi(对就是这么直接)。
我们可以在rt-thread的msh交互环境中使用help查看当前已有哪些命令:
可以看到有一个wifi命令。
接下来我们查看wifi命令的使用方式:
3.1 扫描测试
尝试扫描周围的wifi热点:
可以看到,成功扫描到了周围的wifi热点。
3.2 连接测试
尝试连接其中的一个热点:
然而,不幸的是,发生异常了。
不过,从这里的几个warning打印信息可以看到,应该是因为tcpip线程栈溢出导致的。
3.3 调大tcpip线程栈大小
接下来,我们通过rt-thread settings修改tcpip线程栈的大小。
同样,首先打开rtt settings界面,鼠标指针放到lwip组件图标上:
打开配置项,找到rt_lwip_tcpthread_stacksize配置项,并将其修改为4096:
界面下方可以看到这个lwip线程栈大小的配置项名称为rt_lwip_tcpthread_stacksize。至于这里为什么要改这个配置项,没有在rt-thread用过lwip的同学可能会疑惑。其实,这里可以根据线程名“tcpip”,一路搜索代码,首先可以找到创建名为tcpip线程的代码位置,然后可以找到线程栈大小参数的来源。这里是搜索结果:
ps:因为默认使用的是lwip 2.0.3版本,所以这里只搜索了lwip-2.0.3的代码。
3.4 重新测试配置修改完成后,ctrl+s保存,重新编译项目、烧录、运行,这次能够成功连接wifi热点了:
可以看到,已经成功通过dhcp从热点获取到ip地址了。
四、网络测试
4.1 rt-thread网络组件
前面提到,添加了rw007软件包后,会开启rt-thread的wifi驱动框架;同时,也会开启系统中网络协议相关的组件,主要包括套接字抽象层(sal)、网络接口层、轻量级tcp/ip堆栈(lwip),如下图所示。
其中,lwip的默认版本用的是v2.0.3,也可以切换为其他版本(rt-thread系统中同时提供了lwip的好几个版本可供选择)。
4.2 rt-thread网络组件相关的命令
rt-thread系统网络相关组件打开后,将会向msh中注册几个命令用于测试,具体包括:ifconfig、ping、netstat、dns等,可以在help的输出中找到:
4.3 ping测试
有ip地址了,我们可以用ping命令测试一下能不能访问baidu.com:
可以看到,能够成功ping通baidu.com了。
使用baidu.com的域名能够访问,说明dns整个流程都是ok的,同时网路协议也是没问题的。
五、网络带宽测试
5.1 添加netutils软件包
rt-thread的netutils软件包中提供了iperf命令,可以用于测试网络带宽;
和前面类似的方法,为项目添加netutils组件:
打开“配置项”后,打开iperf的配置项:
修改配置后,ctrl+s保存。
重新编译、烧录、运行项目,help的输出可以看到多了iperf命令。
5.2 iperf命令参数
在rt-thread的msh中运行iperf,默认输出帮助信息:
可以看到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命令,所以就不单独下载了:
5.4 进行iperf测试
进行iperf测试之前,需要注意:
1.最好用pc创建热点,用无线路由器也行,但是需要确保信号强度足够;
2.确保开发板和pc直线的距离不要太远,否则wifi信号较弱,测试的结果可能会偏小;
3.最好在wifi热点较少的环境下进行测试,否则测出的结果数据也会偏小;
下面进行测试,测试步骤如下:
在pc上,创建热点,例如名为rtt,密码为12345678
在pc上,启动iperf服务端:iperf -s -p 5678
在pc上,使用ipconfig/ifconfig命令查看热点的ip地址,例如我在win10上创建的热点,ip地址是:192.168.137.1
在开发板上,连接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的输出;
开发板上整个过程的输出如下:
pc端输出:
可以看到带宽为7.45mbps
5.5 iperf测试小结
实际上,影响wifi带宽测试结果数据的因素很多。我们这里,其中,起决定性的的主要由以下几个方面:
rw007模组本身支持的最高wifi传输速率;
rw007模组的spi接口支持的最高工作频率;
hpm6750 spi接口最高支持的工作频率;
热点(pc或路由器)的wifi最高传输速率;
各种环境因素,例如开发板和pc直接的距离、环境是否有其他热点干扰等等;
六、业务代码——socket测试
前面的ping测试、iperf测试使用的是系统已有组件或软件包。除此之外,也可以通过socket连接网络。这里以一个简单的使用socket获取baidu首页为例(直接使用web_client软件包也可以实现该功能):
#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\\nuint32_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 = 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客户端,依次进行了请求发送、回复接收和回复解析的过程,测试结果:
七、原理简介
以上操作,我们没有任何底层驱动相关代码,就实现了通过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协议实现;
(文章摘选自 rtt @xusiwei1236)
台积电计划在美国生产3纳米芯片
信息安全已成智能家居选择最大痛点,产业应如何合规应对
海外开发者进入中国 海外开发者在中国大有可为
BOE(京东方)宣布200台8K电视永久捐赠社区
什么是联盟链的区块链技术
HPM6750 测评 | 不写一行代码,两分钟实现WiFi联网
共享单车进入2.0时代 可持续发展须勤练内功
p40升级鸿蒙 步骤教程如下
工业级32位通用MCU CH32概述及特点
交换机的基本配置方法
Tesla Model 3“它是世界上最好的车”
AI与动态传感器开拓新领域 走入牧场监控牛只
基于智能优化控制的磨矿过程综合自动化系统
一文了解通配符SSL证书和多层子域
全加器逻辑电路图分析
MOSFET器件用于相移ZVS转换器中可能存在的隐患分析
labview和matlab区别
联想发布入门级工作站系列新品ThinkStation E20
关于判断电线电缆质量好坏的检查方法的介绍
基于虚拟仪器实现模块化测试系统的设计,如何满足理想ATE的需求