Bootstrap

STM32F4以太网LWIP - LAN8720

目录

网络协议简介

常用网络协议

网络协议的分层模型

协议层报文间的封装与拆封

STM32F4以太网MAC简介

MAC简介:

SMI接口(站管理接口):

MII接口(介质独立接口):

RMII接口(精简介质独立接口):

LAN8720

LAN8720简介

LAN8720地址设置

nINT/REFCLKO配置

REFCLK-In模式

REFCLK-Out模式

LAN-8720寄存器

BCR基础控制寄存器(0)

BSR基础状态寄存器(1)

LAN8720特殊功能寄存器(31)

硬件连接

以太网DMA描述符

DMA描述符介绍

DMA描述符链接结构

 LWIP无操作系统移植

 ST以太网驱动库

网卡驱动

LAN8720.c主要程序原理


网络协议简介

  • 常用网络协议

TCP/IP是一个协议簇,包含众多网络协议

如TCP、IP、HTTP、FTP、MQTT、UDP、HRP、DHCP、DNS等等

  • 网络协议的分层模型

应用层: HTTP、FTP、DNS、SMTP邮件协议    应用层处理用户和网络应用之间的通信

传输层:TCP、UDP协议                                      传输层负责网络中不同设备的连接和传输

网络层:IP、ICMP、HRP协议                             网络层在不同网络之间传输数据包(帧格式路由)

链路层:MAC层                                                    链路层凭MAC地址在直连设备之间传输数据       

物理层:物理传输介质                                          

  • 协议层报文间的封装与拆封

当用户发送数据时,将数据在应用层向下交给传输层,传输层会在数据前面加上传输层首部,然后向下交给网络层,网络层会在数据前面加上网络层首部,下交给链路层,链路层加上链路层首部后交给网卡,网卡将数据转换成物理链路上的电平信号,将数据发送到网络中

STM32F4以太网MAC简介

MAC简介:

STM32F407自带有10/100Mbits/s数据传输速率的以太网内核(以太网网络接口卡的控制器,负责以太网中数据帧的发送和接收),这个以太网MAC内核有如下特性:

1. 支持外部PHY接口(以太网外部端口芯片,如LAN8720)实现10/100Mbit/s数据传输速率

2. 通过符合IEEE802.3的MII接口与外接的快速以太网PHY进行通信(MAC内核通过MII或RMII与PHY进行数据交换)

3. 支持全双工和半双工操作

4. 报头和帧起始数据(SFD)在发送路径中插入、在接收路径中删除

5. 可逐帧控制CRC和pad自动生成

6. 可编程帧长度,支持高达16KB的巨型帧

7. 可编程帧间隔(40-69位时间,以8为步长)

8. 支持通过MDIO接口配置和管理PHY设备(通过SMI接口对PHY进行配置)

STM32F407的SMI框图

需要注意的是以太网DMA有各2KB的发送和接收缓冲区

SMI接口(站管理接口):

F407的SMI接口有3种,SMI 和 MII、RMII

SMI称为站管理接口,程序中可以通过这个接口来访问PHY寄存器,对PHY进行配置

SMI接口有两条线,数据线MDIO和时钟线MDCSMI允许应用程序通过时钟线MDC和数据线MDIO访问任意PHY寄存器,可支持访问多达32个PHY应用程序可以从32个PHY中选择一个PHY,发送控制数据或接收状态信息。任意给定时间内只能对一个PHY的一个寄存器进行寻址。

MDC:周期性时钟线,提供最大2.5MHz的参考时序。在空闲状态下为低电平

MDIO:数据输入/输出线,通过MDC时钟信号与PHY设备之间同步传输信息

SMI接口

MII接口(介质独立接口):

介质独立接口(MII)定义了10/100Mbit/s的数据传输速率下MAC子层与PHY之间的互连方式,程序通过该接口使得MAC内核与PHY之间完成数据传输

MII接口

TX_CLK和RX_CLK为发送和接收连续时钟,当内核速率为10Mbit/s时发送和接收时钟为2.5MHZ,当速率为100Mbit/s时为25MHZ(因为发送和接收都是4根线,发送接收线速率=内核速率/4)。

要生成TX_CLK和RX_CLK时钟,必须向外部PHY提供25MHZ时钟,通常我们使用25M的晶振,也可以使用STM32芯片的MCO引脚输出25MHZ的时钟。

外部PHY时钟提供方式

RMII接口(精简介质独立接口):

精简介质独立接口(RMII) 规范用于降低10/100Mbit/s下微控制器与以太网PHY之间的引脚数

根据IEEE 802.3u标准,MII包括16个数据和控制信号的引脚,RMII规范将引脚数减少为7个,但要求RMII的参考时钟必须是50MHz

RMII介质独立标准

RMII时钟源通常使用50MHz的时钟来驱动PHY,或使用PLL电路生成50MHz的频率来驱动PHY

由于Lan8720内部具备倍频功能,因此外部时钟源只需25MHz,会自动倍频后返回到REF_CLK线上,得到50MHz的时钟频率

RMII时钟源

LAN8720

LAN8720简介

LAN8720是低功耗的10/100MHz以太网PHY层芯片,支持通过RMII接口与以太网MAC层通信内置10-BASE-T/100-BASE-TX全双工模块传输模块,支持10Mbps和100Mbps。LAN8720可以通过自协商的方式确定与目的主机最佳的连接方式(速度和双工模式)。支持HPAuto-MDIX自动翻转功能,无需更换网线即可将连接更改为直连(TX接TX,RX接RX)和交叉连接(TX接RX)。

1. 支持RMII接口以减少引脚数

2. 支持全双工和半双工模式

3. 可以使用25M晶振以降低成本

4. 支持SMI串行管理接口

5. 支持MAC接口

LAN8720地址设置

前面说了MAC内核可以通过SMI接口来读写PHY(LAN8720的寄存器),SMI最多可以控制32个PHY芯片,通过不同的PHY芯片地址来对PHY芯片进行操作。LAN8720通过设置RXER/PHYAD0引脚来设置其PHY地址,默认情况下为0,其地址设置如下表所示。STM32F407开发板使用的是默认地址,也就是0x00。

LAN8720的PHY地址设置

nINT/REFCLKO配置

nINTSEL引脚用于设置nINT/REFCLKO引脚的功能。通常默认为低电平。nINT/SEL配置如下表所示:

nINT/SEL引脚配置

REFCLK-In模式

当工作在REFCLK-In模式时,50MHz的外部时钟信号应接到LAN8720的XTAL1/CKIN引脚和STM32F407的RMII-REF-CLK引脚上

REFCLKO引脚工作在REFCLK-IN模式时外部时钟信号接线方式

REFCLK-Out模式

为了降低成本,LAN8720可以从外部的25MHz的晶振中产生REF_CLK时钟。但要使用此功能时,REFCLKO引脚应工作在REFCLK-Out模式,此时REF_CLK时钟源如下图所示。图上外接了一个25MHz的时钟源,REFCLKO接口将内部倍频到50MHz的晶振通过REF_CLK接口供给MAC内核。

REFCLK-Out模式时REF_CLK时钟源

LAN-8720寄存器

PHY是由IEEE 802.3定义的。一般通过SMI对PHY进行管理和控制,也就是读写PHY内部寄存器。PHY内部寄存器的地址空间为5位,可以定义0~31共32个寄存器,但是随着PHY芯片功能的增加,很多PHY芯片采用分页技术来扩展地址空间,定义更多的寄存器,此处不讨论该情况。

IEEE 802.3定义了0~15这16个寄存器的功能,16~31寄存器由芯片制造商自由定义。下面介绍3个重要的LAN8720寄存器

BCR基础控制寄存器(0)

位15  软件复位 置1此位自动清零

位14  回测         0正常运行  1回测模式  回测模式下发送的数据会环回到发送接口,测试网络用

位13  速度选择  0为10Mbps,1为100Mbps。使用自动协商时此位自动失能

位12  自动协商功能 0关闭 1打开

位11  掉电    0正常运行 1进入掉电模式  进入掉电模式前自动协商必须失能

位10  隔离  0正常运行  1PHY的RMII接口电气隔离

位9    重启自动协商功能  0正常运行 1重启自动协商功能  此位自动清零

位8    双工模式  0半双工  1全双工  开启自动协商后此位自动失效

位7:0  保留     

BSR基础状态寄存器(1)

位15  100BASE-T4(4根线) 0不支持T4 1支持T4

位14  100BAST-TX全双工 0不支持TX全双工 1支持TX全双工

位13  100BASE-TX半双工 0不支持TX半双工 1支持TX半双工

位12  10BAST-T全双工 0不支持10MBps全双工 1支持10MBps全双工

位11  10BAST-T半双工 0不支持10MBps半双工 1支持10MBps半双工

位10:6  保留

位5    自动协商功能   0自动协商功能未完成 1自动协商功能完成

位4    远端错误 0无远端错误 1检测到远端错误

位3    自协商功能是否可执行   0可执行自协商功能 1不可执行自协商功能

位2    连接状态  0连接断开  1连接建立

位1    Jabber检测(数据传输异常)   0未检测到Jabber  1检测到Jabber 

位0    扩展功能  0不支持扩展寄存器  1支持扩展寄存器

LAN8720特殊功能寄存器(31)

LAN8720特殊功能寄存器中的2~4bit是我们关心的,因为从这3个bit中我们可以判断当前开发板网络的双工方式和网速。这个寄存器的地址和bit的意义需要我们手动添加到ST的以太网驱动库文件stm32f4x7_eth_conf.h中,而BCR和BSR寄存器定义在stm32f4x7_eth.h中

LAN8720特殊功能寄存器

硬件连接

LAN8720引脚功能

以太网DMA描述符

DMA描述符介绍

STM32F407有一个以太网专用的DMA,DMA可以在CPU完全不干预的情况下,通过描述符有效地将数据从源传送到目标,接收缓冲区和发送缓冲区的数据都可以通过以太网DMA来传送。

共有两个描述符,一个用于发送,一个用于接收。描述符是一种链表,最后一个描述符会指回第一个描述符以构成环形结构。描述符链表位于主机(RAM)的物理存储空间,两个链表的基址分别写入ETH_DMARDLAR(Descriptor List Address Register)寄存器和ETH_DMATDLAR寄存器中。每个描述符最多可指向两个缓冲区。描述符一共有两种结构: 环形结构和链接结构。发送和接收描述符在程序中共用一个结构体,通过存入的寄存器不同来进行功能区分(RDLAR和TDLAR寄存器)。

DMA描述符的两种数据结构

DMA描述符链接结构

ST提供给我们的以太网驱动库使用的描述符是链接结构。链接结构的第二个缓冲区用来存放下一个描述符的地址,最后一个描述符指向第一个描述符。

DMA描述符链接结构

描述符注意事项:

1、一个以太网数据包可以跨越一个或多个DMA描述符

2、一个DMA描述符只能用于一个以太网数据包

3、DMA描述符列表中的最后一个描述符指向第一个,形成链式结构

在ST的以太网驱动库stm32f4x7_eth.h中有个结构体ETH_DMADESCTypeDef,该结构体就是以太网描述符。发送描述符和接收描述符都使用该结构,但

以太网描述符结构体

描述符又分为常规描述符增强描述符,常规描述符和增强描述符又有发送描述符和接收描述符两种。

常规发送描述符

常规接收描述符

在stm32f4x7_eth.c中定义了两个DMA描述符数组,一个用于DMA接收,一个用于DMA发送 

  __align(4) 
   ETH_DMADESCTypeDef  DMARxDscrTab[ETH_RXBUFNB];/* DMA接收描述符数组*/
  __align(4) 
   ETH_DMADESCTypeDef  DMATxDscrTab[ETH_TXBUFNB];/* DMA发送描述符数组 */
  __align(4) 
   uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE]; /* DMA接收缓冲区 */
  __align(4) 
   uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE]; /* DMA发送缓冲区 */

 这两个数组和缓冲区的定义通常是要手动屏蔽掉的,因为此处宏定义的数组大小比较大,占用较多的RAM空间。一般屏蔽后使用动态内存管理自定义同名数组。

 LWIP无操作系统移植

 ST以太网驱动库

 ST提供的以太网驱动库有三个文件

ST以太网驱动库

LAN8720驱动程序

LAN8720的复位引脚默认是接地的,也就是默认复位,不然上电后发热严重(模拟芯片发热问题),初始化时需要手动把复位引脚拉高停止复位

网卡驱动

LAN8720驱动写完以后,我们还要编写ethernetif.c文件。LWIP作者提供了一个ethernet.c文件架构。我们需要根据实际使用的网络芯片来完善这些函数。

LAN8720.c主要程序原理

LAN8720.c中定义了以太网中断服务函数ETH_IRQHandler,中断可以提高数据的发送和接收效率

以太网中断服务函数包含了数据的接收处理流程,详细代码就不赘述了,结合重点代码简单介绍

//以太网中断服务函数
void ETH_IRQHandler(void)
{
	while(ETH_GetRxPktSize(DMARxDescToGet)!=0) 	//检测是否收到数据包   DMARxDescToGet是当前正在使用的接收描述符
	{ 
		lwip_pkt_handle();		//进行数据处理
	}
	ETH_DMAClearITPendingBit(ETH_DMA_IT_R);    //清除DMA接收完成标志位
	ETH_DMAClearITPendingBit(ETH_DMA_IT_NIS);  //清除DMA正常中断标志位
}  

以太网DMA描述符包括4个字段

状态码Status、

控制缓冲区ControlBuffersize、

缓冲区Buffer1Addr、

缓冲区Buffer2NextDescAddr           

32位状态码的最高位是OWN标志位,

OWN=1代表描述符由DMA处理(未接收数据),OWN=0代表描述符由CPU处理(接收到数据)

DMA描述符的Status"寄存器"位含义

以太网中断服务函数ETH_IRQHandler代码流程包括:

首先使用while关键字对当前接收描述符的大小进行循环判断DMARxDescToGet

如果关键字状态"寄存器"的OWN=0、ES=0、LS=1,则代表当前描述符是链式描述符的最后一个描述符,通过Status&FL宏取出状态码中的描述符大小(含4字节CRC校验位)Early/Last Status

如果描述符大小不为0,则代表描述符链表装载完数据,进行数据处理

数据处理是调用网卡协议栈LWIP直接对网卡数据进行解包处理

/*
**当接收到数据后调用   
*/
void lwip_pkt_handle(void)
{
 ethernetif_input(&lwip_netif);//从网络缓冲区中读取接收到的数据包并将其发送给LWIP处理 
}


//网卡接收数据(lwip直接调用)   MAC内核接收到数据要交给LWIP协议栈去解包处理
//netif:网卡结构体指针
//返回值:ERR_OK,发送正常
//       ERR_MEM,发送失败
err_t ethernetif_input(struct netif *netif)
{
	err_t err;
	struct pbuf *p;
	p=low_level_input(netif);  //网卡数据包接收函数
	if(p==NULL) return ERR_MEM;
	err=netif->input(p, netif);
	if(err!=ERR_OK)
	{
		LWIP_DEBUGF(NETIF_DEBUG,("ethernetif_input: IP input error\n"));
		pbuf_free(p);
		p = NULL;
	} 
	return err;
} 


///用于接收数据包的最底层函数
//neitif:网卡结构体指针
//返回值:pbuf数据结构体指针
static struct pbuf * low_level_input(struct netif *netif)
{  
	struct pbuf *p, *q;
	u16_t len;
	int l =0;
	FrameTypeDef frame;
	u8 *buffer;
	p = NULL;
	frame=ETH_Rx_Packet();
	len=frame.length;//得到包大小
	buffer=(u8 *)frame.buffer;//得到包数据地址 
	p=pbuf_alloc(PBUF_RAW,len,PBUF_POOL);//pbufs内存池分配pbuf
	if(p!=NULL)
	{
		for(q=p;q!=NULL;q=q->next)
		{
			memcpy((u8_t*)q->payload,(u8_t*)&buffer[l], q->len);
			l=l+q->len;
		}    
	}
	frame.descriptor->Status=ETH_DMARxDesc_OWN;//设置Rx描述符OWN位,buffer重归ETH DMA 
	if((ETH->DMASR&ETH_DMASR_RBUS)!=(u32)RESET)//当Rx Buffer不可用位(RBUS)被设置的时候,重置它.恢复传输
	{ 
		ETH->DMASR=ETH_DMASR_RBUS;//重置ETH DMA RBUS位 
		ETH->DMARPDR=0;//恢复DMA接收
	}
	return p;
}

;