0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

HPM6750 测评 | 不写一行代码,两分钟实现WiFi联网

先楫半导体HPMicro 2022-07-22 11:13 次阅读

一、创建RT-Thread项目

开始本篇实验前,需要搭建RT-Thread开发环境,具体可以参考:“快来看!先楫芯与RT-Thread碰出火花了”

使用RT-Thread Studio创建名为hpm_net_test的项目:

17ff981c-039c-11ed-9ade-dac502259ad0.png

二、为项目添加RW007支持

2.1 打开RT-Thread Settings

项目创建成功后,打开项目的RT-Thread Settings界面:

181b7168-039c-11ed-9ade-dac502259ad0.png

可以看到,默认情况下SPI驱动框架已经打开了。

BSP中的SPI1驱动也已经打开了:

18342528-039c-11ed-9ade-dac502259ad0.png

2.2 添加RW007软件包

在RT-Thread Settings界面,通过点击“添加软件包”按钮,会弹出RT-Thread Package Center界面:

184550a0-039c-11ed-9ade-dac502259ad0.png

在中间的搜索框中输入RW007,回车,可以找到RW007驱动程序软件包:

1855e9b0-039c-11ed-9ade-dac502259ad0.png

点击界面“添加”按钮,即可将RW007软件包添加到当前项目的包配置中了,此时软件包并没有真正下载下来。点完添加按钮后,界面回到了RT-Thread Settings,此时按Ctrl+S保存,则会开始下载。下载过程中,控制台子窗口中可以看到一些日志输出:

18726040-039c-11ed-9ade-dac502259ad0.png

稍等片刻,可以看到控制台中间有“RW007 v2.0.1 is downloaded successfully.”输出。此时rw007软件包已经成功下载到当前项目中了,具体代码位于packages子目录下:

188dcf4c-039c-11ed-9ade-dac502259ad0.png

2.3 配置RW007驱动

在RT-Thread Settings界面,将鼠标移动到RW007组件上,会弹出悬浮菜单:

18a20502-039c-11ed-9ade-dac502259ad0.png

点击悬浮菜单中的“配置项”,即可进入RW007软件包的配置界面:

18b69058-039c-11ed-9ade-dac502259ad0.png

可以看到,默认有一个RW007 for stm32的配置,就是说RW007默认包含了STM32的驱动。


这里我们需要修改的就是这个example driver port配置项,点击下拉菜单改为不使用示例驱动:

18d622f6-039c-11ed-9ade-dac502259ad0.png

选中后,记得Ctrl+S保存配置。

2.4 编译、烧录、运行项目

在RT-Thread Studio中按Ctrl+B快捷键或点击“锤子”图标,即可开始编译项目。编译完成后,可以看到控制台输出了RAM和Flash占用:

18efca8a-039c-11ed-9ade-dac502259ad0.png

此时,将开发板连接到PC,并使用串口助手或者其他终端工具,连接到新增的串口上。

再到RT-Thread Studio中,按Ctrl+Alt+D快捷键或点击“下载”图标即可进行烧录(或者直接进行调试也可以)。


烧录完成后,可以看到串口终端上有输出:

19109bf2-039c-11ed-9ade-dac502259ad0.png

可以看到,输出了RT-Thread版本信息和RW007模组的序列号以及固件版本信息。这里能够看到RW007模组的固件版本信息,其实HPM6750芯片和RW007模组之间已经可以正常通信了。

三、WiFi测试

接下来,我们进行一些简单的WiFi测试。

添加RW007组件后,默认会打开RT-Thread的WiFi驱动框架,而RT-Thread的WiFi驱动框架中同时带有一个测试命令——wifi(对就是这么直接)。

我们可以在RT-Thread的msh交互环境中使用help查看当前已有哪些命令:

192272c8-039c-11ed-9ade-dac502259ad0.png

可以看到有一个wifi命令。


接下来我们查看wifi命令的使用方式:

19326886-039c-11ed-9ade-dac502259ad0.png

3.1 扫描测试


尝试扫描周围的WiFi热点:

1946298e-039c-11ed-9ade-dac502259ad0.png

可以看到,成功扫描到了周围的WiFi热点。

3.2 连接测试


尝试连接其中的一个热点:

195f900e-039c-11ed-9ade-dac502259ad0.png

然而,不幸的是,发生异常了。

不过,从这里的几个warning打印信息可以看到,应该是因为tcpip线程栈溢出导致的。

3.3 调大tcpip线程栈大小


接下来,我们通过RT-Thread Settings修改tcpip线程栈的大小。

同样,首先打开RTT Settings界面,鼠标指针放到LwIP组件图标上:


197289b6-039c-11ed-9ade-dac502259ad0.png

打开配置项,找到RT_LWIP_TCPTHREAD_STACKSIZE配置项,并将其修改为4096:

19874748-039c-11ed-9ade-dac502259ad0.png

界面下方可以看到这个LwIP线程栈大小的配置项名称为RT_LWIP_TCPTHREAD_STACKSIZE。至于这里为什么要改这个配置项,没有在RT-Thread用过LwIP的同学可能会疑惑。其实,这里可以根据线程名“tcpip”,一路搜索代码,首先可以找到创建名为tcpip线程的代码位置,然后可以找到线程栈大小参数的来源。这里是搜索结果:

199e6900-039c-11ed-9ade-dac502259ad0.png

19a99bf4-039c-11ed-9ade-dac502259ad0.png

19bb72c0-039c-11ed-9ade-dac502259ad0.png

PS:因为默认使用的是lwip 2.0.3版本,所以这里只搜索了lwip-2.0.3的代码。

3.4 重新测试

配置修改完成后,Ctrl+S保存,重新编译项目、烧录、运行,这次能够成功连接WiFi热点了:

19ce79ce-039c-11ed-9ade-dac502259ad0.png

可以看到,已经成功通过DHCP从热点获取到IP地址了。

四、网络测试

4.1 RT-Thread网络组件


前面提到,添加了RW007软件包后,会开启RT-Thread的WiFi驱动框架;同时,也会开启系统中网络协议相关的组件,主要包括套接字抽象层(SAL)、网络接口层、轻量级TCP/IP堆栈(LwIP),如下图所示。

19dff032-039c-11ed-9ade-dac502259ad0.png

其中,LwIP的默认版本用的是v2.0.3,也可以切换为其他版本(RT-Thread系统中同时提供了LwIP的好几个版本可供选择)。

4.2 RT-Thread网络组件相关的命令

RT-Thread系统网络相关组件打开后,将会向msh中注册几个命令用于测试,具体包括:ifconfig、ping、netstat、dns等,可以在help的输出中找到:

19fe2cb4-039c-11ed-9ade-dac502259ad0.png

4.3 ping测试

有IP地址了,我们可以用ping命令测试一下能不能访问baidu.com:

1a0bf902-039c-11ed-9ade-dac502259ad0.png

可以看到,能够成功ping通baidu.com了。

使用baidu.com的域名能够访问,说明DNS整个流程都是OK的,同时网路协议也是没问题的。

五、网络带宽测试

5.1 添加netutils软件包

RT-Thread的netutils软件包中提供了iperf命令,可以用于测试网络带宽;

和前面类似的方法,为项目添加netutils组件:

1a15ac54-039c-11ed-9ade-dac502259ad0.png

打开“配置项”后,打开iperf的配置项:

1a27edf6-039c-11ed-9ade-dac502259ad0.png

修改配置后,Ctrl+S保存。

重新编译、烧录、运行项目,help的输出可以看到多了iperf命令。

5.2 iperf命令参数

在RT-Thread的msh中运行iperf,默认输出帮助信息:

1a34503c-039c-11ed-9ade-dac502259ad0.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命令,所以就不单独下载了:

  1. 1a48fc94-039c-11ed-9ade-dac502259ad0.png

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的输出;

开发板上整个过程的输出如下:

1a5ed8fc-039c-11ed-9ade-dac502259ad0.png

PC端输出:

1a6da990-039c-11ed-9ade-dac502259ad0.png

可以看到带宽为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\\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客户端,依次进行了请求发送、回复接收和回复解析的过程,测试结果:

1a7732f8-039c-11ed-9ade-dac502259ad0.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协议实现;

(文章摘选自RTT @xusiwei1236)

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • WIFI
    +关注

    关注

    81

    文章

    5285

    浏览量

    203203
  • RTThread
    +关注

    关注

    8

    文章

    132

    浏览量

    40797
收藏 人收藏

    评论

    相关推荐

    如何做hpm6750evk2的bootloader?

    我正在做hpm6750evk2的bootloader。设计很简单,boot工程代码只做跳转到1M后的APP工程代码处,APP工程就是做的
    发表于 10-23 19:01

    HPM6750 Bootloader设计

    我正在做hpm6750evk2的bootloader。设计很简单,boot工程代码只做跳转到1M后的APP工程代码处,APP工程就是做的
    发表于 10-23 18:59

    两分钟带你了解步进电机控制的方法

    步进电机是种将电脉冲信号转换为角位移或线位移的电动机。其工作原理基于电磁学原理,通过将电能转换为机械能来实现控制。步进电机控制方法主要包括脉冲控制、‌电流控制、‌PID控制和‌矢量控制等。
    的头像 发表于 09-18 14:47 292次阅读
    <b class='flag-5'>两分钟</b>带你了解步进电机控制的方法

    使用OPA615进行峰值保持电路设计,输出的保持信号在两分钟中内会有0.1V左右的衰减,为什么?

    采用如图所示的保持电路,保持信号为1V 1Khz 15ns脉宽的单脉冲信号,在实际电路中发现,电路通电后,输出的保持信号在两分钟中内会有0.1V左右的衰减,出现这样的个渐变的过程,之后电路输出信号才会保持稳定。每次刚通电都会有这样的现象出现,请问是什么原因造成的?
    发表于 08-13 07:15

    为什么Xtr111输出短路时没有产生保护动作?

    =4.5V, Xtr 111没有发生输出开路时的保护动作,还保持正常工作状态,这跟数据手册描述的不样。 输出短路两分钟以后两分钟以后解除短路,输出线路串入300欧电阻, Xtr 111能正常工作。 为什么输出短路时没有产生保护
    发表于 08-09 07:53

    esp32连接上腾达AC7路由器如何解决?

    你好,我测试了20种路由器和esp32的链接,现在发现腾达AC7路由器很难链接上esp32.或者要两分钟才可以连接上。3.1.1很难链接。 3.1.3版本的软件基本连接上。请问这个问题该如何解决。但是其他型号路由器都很快连
    发表于 06-12 08:08

    HPM6750体验ADC

    1、新建RTT工程,工程中添加对ADC的驱动: 2、保存工程后,添加测试代码。 3、我们根据原理图上的J10接个,只有PE29是ADC3的输出通道 4、先定义通道、任务 #define
    发表于 02-17 16:00

    解决HPM6750EVK2jlink下载

    拿到HPM6750EVK2,使用jlink下载时,我原来用买jlink配的20转10转接板进行连接,下载程序里直报不能连接到开发板。经过查找用手册后,找到了问题。 我的jlink的引脚图与之不对
    发表于 02-16 10:30

    Embedded Studio 编译器教程

    最近入手先辑的HPM6750,需要使用Embedded Studio 编译器来做开发,各位推荐下学习资料。
    发表于 02-04 08:01

    Linux 下编译HPM_Math 工程报错

    /hpm/hpm_sdk/soc/HPM6750/toolchains/gcc/flash_xip.ld -- Segger device name: HPM6750xVMx -- S
    发表于 12-20 12:54

    RT_thread studio中如何配置先辑的hpm_math数学库?

    hpm6750不知道如何在RTThread studio中使用hpm_math中的数学库,想要使用libdspf.a,但是不知道如何配置
    发表于 12-06 18:32

    AD7190连续转换模式采了一分钟数据后出现异常怎么解决?

    AD7190复位后,各个寄存器可以正常读取,但连续采了一两分钟的ADC数据后又出现同样的问题,请问各位大佬有没有什么解决方法。
    发表于 12-01 07:47

    python如何让多行输出为一行

    。但是,我们可以使用end参数将其替换为其他字符,例如空格或逗号,从而实现多行输出为一行。 示例代码如下: print ( "Hello," , end = " " ) print ( "World
    的头像 发表于 11-24 09:45 6972次阅读

    python如何将多行合并成一行

    在Python中,有多种方法可以将多行合并成一行。以下是详细解释和示例: 方法:使用字符串的replace()方法 你可以使用字符串的replace()方法来删除换行符并将多行合并为一行。首先,你
    的头像 发表于 11-24 09:42 4477次阅读

    c语言怎么把代码全部注释掉

    要将C语言代码全部注释掉,即不让代码被编译和执行,可以使用注释语句来实现。C语言提供种注释方式:单行注释和多行注释。 单行注释:使用双斜杠(//)来注释
    的头像 发表于 11-22 10:21 6611次阅读