STM32移植lwip之官方工程修改

2023-11-10

本篇目标:在之前的硬件基础上,修改ST官方移植lwip的工程,使PC机能ping通stm32

材料准备:


跟着文件路径打开其中一个工程,先选择不带操作系统的练习测试
文件路径:STM32F4x7_ETH_LwIP_V1.1.1 -> Project -> Standalone -> tcp_echo_server -> MDK-ARM -> Project.uvproj

先编译一下,出现3个Warning,其中两个是变量定义未使用,不影响暂且不管,还有一个是ethernetif.c文件最后没有空白行,手动添加一行,再次编译~
消除所有错误警告~成功开始的第一步~


从main函数开始理解并修改(英文为官方注释,中文为修改注释):

int main(void)
{
  /*!< At this stage the microcontroller clock setting is already configured to 
       168 MHz, this is done through SystemInit() function which is called from
       startup file (startup_stm32f4xx.s) before to branch to application main.
       To reconfigure the default setting of SystemInit() function, refer to
       system_stm32f4xx.c file
     */

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

#ifdef SERIAL_DEBUG
  DebugComPort_Init();  
#endif

  /*Initialize LCD and Leds */ 
  //LCD_LED_Init();    //硬件没有LCD,也暂时不用LED,将函数注释掉

  /* configure ethernet (GPIOs, clocks, MAC, DMA) */
  ETH_BSP_Config();    //MAC-PHY配置函数,主要理解修改函数

  /* Initilaize the LwIP stack */
  LwIP_Init();    //lwip初始化函数

  /* tcp echo server Init */
  //tcp_echoserver_init();    //tcp服务器建立函数,暂时只建立ping工程,将函数注释掉

  /* Infinite loop */
  while (1)
  {  
    /* check if any packet received */
    if (ETH_CheckFrameReceived())
    { 
      /* process received ethernet packet*/
      LwIP_Pkt_Handle();
    }
    /* handle periodic timers for LwIP*/
    LwIP_Periodic_Handle(LocalTime);
  } 
}

main函数中有两个修改:

  1. 注释 LCD_LED_Init() 函数,暂时用不到
  2. 注释 tcp_echoserver_init() 函数,暂时用不到

其次进入主要配置函数 ETH_BSP_Config() :

  • 这个函数中修改的内容只有一个,找到 DP83848_PHY_ADDRESS 的宏定义(在 stm32f4x7_eth_bsp.h 的第52行),修改原先的 0x01 为 0x00 地址,那么这个地址是怎么来的,等到代码解析的时候再做解剖
  • 函数中重点关注 ETH_GPIO_Config() 函数和 ETH_MACDMA_Config() ,这两个函数分别是配置RMII接口相关GPIO口的复用,配置MAC控制器和使能DMA

接着看 ETH_GPIO_Config() 函数:
由于官方移植lwip用的是MII接口,而之前搭建的硬件接口是RMII,所以需要修改相关宏定义和 GPIO口的复用

void ETH_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    /* Enable GPIOs clocks */
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|
                           RCC_AHB1Periph_GPIOB|
                           RCC_AHB1Periph_GPIOC,
                           ENABLE);     //我们只用到了A,B,C三种引脚,所以修改成只使能A,B,C三个的时钟

  /* Enable SYSCFG clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //使能SYSCFG外设时钟

  /* Configure MCO (PA8) */
  //配置PA8(做为MCO功能)输出时钟信号
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  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);              


  /* MII/RMII Media interface selection --------------------------------------*/
#ifdef MII_MODE
 #ifdef PHY_CLOCK_MCO

  RCC_MCO1Config(RCC_MCO1Source_HSE, RCC_MCO1Div_1); //在PA8引脚上输出25MHZ的时钟信号
 #endif /* PHY_CLOCK_MCO */

  SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_MII);  //与PHY芯片通讯选择MII模式

#elif defined RMII_MODE  //这里要修改宏定义,注释MII_MODE,取消注释RMII_MODE,选择RMII接口模式与PHY芯片进行通讯 

  RCC_MCO1Config(RCC_MCO1Source_PLLCLK,RCC_MCO1Div_2); //添加时钟函数,在PA8引脚上输出50MHZ时钟信号

  SYSCFG_ETH_MediaInterfaceConfig(SYSCFG_ETH_MediaInterface_RMII); //与PHY芯片通讯选择RMII模式
#endif

/* Ethernet pins configuration ************************************************/
   /*
        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
                                                  */
  //修改下面所有对GPIO的初始化为对应RMII接口GPIO的初始化,而RMII所用到的引脚在上面的列表中,共9个引脚
  /* Configure PA1, PA2 and PA7 */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_7;
  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);

  /* Configure 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);

  /* Configure 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);
}

总结修改之前,先做一下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

修改总结:

  1. 修改GPIO时钟使能函数 RCC_AHB1PeriphClockCmd() ,因为只用到了ABC三个引脚,所以修改成只对A,B,C三个引脚进行时钟使能
  2. 修改宏定义,因为用的是RMII接口,所以要注释掉MII_MODE的宏定义,取消注释RMII_MODE的宏定义,这两个宏定义在main.h文件的79行和87行
  3. 添加配置PHY时钟函数 RCC_MCO1Config() ,添加在 #elif defined RMII_MODE 的下面即可
  4. 修改GPIO口初始化成RMII接口的GPIO,这里包括了对GPIOA,GPIOB,GPIOC的初始化以及将三个GPIO口的复用成RMII接口所用

接下来要来看 ETH_MACDMA_Config() 函数中的最后一个函数 ETH_Init() ,这个函数包含了所有MAC控制器相关初始化的配置,所以定位到这个函数
stm32f4xf_eth.c第416行开始:

    /* Reset Timeout counter */
    timeout = 0;
    /* Read the result of the auto-negotiation */
//    RegValue = ETH_ReadPHYRegister(PHYAddress, 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_InitStruct->ETH_Mode = ETH_Mode_FullDuplex;  
//    }
//    else
//    {
      /* Set Ethernet duplex mode to Half-duplex following the auto-negotiation */
//      ETH_InitStruct->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_InitStruct->ETH_Speed = ETH_Speed_10M; 
//    }
//    else
//    {   
      /* Set Ethernet speed to 100M following the auto-negotiation */ 
      //注释掉其他所有内容,只留下下面两个函数:配置为100M以太网
      ETH_InitStruct->ETH_Speed = ETH_Speed_100M;
//    }

修改内容:

  1. 注释掉 stm32f4xf_eth.c 第416-441行的其他内容,只留下 ETH_InitStruct->ETH_Mode = ETH_Mode_HalfDuplex; 和 ETH_InitStruct->ETH_Speed = ETH_Speed_100M;

至此为止,代码修改结束,编译下载到板子上
如果想要修改ip地址,可以找到main.h里面的宏定义:

/*Static IP ADDRESS: IP_ADDR0.IP_ADDR1.IP_ADDR2.IP_ADDR3 */
#define IP_ADDR0   192
#define IP_ADDR1   168
#define IP_ADDR2   0
#define IP_ADDR3   10

修改成自己想要的IP地址便可以了,接下来用pc机来ping一下


ping之前,要确定两件事:

  1. 首先确定pc机连入的网络ip地址和stm32的ip地址是不是同一个网段:
    确定网段
    这里192.168.0.1和192.168.0.10就处于同一个网段

  2. 其次如果是将stm32用网线接入路由器,则要确定stm32所使用的ip地址没有被占用,检测方法就是接入stm32前,先ping设定的地址,看能不能ping通,不能ping通表示没有被占用;这里是直接用网线连接stm32和pc机,所以不用担心这个问题


接下来可以用pc机ping下载好程序的stm32
win+R打开运行,输入cmd,回车
在命令行下输入ping 192.168.0.10
ping通成功,有图有真相
ping


总结:
官方移植程序帮忙做了很多事情,可以方便使用,那么修改也不外乎这么几个地方,多多测试注意就可以成功,当能ping通,搭建好硬件软件环境之后就可以安心地一步步调用lwip的API接口函数建立服务器,客户端等等了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32移植lwip之官方工程修改 的相关文章

  • STM32F103概要

    The STM32F103x4 STM32F103x6 STM32F103xC STM32F103xD and STM32F103xE are a drop in replacement for STM32F103x8 B medium d
  • [屏驱相关]【SWM166-SPI-Y1.28C1测评】+ 有点惊艳的开箱

    耳闻华芯微特许久了 看到论坛得评测活动赶紧上了末班车 毕竟对有屏幕得板子也是很喜欢得 京东快递小哥客客气气 微笑着把快递给了我 好评 直接拆了包 在此之前没看过视频号 所以这个圆盘盘得模具还是有点惊喜的 正面照如下 开机有灯光秀 还有动画
  • 最终启动顺序错误 - STM32L476 的 Eclipse System Workbench 调试

    我正在尝试调试和运行 STM32L476 的简单汇编代码 我已经设置了 Eclipse Oxygen 在 Eclipse 中安装了最新版本的 System Workbench 插件并安装了 ST Link 驱动程序 IDE 成功构建了程序
  • 擦除后无法写入闪存

    所以我不能在擦除后直接写入内部闪存 如果写操作之前没有擦除操作 那么我可以 有什么想法吗 编程函数返回 成功写入 值 但查看内存时 没有写入任何数据 这是代码 uint32 t pageAddress 0x08008000 uint16 t
  • 串口通讯第一次发送数据多了一字节

    先初始化IO再初始化串口 导致第一次发送时 多出一个字节数据 优化方案 先初始化串口再初始化IO 即可正常通讯
  • 1.69寸SPI接口240*280TFT液晶显示模块使用中碰到的问题

    1 69寸SPI接口240 280TFT液晶显示模块使用中碰到的问题说明并记录一下 在网上买了1 69寸液晶显示模块 使用spi接口 分辨率240 280 给的参考程序是GPIO模拟的SPI接口 打算先移植到FreeRtos测试 再慢慢使用
  • 是否可以使用 ping 来测量带宽?

    我们能否从 ping 服务器所需的时间找到互联网带宽 如果可以 是如何完成的 不 ping 不会告诉您任何有关带宽的信息 它只是测量延迟 测量带宽最好通过专门的测试来完成 即传输一堆比特并测量它需要多长时间 您可能需要考虑带宽可能会因许多因
  • 你能在 Java 中运行真正的 ping 吗?

    过去几周我做了相当多的研究 试图创建一个连接诊断工具 我不想只是检查连接是否可用 而是诊断是否存在抖动 数据包丢失等 到目前为止 Java 似乎不支持真正的 ICMP 请求 并且有一些解决方法 但没有一个能够实现我想要做的事情 有谁知道是否
  • 无法使用 OpenOCD 找到脚本文件

    我正在尝试按照本教程将 OpenOCD 与我的 ST 发现板一起使用 https japaric github io discovery README html https japaric github io discovery READM
  • 毕设开题分享 单片机智能教室系统(智能照明+人数统计)

    1 简介 Hi 大家好 今天向大家介绍一个学长做的单片机项目 单片机智能教室系统 智能照明 人数统计 大家可用于 课程设计 或 毕业设计 项目分享 https gitee com feifei1122 simulation project
  • 特殊寄存器

    特殊寄存器 文章目录 前言 一 背景 二 2 1 2 2 总结 前言 前期疑问 STM32特殊寄存器到底是什么 特殊寄存器怎么查看和调试代码 本文目标 记录和理解特殊寄存器 一 背景 最近在看ucosIII文章是 里面提到特殊寄存器 这就进
  • Cortex-M3与M4权威指南

    处理器类型 所有的ARM Cortex M 处理器是32位的精简指令集处理器 它们有 32位寄存器 32位内部数据路径 32位总线接口 除了32位数据 Cortex M处理器也可以有效地处理器8位和16位数据以及支持许多涉及64位数据的操作
  • 如何从 Flex - AIR 执行 ping 操作?

    我很无聊 因为我的开发服务器宕机了 我正在运行命令提示符来无限期地 ping 服务器 这样我就能看到它们何时停止超时 并知道我可以再次工作 与此同时 我想制作一个 Air 应用程序来为我做这件事 这样我就可以让它发出鸣叫声或警报 或者在它开
  • STM32 上的位置无关代码 - 指针

    我已成功在 STM32 上构建并运行位置无关的代码 向量表和 GOT 已修补 一切正常 但我对这样的代码有问题 double myAdd double x return x 0 1 double ptrmyAdd double myAdd
  • 如何使用Python ping ip并仅获取Tk中的ms?

    我想制作一个小 tk 应用程序 连续 ping 一个 ip 并且只显示 MS 例如 10ms 我该怎么办 如果您想使用 Windowsping 您必须解析命令行的输出 这是非常具体的 但应该有效 import os while 1 ping
  • PWM DMA 到整个 GPIO

    我有一个 STM32F4 我想对一个已与掩码进行 或 运算的 GPIO 端口进行 PWM 处理 所以 也许我们想要 PWM0b00100010一段时间为 200khz 但随后 10khz 后 我们现在想要 PWM0b00010001 然后
  • HAL_Delay() 陷入无限循环

    我被 HAL Delay 函数困住了 当我调用此函数 HAL Delay 时 控制陷入无限循环 在寻找问题的过程中 我发现了这个 http www openstm32 org forumthread2145 threadId2146 htt
  • 使用 STM32F0 ADC 单独读取不同的输入

    STM32F072CBU 微控制器 我有多个 ADC 输入 并且希望单独读取它们 STMcubeMX 生成样板代码 假设我希望按顺序读取所有输入 但我无法弄清楚如何纠正这个问题 这篇博文 http blog koepi info 2015
  • awk: hping: 打印 icmp 发起/接收之间的差异

    我有以下输出hping http ports su net hping在 OpenBSD 上 hping icmp ts www openbsd org HPING www openbsd org re0 129 128 5 194 icm
  • stm32l0: 执行MI命令失败。使用 vFlashErase 数据包擦除闪存时出错

    我正在使用 Nucleo STM32L031 和 AC6 STM32 工作台 eclipse 我编写应用程序并进入调试模式 一切正常 直到我在应用程序中添加另一个功能 我注意到当我删除 评论 新函数 软件可以再次进入调试模式 但是当我添加

随机推荐