在线时间4067 小时
UID3441752
注册时间2017-11-21
NXP金币759430
TA的每日心情 | 开心 2024-3-26 15:16 |
---|
签到天数: 266 天 [LV.8]以坛为家I
管理员
- 积分
- 32003
- 最后登录
- 2024-4-9
|
i.MXRT1020 Iperf网络速度测试 实现上述 100Mbps网络测试,需要确认SDK 修改地方如下:
默认的代码 TCP_WND是 2*TCP_MSS,测试速度并不高。如下所示。
需要和开发板上确认的 PHY芯片的硬件连接是 SPEED引脚需要接下拉电阻到GND。引脚状态时低则为100M模式,引脚状态为高为10M模式。
也可以设置SPEED选择寄存器,设置寄存器位SPEED Select为1则是100M模式,设置为9 则是10Mbps模式。
ENET 寄存器位RMII_10T对应的是 100Mbps的操作模式。
jperf脚本软件链接下载地址:
JPerf 应用程序使用jperf-2.0.0/jperf.bat 脚本文件下载地址: https://sourceforge.net/projects ... 2.0.0.zip/download.
当在 Windows环境下打开 jperf-2.0.0/bin 文件夹的时候,需要用如下链接的文件替换 https://iperf.fr/download/windows/iperf-2.0.5b-win32.zip.
当在 Linux环境下使用的时候,iperf binary 版本 2.0.5 需要 单独安装在系统目录中。
在客户端模式下运行 lwIP IPERF,选择 "Server" 按钮,点击运行 [Run iperf!] (上述测试图片的测试结果是在开发板运行Server模式,PC端运行在客户端模式下)。
在服务端模式下运行 lwIP IPERF,选择 "Client“ 按钮,在JPerf中输入 192.168.0.102 作为 板子的 IPv4 地址作为 "Server address" 参数。
开发板参考硬件PHY KSZ8081RNB 连接原理图。
图片
另外在LWIP使用过程中有断线或者断网检测操作,可以参考如下代码。
- bool linkstatus=false;
- tempvalue =0;
- GetLinkStatus(ENET, BOARD_ENET0_PHY_ADDRESS, &linkstatus);
- while ((tempvalue < 100) && (!linkstatus))
- {
- GetLinkStatus(ENET, BOARD_ENET0_PHY_ADDRESS, &linkstatus);
- if (linkstatus)
- {
- phy_speed_t speed;
- phy_duplex_t duplex;
- GetLinkSpeedDuplex(ENET, BOARD_ENET0_PHY_ADDRESS, &speed, &duplex);
- PRINTF("\n\r link =%d \n\r",linkstatus);
- }
- tempvalue++;
- PRINTF("\n\r tempvalue =%d \n\r",tempvalue);
- }
- if (tempvalue == 100)
- {
- __NVIC_SystemReset();
- }
复制代码 TCP发送数据的时候并不是直接送出数据的,而是考虑了后续的数据一起发送,所以采用的是缓存队列机制。 在每次tcp_write函数之前,需要判断一下 pcb->snd_buf (以字节为单位的发送缓冲区)还有多少栈数据空间可用,如果数据长度超过当前发送缓冲区大小或传出段的队列长度pcb->snd_queuelen(当前发送队列记录里面的包的数目)大于lwipopts.h中定义的上限,则tcp_write()函数将失败并返回ERR_MEM。可以使用tcp_sndbuf(pcb) 函数检索输出队列中可用的字节数。使用此函数的正确方法是使用最多tcp_sndbuf(pcb) 字节的数据调用函数。如果函数返回ERR_MEM,应用程序应该等到其他主机成功接收到当前排队的数据后重试。
可开启心跳包机制LWIP_TCP_KEEPALIVE,通过定期发送心跳包,是否收到ACK检测tcp异常的发生(如突然拔网线等)。发送数据前需检查缓冲区剩余长度,tcp_write()只是把数据包加入发送队列,实际发送动作由tcp_output()执行。
- if((tcp_sndbuf(pcb) > TCP_MSS) && (tcp_write(pcb, data, len, TCP_WRITE_FLAG_MORE) == ERR_OK)) {
- /* send current data /
- tcp_output(pcb);
- } else {
- / send data in tcp queue */
- tcp_output(pcb);
- }
复制代码 连续tcp_write超过12次后失败的问题,可以在tcp_out.c文件中找到了如下代码:
- if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
- LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
- goto memerr;
- }
复制代码 这里,TCP_SND_QUEUELEN值为12,TCP_SND_QUEUELEN定义代码。
#define TCP_SND_BUF (2*TCP_MSS)
// 发送缓冲区,为两个MSS的大小
// 此参数限制了tcp_write的次数,系数默认为6, 改为30
#define TCP_SND_QUEUELEN (30 * TCP_SND_BUF)/TCP_MSS
于是将那个默认的系数由6改为30,就可以解决tcp_write的连续多次调用后失败的问题。应该检查没有超过TCP_SND_QUEUELEN,但由于需要分拆数据包,这样实际上可能会超过最大值。
tcp_write这个函数最后一个参数的说明,该函数声明如下。
err_t tcp_write(struct tcp_pcb *pcb, void *dataptr, u16_t len, u8_t copy);
其中第四个参数是一个copy参数,当为0时为不拷贝数据,也就是在dataptr所指的缓冲区里面发送数据,因为调用tcp_write成功后数据并不会立即发送,所以要确保dataptr所指的缓冲区内容保持不变,如果调用tcp_write成功后,再改变dataptr缓冲区可能就会和预期发送的数据不一致。将最后的参数改为1,为1时即拷贝缓冲区内容,当执行tcp_write时,会将dataptr所指向的缓冲区内容先拷贝到发送的缓冲区中,这样的话执行tcp_write之后再改变dataptr所指的内容是不影响数据的正确发送的。
|
|