STM32移植lwip之官方工程修改

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

材料准备:

  • 硬件基础:stm32f407+lan9303
  • 官方资料:包含代码和移植手册(stm32官方移植lwip资料)
  • 修改代码:包含移植后的代码(STM32官方移植lwip修改代码)

跟着文件路径打开其中一个工程,先选择不带操作系统的练习测试
文件路径: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地址是不是同一个网段:
    STM32移植lwip之官方工程修改_第1张图片
    这里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通成功,有图有真相
STM32移植lwip之官方工程修改_第2张图片


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

你可能感兴趣的:(stm32学习lwip移植)