IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 使用STM32F4标准外设库实现网线热插拔- 移植官方思路到自己实际固件工程 -> 正文阅读

[嵌入式]使用STM32F4标准外设库实现网线热插拔- 移植官方思路到自己实际固件工程

前言

从同事工程上改了一个版本出来, 发现如果不插入网线, 不能正常跑. 卡在网卡初始化那里了.
如果不能实现网线热插拔, 我改出的版本不能实际用在客户现场的. 如果不插入网线, 就不能正常用, 这谁受的了啊.

前面做了一个预研使用STM32F4标准外设库实现网线热插拔- 分析STM3240G-EVAL官方工程, 知道ST官方怎么玩网线热插拔了.

今天, 用ST官方工程的思路, 将网线热插拔实现移植到自己工程中, 基本可以用.
但是有一些小问题(还能接受, 也能跟同事和客户解释的通), 先这样.

官方的网线热插拔效果: 不管啥时候插拔网线, 只要再插入网线, 网络操作就好使(e.g. ping), 即使固件开机时, 没有插入网线.

我移植完的效果: 如果固件开机时, 插入了网线,正常情况网卡就能初始化成功, 这种场景下, 再插拔网线, 只要插上网线, 网络操作就好使(e.g. ping). 但是, 如果固件开机时, 没插入网线, 等程序跑起来后, 再插拔网线, 网络操作是不好使的, 很明显, 是少做了一些网卡初始化操作, 但是我暂时找不出来, 同事的工程也是乱乱的. 猜测是网卡没插网线(网卡初始化失败), 后面起的LWIP操作(起了一些LWIP相关线程), 操作的好多数据结构都是无效的, 所以简单设置网卡上线/下线是不好使的. 想了一个折中的方法, 如果检测到网线插入, 但是此时是网线没插入开机启动的情况, 因为我知道此种情况, 网络操作是不好使的, 我就重启固件. 然后就走开机时, 插入网线的操作流程, 剩下就OK了. 就是比官方工程多了一次重启固件的动作. 在我们这个工程中, 重启固件没啥大事. 能接受.

总之吧, 这次只是将问题解决了. 不完美.
以后我自己从头写的固件工程, 如果还有机会使用STM标准外设库(不过以后新工程该使用HAL库了), 我好好弄弄. 整的明明白白的.
这次就先这样.

实验记录

这次记录, 从我开始改之前的git版本和改完做的git版本比对, 看看哪里变了, 就记录下来作为笔记.

IDE

MDK5

用图形化git工具比较任意2个git版本的方法

先在git log列表中, 按住CTRL键, 选中2个版本, 再选择 git比较版本.
在这里插入图片描述

打开网络状态回调宏

opt.h

#ifndef LWIP_NETIF_LINK_CALLBACK
#define LWIP_NETIF_LINK_CALLBACK        1 // 之前是0, 无法做网络回调函数注册
#endif

如果要在LWIP函数中使用bool 类型, 需要加 stdbool.h

#include <stdbool.h>

增加网线热插拔回调函数调用


extern void ETH_link_callback(struct netif* netif);
void Ethernet_Sys_Init(void)
{			  
    struct ip_addr ipaddr;
    struct ip_addr netmask;
    struct ip_addr gw;

 //   printf("TCP/IP initializing... \r\n");
	tcpip_init(NULL, NULL);
 //   printf("TCP/IP initialized. \r\n");
	Create_MAC(CONFIG_Table.MAC);
#if LWIP_DHCP			//启用DHCP服务器 */
    ipaddr.addr  = 0;
    netmask.addr = 0;
    gw.addr 	 = 0;
#else				   	//启用静态IP地址
	IP4_ADDR(&ipaddr,  LWIP_Netcfg.ipaddr[0], LWIP_Netcfg.ipaddr[1], LWIP_Netcfg.ipaddr[2], LWIP_Netcfg.ipaddr[3]);
	IP4_ADDR(&netmask, LWIP_Netcfg.netmask[0], LWIP_Netcfg.netmask[1], LWIP_Netcfg.netmask[2], LWIP_Netcfg.netmask[3]);
	IP4_ADDR(&gw, LWIP_Netcfg.gateway[0], LWIP_Netcfg.gateway[1], LWIP_Netcfg.gateway[2], LWIP_Netcfg.gateway[3]);
#endif   
    netif_add(&stm32_netif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &tcpip_input);
    netif_set_default(&stm32_netif);
#if LWIP_DHCP
    dhcp_start(&stm32_netif);
#endif
    netif_set_up(&stm32_netif);

	// 在LWIP初始化最后面, 注册网线热插拔回调	
	/*  Registers the default network interface.*/
	netif_set_link_callback(&stm32_netif, ETH_link_callback); // 注册网线热插拔回调
}

extern void ETH_Delay(__IO uint32_t nCount);
extern struct netif  			stm32_netif;

// ETH_link_callback 是网线热插拔回调, 从官方工程中移植过来的, 注意将网卡地址, 寄存器号码等核对下.
void ETH_link_callback(struct netif* netif)
{
	__IO uint32_t timeout = 0;
	uint32_t tmpreg, RegValue;
	struct ip_addr ipaddr;
	struct ip_addr netmask;
	struct ip_addr gw;

	if (NULL != netif) {
		if (netif_is_link_up(netif)) {
			/* Restart the autonegotiation */
			if (ETH_InitStructure.ETH_AutoNegotiation != ETH_AutoNegotiation_Disable) {
				/* Reset Timeout counter */
				timeout = 0;
				/* Enable Auto-Negotiation */
				ETH_WritePHYRegister(LAN8720_PHY_ADDRESS, PHY_BCR, PHY_AutoNegotiation);

				/* Wait until the auto-negotiation will be completed */
				do {
					timeout++;
				} while (!(ETH_ReadPHYRegister(LAN8720_PHY_ADDRESS, PHY_BSR) & PHY_AutoNego_Complete)

				         && (timeout < (uint32_t)PHY_READ_TO));

				/* Reset Timeout counter */
				timeout = 0;
				/* Read the result of the auto-negotiation */
				RegValue = ETH_ReadPHYRegister(LAN8720_PHY_ADDRESS, PHY_SR);

				/* Configure the MAC with the Duplex Mode fixed by the auto-negotiation process */
				if ((RegValue & PHY_DUPLEX_STATUS) != (uint32_t)RESET) {
					/* Set Ethernet duplex mode to Full-duplex following the auto-negotiation */
					ETH_InitStructure.ETH_Mode = ETH_Mode_FullDuplex;
				} else {
					/* Set Ethernet duplex mode to Half-duplex following the auto-negotiation */
					ETH_InitStructure.ETH_Mode = ETH_Mode_HalfDuplex;
				}

				/* Configure the MAC with the speed fixed by the auto-negotiation process */
				if (RegValue & PHY_SPEED_STATUS) {
					/* Set Ethernet speed to 10M following the auto-negotiation */
					ETH_InitStructure.ETH_Speed = ETH_Speed_10M;
				} else {
					/* Set Ethernet speed to 100M following the auto-negotiation */
					ETH_InitStructure.ETH_Speed = ETH_Speed_100M;
				}

				/*------------------------ ETHERNET MACCR Re-Configuration --------------------*/
				/* Get the ETHERNET MACCR value */
				tmpreg = ETH->MACCR;
				/* Set the FES bit according to ETH_Speed value */
				/* Set the DM bit according to ETH_Mode value */
				tmpreg |= (uint32_t)(ETH_InitStructure.ETH_Speed | ETH_InitStructure.ETH_Mode);
				/* Write to ETHERNET MACCR */
				ETH->MACCR = (uint32_t)tmpreg;
				_eth_delay_(ETH_REG_WRITE_DELAY);
				tmpreg = ETH->MACCR;
				ETH->MACCR = tmpreg;
			}

			/* Restart MAC interface */
			ETH_Start();
			IP4_ADDR(&ipaddr,  LWIP_Netcfg.ipaddr[0], LWIP_Netcfg.ipaddr[1], LWIP_Netcfg.ipaddr[2], LWIP_Netcfg.ipaddr[3]);
			IP4_ADDR(&netmask, LWIP_Netcfg.netmask[0], LWIP_Netcfg.netmask[1], LWIP_Netcfg.netmask[2], LWIP_Netcfg.netmask[3]);
			IP4_ADDR(&gw, LWIP_Netcfg.gateway[0], LWIP_Netcfg.gateway[1], LWIP_Netcfg.gateway[2], LWIP_Netcfg.gateway[3]);
			netif_set_addr(&stm32_netif, &ipaddr, &netmask, &gw);
			/* When the netif is fully configured this function must be called.*/
			netif_set_up(&stm32_netif);
		} else {
			ETH_Stop();
			/*  When the netif link is down this function must be called.*/
			netif_set_down(&stm32_netif);
		}
	}
}

加入热插拔状态检测函数调用

我用的LAN8720, 没有网络状态改变的中断通知, 只能是随便找个线程, 来主动查询网线插拔状态

PHY_Linked_Status 的定义如下, 就是检测uint16_t的bit2是否为1

/** @defgroup PHY_basic_status_register 
  * @{
  */ 
#define PHY_AutoNego_Complete           ((uint16_t)0x0020)      /*!< Auto-Negotiation process completed */
#define PHY_Linked_Status               ((uint16_t)0x0004)      /*!< Valid link established */
#define PHY_Jabber_detection            ((uint16_t)0x0002)      /*!< Jabber condition detected */

extern void check_net_RJ45_hot_plug_inout(void);

// 检测网线热插拔
void check_net_RJ45_hot_plug_inout(void)
{
	// #define PHY_BCR                          0          // LAN8720 Basic Control Register
	// #define PHY_BSR                          1          // LAN8720 Basic Status Register
	// #define PHY_SR				((uint16_t)31) 		// LAN8720 PHY Special Control/Status Register
	uint16_t RegValue_PHY_BSR = 0;
	OSTimeDlyHMSM(0, 0, 1, 0); // 1秒检查一下网线热插拔
	/* Get Ethernet link status*/
	RegValue_PHY_BSR = ETH_ReadPHYRegister(LAN8720_PHY_ADDRESS, PHY_BSR); // net link status on BSR's bit2

	if (RegValue_PHY_BSR & PHY_Linked_Status) {
		if (gb_ETH_Init_ok) {
			// 固件开机后, 网线是插入的, 且初始化成功过
			if ((RegValue_PHY_BSR & PHY_Linked_Status) != (g_RegValue_PHY_BSR & PHY_Linked_Status)) {
				// 保证只在状态变化时才执行一次
				// 掉线变为在线
				g_RegValue_PHY_BSR = RegValue_PHY_BSR;
				netif_set_link_up(&stm32_netif);
			}
		} else {
			// 开始没插入网线, 导致第一次网卡没初始化成功
			// 这时, 网线插上了, 再咋弄网络操作(e.g. ping)都不好使.
			// 只能尝试重启一次固件, 走正常流程初始化网卡
			set_flag_system_restart(true); // 做个重启标记, 转出去之后, 主程序看到就重启了
		}
	} else {
		if ((RegValue_PHY_BSR & PHY_Linked_Status) != (g_RegValue_PHY_BSR & PHY_Linked_Status)) {
			// 保证只在状态变化时才执行一次
			// 在线变为掉线
			g_RegValue_PHY_BSR = RegValue_PHY_BSR;
			netif_set_link_down(&stm32_netif);
		}
	}

}

在网卡初始化之后, 调用LWIP初始化

void exec_lan8720_init()
{
	LAN8720_Init(); // 这里是不用等网卡是否初始化成功的, 我们后面通过其他任务中转圈来检测网线热插拔状态
	Ethernet_Sys_Init(); // LWIP初始化
}

void start_task(void* p_arg)
{
		// other process
		// ...

		// 在开始任务中调用网卡初始化和LWIP初始化
		#ifndef DEBUG_FLAG_NOT_USE_HTTP_SERVER_INSIDE
		exec_lan8720_init();
		#endif // #ifndef DEBUG_FLAG_NOT_USE_HTTP_SERVER_INSIDE

		// 在开始任务尾巴上, 转圈检测网线热插拔状态
		do {
			// other process
			// ...
			check_net_RJ45_hot_plug_inout(); // 检测网线热插拔
		} while (true);

}

打开 USE_Delay 宏, 使用自己的LWIP延时函数

#define USE_Delay    	//使用默认延时函数,因此注销掉
#ifdef USE_Delay
	#define _eth_delay_    my_ETH_Delay     //用户自己提供的延时函数
                                    
#else
	#define _eth_delay_    ETH_Delay // 默认的_eth_delay功能函数延时精度差
#endif

重新实现LWIP操作延时函数

以前维护工程时, 发现LAN8720初始化不是每次都成功(但是最多初始化10次, 就能初始化成功, 感觉好奇怪, 最后改为只有网卡初始化成功了, 才往下执行), 今天发现是LWIP自用的延时函数时间短了, 重新包装了一个ms延时的函数, 每次LAN8720都能初始化成功(只要先用网线将设备和HUB连在一起)

// .h 加入函数声明 或 暴力的在.c前面extern fuction
extern void my_ETH_Delay(__IO uint32_t nCount);

void my_ETH_Delay(__IO uint32_t nCount)
{
	__IO uint32_t index = 0;

	for (index = nCount; index != 0; index--) {
		OSTimeDlyHMSM(0, 0, 0, 1);
	}
}

增加 ETH_Stop() 实现

检测到网线拔出时用的.
这个函数DISABLE的顺序, 最好和ETH_Start()是反的.

// .h 中加入函数声明 void ETH_Stop(void); 
void ETH_Stop(void)
{  
  /* Stop DMA reception */
  ETH_DMAReceptionCmd(DISABLE); // havee

  /* Stop DMA transmission */
  ETH_DMATransmissionCmd(DISABLE); // have

  /* Disable receive state machine of the MAC for reception from the MII */
  ETH_MACReceptionCmd(DISABLE); // have

  /* Flush Transmit FIFO */
  ETH_FlushTransmitFIFO(); // have

  /* Disable transmit state machine of the MAC for transmission on the MII */
  ETH_MACTransmissionCmd(DISABLE); // have
}

// ETH_Start() 的实现, 可以和ETH_Stop()比较ENABEL, DISABLE的顺序
// ETH_Start 最先ENABLE哪条, ETH_Stop就要最后DISABLE哪条.
void ETH_Start(void)
{
  /* Enable transmit state machine of the MAC for transmission on the MII */  
  ETH_MACTransmissionCmd(ENABLE);
  /* Flush Transmit FIFO */
  ETH_FlushTransmitFIFO();
  /* Enable receive state machine of the MAC for reception from the MII */  
  ETH_MACReceptionCmd(ENABLE);
 
  /* Start DMA transmission */
  ETH_DMATransmissionCmd(ENABLE); 
  /* Start DMA reception */
  ETH_DMAReceptionCmd(ENABLE);   
}

LAN8720用到的几个寄存器

ST官方板子用的DP83848, 我的板子用的LAN8720. 从官方工程移植时, 注意自己板子的网卡地址(硬件原理图相关, 不是固定的地址),网卡寄存器号码, 网卡寄存器含义(datasheet有描述).

LAN8720主要是以下3个寄存器, 网卡插拔状态在PHY_BSR的bit2, PHY_BSR.bit2 = 1 为网线插入, 0 为网线拔出.
BSR means : Basic Status Register

#define PHY_BCR                          0          // LAN8720 Basic Control Register
#define PHY_BSR                          1          // LAN8720 Basic Status Register
#define PHY_SR				((uint16_t)31) 		// LAN8720 PHY Special Control/Status Register

这些寄存器和寄存器定义, 可以看LAN8720 datasheet <<C17146_LAN8720AI-CP-TR_2017-12-12.PDF>> 42页
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

LAN8720_Init()实现

这函数以前是返回是否初始化成功的, 现在不管是否初始化成功了, 管了也没用.
如果插入有效网线(网线一端连接设备,一端连接HUB), 一定能初始化成功
如果没有插入有效网线(包括网线一端连接设备,一端悬空), 一定初始化失败
不管网卡是否初始化成功, 都要往下走, 不能卡在这.

void LAN8720_Init(void)
{
	//	u8 rval=0;
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD,
	                       ENABLE);//使能GPIO时钟 RMII接口
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);   //使能SYSCFG时钟
	SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_RMII); //MAC和PHY之间使用RMII接口
	/*网络引脚设置 RMII接口
	  ETH_MDIO -------------------------> PA2
	  ETH_MDC --------------------------> PC1
	  ETH_RMII_REF_CLK------------------> PA1
	  ETH_RMII_CRS_DV ------------------> PA7
	  ETH_RMII_RXD0 --------------------> PC4
	  ETH_RMII_RXD1 --------------------> PC5
	  ETH_RMII_TX_EN -------------------> PB11
	  ETH_RMII_TXD0 --------------------> PB12
	  ETH_RMII_TXD1 --------------------> PB13
	  ETH_RESET-------------------------> PD3*/
	//配置PA1 PA2 PA7
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_ETH); //引脚复用到网络接口上
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_ETH);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_ETH);
	//配置PC1,PC4 and PC5
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5;
	GPIO_Init(GPIOC, &GPIO_InitStructure);
	GPIO_PinAFConfig(GPIOC, GPIO_PinSource1, GPIO_AF_ETH); //引脚复用到网络接口上
	GPIO_PinAFConfig(GPIOC, GPIO_PinSource4, GPIO_AF_ETH);
	GPIO_PinAFConfig(GPIOC, GPIO_PinSource5, GPIO_AF_ETH);
	//配置PB11, PB12 and PB13
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_ETH); //引脚复用到网络接口上
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_ETH);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_ETH);
	//配置PD3为推完输出
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;	//推完输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
	GPIO_Init(GPIOD, &GPIO_InitStructure);
	LAN8720_RST = 0;					//硬件复位LAN8720
	delay_ms(50);
	LAN8720_RST = 1;				 	//复位结束
	delay_ms(50);
	ETH_MACDMA_Config();		//配置MAC及DMA
}

对网卡初始化成功做个标记

gb_ETH_Init_ok 为标记, 如果固件启动后, 网线不插, ETH_Init就会在中途返回失败
将 ETH_Init() 结果赋值给 gb_ETH_Init_ok , 这样就知道固件启动时, 是否插入了网线启动的.
如果(gb_ETH_Init_ok == true), 说明固件启动时, 是插入网线(网线一端接设备, 一端接HUB)启动的.
如果(gb_ETH_Init_ok == false), 说明固件启动时, 是没插入网线启动的, 如果再检测到网线插入, 就要重启固件, 走插入网线启动固件的正常流程.

在(gb_ETH_Init_ok == true), 用 g_RegValue_PHY_BSR保存一下当前网线插入状态, 这样在网线热插拔时, 可以保证只在网线插拔状态改变时, 执行一次有效的网卡上线或下线操作.

void ETH_MACDMA_Config(void)
{
	// u8 rval;
	//使能以太网MAC以及MAC接收和发送时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_ETH_MAC | RCC_AHB1Periph_ETH_MAC_Tx | RCC_AHB1Periph_ETH_MAC_Rx, ENABLE);
	ETH_DeInit();  								//AHB总线重启以太网
	ETH_SoftwareReset();  						//软件重启网络

	while (ETH_GetSoftwareResetStatus() == SET);//等待软件重启网络完成

	ETH_StructInit(&ETH_InitStructure); 	 	//初始化网络为默认值
	///网络MAC参数设置
	ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable;   			//开启网络自适应功能
	ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable;					//关闭反馈
	ETH_InitStructure.ETH_RetryTransmission = ETH_RetryTransmission_Disable; 		//关闭重传功能
	ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable; 	//关闭自动去除PDA/CRC功能
	ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable;						//关闭接收所有的帧
	ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable;//允许接收所有广播帧
	ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable;			//关闭混合模式的地址过滤
	ETH_InitStructure.ETH_MulticastFramesFilter =
	    ETH_MulticastFramesFilter_Perfect;//对于组播地址使用完美地址过滤
	ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect;	//对单播地址使用完美地址过滤
#ifdef CHECKSUM_BY_HARDWARE
	ETH_InitStructure.ETH_ChecksumOffload =
	    ETH_ChecksumOffload_Enable; 			//开启ipv4和TCP/UDP/ICMP的帧校验和卸载
#endif
	//当我们使用帧校验和卸载功能的时候,一定要使能存储转发模式,存储转发模式中要保证整个帧存储在FIFO中,
	//这样MAC能插入/识别出帧校验值,当真校验正确的时候DMA就可以处理帧,否则就丢弃掉该帧
	ETH_InitStructure.ETH_DropTCPIPChecksumErrorFrame =
	    ETH_DropTCPIPChecksumErrorFrame_Enable; //开启丢弃TCP/IP错误帧
	ETH_InitStructure.ETH_ReceiveStoreForward =
	    ETH_ReceiveStoreForward_Enable;     //开启接收数据的存储转发模式
	ETH_InitStructure.ETH_TransmitStoreForward =
	    ETH_TransmitStoreForward_Enable;   //开启发送数据的存储转发模式
	ETH_InitStructure.ETH_ForwardErrorFrames = ETH_ForwardErrorFrames_Disable;     	//禁止转发错误帧
	ETH_InitStructure.ETH_ForwardUndersizedGoodFrames = ETH_ForwardUndersizedGoodFrames_Disable;	//不转发过小的好帧
	ETH_InitStructure.ETH_SecondFrameOperate = ETH_SecondFrameOperate_Enable;  		//打开处理第二帧功能
	ETH_InitStructure.ETH_AddressAlignedBeats = ETH_AddressAlignedBeats_Enable;  	//开启DMA传输的地址对齐功能
	ETH_InitStructure.ETH_FixedBurst = ETH_FixedBurst_Enable;            			//开启固定突发功能
	ETH_InitStructure.ETH_RxDMABurstLength =
	    ETH_RxDMABurstLength_32Beat;     		//DMA发送的最大突发长度为32个节拍
	ETH_InitStructure.ETH_TxDMABurstLength = ETH_TxDMABurstLength_32Beat;			//DMA接收的最大突发长度为32个节拍
	ETH_InitStructure.ETH_DMAArbitration = ETH_DMAArbitration_RoundRobin_RxTx_2_1;

	// 配置ETH
	if (ETH_SUCCESS == ETH_Init(&ETH_InitStructure, LAN8720_PHY_ADDRESS)) {
		gb_ETH_Init_ok =
		    true; // 只有在固件启动时, 插入网线初始化成功了, 后面的网线热插拔才好使. 暂时是这样
		// 备份一下第一次网卡初始化的网线插入状态
		g_RegValue_PHY_BSR = ETH_ReadPHYRegister(LAN8720_PHY_ADDRESS, PHY_BSR); // net link status on BSR's bit2
	}

	ETH_DMAITConfig(ETH_DMA_IT_NIS | ETH_DMA_IT_R, ENABLE);  	//使能以太网接收中断
}

本次实验结束

就这些改动了, 研究了4,5天.

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-02-03 01:20:18  更:2022-02-03 01:21:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 10:18:09-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码