基于正点原子阿波罗F429开发板的LWIP应用(1)——网络ping通

说在开头

正点原子F429开发板主芯片采用的是STM32F429IGT6,网络PHY芯片采用的是LAN8720A(V1)和YT8512C(V2),采用的是RMII连接,PHY_ADDR为0;在代码中将会对不同的芯片做出适配。

CubeMX版本:6.6.1;

F4芯片组Pack包版本:STM32Cube FW_F4 V1.27.0;

1、CubeMX配置过程

  • 打开System Core点击RCC使能外部高速时钟(25M晶振)和低速设置时钟(32.768K晶振);
  • 打开RTC:点击Timers------>RTC,勾选"Active ClockSource",其余参数保持默认
  • 打开Clock Configuration设置系统时钟树:系统时钟拉满,设为180M(记得时钟树需要手动设置PLL来源是HSE、sSystem Clock来源是HSE经过PLL分频后的PLLCLK);将RTC的时钟源设为LSE(外部32.768K晶振);
  • 设置LED引脚,PB0和PB1都为GPIO_Output模式,默认输出低电平;
  • 使能串口1:点击Connectivity------>USART1,模式设置为Asynchronous,其余参数默认;
  • 使能I2C2:点击Connectivity------>I2C2,模式设置为I2C2,在下面的"Parameter Settings"将Primary slave address的值设为64(设置FC8574的地址是64),之后将I2C2的GPIO设置为PH4和PH5;
  • 使能ETH:点击Connectivity------>ETH,设置为RMII模式,在下面的"Parameter Settings"将Primary slave address的值设为1536;在旁边的"NVIC Settings"勾选"ETH global interrupt";将ETH_TXD0和ETH_TXD1的引脚设为PG13和PG14;
  • 使能LWIP:点击Middleware------>LWIP,勾选Enable,在下面的"Platform Settings"将Driver PHY设为LAN8742,将BSP_COMPONENT_DRIVER也设为LAN8742;在下面的"Key Options"中找到"Network Interfaces Options"类,展开它的选项,将"LWIP_NETIF_HOSTNAME"设为Enable;
  • 进入Project Manager页面设置工程设置:工程名和保存地址自定义,设置IDE为MDK;然后进入Code Generator选项,先勾选只添加必要的库文件到工程、然后勾选"Generate peripheral initialization as a pair of ".c/h' fles per periphera",其含义是生成的外设初始化代码是否要拆分成.c和.h文件;
  • 最后点击右上角的"GENENATE CODE"即可生成代码;

2、MDK代码修改

  • 修改MDK设置;

  • main.h添加头文件和宏定义;

    cpp 复制代码
    #include "stdio.h"
    #include "string.h"
    
    #define LAN8720A  0
    #define YT8512C   1
    
    extern uint8_t PHY_TYPE;
    
    #define YT8512C_PHYSCSR                 ((uint16_t)0x0011U)		
    #define YT8512C_PHYSCSR_AUTONEGO_DONE   ((uint16_t)0x0800U)
    #define YT8512C_PHYSCSR_HCDSPEEDMASK    ((uint16_t)0xE000U)
    #define YT8512C_PHYSCSR_10BT_HD         ((uint16_t)0x0000U)
    #define YT8512C_PHYSCSR_10BT_FD         ((uint16_t)0x2000U)
    #define YT8512C_PHYSCSR_100BTX_HD       ((uint16_t)0x4000U)
    #define YT8512C_PHYSCSR_100BTX_FD       ((uint16_t)0x6000U)
    #define YT8512C_PHYSCSR_1000BTX_HD      ((uint16_t)0x8000U)
    #define YT8512C_PHYSCSR_1000BTX_FD      ((uint16_t)0xA000U) 
  • usart.c添加串口重定向;

    cpp 复制代码
    int fputc(int ch, FILE *f)
    {
    	//具体哪个串口可以更改huart1为其它串口
    	HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1 , 0x0f);
    	return ch;
    }
  • stm32f4xx_it.c添加程序运行指示灯LED;

    cpp 复制代码
    //stm32f4xx_it.c开头添加:static uint16_t led_count = 0;
    //SysTick_Handler函数中" HAL_IncTick();"后添加以下代码:
    	led_count++;
    	if(led_count >= 250)
    	{
    		led_count = 0;
    		HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);//LED0翻转
    	}
  • i2c.c增加PCF8574驱动代码;

    cpp 复制代码
    //i2c.c添加:
    void PCF8574_WriteBit(uint8_t IO_Num,uint8_t IO_Sta)
    {
    	uint8_t IO_Sta_Get[2]={0};
    	  HAL_I2C_Master_Receive(&hi2c2, 0x40, IO_Sta_Get, 1, 1000);
    	  if(IO_Sta==0)//清零
    	  {
    		  IO_Sta_Get[0]=IO_Sta_Get[0]&(~(1<<IO_Num));
    	  }else{
    		  IO_Sta_Get[0]=IO_Sta_Get[0]|(1<<IO_Num);
    	  }
    	  HAL_I2C_Master_Transmit(&hi2c2, 0x40, IO_Sta_Get, 1, 1000);
    }
     
    uint8_t PCF8574_ReadBit(uint8_t IO_Num)
    {
    	uint8_t IO_Sta_Get[2]={0};
    	HAL_I2C_Master_Receive(&hi2c2, 0x40, IO_Sta_Get, 1, 1000);
    	return IO_Sta_Get[0];
    }
    //i2c.h添加:
    void PCF8574_WriteBit(uint8_t IO_Num,uint8_t IO_Sta);
    uint8_t PCF8574_ReadBit(uint8_t IO_Num);
  • lan8742.c增加PHY芯片适配代码;

    cpp 复制代码
    //开头增加头文件:
    #include "main.h"
    
    //修改LAN8742_GetLinkState函数为如下内容:
    int32_t LAN8742_GetLinkState(lan8742_Object_t *pObj)
    {
      uint32_t readval = 0;
      
      /* Read Status register  */
      if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BSR, &readval) < 0)
      {
        return LAN8742_STATUS_READ_ERROR;
      }
      
      /* Read Status register again */
      if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BSR, &readval) < 0)
      {
        return LAN8742_STATUS_READ_ERROR;
      }
      
      if((readval & LAN8742_BSR_LINK_STATUS) == 0)
      {
        /* Return Link Down status */
        return LAN8742_STATUS_LINK_DOWN;    
      }
      
      /* Check Auto negotiaition */
      if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &readval) < 0)
      {
        return LAN8742_STATUS_READ_ERROR;
      }
      
    	/*判断BCR寄存器的第12位是否为1,1 开启自协商;0  关闭自协商*/
      if((readval & LAN8742_BCR_AUTONEGO_EN) != LAN8742_BCR_AUTONEGO_EN)//关闭
      {
        /*
    			未开启自协商就读取BCR寄存器判断速率和双工状态:
    			LAN8720A
    				第13位,1:100M, 0 10M
    				第8位,1:FULLDUPLEX, 0 HALFDUPLEX
    			YT8512C:
    				第6位+第13位:(0,1) 100M,(0,0)10M 
    				第8位,1:FULLDUPLEX, 0 HALFDUPLEX
    		*/
    		if(PHY_TYPE == YT8512C)
    		{
    			if((readval & 0x0040) == 0x0040) //只有在第6位为0时才可以通过判断第13位来判断状态
    			{
    				return LAN8742_STATUS_READ_ERROR;
    			}
    		}
    
    		if(((readval & LAN8742_BCR_SPEED_SELECT) == LAN8742_BCR_SPEED_SELECT) && ((readval & LAN8742_BCR_DUPLEX_MODE) == LAN8742_BCR_DUPLEX_MODE)) 
        {
          return LAN8742_STATUS_100MBITS_FULLDUPLEX;
        }
        else if ((readval & LAN8742_BCR_SPEED_SELECT) == LAN8742_BCR_SPEED_SELECT)
        {
          return LAN8742_STATUS_100MBITS_HALFDUPLEX;
        }        
        else if ((readval & LAN8742_BCR_DUPLEX_MODE) == LAN8742_BCR_DUPLEX_MODE)
        {
          return LAN8742_STATUS_10MBITS_FULLDUPLEX;
        }
        else
        {
          return LAN8742_STATUS_10MBITS_HALFDUPLEX;
        }  		
      }
      else /* Auto Nego enabled 开启自协商*/
      {
        /*
    			开启自协商后读取SR寄存器判断速率和双工状态:
    		LAN8720A(SR寄存器地址:0x1f):
    				第12位:判断自协商状态,1 已完成自协商;0 未进行或未开启自协商
    				第4到2位:
    					001 = 10BASE-T half-duplex     ==0x0004
    					101 = 10BASE-T full-duplex     ==0x0014
    					010 = 100BASE-TX half-duplex   ==0x0008
    					110 = 100BASE-TX full-duplex	 ==0x0018
    			YT8512C(SR寄存器地址:0x11):--一定要在自协商结束后才有效
    			  第11位:判断自协商状态,1 已完成自协商;0 未进行或未开启自协商
    				第15到13位:
    					000 = 10BASE-T half-duplex     ==0x0000
    					001 = 10BASE-T full-duplex     ==0x2000
    					010 = 100BASE-TX half-duplex   ==0x4000
    					011 = 100BASE-TX full-duplex	 ==0x6000
    					100 = 1000BASE-TX half-duplex  ==0x8000
    					101 = 1000BASE-TX full-duplex	 ==0xA000
    		*/		
    
    		if(PHY_TYPE == LAN8720A)
    		{
    			if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_PHYSCSR, &readval) < 0)
    			{
    				return LAN8742_STATUS_READ_ERROR;
    			}
    			/* Check if auto nego not done */
    			if((readval & LAN8742_PHYSCSR_AUTONEGO_DONE) == 0)
    			{
    				return LAN8742_STATUS_AUTONEGO_NOTDONE;
    			}
    			
    			if((readval & LAN8742_PHYSCSR_HCDSPEEDMASK) == LAN8742_PHYSCSR_100BTX_FD)
    			{
    				return LAN8742_STATUS_100MBITS_FULLDUPLEX;
    			}
    			else if ((readval & LAN8742_PHYSCSR_HCDSPEEDMASK) == LAN8742_PHYSCSR_100BTX_HD)
    			{
    				return LAN8742_STATUS_100MBITS_HALFDUPLEX;
    			}
    			else if ((readval & LAN8742_PHYSCSR_HCDSPEEDMASK) == LAN8742_PHYSCSR_10BT_FD)
    			{
    				return LAN8742_STATUS_10MBITS_FULLDUPLEX;
    			}
    			else
    			{
    				return LAN8742_STATUS_10MBITS_HALFDUPLEX;
    			}
    		}
    		else if(PHY_TYPE == YT8512C)
    		{
    			if(pObj->IO.ReadReg(pObj->DevAddr, YT8512C_PHYSCSR, &readval) < 0)
    			{
    				return LAN8742_STATUS_READ_ERROR;
    			}		
    			/* Check if auto nego not done */
    			if((readval & YT8512C_PHYSCSR_AUTONEGO_DONE) == 0)
    			{
    				return LAN8742_STATUS_AUTONEGO_NOTDONE;
    			}
    			
    			if((readval & YT8512C_PHYSCSR_HCDSPEEDMASK) == YT8512C_PHYSCSR_100BTX_FD)
    			{
    				return LAN8742_STATUS_100MBITS_FULLDUPLEX;
    			}
    			else if ((readval & YT8512C_PHYSCSR_HCDSPEEDMASK) == YT8512C_PHYSCSR_100BTX_HD)
    			{
    				return LAN8742_STATUS_100MBITS_HALFDUPLEX;
    			}
    			else if ((readval & YT8512C_PHYSCSR_HCDSPEEDMASK) == YT8512C_PHYSCSR_10BT_FD)
    			{
    				return LAN8742_STATUS_10MBITS_FULLDUPLEX;
    			}
    			else if ((readval & YT8512C_PHYSCSR_HCDSPEEDMASK) == YT8512C_PHYSCSR_10BT_HD)
    			{
    				return LAN8742_STATUS_10MBITS_HALFDUPLEX;
    			}			
    		}
      }
    	return LAN8742_STATUS_READ_ERROR;
    }
  • lwip.c增加热插拔代码;

    cpp 复制代码
    //修改ethernet_link_status_updated函数为如下内容:
    static void ethernet_link_status_updated(struct netif *netif)
    {
      if (netif_is_up(netif))
      {
    /* USER CODE BEGIN 5 */
    		netif_set_up(netif);
    #if(LWIP_DHCP == 1)		
    		dhcp_start(netif);
    #endif
    		printf("网线插入\n");
    /* USER CODE END 5 */
      }
      else /* netif is down */
      {
    /* USER CODE BEGIN 6 */
    		netif_set_down(netif);
    #if(LWIP_DHCP == 1)		
    		dhcp_stop(netif);
    #endif
    		printf("网线拔出\n");
    /* USER CODE END 6 */
      }
    }
  • ethernetif.c增加开启自协商和PHY复位代码

    cpp 复制代码
    //low_level_init函数最后LAN8742_Init(&LAN8742);语句后添加开启自协商代码:
    LAN8742_StartAutoNego(&LAN8742);
    HAL_Delay(2000);
    
    //HAL_ETH_MspInit函数最后添加PHY识别和复位代码:
    #include "i2c.h"	
    
    uint32_t regval;
    HAL_ETH_ReadPHYRegister(&heth, 0, 2, &regval);
    
    if (regval && 0xFFF == 0xFFF)                           /* 旧板卡(LAN8720A)*/
    {
    	 PHY_TYPE = LAN8720A;
    	 PCF8574_WriteBit(7,1);                  /* 硬件复位 */
    	 HAL_Delay(100);
    	 PCF8574_WriteBit(7,0);                  /* 复位结束 */
    	 HAL_Delay(100);
    }
    else                                                    /* 新板卡(YT8512C) */
    {
    	 PHY_TYPE = YT8512C;
    	 PCF8574_WriteBit(7,0);                  /* 硬件复位 */
    	 HAL_Delay(100);
    	 PCF8574_WriteBit(7,1);                  /* 复位结束 */
    	 HAL_Delay(100);
    }	
  • main.c增加变量和业务代码;

    cpp 复制代码
    //main.c开头添加:
    extern struct netif gnetif;
    
    uint8_t PHY_TYPE = LAN8720A;
    
    //main函数while(1)前增加以下代码:
    #if(LWIP_DHCP == 1)
    	while(gnetif.ip_addr.addr == 0)
    	{
    		MX_LWIP_Process();
    	}
    	
    	printf("DHCP succeed:%d.%d.%d.%d\n\n", 
    	 ((gnetif.ip_addr.addr)&0x000000ff), (((gnetif.ip_addr.addr)&0x0000ff00)>>8), 
    	 (((gnetif.ip_addr.addr)&0x00ff0000)>>16), ((gnetif.ip_addr.addr)&0xff000000)>>24);
    #endif
    
    //main函数while(1)中增加以下代码:
        MX_LWIP_Process();

修改完成后编译:0警告和0错误;

烧录后插入路由器中串口打印板子的IP地址,我这打印的是:DHCP succeed:192.168.1.251。(一定要插入路由器中,因为当前代码采用的是DHCP模式,下一篇将教大家如何在此代码的基础上加入静态IP代码)

本文对应的MDK工程和CubeMX工程如下:https://download.csdn.net/download/qq_44712722/90868312

相关推荐
whaosoft-1437 分钟前
51c嵌入式※~合集7~Linux
嵌入式硬件
LeonDL1681 小时前
YOLOv8 在单片机上的几种部署方案
人工智能·python·单片机·嵌入式硬件·深度学习·yolo·yolov8 在单片机上的部署
LeonDL1681 小时前
YOLOv8 在单片机上部署的缺点和应对方案
python·单片机·嵌入式硬件·深度学习·yolo·yolov8在单片机上的缺点·yolov8 在单片机上的优化
尚久龙2 小时前
STM32实现RS485通讯
stm32·单片机·嵌入式硬件
嵌入式Linux,2 小时前
ESP32和STM32 就不应该放在一起比,
stm32·单片机·嵌入式硬件
硬件智障2 小时前
51单片机实现流水灯
单片机·嵌入式硬件·51单片机
暮雪倾风3 小时前
【STM32】ST-Link V2.1制作
stm32·单片机·嵌入式硬件
yuanpan3 小时前
支持python的单片机有哪些
开发语言·python·单片机
MaoXian_n4 小时前
[IMX] 05.串口 - UART
汇编·arm开发·驱动开发·单片机·嵌入式硬件
Camellia03114 小时前
嵌入式学习--江协51单片机day8
嵌入式硬件·学习·51单片机