基于正点原子阿波罗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

相关推荐
国科安芯3 小时前
ASP4644芯片低功耗设计思路解析
网络·单片机·嵌入式硬件·安全
充哥单片机设计3 小时前
【STM32项目开源】基于STM32的智能厨房火灾燃气监控
stm32·单片机·嵌入式硬件
CiLerLinux10 小时前
第四十九章 ESP32S3 WiFi 路由实验
网络·人工智能·单片机·嵌入式硬件
时光の尘10 小时前
【PCB电路设计】常见元器件简介(电阻、电容、电感、二极管、三极管以及场效应管)
单片机·嵌入式硬件·pcb·二极管·电感·三极管·场效应管
Lu Zelin11 小时前
单片机为什么不能跑Linux
linux·单片机·嵌入式硬件
宁静致远202112 小时前
stm32 freertos下基于hal库的模拟I2C驱动实现
stm32·嵌入式硬件·freertos
Wave84516 小时前
STM32--智能小车
stm32·单片机·嵌入式硬件
wdfk_prog18 小时前
[Linux]学习笔记系列 -- lib/timerqueue.c Timer Queue Management 高精度定时器的有序数据结构
linux·c语言·数据结构·笔记·单片机·学习·安全
充哥单片机设计1 天前
【STM32项目开源】基于STM32的智能家居环境(空气质量)检测系统
stm32·单片机·嵌入式硬件
夜月yeyue1 天前
ART 加速器、流水线与指令预测的关系详解
linux·服务器·c语言·单片机·嵌入式硬件·性能优化·嵌入式高阶技巧