当前位置: 首页 > news >正文

基于正点原子阿波罗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添加头文件和宏定义;
    #include "stdio.h"
    #include "string.h"#define LAN8720A  0
    #define YT8512C   1extern 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添加串口重定向;
    int fputc(int ch, FILE *f)
    {//具体哪个串口可以更改huart1为其它串口HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1 , 0x0f);return ch;
    }
  • stm32f4xx_it.c添加程序运行指示灯LED;
    //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驱动代码;
    //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芯片适配代码;
    //开头增加头文件:
    #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 HALFDUPLEXYT8512C:第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     ==0x0004101 = 10BASE-T full-duplex     ==0x0014010 = 100BASE-TX half-duplex   ==0x0008110 = 100BASE-TX full-duplex	 ==0x0018YT8512C(SR寄存器地址:0x11):--一定要在自协商结束后才有效第11位:判断自协商状态,1 已完成自协商;0 未进行或未开启自协商第15到13位:000 = 10BASE-T half-duplex     ==0x0000001 = 10BASE-T full-duplex     ==0x2000010 = 100BASE-TX half-duplex   ==0x4000011 = 100BASE-TX full-duplex	 ==0x6000100 = 1000BASE-TX half-duplex  ==0x8000101 = 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增加热插拔代码;
    //修改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);
    #endifprintf("网线插入\n");
    /* USER CODE END 5 */}else /* netif is down */{
    /* USER CODE BEGIN 6 */netif_set_down(netif);
    #if(LWIP_DHCP == 1)		dhcp_stop(netif);
    #endifprintf("网线拔出\n");
    /* USER CODE END 6 */}
    }
  • ethernetif.c增加开启自协商和PHY复位代码
    //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增加变量和业务代码;
    //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工程如下:
 

相关文章:

  • YOLOv8 在单片机上的几种部署方案
  • 【日常笔记】wps如何将值转换成东西南北等风向汉字
  • Spring Boot与Kafka集成实践:从入门到实战
  • 使用 docker-volume-backup 备份 Docker 卷
  • Unity3D HUD UI性能优化方案
  • 深入解析Java微服务架构:Spring Boot与Spring Cloud的整合实践
  • 一个由微软开源的 Python 工具,用于将多种文件格式转换为 Markdown 格式
  • B树与B+树全面解析
  • iOS热更新技术要点与风险分析
  • 用 SamGeo 库实现遥感影像自动分割:从本地 TIFF 到 SHP/GeoJSON 的一站式处理(Python 脚本实现)
  • Java POJO接收前端null值设置
  • JESD204 ip核使用与例程分析(二)
  • Spring Boot 与 RabbitMQ 的深度集成实践(三)
  • MAC电脑中右键后复制和拷贝的区别
  • LabVIEW数据库使用说明
  • labview硬件开发板——LED流水灯
  • 在linux里上传本地项目到github中
  • NW860NW894美光闪存颗粒NX770NX789
  • 网络安全之大模型隐私攻击技术
  • 计算机视觉与深度学习 | EMD-KPCA-LSTM、EMD-LSTM、LSTM回归预测对比,多输入单输出(Matlab完整程序和数据)
  • 讲述“外国货币上的中国故事”,《世界钱币上的中国印记》主题书刊出版发布
  • 黄仁勋:新一代计算平台GB300三季度上市,AI计算能力每十年提升100万倍
  • 莱布雷希特专栏:古典乐坛边缘人
  • 国新办10时将举行新闻发布会,介绍4月份国民经济运行情况
  • 上市公司重大资产重组新规九要点:引入私募“反向挂钩”,压缩审核流程
  • 首次公布!我国空间站内发现微生物新物种