以太网

在进行本节之前,首先解决大家的一个疑惑点:Client和Client_Socket有什么区别或分别代表的含义?

Socket标准定义为套接字,应用于主流的网络设计程序,具有使用简单,多平台移植方便的特点。在Socket应用中,使用一个套接字来记录网络的一个连接,套接字是一个整数,就像操作文件一样,利用一个文件描述符,进行打开、读、写、关闭等操作。在网络中,可以对Socket 套接字进行类似的操作,比如开启一个网络的连接、读取连接主机发送来的数据、向连接的主机发送数据、终止连接等操作。LwIP设计目的主要应用于嵌入式平台,对于Socket的支持并不完全,只是通过对netconn进行封装实现部分功能,使得LwIP也具有多平台应用的特性,通过Socket方式的了解能够极大简化通信过程的理解,快速实现应用开发。

Demo应用中,使用的开发板为MB-039,在工程中使用LwIP+FreeRTOS,实验展示如何制作一个客户端并发送数据,板载Ethernet相关的硬件部分电路如下:

“基于MM32F3270

MB-039 完整原理图可以通过MM32官网下载。

各个信号引脚对应如下:

“基于MM32F3270

“基于MM32F3270

通过配置复用相关引脚为RMII相关的功能,初始化以太网功能,执行FreeRTOS的启动。具体过程可参考样例初始化程序中代码。

在进行Client_Socket实验前,我们先了解需要使用到的应用功能函数:

(1)socket ()

(2)connect ()

(3)write ()

(1) socket ()

Socket()指向lwip_socket(),功能为申请一个套接字,lwip_socket()源码如下:

int
lwip_socket(int domain, int type, int protocol)
{
  struct netconn *conn;
  int i;

  LWIP_UNUSED_ARG(domain); /* @todo: check this */

  /* create a netconn */
  switch (type) {
    case SOCK_RAW:
      conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW),
             (u8_t)protocol, DEFAULT_SOCKET_EVENTCB);
      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
      break;
    case SOCK_DGRAM:
      conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain,
                                       ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)),
                                       DEFAULT_SOCKET_EVENTCB);
      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
#if LWIP_NETBUF_RECVINFO
      if (conn) {
        /* netconn layer enables pktinfo by default, sockets default to off */
        conn->flags &= ~NETCONN_FLAG_PKTINFO;
      }
#endif /* LWIP_NETBUF_RECVINFO */
      break;
    case SOCK_STREAM:
      conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), DEFAULT_SOCKET_EVENTCB);
      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
      break;
    default:
      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
                                  domain, type, protocol));
      set_errno(EINVAL);
      return -1;
  }

  if (!conn) {
    LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
    set_errno(ENOBUFS);
    return -1;
  }

  i = alloc_socket(conn, 0);

  if (i == -1) {
    netconn_delete(conn);
    set_errno(ENFILE);
    return -1;
  }
  conn->socket = i;
  done_socket(&sockets[i - LWIP_SOCKET_OFFSET]);
  LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
  set_errno(0);
  return i;
}

从源码中我们可以看出,本质上是对netconn_new()进行封装。我们关注一下其参数,domain表示协议簇,对于IP/TCP来说该值始终为AF_INET。重点需要关注一下type,我们查看API手册对于几种类型的解释如下:

1. SOCK_STREAM:提供可靠的(即能保证数据正确传送到对方)面向连接Socket服务,多用于资料(如文件)传输,如TCP协议。

2. SOCK_DGRAM:是提供无保障的面向消息的Socket服务,主要用于在网络上发广播信息,如UDP协议,提供无连接不可靠的数据报交付服务。

3. SOCK_RAW:表示原始套接字,它允许应用程序访问网络层的原始数据包,这个套接字用得比较少,暂时不用理会它。

Protocol指定套接字使用的协议,对于IPv4,TCP协议提供SOCK_STREAM服务,只有UDP协议提供SOCK_DGRAM服务。

(2) connect ()

connect()指向lwip_connect()(源码较长,就不进行粘贴了),函数的作用与前文介绍netconn_connect功能一致,通过源码可以知道其是通过对netconn_connect的封装实现。在TCP客户端连接中,调用这个函数将发生握手过程,并最终建立新的TCP连接。对于UDP来说调用这个函数只是在UDP控制块中记录远端IP地址与端口号。

(3) write ()

Write()指向lwip_write,源码如下,其通过调用lwip_send实现,flags为0。

ssize_t
lwip_write(int s, const void *data, size_t size)
{
  return lwip_send(s, data, size, 0);
}

了解了以上3个API,接下来开始创建Client_Socket工程:

static void client(void *thread_param)
{
  int sock = -1;
  struct sockaddr_in client_addr;  
  ip4_addr_t ipaddr;  
  uint8_t send_buf[]= " This is MM32F3270 TCP Client_Socket Demo \n";

  IP4_ADDR(&ipaddr,DEST_IP_ADDR0,DEST_IP_ADDR1,DEST_IP_ADDR2,DEST_IP_ADDR3);
  while(1)
  {
    sock = socket(AF_INET, SOCK_STREAM, 0);    //(1)
    if (sock < 0)
    {
      vTaskDelay(10);
      continue;
    } 

    client_addr.sin_family = AF_INET;           //(2)
    client_addr.sin_port = htons(DEST_PORT);   //(3)
    client_addr.sin_addr.s_addr = ipaddr.addr;   //(4)
    memset(&(client_addr.sin_zero), 0, sizeof(client_addr.sin_zero));    

    if (connect(sock, 
               (struct sockaddr *)&client_addr, 
                sizeof(struct sockaddr)) == -1)    //(5)
    {
        printf("Connect failed!\n");
        closesocket(sock);
        vTaskDelay(10);
        continue;
    }                                               
    while (1)
    {
      if(write(sock,send_buf,sizeof(send_buf)) < 0)   //(6)
        break; 
      vTaskDelay(1000);
    } 
    closesocket(sock);
  }
}

(1)申请一个套接字:socket

(2)协议簇类型(AF_INET用于TCP/IP协议)

(3)将端口赋值给client_addr的sin_port成员

(4)将地址赋值给client_addr的sin_addr.s_addr成员

(5)创建连接,将sock与地址端口进行绑定,建立连接

(6)发送数据

到这里已经完成了Client Socket工程的创建,还有一步比较重要的是配置Client与Server端的IP,将数据发送给服务器端。

在Windows下,通过打开命令行窗口输入:ipconfig可以获取本机地址与服务器的地址。

“基于MM32F3270

可以观察到PC地址为:192.168.105.34,在sys_arch.h文件中对DEST_IP_ADDR0 、DEST_IP_ADDR1、DEST_IP_ADDR2、DEST_IP_ADDR3进行修改,DEST_PORT可选用空闲端口,设备IP需要设置在同一个网段内通信才能进行IP_ADDR0、IP_ADDR1 、IP_ADDR2,需要与PC地址保持一致,IP_ADDR3可以随意设置(和PC地址不一致即可)。

#define DEST_IP_ADDR0               192
#define DEST_IP_ADDR1               168
#define DEST_IP_ADDR2               105
#define DEST_IP_ADDR3               34

#define DEST_PORT                  5001

#define IP_ADDR0                    192
#define IP_ADDR1                    168
#define IP_ADDR2                    105
#define IP_ADDR3                    130

将程序下载入开发板中,使用SSCOM工具进行如下设置:

“基于MM32F3270以太网

点击侦听:

“基于MM32F3270以太网

可以观察到正常侦听并接收到数据,表明实验成功。Demo程序可登录MindMotion的官网(http://www.mindmotion.com.cn/download.aspx?cid=2542&page=2)下载MM32F3270 lib_Samples,工程路径如下:

~\MM32F3270_Lib_Samples_V0.90\Demo_app\Ethernet_Demo\ETH_RTOS\Freertos_Client_socket

来源:灵动MM32MCU
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 25

前言

网络中传递着各种各样的数据包,当设备连接到网络后,为了减少对接收到的数据进行处理的负荷,就需要对设备接收到的数据包进行过滤。STM32MCU的以太网外设提供多种数据包过滤的模式。可以根据以太网帧的目标MAC 地址,源 MAC地址进行过滤,STM32H7系列还提供对 VLANtag和 IP地址,UDP/TCP端口的过滤。

拿 MAC地址过滤来说,SM32MCU支持:单播目标地址过滤,多播目标地址过滤,单播源地址过滤和广播地址过滤。单播目标地址过滤和多播目标地址过滤又分为:Perfect地址过滤和 Hash地址过滤。

perfect地址过滤就是把接收到的以太网帧中的目标地址与 MAC地址寄存器中保存的地址进行比较,如果匹配,数据包就被接受,否则就被丢掉。还可以通过设置“反向过滤”,来翻转过滤的结果,接收到的以太网帧中的目标地址与MAC地址寄存器中保存的地址如果不匹配,数据包就被接收,否则就被丢掉。

Hash地址过滤不是直接比较 MAC地址,而是计算目标 MAC地址的 CRC32值,取其高 6位作为索引去查询 Hash表寄存器中对应的值,来判断是否接收该数据帧。Hash地址过滤的方法稍微复杂,本文接下来将基于STM32H743Nucleo板,通过具体的例程介绍如何实现 Hash地址过滤。

MAC 地址Hash 过滤

过滤原理

在 Hash地址过滤模式下,以太网 MAC通过一张 64位的 Hash表来进行过滤。这张表存储在两个 32位的寄存器中。STM32H743的寄存器 ETH_MACHT0R 保存着 Hash表的前 32位,ETH_MACHT1R中保存着 Hash表的后 32位值。

MAC接收到以太网帧后,会自动计算目标 MAC地址的 CRC值,然后用该 CRC值的高 6位,作为索引号去前面提到的 Hash表寄存器中查找对应位,如果该位的值是 1,则收到的以太网帧通过。否则就丢掉。例如,计算出的 CRC高6位是 0,则对应 ETH_MACHT0R的 bit0,如果该位是 1,则通过。

在初始化的时候,应该根据想要接收的目标 MAC地址,先设置好 ETH_MACHT0R和 ETH_MACHT1R寄存器的值。Hash地址过滤将 48位的 MAC地址,对应到 6位的 Hash值,肯定会出现多个MAC地址对应到一个 6位 Hash值的情况,所以这种过滤方式也被称作 imperfect过滤模式。

Hash值的计算方法

Hash地址过滤模式,最关键的是如何计算6位的Hash值。在RM0433中介绍了 Hash的产生方法,具体如下:

1. 计算目标 MAC地址的 CRC32值。计算 CRC32的方法参见 IEEE802.3的第 3.2.8章中FCS的说明 。根据IEEE802.3中 CRC值的计算要求,和以太网帧中 MAC地址传输的顺序,MAC地址的 CRC值计算方法如下:

  • 第一个 32位数据进行补码运算
  • 输入的数据都进行按位反转顺序
  • 进行 CRC32计算,多项式为 0x4C11DB7
  • 对最终输出数据进行补码运算

2. 对第一步的计算值进行按位反转顺序

3. 取第二步计算值的高 6位

然后就可以根据计算出来的 Hash值,去设置 ETH_MACHT0R和 ETH_MACHT1R寄存器了。

MAC地址过滤的寄存器配置

目标 MAC地址过滤的寄存器配置见下表:

“STM32以太网MAC

例程说明

下面我们将用一个例子来说明如何配置Hash地址过滤。

在该例程中,我们希望 STM32H743Nucleo板只接收广播,发往自己的单播 MAC地址的消息,以及两个特定多播MAC地址的消息。

单播 MAC地址为:00:80:E1:00:00:00,

多播 MAC地址为:01:0c:0d:01:01:03和 01: 00: 5e: a8: 00: 0a。

例程中,我们需要做以下设置:

1. 设置数据包过滤寄存器 ETH_MACPFR中相关位设置,使能单播perfect过滤,多播 Hash过滤,不屏蔽广播消息。

“STM32以太网MAC

2.将单播地址设置到 ETH_MACA0HR和 ETH_MACA0LR中,并使能该地址。那么所有发往00:80:E1:00:00:00的单播数据包都能被收到,其他的单播数据包将被丢掉。

3.设置 Hash过滤表寄存器。在初始化以太网外设时,利用 STM32H743的 CRC外设自动计算 MAC地址的 CRC32值,再得到对应的 Hash值,根据该值去初始化ETH_MACHT0R和 ETH_MACHT1R寄存器。H743Nucleo将可以接收发往 01:0c:0d:01:01:03和 01:00: 5e: a8: 00: 0a MAC地址的多播消息,其他的多播消息都被丢掉。

CRC外设初始化代码:

“STM32以太网MAC

计算并使能 HashMAC地址过滤的代码:

“STM32以太网MAC

运行结果

将附件的例程烧录到H743Nucleo板,通过 XCAP连续发送下面的 6条消息。

“STM32以太网MAC

包括:

两条单播消息,目标MAC地址分别是:00:80:E1:00:00:00和 02:00:00:00:00:00。

三条多播消息,目标 MAC地址分别是:01:0c:0d:01:01:03,01: 00: 5e: a8: 00:0a和 01:0c:0d:01:01:ff。

一条广播消息。

从程序的打印信息里可以看到,H743Nucleo板接收到了其中的 4条消息,MAC地址没有设置的一条单播消息

(02:00:00:00:00:00)和一条多播消息(01:0c:0d:01:01:ff)都被过滤掉了。

“STM32以太网MAC

来源:STM32单片机
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 246

意法半导体的新芯片组让用户可以利用最新的以太网供电(PoE)规范IEEE 802.3bt,快速开发性能可靠、节省空间的用电设备(PD)。

PM8804PM8805可用于用电设备的PoE转换器电路,支持功率等级最高71W的8级PoE设备。新芯片组可节省电路板空间,增强产品可靠性,缩短上市时间,适用于下一代通信连接设备,包括5G“小型蜂窝”、WLAN接入点、交换机和路由器。意法半导体的新PoE芯片组的目标应用还包括智能建筑和智能办公设备,例如,IP摄像头、门禁系统、显示面板、灯具、电动窗帘或百叶窗控制器、视频通话系统、IP电话和桌面控制台。

PM8804可实现一个功能完整的用于48V隔离式反激式或正激式转换器的PWM控制器,以及用于高效有源钳位正激式转换器拓扑的双低边栅极驱动器。工作频率可选,最高1MHz,可以在高功率密度应用中使用小外部滤波器和去耦元器件。PM8804还具有20mA输出的高压启动稳压器,有助于节省电路板空间和物料清单。

PM8805配套芯片包含2个有源电桥、1个用于驱动高边MOSFET的电荷泵、1个热插拔FET,IEEE 802.3bt标准接口。集成有源桥可以节省8个分立MOSFET及其驱动电路所占用的空间。PM8805产生一个电源就绪信号,用于启用PM8804和其它电路(例如,LED驱动器)并支持维持功率签名(MPS)电流控制,允许用电设备进入省电待机状态而不会断开连接。

这两款产品都已量产。PM8804采用3mm x 3mm、0.5mm间距的VFQFPN-16封装。PM8805采用裸焊盘的8mm x 8mm散热增强型VFQFPN-43封装。

围观 396

我们现今使用的网络接口均为以太网接口,目前大部分处理器都支持以太网口。目前以太网按照速率主要包括10M、10/100M、1000M三种接口,10M应用已经很少,基本为10/100M所代替。目前我司产品的以太网接口类型主要采用双绞线的RJ45接口,且基本应用于工控领域,因工控领域的特殊性,所以我们对以太网的器件选型以及PCB设计相当考究。从硬件的角度看,以太网接口电路主要由MAC(Media Access Controlleroler)控制和物理层接口(Physical Layer,PHY)两大部分构成。大部分处理器内部包含了以太网MAC控制,但并不提供物理层接口,故需外接一片物理芯片以提供以太网的接入通道。面对如此复杂的接口电路,相信各位硬件工程师们都想知道该硬件电路如何在PCB上实现。

下图 1以太网的典型应用。我们的PCB设计基本是按照这个框图来布局布线,下面我们就以这个框图详解以太网有关的布局布线要点。

以太网PCB布局布线
图1:以太网典型应用

1. 图 2网口变压器没有集成在网口连接器里的参考电路PCB布局、布线图,下面就以图 2介绍以太网电路的布局、布线需注意的要点。

以太网PCB布局布线
图2:变压器没有集成在网口连接器的电路PCB布局、布线参考

a) RJ45和变压器之间的距离尽可能的短,晶振远离接口、PCB边缘和其他的高频设备、走线或磁性元件周围,PHY层芯片和变压器之间的距离尽可能短,但有时为了顾全整体布局,这一点可能比较难满足,但他们之间的距离最大约10~12cm,器件布局的原则是通常按照信号流向放置,切不可绕来绕去;

b) PHY层芯片的电源滤波按照要芯片要求设计,通常每个电源端都需放置一个退耦电容,他们可以为信号提供一个低阻抗通路,减小电源和地平面间的谐振,为了让电容起到去耦和旁路的作用,故要保证退耦和旁路电容由电容、走线、过孔、焊盘组成的环路面积尽量小,保证引线电感尽量小;

c) 网口变压器PHY层芯片侧中心抽头对地的滤波电容要尽量靠近变压器管脚,保证引线最短,分布电感最小;

d) 网口变压器接口侧的共模电阻和高压电容靠近中心抽头放置,走线短而粗(≥15mil);

e) 变压器的两边需要割地:即RJ45连接座和变压器的次级线圈用单独的隔离地,隔离区域100mil以上,且在这个隔离区域下没有电源和地层存在。这样做分割处理,就是为了达到初、次级的隔离,控制源端的干扰通过参考平面耦合到次级;

f) 指示灯的电源线和驱动信号线相邻走线,尽量减小环路面积。指示灯和差分线要进行必要的隔离,两者要保证足够的距离,如有空间可用GND隔开;

g) 用于连接GND和PGND的电阻及电容需放置地分割区域。

2. 以太网的信号线是以差分对(Rx±、Tx±)的形式存在,差分线具有很强共模抑制能力,抗干扰能力强,但是如果布线不当,将会带来严重的信号完整性问题。下面我们来一一介绍差分线的处理要点:

a) 优先绘制Rx±、Tx±差分对,尽量保持差分对平行、等长、短距,避免过孔、交叉。由于管脚分布、过孔、以及走线空间等因素存在使得差分线长易不匹配,时序会发生偏移,还会引入共模干扰,降低信号质量。所以,相应的要对差分对不匹配的情况作出补偿,使其线长匹配,长度差通常控制在5mil以内,补偿原则是哪里出现长度差补偿哪里;

b) 当速度要求高时需对Rx±、Tx±差分对进行阻抗控制,通常阻抗控制在100Ω±10%;

c) 差分信号终端电阻(49.9Ω,有的PHY层芯片可能没有)必须靠近PHY层芯片的Rx±、Tx±管脚放置,这样能更好的消除通信电缆中的信号反射;

d) 差分线对上的滤波电容必须对称放置,否则差模可能转成共模,带来共模噪声,且其走线时不能有stub ,这样才能对高频噪声有良好的抑制能力。

以太网PCB布局布线

3. 变压器集成在连接器的以太网电路的PCB布局、布线较不集成的相对简单很多,下图 3是采用一体化连接器的网口电路的PCB布局、布线参考图:

以太网PCB布局布线
图3:一体化连接器的网口PCB布局、布线参考图

从上图可以看出,图 3和图 1的不同之处在于少了网口变压器,其它大体相同。不同之处主要体现在网口变压器已集成至连接器里,所以地平面无需进行分割处理,但我们依然需要将一体化连机器的外壳连接到连续的地平面上。

以太网布局布线方面的要大致就这些,好的PCB布局布线不仅可以保证电路性能,还可以提高电路性能,笔者水平有限,不足之处欢迎指正交流。

转自:博客园 - Aliank

围观 393

前言

在这篇文章中,我将介绍如何从零开始建立一个以太网工程。

ST 推出的 Nucleo-144 板子上集成了以太网接口,所以在本文中,将以 STM32F746-Nucelo 板为例,通过CubeMXv4.18 来新建一个 TCPEchoserver 的程序。

用 CubeMX 建立基于 STM32F746-Nucleo 的工程

用 CubeMX 进行初始化配置

这回我们直接选择 STM32F746-Nucleo 板上对应的芯片 STM32F746ZGT6U,而不是选择 STM32F746-Nucleo 板。

1. 新建一个 Project,在向导中选择 STM32F746ZGT6U。

从零开始使用 CubeMX 创建以太网工程

这个时候我们看到的还是一个空的工程。如下图:

从零开始使用 CubeMX 创建以太网工程

2.外设使能,引脚配置

2.1 以太网外设引脚配置

Nucleo-144 板上用的 PHY LAN8742A,RMII 接口。在 Cubemx 中使能 ETH 外设,选择 RMII 接口。Cubemx 会自动配置对应的以太网接口。如下图:

从零开始使用 CubeMX 创建以太网工程

STM32 的很多引脚都有复用功能,同一个功能也可以 remap 到不同的引脚。所以这里要记得将 CubeMX 自动配置的引脚和实际电路中使用的引脚进行对比,保证是一致的。

从 UM1974 中可以找到 Nucleo-144 板上以太网引脚分配表。对比这张表格和 CubeMX 的默认配置,会发现 PB11,PB12 引脚在 STM32F746-Nucleo 板中没有用做以太网的接口,而是用作其他用途了。

STM32F746-Nucleo 上的引脚分配:

从零开始使用 CubeMX 创建以太网工程

CubeMX 的默认分配:
从零开始使用 CubeMX 创建以太网工程

在 Cubemx 中修改引脚配置:
修改方法见下图,用同样的方法配置 PG11 和 PG13。配置 PG11 和 PG13 后,对应 PB11 和 PB12 会自动清除之前的配置,以免冲突。
从零开始使用 CubeMX 创建以太网工程

到现在位置,已经将所有的 GPIO 口都配置好了。
在 Configuration 页面中,还可以看到所有配置的 GPIO。并可以做进一步的配置,这里就先用默认的设置。
从零开始使用 CubeMX 创建以太网工程

2.2 使能 LwIP 协议栈

在这个工程内,我们会用到 LwIP 协议栈,所以还需要在这一页的 Middlewares 部分将 LWIP 勾选上。之后就可以在Configuration 页面对 LWIP 协议栈进行配置了。

从零开始使用 CubeMX 创建以太网工程

3.时钟配置

接下来进行时钟配置。CubeMX 默认系统时钟 16MHz,但以太网外设需要至少 25MHz 的系统时钟,所以这里会看到 Clock Configuration 页面显示"X"

打开 Clock Configuration 页面会自动跳出一个提示框,可以选择让 CubeMX 来帮你自动调整时钟配置,也可以自己手动进行调整。这里,我选择让 CubeMX 自动配置,CubeMX 会自动将时钟配成 216MHz。

从零开始使用 CubeMX 创建以太网工程

4. 配置以太网参数

从零开始使用 CubeMX 创建以太网工程

在 Parameter Settings 页面,可以配置 MAC 地址,PHY 的地址,是否进行自动协商等。
这里,我们设置了 MAC 地址为本地地址 02 :00 :0 :00 :00 :00。LAN8742a 的 PHY 地址由上电时 PHYAD0 的状态决定。根据STM32F746-Nucleo 板的原理图,设置 PHY 地址为 0。

从零开始使用 CubeMX 创建以太网工程

接收数据的模式有轮询和中断两种方式,中断方式需要和操作系统一起使用,这里我们没有使用任何操作系统,所以在 RX Mode 这一项只能选择 Polling Mode。

最后一项是”TX IP Header Checksum Computation”,STM32 的 MAC 控制器可以在发送数据时自动添加 IP 数据报的 checksum,如果需要这项功能,就将这一项设置为“By hardware”

在 Advanced Parameters 页,可以根据所用的 PHY 修改寄存器的地址和一些 MASK 的设置。因为 STM32F746 的两款开发板上用的都是 PHY LAN8742A,所以 CubeMX 中默认的配置是以 LAN8742A 为例进行设置的。所以这里,我们不需要做任何修改就可以直接用。但如果是其他的 PHY,可以在 PHY 这一项选择“user PHY”,然后根据所用 PHY 的数据手册,配置下面的参数,对于部分无法通过 CubeMX 进行配置的参数,需要手动的修改代码。将有冲突的地方删除,或者添加某个功能。

Advanced Parameters 页分为三个部分:

• External PHY Configuration 。复位延时,读/写超时的参数设置
• Common :External PHY Configuration。PHY 的基础寄存器配置,这部分寄存器对于大部分 PHY 都是相同或类似的。
• Extended :External PHY Configuration。 PHY 的扩展寄存器配置,这部分对于每个 PHY 都是不一样的。如果是使用非 CubeMX 默认的 PHY,这部分内容需要特别注意。

从零开始使用 CubeMX 创建以太网工程

4. 修改 LWIP 的参数

配置好以太网的参数后,点击 OK,回到 CubeMX 的配置界面。选择 LWIP 继续进行参数配置。

从零开始使用 CubeMX 创建以太网工程

首先是 GeneralSettings 页面,在这里我们可以看到 LWIP 的版本号。配置 IP 地址信息,可以选择通过 DHCP 的方式动态分配 IP,也可以分配一个静态的 IP 地址。这里,我们选择配置静态的 IP 地址 192.168.0.10,子网掩码 255.255.255.0,网关192.168.0.1。ICMP 协议打开,因为我们用的是 TCP 协议,所以把 UDP 协议关掉。

不用担心不知道每项参数是做什么用的,选择每一项参数后都会在窗口的底部显示该项参数的解释

从零开始使用 CubeMX 创建以太网工程

在 Key Options 这一页里,有更多的参数可以配置。关于接收/发送内存的配置也是在这里。选择右上方的“Show Advanced Parameters”后,还有更多的参数配置项。这里,我们也可以不做修改,使用默认值。CubeMX 中每个参数项的名称和代码中的名称相同,这样也方便了在代码中进行查找。

从零开始使用 CubeMX 创建以太网工程

到此为止,我们在 CubeMX 中需要做的配置就全部完成了。选择 Project——>Generate Code,生成初始的工程。

从零开始使用 CubeMX 创建以太网工程

添加用户代码

用 IAR 打开前面已经生成好的工程。我们还需要两步就可以完成一个简单的 TCP EchoServer 程序了。

1.新建 tcp_echoserver.c 文件,在 tcp_echoserver.c 里要做下面这几件事情:

1)新建一个 tcp_echoserver_pcb(调用 tcp_new 函数);
2)将新建的 tcp_echoserver_pcb 与要监听的端口绑定(调用 tcp_bind 函数)
3)转成监听状态(调用 tcp_listen 函数)
4)注册回调函数 tcp_echoserver_accept,当有新连接建立后会调用该函数(调用 tcp_accept 函数)
5)注册回调函数 tcp_echoserver_recv,当该连接接收到数据后会调用该函数(调用 tcp_recv 函数)
6)完成 tcp_echoserver_recv 函数,在该函数内,将收到的数据再发出去。

需要注意,本文的目的是示例如何用 CubeMX 建立一个简单的 TCP EchoServer 程序,所以考虑的都是最基本简单的情况。

比如,在回发数据部分,我们假设 Client 发来的数据都在一个 Pbuf 的大小以内。
完成 tcp_echoserver.c 后,将其加入到工程项目中。

#include "stats.h"
#include "tcp.h"
void tcp_echoserver_init(void);
static err_t tcp_echoserver_accept(void *arg, struct tcp_pcb *newpcb,err_t err);
static err_t tcp_echoserver_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p,err_t
err);
static struct tcp_pcb *tcp_echoserver_pcb;
void tcp_echoserver_init(void)
{
 err_t err;
 tcp_echoserver_pcb = tcp_new();

 if(tcp_echoserver_pcb !=NULL)
 {
 err = tcp_bind(tcp_echoserver_pcb,IP_ADDR_ANY,7);
 if(err == ERR_OK)
 {
 tcp_echoserver_pcb = tcp_listen(tcp_echoserver_pcb);
 tcp_accept(tcp_echoserver_pcb,tcp_echoserver_accept);
 }
 else
 {
 memp_free(MEMP_TCP_PCB, tcp_echoserver_pcb);
 }

 }

}
static err_t tcp_echoserver_accept(void *arg, struct tcp_pcb *newpcb,err_t err)
{
 /* initialize lwip tcp_recv callback function for newpcb */
 tcp_recv(newpcb, tcp_echoserver_recv);

 return ERR_OK;
}
static err_t tcp_echoserver_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p,err_t
err)
{

 tcp_write(tpcb,p->payload,p->len,1);
 pbuf_free(p);
 return ERR_OK;
}

2. 在 main 函数中添加 tcp_echoserver_init(),在 while(1)中添加 MX_LWIP_Process()查询接收数据。记得要将代码加在/*USER CODE BEGIN*/和/*USER CODE END*/之间,这样才不会在下次用 CubeMX 生成代码时被覆盖掉。

extern void tcp_echoserver_init(void);
int main(void)
{
 MX_LWIP_Init();

 /* USER CODE BEGIN 2 */
 tcp_echoserver_init();
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
 /* USER CODE END WHILE */
 /* USER CODE BEGIN 3 */
 MX_LWIP_Process();
 }
 /* USER CODE END 3 */
}

一个简单的 TCP Echoserver 程序就完成了。

测试结果

我们来看一看 ping 测试和 TCP 测试工具的结果
1. 通过电脑(192.168.0.11)ping STM32F746-Nucleo 板(192.168.0.10)

从零开始使用 CubeMX 创建以太网工程

2.通过 TCP 测试工具模拟客户端,向 STM32F746-Nucleo 板发一串数据。
从零开始使用 CubeMX 创建以太网工程

测试结果说明我们刚刚建立的 TCP EchoServer 程序已经能正常工作了。

来源: eefocus

围观 749

单片机的种类繁多,从低端到高端,有以51单片机为代表的8位单片机和以ARM为代表的32位单片机,不同档次的单片机实现网络接口的方法不同。对于像ARM等高端处理器一般都可以运行嵌入式操作系统,例如嵌入式Linux。对于无操作系统要求的单片机如何实现网络接入,我下面将这些方案按TCP/IP协议栈的不同归结为两大类:第一类是传统的软件TCP/IP协议栈方案;第二类是最新的硬件TCP/IP协议栈方案。下面我就这两类方案的实现方式进行分析。

1、MAC+PHY方案

所谓的TCP/IP协议栈是一系列网络协议的统称,不仅包括我们熟知的TCP协议和IP协议,还有网络层的ICMP(Internet控制报文)协议、IGMP(Internet 组管理)协议、ARP(地址解析)协议,传输层的UDP(用户数据包)协议,应用层的HTTP(超文本传输)协议、DNS(域名解析)协议、FTP(文件传送)协议、SMTP(简单邮件管理)协议等等。

传统的以太网接入方案如下图,由MCU+MAC+PHY再加入网络接口实现以太网的物理连接,通过在主控芯片中植入TCP/IP协议代码实现通信及上层应用。

图3-1-1 MAC+PHY以太网方案

应用这种软件TCP/IP协议栈方式实现的比较成熟方案有ENC28J60, CS8900A,DM9000,当然也有像MM32F103这类(内部自带MAC)+PHY等方案。

由于软件协议栈操作需要主控MCU不断地响应中断,这在很大程度上占用了MCU的运算/时钟资源。经过测试发现,单线程操作的情况下,MCU的运行速度和数据的处理速度仅能满足需要,但随着线程增多,MCU的工作效率直线下降,会严重影响通信质量。

代码量方面,即便是采用轻量级的TCP/IP协议栈LWIP协议,也会为主控芯片带来超过40KB的代码量,这对于本身内存资源匮乏的单片机来说负荷过重。

再从安全性的角度,设备并入互联网之后必须考虑网络安全问题,这种软件协议栈的方式系统一旦受到复杂的恶意攻击,单片机很有可能瘫痪掉,这对系统就是致命性打击,虽然目前网络技术不断发展,各类新的加密技术试图让通信变得更加安全,但是还会出现各种各样的漏洞。

2、硬件协议栈芯片方案

硬件协议栈芯片方案如下图所示。由MCU+硬件协议栈芯片(内含MAC和PHY)直接加网络接口,便可方便的实现单片机联网,所有的处理TCP/IP协议的工作都是通过这位MCU的“小秘书”——硬件协议栈芯片来完成。

图3-2-1 硬件协议栈芯片方案

这套方案是由WIZnet首次提出,并成功推出以太网系列芯片:W5100、W5200、W5300和W5500。

所谓硬件协议栈是指通过将传统的软件TCP/IP协议栈用硬件化的逻辑门电路来实现,如下图所示。

图3-2-2 TCP/IP硬件协议栈内核原理简图

以太网芯片的内核由传输层的TCP、UDP、ICMP、IGMP等协议、网络层的IP、ARP、PPPoE等协议以及链路层的MAC构成,再加上物理层的PHY和外围的寄存器、内存、SPI接口组成了这一整套硬件化的以太网解决方案。

这套硬件TCP/IP协议栈代替了以往的MCU来处理这些中断请求,即MCU只需要处理面向用户的应用层数据即可,传输层、网络层、链路层及物理层全部由外围WIZnet的芯片完成。这套方案从硬件开销和软件开发两个方面来简化前面所述的五层网络模型,简化产品开发方案。这样一来,工程师们就不必再面对繁琐的通信协议代码,只需要了解简单的寄存器功能以及Socket编程便能完成产品开发工作的的网络功能开发部分。

由于硬件协议栈的加入协助单片机处理了几乎所有的TCP/IP协议工作,不仅极大地减少了单片机的中断次数,让单片机腾出更多资源去完成其他工作,而且硬件化的电路处理协议会更加快速、稳定。经试验测试,单线程下,该方案的通信速度是软件协议方案的10倍左右;随着线程的增加,因为硬件协议栈是通过独立的Socket进行通信,因而通信速度实现累加,而且单片机工作效率仍然会维持在高位。

代码量方面,因为这套方案主要是完成对Socket的编程以及寄存器的调用,因此仅有10K左右的代码量,远小于软件协议方案,对51以及MM32等内存很有限的单片机来说非常适用。

从成本角度来讲,硬件协议栈芯片的价格跟用MAC+PHY比起来基本差不多。而前者简单易用,用很短时间便能完成产品的开发过程。另外,官方例程库及上位机程序丰富,也缩短了测试过程,后期基本免于维护。

最后安全性方面,硬件化的逻辑门电路来处理TCP/IP协议是不可攻击的,也就是说网络攻击和病毒对它无效,这也充分弥补了网络协议安全性不足的短板。也正是因为这一优势,硬件协议栈技术在未来物联网以及智能家居领域有着广泛的发展前景,让人们尽情享受现代科技带来的乐趣的同时,免受安全问题的困扰。

当然,不可避免的硬件化的协议栈相对来说失去了软件协议栈那样的灵活性。目前只支持4个/8个Socket,不能随时开启更多Socket。但是,在嵌入式应用中8个Socket已经足够应对超过大部分的应用。

围观 754

页面

订阅 RSS - 以太网