STM32网络丢包问题分析

发布者:翩翩轻舞最新更新时间:2022-01-13 来源: eefocus关键字:STM32  网络丢包  RAW  API  方式 手机看文章 扫描二维码
随时随地手机看文章

1. 测试环境说明

硬件平台:NUCLEO-F767ZI 开发板(STM32F7,Cortex-M7,216MHz,2MB Flash,512KB SRAM


操作系统:FreeRTOS v9.0.0(CMSIS-RTOS v1.02)

TCP/IP协议栈:LwIP v2.0.0


这里所描述的网络丢包问题的测试程序,是使用 STM32CubeMX 工具(库版本为 STM32Cube_FW_F7_V1.7.0 ),基于 FreeRTOS 和 LwIP 实现的一个以太网 Demo 程序。协议栈已实现 ICMP 包的 echo 功能(即可以通过其他以太网设备 ping 开发板),此外,我们在该程序框架之上添加了 tcp_echoserver 和 udp_echoserver 功能,进行 TCP 和 UDP 网络性能测试,均采用 RAW API 方式实现。

  

相关的几个测试工具:


Ping 测试工具(ATKKPING): http://download.csdn.net/detail/luckydarcy/9914445

TCP&UDP测试工具 V1.02: http://download.csdn.net/detail/luckydarcy/9895750

TCP/UDP Socket调试工具V2.3: http://download.csdn.net/detail/luckydarcy/9895746


2. 以太网控制器

要分析网络丢包问题,我们先来看一下 STM32F7 的以太网控制器提供了哪些资源。如下图所示,我们可以把 STM32F7 的以太网控制器划分为三部分,从左到右分别是:DMA 控制器、MAC 控制器、PHY 接口。NUCLEO-F767ZI 开发板上的 PHY 芯片是 8742A,通过 RMII 与 MAC 控制器相连。

需要注意的是,这里的 DMA 是以太网外设专用的,它包含两个 FIFO 缓冲区,分别用于以太网数据帧的接收和发送,大小均为 2K 字节。


以太网数据接收模式设置为中断模式,当产生中断或由发送需求时,对于任务来说,以太网数据的接收和发送是通过操作描述符列表和数据缓冲区来完成的。


3. 数据的接收流程

下面我们来看一下以太网数据的接收流程:


中断向量表“__vector_table”中定义了以太网外设中断处理函数 ETH_IRQHandler,对于 Rx 中断来说,实际上调用的是回调函数 HAL_ETH_RxCpltCallback,而该函数只做了一件事,那就是释放信号量:


/**

  * @brief  Ethernet Rx Transfer completed callback

  * @param  heth: ETH handle

  * @retval None

  */

void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *heth)

{

  osSemaphoreRelease(s_xSemaphore);

}


该信号量在 low_level_init 里面被定义为二值信号量,也就是互斥量:


  osSemaphoreDef(SEM);

  s_xSemaphore = osSemaphoreCreate(osSemaphore(SEM) , 1 );


而等待该信号量的是一个称为“ethernetif_input”的线程,我们可以称它为中断服务程序 ISR,它作为整个 LwIP 协议栈的入口,它在 low_level_init 中被定义为 realtime 优先级别的线程:


osThreadDef(EthIf, ethernetif_input, osPriorityRealtime, 0, INTERFACE_THREAD_STACK_SIZE);


线程 ethernetif_input 所做的工作也就是等待该信号量,当接收到以太网数据帧,中断处理函数就会释放信号量,从而使得 ethernetif_input 线程进入就绪态,之后便等待操作系统调度,进而进行数据帧解析。


4. 数据的发送流程

数据的发送流程根据 LwIP 的配置有所区别,但最终都会调用 low_level_output 函数。该函数也是通过操作描述符列表和数据缓冲区来完成发送动作。


和接收流程不同的是,发送的动作没有使用信号量进行同步,而是根据应用程序的需求进行调用。也就是说,只要应用程序有发送数据的需求都可以直接调用相应的API进行发送。那么,这样就会造成资源冲突,所以在更底层的 HAL_ETH_TransmitFrame 函数中,使用了网卡句柄的锁进行保护:


__HAL_LOCK(heth);

  ......

__HAL_UNLOCK(heth);


这样确实可以解决资源冲突的问题,但是这个 Demo 程序的问题在于,当前运行的任务无论有没有拿到锁(网卡资源),low_level_output 都返回 OK。这样就会造成丢包现象。


5. 验证测试

经过上面的分析,我们可以确认,在这个 Demo 程序中,以太网数据的接收和发送机制是存在缺陷的。针对这些缺陷,我们采用 Ping 和 UDP echo 进行测试,并在关键位置添加统计信息。


一个是 ICMP 的 echo 计数(ping_times),我们在程序认为发送成功时才计数:


/* send an ICMP packet */

ret = ip4_output_if(p, src, LWIP_IP_HDRINCL,ICMP_TTL, 0, IP_PROTO_ICMP, inp);

if (ret != ERR_OK) {

  // ......

  }else{

    ping_times++;

  }


另一个是 UDP 的 echo 计数(udp_times),同样,我们在程序认为发送成功时才计数:


static void udp_echoserver_recv_callback(......)

{

    if(ERR_OK == udp_sendto(upcb, p, addr, port))udp_times++;

    pbuf_free(p);

}


另外,我们在 low_level_output 的各个出错部分添加出错统计(output_err),比如:


/* Prepare transmit descriptors to give to DMA */ 

if(HAL_OK != HAL_ETH_TransmitFrame(&heth, framelength)) {

output_err++;

}


5.1 PC直接连接STM32F7

测试一、UDP echo测试(间隔100ms,长度1000字节)

PC 机计数显示成功发送 18005 个数据包,成功接收 17999 个数据包。也即丢失 6 个,丢包率为 0.0333%。

这里写图片描述

STM32F7 打印数据显示,程序“认为”成功发送 18005 个 UDP 数据包,但实际上有 6 个没有发送成功。与 PC 端统计数据相符。


(串口打印数据只需关注最后三个数字,分别表示 ping_times、udp_times、output_err)

这里写图片描述

测试二、UDP echo测试(间隔10ms,长度1000字节)

PC 机计数显示成功发送 59255 个数据包,成功接收 59233 个数据包。也即丢失 22 个,丢包率为 0.0371%。

这里写图片描述

STM32F7 打印数据显示,程序“认为”成功发送 59255 个 UDP 数据包,但实际上有 22 个没有发送成功。与 PC 端统计数据相符。

这里写图片描述

测试三、UDP echo测试(间隔1ms,长度1000字节)

PC 机计数显示成功发送 1920341 个数据包,成功接收 1919724 个数据包。也即丢失 617 个,丢包率为 0.0321%。

这里写图片描述

STM32F7 打印数据显示,程序“认为”成功发送 1920341 个 UDP 数据包,但实际上有 617 个没有发送成功。与 PC 端统计数据相符。

这里写图片描述

测试四、Ping测试(以最快速度Ping,长度32字节)

PC 机计数显示成功发送 15409 个 ICMP 包,超时 8 个,丢包率为 0.05%。

这里写图片描述

STM32F7 打印数据显示,程序“认为”成功发送 15409 个 ICMP 包,但实际上有 1 个没有发送成功。与 PC 端显示丢失 8 个不相符。

这里写图片描述

测试五、Ping测试(以最快速度Ping,长度1472字节)

PC 机计数显示成功发送 15402 个 ICMP 包,超时 30 个,丢包率为 0.19%。

这里写图片描述

STM32F7 打印数据显示,程序“认为”成功发送 15402 个 ICMP 包,但实际上有 2 个没有发送成功。与 PC 端显示丢失 30 个不相符。

这里写图片描述

5.2 PC通过交换机连接STM32F7(交换机连接外网)

测试一、UDP echo测试(间隔10ms,长度1000字节)

PC 机计数显示成功发送 61240 个数据包,成功接收 61209 个数据包。也即丢失 31 个,丢包率为 0.0506%。

这里写图片描述

STM32F7 打印数据显示,程序“认为”成功发送 61240 个 UDP 数据包,但实际上有 12 个没有发送成功。与 PC 端显示丢失 31 个不相符。

这里写图片描述

测试二、Ping测试(以最快速度Ping,长度1472字节)

PC 机计数显示成功发送 21827 个 ICMP 包,超时 161 个,丢包率为 0.74%。

这里写图片描述

STM32F7 打印数据显示,程序“认为”成功发送 21827 个 ICMP 包,但实际上有 3 个没有发送成功。与 PC 端显示丢失 161 个不相符。

这里写图片描述

6. 总结

根据以上测试,我们可以判断,不管是 UDP 测试还是 ICMP 测试,STM32F7 接收到的数据包都与 PC 端统计的成功发送数量完全相同。也就是说,对于 STM32F7 来说并没有丢包。但对于 PC 来说,确实是丢包了。情况如下:


在 UDP 的 echo 测试中,我们发现在与 PC 直连的环境下,STM32F7 的发送失败统计数据与 PC 端统计的丢包数据完全吻合。而在交换机环境下,STM32F7 的发送失败统计数据却小于 PC 端的丢包数据。


在 Ping 测试中,不管直连还是存在交换机,STM32F7 接收到的包与 PC 端发送的一致,但 STM32F7 的发送失败统计数据却总小于 PC 端的丢包数据。但 Ping 存在超时时间等条件限制,建议以 UDP 测试数据为准。


经分析认为,STM32F7 出现网络丢包的主要原因不在于 LwIP 协议栈、网卡驱动以及中断响应,而是该 Demo 程序所实现的以太网数据收发机制存在缺陷所致。即:


对于接收部分,采用二值信号量来同步以太网外设中断和中断服务程序 ISR 是个不错的主意,在上述测试中也确实没出现接收端丢包的情况。但是如果网络数据过于频繁,系统任务繁重,使得中断服务程序还没执行完就出现了下一个中断,也可能会导致丢包。


对于发送部分,采用网卡句柄的锁来保护共享资源的做法有待商榷,Demo 中的这种机制会直接导致资源冲突的时候丢包。


此外,根据测试情况,Demo 程序中应该还存在其他导致数据包发送时丢失的路径。所以,建议相关开发工程师不要过分依赖 Demo 程序,如果确定使用 STM32 + FreeRTOS + LwIP 的设计方案,应该明确项目需求,在硬件资源有限的条件下,结合 FreeRTOS 和 LwIP 协议栈的特性设计出更合理的程序。

关键字:STM32  网络丢包  RAW  API  方式 引用地址:STM32网络丢包问题分析

上一篇:STM32库函数EXTI_GetFlagStatus和EXTI_GetITStatus的区别
下一篇:STM32软件定时器的设计

推荐帖子

新手求助CM. 01Z Z5U 1KV具体代表的什么?
我在网上该搜的搜搜了,没搜到,求大神新手求助CM.01ZZ5U1KV具体代表的什么?
学电的石头 单片机
RL78单片机Timer
TDR寄存器的作用是什么呢??是不是计数到TDR的这个值???还有一点,我的datasheet怎么没有介绍这个寄存器??RL78单片机Timer这个datasheet和你的对比一下看看是不是一样的看看又没有
HanChengYu 瑞萨电子MCU
【米尔边缘AI计算盒FZ5测评】pynq框架——Helloworld!
本次将进行PYNQ框架的第一个例程,该例程将使用两种方法实现图像缩放,图像缩放的最经典算法为双线性插值,期间存在着大量的计算,所以首先将在ARM内核上实现该算法,然后利用FPGA部分进行计算任务的卸载,最终对比两种方法得到的效果。首先利用HLS生成计算加速所需要的硬件IP,打开HLS的命令行窗口,首先对tcl脚本进行简单的修改,主要修改的是芯片的型号:改完以后运行./build_ip.sh命令,得到对应的加速IP。下面就需要进行Vivad
zzx1997 嵌入式系统
TMS320F2812DSP的嵌入式温度测量系统
为了实现嵌入式温度测量系统,提出了基于MZBB-2铂薄膜热敏与TMS320F2812DSP控制芯片的嵌入式解决方案,完成了该系统的硬件设计与软件设计。系统硬件组成包括TMS320F2812DSP处理器、FPGA控制器、ADC转换电路等部分,其中TMS320F2812DSP处理器是控制系统的核心,该芯片通过片上寄存器控制负责ADC转换的控制工作,并且完成电阻数据采集、温度计算,并且将温度测量结果由通信系统发送给控制系统。实验结果表明,温度测量精度达到设计要求,满足了实时温度采集的要求
Aguilera 微控制器 MCU
Python实现堆栈和队列详解
python实现堆栈堆栈是一个后进先出的数据结构,其工作方式就像一堆汽车排队进去一个死胡同里面,最先进去的一定是最后出来。我们可以设置一个类,用列表来存放栈中元素的信息,利用列表的append()和pop()方法可以实现栈的出栈pop和入栈push的操作,list.append(obj)意思是向列表添加一个对象obj,list.pop(index=-1)意思是删除指定位置的对象,默认是最后一个对象,也就是说list.pop(),是删除列表中下标最大的元素。可先将Stack类写入文件s
clinken MicroPython开源版块
主流的照度计产品有哪些?
主流的照度计产品有哪些?主流的照度计产品有哪些?这玩意还分是主流?非主流现在的照度计都是数字的,都差不多直接淘宝一搜看销量,不过这玩意一般都是工业用吧!直接搜搜,然后嗖嗖深圳荟彩分光照度计、分光亮度计等 赞成,照度计不分主流和非主流,先看用途,如果只是一般的参考价值的,对精准度要求不高的,网上大把的;如果要求精准的,首先仪器测量要精准,有认证,最重要的要性价比高。深圳荟彩照度计性价比蛮高的,可以作为参考之一
依诺儿 电源技术
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved