Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
nuc980
socket
NK-980IOT测评之EMAC测试 rtthread sal socket
发布于 2022-03-19 14:56:35 浏览:2235
订阅该版
[tocm] 使用新唐NK-980IOT开发板测试EMAC模块,nuc980已经在RT-Thread上实现了大部分的硬件驱动包括emac以太网部分。因为有了驱动,我可以很方便在rtthread通过sal socket接口抽象层来访问互联网世界。sal层通过lwip协议栈来驱动emac以太网模块,我要做的测试就是在rtthread上使用 ipref 和netio工具测试网络性能,然后在体验下使用http client、http server、mqtt client 等软件包的便利性。 ##### 先介绍一波这个开发板和芯片性能 **NK-980IOT开发板 是新唐科技提供工业物联网开发平台采用 NUC980DK61Y 微处理器,此为一套完整的工业用物联网开平台,包含了完整的硬件设计与软件参考设计。内核为新唐执行速度 300 MHz 的 ARM9 MPU,内建 64 MB DDR 内存、单一 10/100 以太网口、2 个高速 USB 主机、1 Gb SPI NAND Flash 存储装置、麦克风输入、立体声耳机输出与 Arduino 兼容接口。** ##### 再搬过来芯片手册对于emac控制器的介绍 **以太网MAC** - **IEEE标准802.3 CSMA/CD协议。** - **IEEE标准1588–2002协议的以太网帧时间戳。** - **两套以太网MAC。** - **支持10 Mbps或100 Mbps操作的半双工和全双工。** - **RMII(精简媒体独立接口)和串行管理接口(MDC/MDIO)。** - **用于流量控制的暂停和远程暂停功能。** - **长帧(大于1518字节)和短帧(小于64字节)接待** - **用于以太网MAC地址识别的CAM功能。** - **支持魔法包识别,将系统从断电状态唤醒模式** - **内置DMA。** 这个芯片架构设计除了没有浮点运算单元和lcd控制器外其他的外设和芯片性能都是吊打一切mcu的。芯片上是直接内置64M DDR2内存而且和芯片一样都是300M的时钟频率,多路串口和CAN接口,再加上音频输入输出接口,以及以太网功能,在使用rtthread os可以很方便做物联网网关之类的应用。 NK-980IOT板子上是有一路以太网接口的,使用的是ip101gr phy芯片。(还可以设计成POE供电)。因为使用标准的rmii接口和mdio,nuc980理论上是可以驱动任何带有rmii和mdio接口的以太网phy芯片,比如LAN8720A、RTL8201、KSZ8081、DP83848C、DM9161CEP等等。当然使用新塘原厂设计是最好的,可以少走很多弯路。 因为nuc980芯片上支持双网口有两个emac控制器,本来想测试一下nuc980双网口在rtthread上的表现的。只需要在emac1上接一个ip101gr phy芯片就可以实现双网口了,但是看了一下原理图发现emac1是部分引脚(PF0 - PF6)连接的是sd卡并没有引出到gpio。当然我可以魔改它焊几根线出来,不过现在是在测评所以不方便魔改。 ##### 测试前准备 - NK-980IOT开发板一个 - 网线n根 - 千兆交换机一个 - 电脑一台 - RT-Thread studio - NuWriter ### rtthread studio上开始新建nuc980工程 首先从打开studio sdk 管理器,安装nk-980iot的bsp包。然后新建工程,下载好软件包测试。 ![000_20220321223618.png](https://oss-club.rt-thread.org/uploads/20220321/438b923c8e74efcc23d39e467039ae9d.png.webp) ![001_20220319155422.png](https://oss-club.rt-thread.org/uploads/20220321/7ce119c81a83c96b7ef7d172f422355d.png.webp) ![002_20220320170517.png](https://oss-club.rt-thread.org/uploads/20220321/a2e2eeab8d81d9da5f67f6a16338d7a3.png.webp) ### 下载到sdram启动界面 使用uboot启动也是一样的,只不过是uboot从spi nand flash加载到ddr ram运行。我在测试阶段,为了更方便所以直接然芯片从USB启动。电脑上会有显示WinUSB driver(Nuvoton VCOM)),通过NuWriter软件直接将代码写到ddr ram然后软件可以直接将代码引导启动,类似uboot一样。 ![003_20220321224256.png](https://oss-club.rt-thread.org/uploads/20220321/42cc37a744f888c814f1bdcad9f29d5d.png.webp) 启动后很快就启动了以太网phy,phy完成了自动协商切换成100M全双工模式。紧接着就通过dhcp获取到了ip地址。 ![004_20220321224347.png](https://oss-club.rt-thread.org/uploads/20220321/9f29682567914507b6873299c3760e0c.png) ### **使用iperf 测试 tcp server 接收tcp数据包** ![005_20220321224513.png](https://oss-club.rt-thread.org/uploads/20220321/bd78d3b1f5364aa103ca7d572a8d28b9.png.webp) 这个测试使用 nk-980iot 作为 tcp server ,电脑端jiperf 作为 tcp client 。数据包是从电脑端发送给980的。这个速度确实有点慢,而且速度抖动很大。目前为止还没找到原因在哪,估计是iperf接收buffer太小了。 ### **使用iperf 测试 tcp client 发送tcp数据包** ![006_20220321224632.png](https://oss-club.rt-thread.org/uploads/20220321/3ddf203060190c49ed973392a939fc10.png.webp) 这个测试使用 nk-980iot 作为 tcp client,电脑端jiperf 作为 tcp server。数据包是从980发送给电脑端的。这个速度一直保持在44Mbps/s 大约是5MB/s的传输速度,而且速度稳定,网络抖动小。 ### **使用iperf 测试 udp server 接收udp数据包** ![007_20220321225047.png](https://oss-club.rt-thread.org/uploads/20220321/1614bbf95c6db5f13d19513d246d9c0c.png.webp) 这个测试使用 nk-980iot 作为 udp server ,电脑端jiperf 作为 udp client 。数据包是从电脑端发送给980的。这个速度最高值在10Mbps/s左右,但是网络速度稳定波动比较大,因为udp是不会像tcp那样有流控和滑动窗口机制的,udp只管发送,所以这样的速度也不奇怪。 ### **使用iperf 测试 udp client 发送udp数据包** ![008_20220321225509.png](https://oss-club.rt-thread.org/uploads/20220321/94d18f855ecb8f16d42d98250380d941.png.webp) 这个测试使用 nk-980iot 作为 udp client,电脑端jiperf 作为 udp server。数据包是从980发送给电脑的。这个速度最高值差不多在60Mbps/s左右 大约7M/s,传输也比较稳定,但是还是有点大波动。 ### **使用netio测试tcp server** ![009_20220321230102.png](https://oss-club.rt-thread.org/uploads/20220321/480f35b8b1b15e0abf111d8048a85425.png.webp) 因为netio只能运行在tcp server模式,所以只测试了tcp server工作状态的数据。发现netio更iperf测试的速度完全不一样,竟然发送速度达到了11MB/s 接收速度也达到了5M/s。可以看到32k包大小的时候达到发送的峰值,4k包大小的时候达到接收的峰值。所以发送接收包大小是对网络速度有直接影响的。 ### netdev操作以太网 使用netdev的接口操作以太网,控制以太网开启关闭dhcp,还有一系列的网络状态变化回调,获取ip地址,网口物理层端口或者连接。这个代码可以用在实际项目中实现启动网络程序和断线重连的快速检测。 ```c /* * Change Logs: * Date Author Notes * 2022-03-19 chenbin */ #include "rtthread.h" #ifdef RT_USING_SAL #include
#endif #ifdef RT_USING_NETDEV //#include
#include
#include
#endif #define DBG_TAG "net" #define DBG_LVL DBG_LOG #include
typedef struct { int8_t mode; //模式 0:关闭 1:开启,默认是1开启状态 int8_t dhcp; //协议 1:开启dhcp client 0:关闭dhcp client,默认是1开启状态 char ip_str[32]; char gw_str[32]; char sm_str[32]; char dns1_str[32]; char dns2_str[32]; }user_eth_config_t; typedef struct { struct netdev *netdev; uint8_t mac[6]; ip_addr_t ip_addr; ip_addr_t sm_addr; ip_addr_t gw_addr; ip_addr_t dns1_addr; ip_addr_t dns2_addr; }user_eth_context_t; user_eth_context_t eth_context = {0}; user_eth_config_t eth_config = { .dhcp = 1, .ip_str = "192.168.1.30", .gw_str = "192.168.1.1", .sm_str = "255.255.255.0", .dns1_str = "223.5.5.5", .dns2_str = "114.114.114.114", }; void netdev_addr_callback(struct netdev *netdev, enum netdev_cb_type type) { if(type == NETDEV_CB_ADDR_IP) { LOG_I("%s : IP CHANGE",netdev->name); ip_addr_copy(eth_context.ip_addr, netdev->ip_addr); netdev_ip4addr_ntoa_r(ð_context.ip_addr, eth_config.ip_str, sizeof(eth_config.ip_str)); }else if(type == NETDEV_CB_ADDR_NETMASK) { ip_addr_copy(eth_context.sm_addr, netdev->netmask); netdev_ip4addr_ntoa_r(ð_context.sm_addr, eth_config.sm_str, sizeof(eth_config.sm_str)); }else if(type == NETDEV_CB_ADDR_GATEWAY) { ip_addr_copy(eth_context.gw_addr, netdev->gw); netdev_ip4addr_ntoa_r(ð_context.gw_addr, eth_config.gw_str, sizeof(eth_config.gw_str)); }else if(type == NETDEV_CB_ADDR_DNS_SERVER) { ip_addr_copy(eth_context.dns1_addr, netdev->dns_servers[0]); netdev_ip4addr_ntoa_r(ð_context.dns1_addr, eth_config.dns1_str, sizeof(eth_config.dns1_str)); ip_addr_copy(eth_context.dns2_addr, netdev->dns_servers[1]); netdev_ip4addr_ntoa_r(ð_context.dns2_addr, eth_config.dns2_str, sizeof(eth_config.dns2_str)); } } void netdev_status_callback(struct netdev *netdev, enum netdev_cb_type type) { if(type == NETDEV_CB_STATUS_INTERNET_UP) { LOG_I("%s : INTERNET_UP",netdev->name); rt_kprintf("ip : %s\n", eth_config.ip_str ); rt_kprintf("sm : %s\n", eth_config.sm_str ); rt_kprintf("gw : %s\n", eth_config.gw_str ); rt_kprintf("dns1 : %s\n", eth_config.dns1_str ); rt_kprintf("dns2 : %s\n", eth_config.dns2_str ); }else if(type == NETDEV_CB_STATUS_LINK_UP) { LOG_I("%s : LINK_UP",netdev->name); if(eth_config.dhcp) { LOG_I("DHCP start"); netdev_dhcp_enabled(netdev,1); }else { LOG_I("DHCP stop"); netdev_dhcp_enabled(netdev,0); netdev_ip4addr_aton(eth_config.ip_str, ð_context.ip_addr); netdev_ip4addr_aton(eth_config.sm_str, ð_context.sm_addr); netdev_ip4addr_aton(eth_config.gw_str, ð_context.gw_addr); netdev_ip4addr_aton(eth_config.dns1_str, ð_context.dns1_addr); netdev_ip4addr_aton(eth_config.dns2_str, ð_context.dns2_addr); netdev_set_ipaddr(netdev, ð_context.ip_addr); netdev_set_netmask(netdev, ð_context.sm_addr); netdev_set_gw(netdev, ð_context.gw_addr); netdev_set_dns_server(netdev,0, ð_context.dns1_addr); netdev_set_dns_server(netdev,1, ð_context.dns2_addr); } }else if(type == NETDEV_CB_STATUS_UP) { LOG_I("%s : UP",netdev->name); }else if(type == NETDEV_CB_STATUS_DOWN) { LOG_I("%s : DOWN",netdev->name); }else if(type == NETDEV_CB_STATUS_LINK_DOWN) { LOG_I("%s : LINK_DOWN",netdev->name); }else if(type == NETDEV_CB_STATUS_INTERNET_DOWN) { LOG_I("%s : INTERNET_DOWN",netdev->name); } } void user_network_eth_init(void) { struct netdev *netdev; LOG_I("network mode:%d", eth_config.mode); //netdev = netdev_get_first_by_flags(NETDEV_FLAG_LINK_UP | NETDEV_FLAG_UP | NETDEV_FLAG_ETHERNET); netdev = netdev_get_by_name("e0"); if(netdev != NULL) { eth_context.netdev = netdev; LOG_I("network:%s", netdev->name); netdev_set_status_callback(netdev,netdev_status_callback); netdev_set_addr_callback(netdev,netdev_addr_callback); } } ``` ##### 通过netdev设置静态ip地址 ![011_20220322000451.png](https://oss-club.rt-thread.org/uploads/20220322/e9154990f8aca003ba40bcc4875cb744.png) ### 测试http client和http server功能 配置软件包webclient ![020_20220327163851.png](https://oss-club.rt-thread.org/uploads/20220327/c8cf0016b10fa5b8c03061709d4618d7.png) 配置软件包webnet ![021_20220327164931.png](https://oss-club.rt-thread.org/uploads/20220327/3a4d6743559df2f2b49b682377b3ed22.png.webp) > 页面文件准备 > > WebNet 软件包示例中需要获取本地静态页面,需要文件系统的支持(FAT 文件系统,ROMFS 文件系统等,只需要支持 RT-Thread 的设备虚拟文件系统)。 > > 静态页面需要上传到文件系统中服务器根目录下(示例中使用根目录为 /webnet)。设备挂载文件系统成功,需要依次执行下面操作: > > 1. 使用 `mkdir webnet` 命令创建 WebNet 软件包根目录 **/webnet**,并使用 `cd webnet` 命令进入该目录; > > 2. 使用 `mkdir admin` 和 `mkdir upload` 命令创建 **/webnet/admin** 和 **/webnet/upload** ,用于 AUTH 功能和 Upload 功能测试; > > 3. 将 WebNet 软件包 /sample 目录下的:**index.html**、**index.shtml**、**version.asp** 三个文件依次上传到设备 **/webnet** 目录(WebNet 根目录)中。(可以使用 TFTP 工具上传文件,具体操作方式参考 [TFTP 使用说明](https://github.com/RT-Thread-packages/netutils/blob/master/tftp/README.md)) > > 创建目录和上传文件成功之后,就可以启动例程,测试 WebNet 软件功能。 **因为暂时没有测试文件系统,为了减少操作,所以将sd挂载在rtthread的根目录。/webnet目录对应sd卡中webnet目录,然后将文件拷贝过去。** ### 从本地局域网下载一个3D打印文件有4.8M左右。 ![022_20220327202506.png](https://oss-club.rt-thread.org/uploads/20220327/30521e34e7355816201310d2a12542ba.png) ### web_get_test 测试http get请求 ![23_20220327202830.png](https://oss-club.rt-thread.org/uploads/20220327/326aee5000938677cde93802b7dd8070.png) ### web_post_test 测试http post请求 ![24_20220327202845.png](https://oss-club.rt-thread.org/uploads/20220327/b948ca0f811e1701dcbf9569a86fd3e6.png) ### http server 测试 WebNet 在测试之前,我需要把根文件系统换成sd卡。因为默认的根文件系统是ramdisk,每次重启文件就没了,虽然速度确实快。 ![25_20220327204054.png](https://oss-club.rt-thread.org/uploads/20220327/066d7cfe9fbf5765d5b26ca8c6951316.png) ### 启动webnet 浏览http server中的网页 ![26_20220327204427.png](https://oss-club.rt-thread.org/uploads/20220327/499a49271b2f1fc69c4ad8f5a5c68eaf.png.webp) ### 上传文件 ![27_20220327204659.png](https://oss-club.rt-thread.org/uploads/20220327/df6f084041b5af83203ec30f1f15dfbe.png.webp) ![28_20220327204732.png](https://oss-club.rt-thread.org/uploads/20220327/7346ff4a8895d76654d59a547cb7e161.png.webp) ### 测试modbus tcp slave功能 使用socket select api可以支持多个modbus poll主机轮询。 ![29_20220327210149.png](https://oss-club.rt-thread.org/uploads/20220327/67d296734cc0ef3a7d740aa138ae8d7b.png.webp) ### 测试mqtt客户端功能 使免费公共的mqtt broker 服务器做测试 https://www.emqx.com/zh/mqtt/public-mqtt5-broker 还有PC端客户端 https://mqttx.app/zh ![30_20220327212633.png](https://oss-club.rt-thread.org/uploads/20220327/2a9a1a833ae1f1cc8d79b9b7c26ddb0e.png.webp) ### 测试代码仓库 gitee https://gitee.com/cazure/nk-980iot-rtthread-test
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
文武斌
这家伙很懒,什么也没写!
文章
6
回答
74
被采纳
2
关注TA
发私信
相关文章
1
W5500 如何实现断开重连?
2
AT组件连接BC26并使用Webclient软件包GET方式请求失败
3
Posix Socket采用select机制最多能监听多少个Socket
4
socket第三个参数无效
5
添加SAL组件后socket相关函数均提示declared implicitly
6
mqtt pipe 里面使用到了dfs, socket 是怎么关联起来dfs的?
7
socket应用方案选择
8
closesocket函数调用会阻塞
9
基于AT Socket的测速工具
10
关于网络编程socket
推荐文章
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
UART
WIZnet_W5500
ota在线升级
PWM
freemodbus
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
Debug
中断
编译报错
rt_mq_消息队列_msg_queue
SFUD
keil_MDK
msh
ulog
C++_cpp
MicroPython
本月问答贡献
a1012112796
20
个答案
3
次被采纳
红枫
8
个答案
2
次被采纳
踩姑娘的小蘑菇
7
个答案
2
次被采纳
三世执戟
7
个答案
1
次被采纳
张世争
6
个答案
1
次被采纳
本月文章贡献
YZRD
3
篇文章
6
次点赞
catcatbing
3
篇文章
6
次点赞
lizimu
2
篇文章
12
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部