GD32F470之网络lwip+UDP配置+lan8720芯片

这篇具有很好参考价值的文章主要介绍了GD32F470之网络lwip+UDP配置+lan8720芯片。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

先申明,本栏目用的都是GD32F470芯片240M,软件用的是keil,编写用的是C++(其实和C没有区别).

和STM32的lwip配置大致一样,主要不一样的地方在于
PHY的配置顺序问题,下面会讲到.

头文件部分:

我用的是lan8720,所以头文件要修改一下,在gd32f4xx_enet.h中。
把PHY_TYPE改为LAN8700,
PHY_ADDRESS改为0,
这是lan8720需要的。
然后就不需要修改了。里面的宏不会有问题,可以和原子的lan8720头文件对比一下。

#ifndef _PHY_H_
#define DP83848                          0
#define LAN8700                          1
#define PHY_TYPE                         LAN8700
//#define PHY_TYPE                         DP83848
//#define PHY_ADDRESS                      ((uint16_t)1U)                         /*!< phy address determined by the hardware */
#define PHY_ADDRESS                      ((uint16_t)0U)                         /*!< phy address determined by the hardware */

lwip部分:

整体上和原子的不会有很多区别,直接把原子的全部搬过来也是可以的。你也可以搬GD32例程的lwip过来也行。

GD32F470之网络lwip+UDP配置+lan8720芯片
GD32F470之网络lwip+UDP配置+lan8720芯片
GD32F470之网络lwip+UDP配置+lan8720芯片
其中Lwip/Core,Lwip/Arch,Lwip/Api都和STM32的是一样一模.

Lwip/Netif的ethernetif.c文件,和GD32例程一样,这和STM32的例程就有点不一样的。

#include "netif/ethernetif.h" 

#include "lwip_comm.h" 
#include "netif/etharp.h"  
#include "string.h"  
#include "sys.h"
#include "network.h"  

uint32_t current_pbuf_idx =0;

/* ENET RxDMA/TxDMA descriptor */
extern enet_descriptors_struct  rxdesc_tab[ENET_RXBUF_NUM], txdesc_tab[ENET_TXBUF_NUM];


/*global transmit and receive descriptors pointers */
extern enet_descriptors_struct  *dma_current_txdesc;
extern enet_descriptors_struct  *dma_current_rxdesc;

//extern uint8_t 	LocalMacAddr[6];				//本地Mac地址
//uint8_t 	LocalMacAddr[6] = {2,10,15,14,13,6};	//本地Mac地址

//由ethernetif_init()调用用于初始化硬件
//netif:网卡结构体指针 
//返回值:ERR_OK,正常
//       其他,失败
static void low_level_init(struct netif *netif)
{ 
    uint32_t i = 0;
  
    netif->hwaddr_len=ETHARP_HWADDR_LEN;  //设置MAC地址长度,为6个字节
		//初始化MAC地址,设置什么地址由用户自己设置,但是不能与网络中其他设备MAC地址重复
		netif->hwaddr[0]=lwipdev.mac[0]; 
		netif->hwaddr[1]=lwipdev.mac[1]; 
		netif->hwaddr[2]=lwipdev.mac[2];
		netif->hwaddr[3]=lwipdev.mac[3];   
		netif->hwaddr[4]=lwipdev.mac[4];
		netif->hwaddr[5]=lwipdev.mac[5];
	
		/* initialize MAC address in ethernet MAC */ 
    enet_mac_address_set(ENET_MAC_ADDRESS0, netif->hwaddr);
	
		netif->mtu=1500;//最大允许传输单元,允许该网卡广播和ARP功能
	
    netif->flags|=NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
	
    /* initialize descriptors list: chain/ring mode */
#ifdef SELECT_DESCRIPTORS_ENHANCED_MODE
    enet_ptp_enhanced_descriptors_chain_init(ENET_DMA_TX);
    enet_ptp_enhanced_descriptors_chain_init(ENET_DMA_RX);
#else

    enet_descriptors_chain_init(ENET_DMA_TX);
    enet_descriptors_chain_init(ENET_DMA_RX);
    
//    enet_descriptors_ring_init(ENET_DMA_TX);
//    enet_descriptors_ring_init(ENET_DMA_RX);

#endif /* SELECT_DESCRIPTORS_ENHANCED_MODE */

    /* enable ethernet Rx interrrupt */
    {   int i;
        for(i=0; i<ENET_RXBUF_NUM; i++){ 
           enet_rx_desc_immediate_receive_complete_interrupt(&rxdesc_tab[i]);
        }
    }
		
#ifdef CHECKSUM_BY_HARDWARE
    /* enable the TCP, UDP and ICMP checksum insertion for the Tx frames */
    for(i=0; i < ENET_TXBUF_NUM; i++){
        enet_transmit_checksum_config(&txdesc_tab[i], ENET_CHECKSUM_TCPUDPICMP_FULL);
    }
#endif /* CHECKSUM_BY_HARDWARE */
		
		/* note: TCP, UDP, ICMP checksum checking for received frame are enabled in DMA config */

    /* enable MAC and DMA transmission and reception */
    enet_enable();
		
		
}

//用于发送数据包的最底层函数(lwip通过netif->linkoutput指向该函数)
//netif:网卡结构体指针
//p:pbuf数据结构体指针
//返回值:ERR_OK,发送正常
//       ERR_MEM,发送失败
static err_t low_level_output(struct netif *netif, struct pbuf *p)
{

    struct pbuf *q;
    int framelength = 0;
    uint8_t *buffer;

    while((uint32_t)RESET != (dma_current_txdesc->status & ENET_TDES0_DAV)){
    }  
    buffer = (uint8_t *)(enet_desc_information_get(dma_current_txdesc, TXDESC_BUFFER_1_ADDR));
    
    /* copy frame from pbufs to driver buffers */
    for(q = p; q != NULL; q = q->next){ 
        memcpy((uint8_t *)&buffer[framelength], q->payload, q->len);
        framelength = framelength + q->len;
    }
    
    /* note: padding and CRC for transmitted frame 
       are automatically inserted by DMA */

    /* transmit descriptors to give to DMA */ 
#ifdef SELECT_DESCRIPTORS_ENHANCED_MODE
    ENET_NOCOPY_PTPFRAME_TRANSMIT_ENHANCED_MODE(framelength, NULL);
#else
    ENET_NOCOPY_FRAME_TRANSMIT(framelength);
#endif /* SELECT_DESCRIPTORS_ENHANCED_MODE */

    return ERR_OK;
}

//用于接收数据包的最底层函数
//neitif:网卡结构体指针
//返回值:pbuf数据结构体指针
static struct pbuf * low_level_input(struct netif *netif)
{
    struct pbuf *p, *q;
    u16_t len;
    int l =0;
    uint8_t *buffer;
     
    p = NULL;
    
    /* obtain the size of the packet and put it into the "len" variable. */
    len = enet_desc_information_get(dma_current_rxdesc, RXDESC_FRAME_LENGTH);
    buffer = (uint8_t *)(enet_desc_information_get(dma_current_rxdesc, RXDESC_BUFFER_1_ADDR));
    
    /* we allocate a pbuf chain of pbufs from the Lwip buffer pool */
    p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
    
    /* copy received frame to pbuf chain */
    if (p != NULL){
        for (q = p; q != NULL; q = q->next){ 
            memcpy((uint8_t *)q->payload, (u8_t*)&buffer[l], q->len);
            l = l + q->len;
        }    
    }
  
#ifdef SELECT_DESCRIPTORS_ENHANCED_MODE
    ENET_NOCOPY_PTPFRAME_RECEIVE_ENHANCED_MODE(NULL);
  
#else
    
    ENET_NOCOPY_FRAME_RECEIVE();
#endif /* SELECT_DESCRIPTORS_ENHANCED_MODE */

    return p;
}

//网卡接收数据(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;
}

//此函数使用low_level_init()函数来初始化网络
//netif:网卡结构体指针
//返回值:ERR_OK,正常
//       其他,失败
err_t ethernetif_init(struct netif *netif)
{
    LWIP_ASSERT("netif != NULL", (netif != NULL));
  
#if LWIP_NETIF_HOSTNAME
    netif->hostname="lwip"; //主机名字
#endif

    netif->name[0]=IFNAME0;
    netif->name[1]=IFNAME1;
    netif->output=etharp_output;
    netif->linkoutput=low_level_output;
    low_level_init(netif);
    return ERR_OK;
}




















重要配置代码部分

然后说到Lwip/App中的lwip_comme文件里面的lwip_comm_init()的函数,
注释有详细的配置流程。

重点是先不需要对内部enet初始化,和例程不一样,因为我们要对LAN8720初始化,
而enet_init库函数会对外部phy(LAN8720)读取,根据LAN8720来配置ENET_MAC_CFG 寄存器,这时候需要一致,不然出错。

//LWIP初始化(LWIP启动的时候使用)
//返回值:0,成功
//       1,内存错误
//       2,LAN8720初始化失败
//       3,网卡添加失败.


//第4点很重要,先配置LAN8720,再配置内部enet

//1.使能以太网时钟:
//	配置RCU模块来使能HCLK时钟和以太网发送/接收时钟。 
//2.配置通讯接口:
//	配置SYSCFG模块,选择接口模式(MII或RMII);
//	配置GPIO模块,将相应的功能脚映射到复用功能11(AF11)上。 
//3.等待复位完成:
//	轮询 ENET_DMA_BCTL 寄存器直到 SWR 位复位(SWR 位在上电复位后或系统复位后
//	默认置位)。 
//4.获取并配置PHY寄存器参数:
//	根据 HCLK 频率,配置 SMI 时钟频率,并访问 PHY 寄存器获取 PHY 的信息(例如是否
//	支持半/全双工,是否支持 10M/100Mbit 速度等等)。根据外部 PHY 支持的模式,配置
//	ENET_MAC_CFG 寄存器使与 PHY 寄存器信息一致。 

//5.初始化以太网DMA模块用于数据传输:
//	配 置 ENET_DMA_BCTL , ENET_DMA_RDTADDR , ENET_DMA_TDTADDR 和
//	ENET_DMA_CTL 寄存器,完成 DMA 模块初始化(详细信息请参考 DMA 控制器描述章
//	节)。
//6.初始化用于存放描述符列表以及数据缓存的物理内存空间:
//	根据 ENET_DMA_RDTADDR 和 ENET_DMA_TDTADDR 寄存器中的地址,初始化发送
//	和接收描述符(DAV=1),以及数据缓存。
//7.使能MAC和DMA模块,开始发送和接收:
//	置位 ENET_MAC_CFG 寄存器中的 TEN 和 REN 位,开启 MAC 发送器和接收器。置位
//	ENET_DMA_CTL 寄存器中的 STE 位和 SRE 位,使能 DMA 的发送和接收。
u8  Lwip_comm_Class::lwip_comm_init(void)
{
  u8 retry=0,enet_init_flag=0;
	struct netif *Netif_Init_Flag;			//调用netif_add()函数时的返回值,用于判断网络初始化是否成功
	struct ip_addr ipaddr;  						//ip地址
	struct ip_addr netmask; 						//子网掩码
	struct ip_addr gw;      						//默认网关 

	
	//若修改IP地址导致无法通信,无法修改回正确的IP地址,则使用以下默认的IP地址,重新下载程序
	
	lwip_comm_default_ip_set(&lwipdev);	//设置默认IP等信	

	LAN_8720_my_Private_Obj->IO_ETH_RST_M4();
	LAN_8720_my_Private_Obj->Lan8720_Io_Config_Init();

	//里面配了时钟 ,复位 MAC 所有内核寄存器
	while(LAN_8720_my_Private_Obj->LaN8720_Config_Init())
	{
			
			retry++;
			if(retry>5) {retry=0;return 3;} //LAN8720初始化失败
	
	}
	
	//初始化内部enet的内部寄存器和外部phy一致   DMA初始化
	if(LAN_8720_my_Private_Obj->enet_Global_Init()!=SUCCESS)
		return 4;
	
	lwip_init();						//初始化LWIP内核

	IP4_ADDR(&ipaddr,lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);
	IP4_ADDR(&netmask,lwipdev.netmask[0],lwipdev.netmask[1] ,lwipdev.netmask[2],lwipdev.netmask[3]);
	IP4_ADDR(&gw,lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]);
	
	//这里配置MAC地址 ethernetif_init不netif_set_link_up。和原子的在这个函数有netif_set_link_up
	Netif_Init_Flag=netif_add(&lwip_netif,&ipaddr,&netmask,&gw,NULL,&ethernetif_init,&ethernet_input);//向网卡列表中添加一个网口
	
	if(Netif_Init_Flag==NULL)
	{
		return 5;//网卡添加失败 
	}
	else//网口添加成功后,设置netif为默认值,并且打开netif网口
	{
		netif_set_default(&lwip_netif); //设置netif为默认网口
		netif_set_up(&lwip_netif);		//打开netif网口
		 // netif_set_link_up(&lwip_netif);                   //开启网卡连接
	}
	
	//配置udp连接
	if(udp_config_init(&lwipdev,8089)!=ERR_OK)
			return 6;//配置udp错误
	
	return 0;//操作OK.
}   

其中的enet_clk_and_Mac_Reg_Config函数,里面重要的有注释

uint32_t LAN_8720_Class::enet_clk_and_Mac_Reg_Config()
{

    ErrStatus reval_state = ERROR;
    
    /* enable ethernet clock  */
    rcu_periph_clock_enable(RCU_ENET);
    rcu_periph_clock_enable(RCU_ENETTX);
    rcu_periph_clock_enable(RCU_ENETRX);
    
    /* reset ethernet on AHB bus */
    enet_deinit();

    reval_state = enet_software_reset();//先复位 MAC 所有内核寄存器复位。然后等待复位完成,最后MAC 内部寄存器正常工作
    if(ERROR == reval_state){
        return reval_state;
    }
		
		reval_state=SUCCESS;
		
  return reval_state;
}

enet_Global_Init函数:注释是关键。

//先不需要对内部enet初始化,和例程不一样,因为我们要对LAN8720初始化,
//而enet_init会对外部phy(LAN8720)读取,根据LAN8720来配置ENET_MAC_CFG 寄存器,需要一致。
uint32_t LAN_8720_Class::enet_Global_Init()
{
		u8 enet_init_flag=0;
	//再初始化一次.
	 enet_init_flag = enet_init(ENET_AUTO_NEGOTIATION, ENET_AUTOCHECKSUM_DROP_FAILFRAMES, ENET_BROADCAST_FRAMES_PASS);
	
//		printf("enet_init_flag2:%d\r\n",enet_init_flag);

//		printf("ENET_MAC_CFG2:%x\r\n",ENET_MAC_CFG);//寄存器是cc00 。全双工+100M
	return enet_init_flag;

}

到这里。基本配置基本都差不多了。
那些IO配置,LAN8720的配置我就不贴上,记得使能时钟就行。
syscfg_enet_phy_interface_config(SYSCFG_ENET_PHY_RMII);

UDP部分:

对UDP的初始化udp_config_init在最上面的函数中已经初始过了,和原子是一样的。

//UDP
u8 udp_config_init(lwip_dev *lwipx, u16 udpport)
{
	 	err_t err;
		struct ip_addr rmtipaddr;  	//远端ip地址
	
		udp_connect_Status = 0;
	
		udppcb=udp_new();

		if(udppcb)//创建成功
		{
     //  printf("udp_create_success\r\n");	
																	
			IP4_ADDR(&rmtipaddr,lwipx->remoteip[0],lwipx->remoteip[1],lwipx->remoteip[2],lwipx->remoteip[3]);

			//err=udp_connect(udppcb,IP_ADDR_ANY,UDP_PORT);//UDP客户端连接到指定IP地址和端口号的服务器
			err=udp_connect(udppcb,&rmtipaddr,udpport);//UDP客户端连接到指定IP地址和端口号的服务器

			if(err==ERR_OK)
			{
				err=udp_bind(udppcb,IP_ADDR_ANY,udpport);//绑定本地IP地址与端口号
				if(err==ERR_OK)	//绑定完成
				{
					udp_recv(udppcb,udp_demo_recv,NULL);//注册接收回调函数 
					udp_connect_Status = 1;
				}
				else
				{
					udp_connect_Status=0;
				}
			}
			else 
			{
				udp_connect_Status=0;	
			}				
		}
		else 
		{
			udp_connect_Status=0;
		}
		
		return err;
}

然后调用这两个函数,
Global_Lwip_comm_Obj->lwip_periodic_handle();
Global_Lwip_comm_Obj->lwip_pkt_handle();

有数据的话标志位会置1,然后判断标志位就可以读取数据了。文章来源地址https://www.toymoban.com/news/detail-407464.html

		//网络的,还要判断是否有数据来。
	 if(enet_rxframe_size_get()>0)
	 {
			Global_Lwip_comm_Obj->lwip_periodic_handle();
			Global_Lwip_comm_Obj->lwip_pkt_handle();
		
			/*****/
				//处理数据
		/************/
	 }

到了这里,关于GD32F470之网络lwip+UDP配置+lan8720芯片的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • GD32F450+LAN8720A,#FreeRTOS_Plus_TCP 网络协议栈移植教程

    (此博文在2023年10月写完后,在2023年11月有更新,更新内容包括博文内容与代码文件,代码效果不变,但更新后的逻辑更合理) FreeRTOS-Plus-TCP 是一种适用于 FreeRTOS 的可扩展的开源和线程安全 TCP/IP 堆栈。 FreeRTOS-Plus-TCP 提供了一个熟悉的 基于标准 Berkeley 套接字的接口, 简单易用

    2024年01月16日
    浏览(49)
  • STM32H743+LWIP+LAN8720+STM32cubeMX6.8.0

    最详细 一步到位 带程序 无偿分享   经历一个星期的痛苦,程序终于调试ping通了 网上的H743的博客我一个一个试一个一个试,到最后没有一个正常ping通,写本篇博客的目的就是为了后续再进行调试的人不在踩坑,听懂掌声,哈哈哈。 废话就不多说了,正文开始: 1、打开S

    2024年02月07日
    浏览(41)
  • 【STM32】HAL库-以太网外设-LAN8720A-LWIP-无操作系统

    KEIL:MDK_ARM_5.27 MCU:STM32F429IGT6 PHY_IC:LAN8720A LWIP:LWIP2.1.2 STM32CUBEMX:6.6.1 HAL:V1.27.1 LAN8720A使用RMII接口与STM32的ETH外设进行数据通信 STM32使用SMI接口读/写LAN8720A的寄存器 LAN8720A由外部25MHz晶振提供时钟,LED2/NINTSEL引脚配置为下拉,故PHY(LAN8720A)提供50MHz时钟给RMII的NINT/REFCLKO(此时引脚

    2024年02月08日
    浏览(47)
  • RT-Thread Studio配置LAN8720+LWIP+TCP服务器实现

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 由于项目上需要使用RT-Thread建立TCP服务器实现与客户端的数据交互,查阅了不少资料以及踩了不少坑,这里记录和分享一下实现的过程,希望能帮助到有需要的同学,您的支持是我创作的最大动力,谢谢

    2024年01月25日
    浏览(45)
  • STM32踩坑:LAN8720未接网线,上电后再接网线,网络模块无法正常使用

    最近因为做的项目出了BUG,STM32 单片机在未接网线的状态下,上电一段时间后,将网线插入网口后,IP地址ping不通,网络模块无法正常使用,重启一下程序就没问题了。 这次的问题查找全靠网友,把问题扔给百度,然后就能看见一大群网友的评论,都反馈有 LAN8720 在没有接网

    2024年02月03日
    浏览(35)
  • STM32的以太网外设+PHY(LAN8720)使用详解(5):MAC及DMA配置

    stm32的ETH外设挂载在AHB1总线上,位于RCC_AHB1ENR的bit25-bit27: 相关语句如下: 直接调用ETH_DeInit函数来复位ETH外设 上述语句操作的寄存器如下: 首先设置位25为1复位以太网MAC(复位MAC寄存器到默认值),然后设置为0取消复位。 首先调用ETH_SoftwareReset函数复位MAC的DMA 上述语句操

    2024年02月03日
    浏览(42)
  • ESP32以太网(ETH)环境和参数配置,基于内部mac和外部PHY(LAN8720A)

    ESP32在网上的资料很多,但问题也各式各样。由于ESP32主要做wifi功能,因此对于以太网的资料也很少。相对应的开发板也很少。 本人使用的是淘宝上购买的雨甄机电的带网口的开发板(如下图) 安信可ESP-32S 参考资料主要以热心博主《兴趣使然_ 》的 (5条消息) ESP32 单片机学习

    2024年02月15日
    浏览(44)
  • Linux 网络驱动实验(PHY芯片LAN8720)

    和自己工作的IOT项目类似。项目里使用AWS的框架,分为linux系统和freertos系统。Freetros里需使用AT指令驱动4g,不同的模组驱动有差异,需自己实现模组AT驱动然后注册到AWS框架里面。 网络驱动是linux 里面驱动三巨头之一,linux 下的网络功能非常强大,嵌入式linux 中也常常用到网

    2024年02月06日
    浏览(43)
  • GD32f303之rs485配置

            rs485是一种硬件通信接口,USART引脚的TTL电平通过SP485芯片转换为差分信号,+2V~+6V表示\\\"0\\\",- 6V~- 2V表示\\\"1\\\"。RS485有两线制和四线制两种接线,四线制是全双工通讯方式,本文采用两线制半双工通讯方式。

    2024年02月13日
    浏览(50)
  • Linux 有线网络驱动实验(PHY芯片LAN8720)

    和自己工作的IOT项目类似。项目里使用AWS的框架,分为linux系统和freertos系统。Freetros里需使用AT指令驱动4g,不同的模组驱动有差异,需自己实现模组AT驱动然后注册到AWS框架里面。 网络驱动是linux 里面驱动三巨头之一,linux 下的网络功能非常强大,嵌入式linux 中也常常用到网

    2024年02月04日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包