精华内容
下载资源
问答
  • 基于STM32F103 平台,在 RT_Thread 系统中 lwip 移植。能ping通和udp收发。
  • 硬件是基于正点原子探索者开发板,软件是基于最简单的stm32的FreeRTOS版本工程demo来移植的官方的lwip引用,tcp/udp/web分别单独的文件中,使用简单,代码容易看懂。
  • stm32f4xx+freeRTOS+LWIP移植,亲测可用的,
  • LwIP移植手册.pdf

    2020-09-24 11:29:16
    轻量级协议栈,可以使用在无系统如单片机、boot启动阶段。我们使用在boot阶段,通过移植lwip,实上层的ftp功能,提高版本下载速度。
  • 来自官网的STM32F407+DP83848例程进行的直接修改教程。
  • 焦海波的uCOS平台下的LwIP移植笔记,介绍的非常详细,很好的东西,找了很久才找到的,拿出来跟大家分享一下吧。配合着其他的文档一起看,感觉对学习ucos下LWIP的移植很有帮助。
  • STM32F407移植freemodbus和LWIP使用modbus tcp实验,代码已验证通过,可拿来直接使用
  • STM32F407_DP83848_Lwip移植方法
  • uCOS平台下的LwIP移植笔记,系统接口、信号量、任务,邮箱等移植
  • LWIP移植和使用

    2020-07-03 20:14:47
    LWIP移植文件介绍 手把手教你移植LWIP(ENC28J60) LwIP学习笔记——LwIP无操作系统移植 LwIP BUG之ARP缓存 Lwip ARP分析(1) ping不通 项目里pc无法ping通单片机,抓包发现是ARP包没有返回,通过底层打印发现可以收...

    作者

    QQ群:852283276
    微信:arm80x86
    微信公众号:青儿创客基地
    B站:主页 https://space.bilibili.com/208826118

    参考

    LWIP移植文件介绍
    手把手教你移植LWIP(ENC28J60)
    LwIP学习笔记——LwIP无操作系统移植
    LwIP BUG之ARP缓存
    Lwip ARP分析(1)
    Lwip之如何动态更改IP地址

    ping不通

    项目里pc无法ping通单片机,抓包发现是ARP包没有返回,通过底层打印发现可以收包,
    ethernetif_input查看lwip对arp包处理的是否正确,

    //sys_arch.c
    u32_t sys_now()
    {
      return LocaTime;
    }
    

    动态修改IP

    tcp_close(u_sTcp_pcb[i]);
    netif_set_down(&u_sNetif); //先禁用网卡
    netif_set_gw(&u_sNetif, &GW_updata);        //重新设置网关地址
    netif_set_netmask(&u_sNetif, &Mask_update); //重新设置子网掩码
    netif_set_ipaddr(&u_sNetif, &ip_update);    //重新设置IP地址
    //  netif_set_addr(&u_sNetif, &ip_update, &Mask_update, &GW_updata);
    netif_set_up(&u_sNetif);  //启用网卡
    
    展开全文
  • ucos上lwip移植详细步骤—焦海波

    热门讨论 2011-12-08 17:12:10
    焦海波老师的ucos_lwip移植笔记,十分详细,而且还有阶段性的源码,十分珍贵的资料!
  • Lwip移植过程(基于FreeRTOS v10.2.1)

    千次阅读 2020-01-13 12:50:44
    Lwip移植过程(基于FreeRTOS) 准备过程 首先准备带FreeRTOS的工程模板,如下图所示; 下载LWIP源码,这里使用2.1.2版本,官网下载地址,拷贝源码到工程中去,如下图所示; 将LwIP源文件添加到工程中去 ...

    Lwip移植过程(基于FreeRTOS)

    准备过程

    • 首先准备带FreeRTOS的工程模板,如下图所示;

    • FreeRTOS模板

    • 下载LWIP源码,这里使用2.1.2版本,官网下载地址,拷贝源码到工程中去,如下图所示;

    image

    将LwIP源文件添加到工程中去

    • LWIP/api

    image

    • LWIP/core

    image

    • LWIP/core/ipv4

    • LWIP/netif

    添加头文件信息

    移植修改

    1. 编译后发现很多error,如下图所示

    2. 添加lwipopts.h,在源码文件夹test\fuzz下可以找到该文件,如下图所示,该文件主要用于Lwip参数的配置,供用户修改,默认参数配置在opt.h文件中配置;

    3. lwip-2.1.2文件夹下创建user文件夹,放置网络相关的用户配置文件,如下图所示

    4. 添加lwipopts.h头文件路径,如下图所示

    5. 再次编译,缺少arch/cc.h文件,如下图所示

    6. 添加arch/cc.h文件,将下图文件夹下的3个*.h拷到lwip-2.1.2/user/arch*文件夹下
      在这里插入图片描述

    7. 修改cc.h文件内容如下

    /*
     * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice,
     *    this list of conditions and the following disclaimer.
     * 2. Redistributions in binary form must reproduce the above copyright notice,
     *    this list of conditions and the following disclaimer in the documentation
     *    and/or other materials provided with the distribution.
     * 3. The name of the author may not be used to endorse or promote products
     *    derived from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
     * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
     * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
     * OF SUCH DAMAGE.
     *
     * This file is part of the lwIP TCP/IP stack.
     *
     * Author: Adam Dunkels <adam@sics.se>
     *
     */
    #ifndef __ARCH_CC_H__
    #define __ARCH_CC_H__
    
    /* Include some files for defining library routines */
    #include <stdio.h> /* printf, fflush, FILE */
    #include <string.h>
    #include <stdlib.h> /* abort */
    //#include <errno.h>
    #if (!defined(__CC_ARM)) && (!defined(__ARMCC_VERSION)) && (!defined(__ICCARM__))
    #include <sys/time.h>
    #endif
    
    #include "FreeRTOSConfig.h"
    
    #ifndef BYTE_ORDER
    #define BYTE_ORDER  LITTLE_ENDIAN
    #endif
    
    #define LWIP_PLATFORM_BYTESWAP 0
    
    /** @todo fix some warnings: don't use #pragma if compiling with cygwin gcc */
    //#ifndef __GNUC__
    #if (!defined(__ICCARM__)) && (!defined(__GNUC__)) && (!defined(__CC_ARM))
    	#include <limits.h>
    	#pragma warning (disable: 4244) /* disable conversion warning (implicit integer promotion!) */
    	#pragma warning (disable: 4127) /* conditional expression is constant */
    	#pragma warning (disable: 4996) /* 'strncpy' was declared deprecated */
    	#pragma warning (disable: 4103) /* structure packing changed by including file */
    #endif
    
    #define LWIP_PROVIDE_ERRNO
    
    #if ( configUSE_POSIX_ERRNO == 1 )
    extern int FreeRTOS_errno;
    #ifndef errno
    #define errno FreeRTOS_errno
    #endif
    #endif
    
    /* Define generic types used in lwIP */
    #define LWIP_NO_STDINT_H    1
    typedef unsigned   char    u8_t;
    typedef signed     char    s8_t;
    typedef unsigned   short   u16_t;
    typedef signed     short   s16_t;
    typedef unsigned   long    u32_t;
    typedef signed     long    s32_t;
    
    typedef size_t mem_ptr_t;
    typedef u32_t sys_prot_t;
    
    
    
    /* Define (sn)printf formatters for these lwIP types */
    #define X8_F  "02x"
    #define U16_F "hu"
    #define S16_F "hd"
    #define X16_F "hx"
    #define U32_F "lu"
    #define S32_F "ld"
    #define X32_F "lx"
    #define SZT_F U32_F
    
    
    /* Compiler hints for packing structures */
    #if defined(__ICCARM__)
    #define PACK_STRUCT_STRUCT __packed
    #else
    #define PACK_STRUCT_STRUCT __attribute__( (packed) )
    #endif
    
    #if 0
    #ifndef LWIP_DEBUG_USE_PRINTF
    #define LWIP_LOGE(fmt,arg...)   LOG_E(lwip, "[lwip]: "fmt,##arg)
    #define LWIP_LOGW(fmt,arg...)   LOG_W(lwip, "[lwip]: "fmt,##arg)
    #define LWIP_LOGI(fmt,arg...)   LOG_I(lwip ,"[lwip]: "fmt,##arg)
    #endif
    #endif
    
    #ifdef LWIP_DEBUG_USE_PRINTF
    /* Plaform specific diagnostic output */
    #define LWIP_PLATFORM_DIAG(x)   do { printf x; } while(0)
    #else
    #define LWIP_PLATFORM_DIAG(x)   do { printf(x) ; } while(0)
    #endif
    
    #define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \
                                         x, __LINE__, __FILE__); fflush(NULL); abort();} while(0)
    
    
    //#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \
    //  printf(("Assertion \"%s\" failed at line %d in %s\n", message, __LINE__, __FILE__)); \
    //  handler;} } while(0)
    
    
    /* C runtime functions redefined */
    //#define snprintf _snprintf //2015-07-22 Cheng Liu @132663
    
    u32_t dns_lookup_external_hosts_file(const char *name);
    
    #define LWIP_RAND() ((u32_t)rand())
    
    #endif /* __ARCH_CC_H__ */
    
    
    
    1. 修改lwipopt.h文件内容,代码如下
    /*
     * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
     * All rights reserved. 
     * 
     * Redistribution and use in source and binary forms, with or without modification, 
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice,
     *    this list of conditions and the following disclaimer.
     * 2. Redistributions in binary form must reproduce the above copyright notice,
     *    this list of conditions and the following disclaimer in the documentation
     *    and/or other materials provided with the distribution.
     * 3. The name of the author may not be used to endorse or promote products
     *    derived from this software without specific prior written permission. 
     *
     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
     * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
     * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
     * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
     * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
     * OF SUCH DAMAGE.
     *
     * This file is part of the lwIP TCP/IP stack.
     * 
     * Author: Simon Goldschmidt
     *
     */
    #ifndef LWIP_HDR_LWIPOPTS_H__
    #define LWIP_HDR_LWIPOPTS_H__
    
    /* Prevent having to link sys_arch.c (we don't test the API layers in unit tests) */
    /* NO_SYS=1 无操作系统,0有操作系统,这里使用FreeRTOS */
    #define NO_SYS                          0   
    #define LWIP_TIMERS                     1
    #define SYS_LIGHTWEIGHT_PROT            1
    
    #define LWIP_NETCONN                    0
    #define LWIP_SOCKET                     0
    #define SYS_LIGHTWEIGHT_PROT            0
    
    #define LWIP_IPV6                       0
    #define IPV6_FRAG_COPYHEADER            0
    #define LWIP_IPV6_DUP_DETECT_ATTEMPTS   0
    
    /* Enable some protocols to test them */
    #define LWIP_DHCP                       0
    #define LWIP_AUTOIP                     0
    
    #define LWIP_IGMP                       1
    #define LWIP_DNS                        1
    
    #define LWIP_ALTCP                      1
    
    /* Turn off checksum verification of fuzzed data */
    #define CHECKSUM_CHECK_IP               0
    #define CHECKSUM_CHECK_UDP              0
    #define CHECKSUM_CHECK_TCP              0
    #define CHECKSUM_CHECK_ICMP             0
    #define CHECKSUM_CHECK_ICMP6            0
    
    /* Minimal changes to opt.h required for tcp unit tests: */
    #define MEM_SIZE                        16000
    #define TCP_SND_QUEUELEN                40
    #define MEMP_NUM_TCP_SEG                TCP_SND_QUEUELEN
    #define TCP_OVERSIZE                    1
    #define TCP_SND_BUF                     (12 * TCP_MSS)
    #define TCP_WND                         (10 * TCP_MSS)
    #define LWIP_WND_SCALE                  1
    #define TCP_RCV_SCALE                   2
    #define PBUF_POOL_SIZE                  400 /* pbuf tests need ~200KByte */
    
    /* Minimal changes to opt.h required for etharp unit tests: */
    #define ETHARP_SUPPORT_STATIC_ENTRIES   1
    
    #define LWIP_NUM_NETIF_CLIENT_DATA      1
    #define LWIP_SNMP                       1
    #define MIB2_STATS                      1
    #define LWIP_MDNS_RESPONDER             1
    
    #endif /* LWIP_HDR_LWIPOPTS_H__ */
    
    
    1. 添加带操作系统的网络接口文件sys_arch.csys_arch.h
      在这里插入图片描述

    2. 在工程中添加sys_arch.c

    • LWIP/arch

    1. 再次编译,出现错误,是因为在网络接口的文件下添加了slipif.c SLIP组件文件,这里屏蔽掉就好,再次编译就好;其实在lwipopt.h中也可以删除了ipv6的宏定义,工程文件中的很多网络接口都可以屏蔽掉,根据使用情况添加即可。



    添加PHY驱动

    物理层驱动芯片:DM9161

    驱动参考MDK的例程进行修改,若采用的芯片与官方提供的一致,可直接使用,仅需更改物理地址即可;
    MDK下的驱动路径如下图所示,在ETH文件夹内;
    也可以使用MDK官方提供的模板,在MDK安装路径下可以找到。
    

    1. 在工程文件的user目录下添加以太网驱动文件夹ETH_driver,并添加MDK文件夹下的驱动,这里我们复制如下图所示的文件,并修改文件名为自己的驱动芯片,该文件内容一般不需要做任何改动即可使用

    2. 添加文件到工程中去,并添加头文件路径


    1. 修改驱动芯片相应的寄存器映射地址,在PHY_XXXX.h中修改,这里根据字节使用的芯片手册进行更改即可。

    添加MAC驱动

    说明:MAC驱动在MDK安装包里也有,在D:\Keil_v5\ARM\PACK\Keil路径下,如下图所示,选择相应文件下的驱动即可

    1. 我这里使用的是STM32H7xx的芯片,复制下图中的文件到user/ETH_Driver目录下,并添加到工程中去

    2. 添加驱动头文件
      在这里插入图片描述
      在这里插入图片描述
    3. 编译会发现缺少MX_Device.h文件,如下图所示
    4. 添加MX_Device.h文件,我们需要到MDK的目录下去搜索,比如我这里用的STM32H7xx,那么就再如下图文件夹下搜索,其实都是官方开发板下的demo,检索完,单开任意一个复制其文件就行

    5. 修改MX_Device.h文件内容,该文件主要定义了官方开发板的一些管脚使用信息,这里我们不需要删掉即可,

    修改后内容如下:

    /******************************************************************************
     * File Name   : MX_Device.h
     * Date        : 06/06/2019 08:02:00
     * Description : STM32Cube MX parameter definitions
     * Note        : This file is generated by STM32CubeMX (DO NOT EDIT!)
     ******************************************************************************/
    
    #ifndef __MX_DEVICE_H
    #define __MX_DEVICE_H
    
    /*---------------------------- Clock Configuration ---------------------------*/
    
    #define MX_LSI_VALUE                            32000
    #define MX_LSE_VALUE                            32768
    #define MX_HSI_VALUE                            64000000
    #define MX_HSE_VALUE                            25000000
    #define MX_EXTERNAL_CLOCK_VALUE                 12288000
    #define MX_PLLDSIFreq_Value                     500000000
    #define MX_SYSCLKFreq_VALUE                     400000000
    #define MX_HCLKFreq_Value                       100000000
    #define MX_CortexFreq_Value                     400000000
    #define MX_APB1Freq_Value                       25000000
    #define MX_APB2Freq_Value                       25000000
    #define MX_CECFreq_Value                        32000
    #define MX_RTCFreq_Value                        32000
    #define MX_USBFreq_Value                        400000000
    #define MX_WatchDogFreq_Value                   32000
    #define MX_DSIFreq_Value                        96000000
    #define MX_DSIPHYCLKFreq_Value                  96000000
    #define MX_DSITXEscFreq_Value                   20000000
    #define MX_SPDIFRXFreq_Value                    400000000
    #define MX_MCO1PinFreq_Value                    64000000
    #define MX_MCO2PinFreq_Value                    400000000
    
    
    /*-------------------------------- CORTEX_M7  --------------------------------*/
    
    #define MX_CORTEX_M7                            1
    
    /* GPIO Configuration */
    
    /*-------------------------------- SYS        --------------------------------*/
    
    #define MX_SYS                                  1
    
    /* GPIO Configuration */
    
    /*-------------------------------- NVIC       --------------------------------*/
    
    #define MX_NVIC                                 1
    
    /*-------------------------------- GPIO       --------------------------------*/
    
    #define MX_GPIO                                 1
    
    /* GPIO Configuration */
    
    #endif  /* __MX_DEVICE_H */
    
    
    
    1. 重新编译,发现缺少定义

      DMARxDscrTab 以太网 Rx DMA描述符
      DMATxDscrTab 以太网 Tx DMA描述符
      Rx_Buff 以太网 接收缓存



    6. 在EMAC_STM32H7XX.c文件头中,我们可以找到如下说明,我们可以根据该说明新建一个ETH_Configuration.c文件,并按照说明实现即可

    Configuration tab
    -----------------
      1. Under Connectivity open \b ETH Configuration:
         - <b>GPIO Settings</b>: review settings, no changes required
              Pin Name | Signal on Pin | GPIO mode | GPIO Pull-up/Pull..| Maximum out | User Label
              :--------|:--------------|:----------|:-------------------|:------------|:----------
              PA1      | ETH_REF_CLK   | Alternate | No pull-up and no..| High        |.
              PA2      | ETH_MDIO      | Alternate | No pull-up and no..| High        |.
              PA7      | ETH_CRS_DV    | Alternate | No pull-up and no..| High        |.
              PC1      | ETH_MDC       | Alternate | No pull-up and no..| High        |.
              PC4      | ETH_RXD0      | Alternate | No pull-up and no..| High        |.
              PC5      | ETH_RXD1      | Alternate | No pull-up and no..| High        |.
              PG11     | ETH_TX_EN     | Alternate | No pull-up and no..| High        |.
              PG13     | ETH_TXD0      | Alternate | No pull-up and no..| High        |.
              PG14     | ETH_TXD1      | Alternate | No pull-up and no..| High        |.
    
         - <b>NVIC Settings</b>: enable interrupts
              Interrupt Table                      | Enable | Preemption Priority | Sub Priority
              :------------------------------------|:-------|:--------------------|:------------
              Ethernet global interrupt            |\b ON   | 0                   | 0
    
         - <b>Parameter Settings</b>: configure descriptor and RX buffer memory locations
              General:Ethernet Configuration | Value
              :------------------------------|:-------
              Ethernet MAC Address           | unused
              Tx Descriptor Length           | \b 4
              First Tx Descriptor Address    | \b 0x30040060
              Rx Descriptor Length           | \b 4
              First Rx Descriptor Address    | \b 0x30040000
              Rx Buffers Address             | \b 0x30040200
              Rx Buffers Length              | \b 1524          
    
         \n\note
         Add <b>"RxDecripSection", "TxDecripSection" and "RxArraySection" </b> sections to the Scatter file if GNU Compiler or Arm Compiler 6 is used.\n      
         Example:
         \code{.sct}
           RW_ETH_RX_DESC 0x30040000 0x00000060 {
             *(.RxDecripSection)
           }
           RW_ETH_TX_DESC 0x30040060 0x000001A0 {
             *(.TxDecripSection)
           }
           RW_ETH_RX_BUF  0x30040200 0x00001800 {
             *(.RxArraySection)
           }
         \endcode
         \endnote
    
         - <b>User Constants</b>: not used
    
         Click \b OK to close the ETH Configuration dialog
     
      2. Under System open \b CORTEX_M7 Configuration
         - <b>Parameter Settings</b>: optionally enable cache and configure MPU
              Cortex Interface Settings    | Value
              :----------------------------|:-------
              CPU ICache                   | Enabled (optional)
              CPU DCache Length            | Enabled (optional)
              
              Cortex MPU Control Settings  | Value
              :----------------------------|:-------
              MPU Control Mode             | Background Region Privileged accesses only
              
              Cortex MPU Region 0 Settings | Value
              :----------------------------|:-------
              MPU Region                   | \b Enabled
              MPU Region Base Address      | \b 0x30040000
              MPU Region Size              | \b 256B
              MPU SubRegion Disable        | \b 0x0
              MPU TEX field level          | \b level 0
              MPU Access Permission        | \b ALL ACCESS PERMITTED
              MPU Instruction Access       | \b ENABLE
              MPU Shareability Permission  | \b ENABLE
              MPU Cacheable Permission     | \b DISABLE
              MPU Bufferable Permission    | \b ENABLE
    */
    
    
    GPIO初始化;
    NVIC中断配置;
    以太网DMA接收/发送描述符的配置;
    另外需要对MPU进行配置。
    
    1. ETH_Configuration.c文件内容如下:
    #include "includes.h"
    
    
    /* Ethernet Rx DMA 描述符 */
    __attribute__((at(0x30040000))) ETH_DMADescTypeDef  DMARxDscrTab[ETH_RX_DESC_CNT]; 
    
    /* Ethernet Tx DMA 描述符 */
    __attribute__((at(0x30040060))) ETH_DMADescTypeDef  DMATxDscrTab[ETH_TX_DESC_CNT]; 
    
    /* Ethernet 接收缓冲 */
    __attribute__((at(0x30040200))) uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_MAX_PACKET_SIZE]; 
    
    
    ETH_HandleTypeDef heth;
    
    
    /*
    *********************************************************************************************************
    *	函 数 名: HAL_ETH_MspInit
    *	功能说明: 以太网初始化调用的底层回调,用于初始化IO,时钟和中断
    *	形    参: ---
    *	返 回 值: 无
    *********************************************************************************************************
    */
    void HAL_ETH_MspInit(ETH_HandleTypeDef* heth)
    {
    	GPIO_InitTypeDef GPIO_InitStruct;
    
    	/*
    		PC1     ------> ETH_MDC
    		PA1     ------> ETH_REF_CLK
    		PA2     ------> ETH_MDIO
    		PA7     ------> ETH_CRS_DV
    		PC4     ------> ETH_RXD0
    		PC5     ------> ETH_RXD1
    		PB13    ------> ETH_TXD1
    		PG11    ------> ETH_TX_EN
    		PG13    ------> ETH_TXD0 
    	*/
    	if(heth->Instance==ETH)
    	{
    		/* 使能外设时钟 */
    		__HAL_RCC_ETH1MAC_CLK_ENABLE();
    		__HAL_RCC_ETH1TX_CLK_ENABLE();
    		__HAL_RCC_ETH1RX_CLK_ENABLE();
    
    		/* 使能时钟 */
    		__HAL_RCC_GPIOA_CLK_ENABLE();
    		__HAL_RCC_GPIOB_CLK_ENABLE();
    		__HAL_RCC_GPIOC_CLK_ENABLE();
    		__HAL_RCC_GPIOG_CLK_ENABLE();
    
    		
    		/* 配置PA1, PA2 , PA7 */
    		GPIO_InitStruct.Pin =  GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
    		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
    		GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    		GPIO_InitStruct.Pull = GPIO_NOPULL ; 
    		GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
    		HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    		/* 配置PB13 */
    		GPIO_InitStruct.Pin = GPIO_PIN_13;
    		HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    
    		/* 配置PC1, PC4和PC5 */
    		GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; 
    		HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);	
    
    		/* 配置PG11, PG12和PG13 */
    		GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_13;
    		HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
    
    		/* 设置中断优先级 */
    		HAL_NVIC_SetPriority(ETH_IRQn, 3, 0);
    		HAL_NVIC_EnableIRQ(ETH_IRQn);	
    	}
    }
    
    /*
    *********************************************************************************************************
    *	函 数 名: ETH_IRQHandler
    *	功能说明: 以太网回调函数
    *	形    参: 无
    *	返 回 值: 无
    *********************************************************************************************************
    */
    void ETH_IRQHandler(void)
    {
    	HAL_ETH_IRQHandler(&heth);
    }
    
    1. 再次编译,一般情况就没有错误了。

    添加网卡驱动接口

    为了便于移植,这里直接使用MDK提供的ethernetif.c文件进行移植操作,文件路径如下;
    同时还需要拷贝ethif_config.h文件,路径见下图
    


    1. 添加文件到工程中去,如下所示


    2. 重新编译,无错误,到此移植完成

    添加创建任务,进行Ping测试

    添加lwip相关头文件
    创建以太网初始化函数,代码如下
    
    void net_init(void) 
    {
    	struct ip4_addr ipaddr;
    	struct ip4_addr netmask;
    	struct ip4_addr gw;
    
    	/* 创建协议栈线程 */
    	tcpip_init(NULL, NULL);
    
    #if LWIP_DHCP
    	ipaddr.addr = 0;
    	netmask.addr = 0;
    	gw.addr = 0;
    #else
    	IP4_ADDR(&ipaddr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
    	IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1 , NETMASK_ADDR2, NETMASK_ADDR3);
    	IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
    #endif
    
    	/* 将网络接口添加到netif_list列表 */
    	netif_add(&netif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &ethernet_input);
    
    	/*  注册默认网络接口 */
    	netif_set_default(&netif);
    	netif_set_up(&netif);
    
    	#if LWIP_DHCP
    		dhcp_start (&netif);
    	#endif
    }
    
    
    1. 通过FreeRTOS创建一个eth任务,代码如下:
    void vTaskEthCheck(void *pvParameters)
    {
        /* 初始化网络 */
        printf("开始初始化网络.....");
        net_init();
        printf("初始化网络完成");
        while(1)
        {
        vTaskDelay(300); 
        }
    
    1. 编译运行,打开串口调试助手,发现有断言错误,如下图所示:

    1. 这是由于lwip使用了FreeRTOS,因此在tcpip.c里面会调用sys_thread_new创建一个TCP任务,如下图所示

    1. lwipopt.h中添加上图中用到的宏定义,如下图所示

    1. 继续编译、下载,能够正常初始化网络,但无法ping通,如下图所示

    1. 这是由于没加添加网卡接收任务,导致下位机未对接收的网卡数据产生反应,需要在ethernetif.c添加如下内容
    //1.添加信号量定义
    xSemaphoreHandle s_xSemaphore = NULL;
    
    //2.在下面函数增加创建任务语句,如下
    static void
    low_level_init(struct netif *netif)
    {
        .....//省略
        /* 创建接收处理任务 */
        s_xSemaphore = xSemaphoreCreateBinary();
    	sys_thread_new("ethernetif_task",
                      ethernetif_task,          /* 任务入口函数 */
                      NULL,        	            /* 任务入口函数参数 */
                      TCPIP_THREAD_STACKSIZE,   /* 任务栈大小 */
                      2);                       /* 任务的优先级 */
    }
    
    //修改void ethernetif_poll (struct netif *netif) 函数如下
    
    void ethernetif_poll (struct netif *netif) 
    {
      struct ethernetif *eth = netif->state;
    
        while(1)
        {
            xSemaphoreTake(s_xSemaphore, portMAX_DELAY );
            taskENTER_CRITICAL();
            if (!eth->phy_ok || eth->link == ARM_ETH_LINK_DOWN) 
            {}
            if ((eth->rx_event) || (!eth->event_rx_frame)) 
            {
                eth->rx_event = false;
                /* process received ethernet packet */
                
                ethernetif_input (netif);
            }
            taskEXIT_CRITICAL(); 
        }
    }
    
    

    修改之后可以ping通

    使用NETCONN 接口测速

    展开全文
  • lwip移植加tcpip客户端功能代码,在ucos系统基础上移植lwip,并使用raw接口进行客户端服务编写
  • lwip2.1.0移植例程

    2018-10-31 17:28:59
    lwip2.1.0移植参考例程,结合lwip2.1.0源码进行移植,提供cc.h等配置文件
  • i.MX - RT1052 LwIP移植

    2020-11-13 23:23:12
    LwIP是 TCP / IP协议套件的轻量级实现,该套件最初是由瑞典计算机科学研究所的计算机和网络体系结构(CNA)实验室的 Adam Dunkels编写的,但现在正由一组来自世界各地的开发者积极推进开发。 LwIP TCP / IP实现的...

    写在前面:

    本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。

    LwIP是 TCP / IP协议套件的轻量级实现,该套件最初是由瑞典计算机科学研究所的计算机和网络体系结构(CNA)实验室的 Adam Dunkels编写的,但现在正由一组来自世界各地的开发者积极推进开发。
    LwIP TCP / IP实现的重点是减少 RAM使用量,同时仍具有完整的 TCP。 这使 LwIP适用于具有数十 KB的可用 RAM且可容纳约 40KB的代码 ROM的嵌入式系统。


    LwIP主页:http://savannah.nongnu.org/projects/lwip/

    LwIP WiKi:https://lwip.fandom.com/wiki/LwIP_Wiki



    ENET MAC 信号引脚定义:

    • ENET_MDC:数据时钟信号。为 PHY提供时序参考,以实现 MDIO 信号上的数据传输

      MII / RMII 有该线。

    • ENET_MDIO:数据管理信号。在外部 PHY 和媒体访问控制器之间传输控制信息。数据是与 MDC 同步。此信号是复位后的输入。

      MII / RMII 有该线。

    • ENET_TX_DATA0:串行输出,以太网发送数据位(最先传输)。仅在 TX_EN 断言期间有效。

      MII / RMII 有该线。

    • ENET_TX_DATA1:串行输出,以太网发送数据位。仅在 TX_EN 断言期间有效。

      MII / RMII 有该线。

    • ENET_TX_DATA2:串行输出,以太网发送数据位。仅在 TX_EN 断言期间有效。

      MII 有该线。

    • ENET_TX_DATA3:串行输出,以太网发送数据位。仅在 TX_EN 断言期间有效。

      MII 有该线。

    • ENET_TX_ER:传输错误(可选)。在断言一个或多个时钟周期的同时也断言 TX_EN,PHY 发送一个或多个非法符号。

      MII / RMII 有该线。

    • ENET_TX_EN:传输使能信号。此信号必需与数据前导符的起始位同步出现,并在传输完毕前一直保持。

      MII / RMII 有该线。

    • ENET_TX_CLK:在MII 模式下的传输时钟。为 TX_EN、TX_DATA[3:0] 和 TX_ER 提供时序参考。

      MII 有该线。

    • ENET_RX_DATA0:以太网接收数据位(最先传输)。当 RX_EN 被断言时,从 PHY 传输到 MAC 控制器。

      MII / RMII 有该线。

    • ENET_RX_DATA1:以太网接收数据位。当 RX_EN 被断言时,从 PHY 传输到 MAC 控制器。

      MII / RMII 有该线。

    • ENET_RX_DATA2:以太网接收数据位。当 RX_EN 被断言时,从 PHY 传输到 MAC 控制器。

      MII 有该线。

    • ENET_RX_DATA3:以太网接收数据位。当 RX_EN 被断言时,从 PHY 传输到 MAC 控制器。

      MII 有该线。

    • ENET_RX_ER:接收错误。当用 RX_DV 置位时,表明 PHY 在当前帧中检测到错误。

      MII / RMI 有该线。

    • ENET_RX_EN:接收使能信号。断言此输入表示 PHY 在 MII 上存在有效的半字节。从帧的第一个恢复的半字节到最后的半字节,RX_EN 必须保持有效。断言 RX_EN 必须不迟于 SFD 开始并且排除任何 EOF。在 RMII 模式下,此引脚还生成 CRS 信号。

      MII / RMI 有该线。

    • ENET_RX_CLK:在 MII 模式下的接收时钟。为 RX_EN、RX_DATA[3:0] 和 RX_ER 提供时序参考。

      MII 有该线。

    • ENET_CRS:载波检测。置为有效时,指示发送或接收介质不空闲。 在 RMII 模式下,该信号存在于 RMII_CRS_DV 引脚上。

      MII 有该线。

    • ENET_COL:冲突检测。在检测到冲突时断言,并在冲突持续时保持断言。未为全双工模式定义此信号。

      MII 有该线。

    • ENET_REF_CLK:在 RMII 模式下的参考时钟。该信号是接收、发送和控制接口的参考时钟。
      RMII 有该线。

    • ENET_1588EVENT0_OUT:捕获/比较块输入/输出事件总线信号。当配置为捕获并检测到上升沿时,当前计时器值被锁定并传输到相应的ENET-TCCRN 登记簿软件。当配置为比较时,对应的当计时器达到中编程的比较值注册ENET。中断或DMA 请求可以是如果设置了ENET TCSRN[TIE]或ENET TCSRN[TDRE]中的相应位,则触发。
      ENET_1588_EVENT0_OUT 有一个可编程的输出宽度,见 IOMUXC_GPR0[CLK_STRETCH],相对于所有其他事件输出信号延迟一个时钟周期。

      MII / RMII 有该线。

    • ENET_1588EVENT0_IN:捕获/比较块输入/输出事件总线信号。当配置为捕获并检测到上升沿时,当前计时器值被锁定并传输到相应的ENET-TCCRN 登记簿软件。当配置为比较时,对应的当定时器达到寄存器中编程的比较值ENET_TCCRn。中断或DMA请求可以是如果ENET TCSRN[TIE]中的对应位触发或设置了ENET TCSRN[TDRE]。

      MII / RMII 有该线。

    • ENET_1588EVENT1_OUT:捕获/比较块输入/输出事件总线信号。当配置为捕获时,上升沿是检测到时,当前定时器值被锁定并传输到相应的ENET_TCRN 寄存器中,以便软件检查。当配置为比较时,对应的信号1588_事件被断言为1 计时器达到比较值时循环在寄存器ENET 中编程。如果ENET TCSRN[TIE]或ENET U TCSRN[TDRE]已设置。

      MII / RMII 有该线。

    • ENET_1588EVENT1_IN:捕获/比较块输入/输出事件总线信号。当被配置为捕捉并检测到上升沿时,当前定时器值被锁定并传送到相应的ENET_TCRN 寄存器中以供软件检查。当配置为比较时,为一个计时器达到比较值时循环在寄存器ENET 中编程。安如果ENET TCSRN[TIE]或ENET U TCSRN[TDRE]已设置。

      MII / RMII 有该线。

    • ENET_1588EVENT2_OUT:捕获/比较块输入/输出事件总线信号。当被配置为捕捉并检测到上升沿时,当前定时器值被锁定并传送到相应的ENET_TCRN 寄存器中以供软件检查。当配置为比较时,当定时器达到在寄存器ENET_TCRN 中编程的比较值时,对应的信号1588_EVENT 被断言一个周期。如果设置了ENET TCSRN[TIE]或ENETTCSRN[TDRE]中的相应位,则可以触发中断或DMA 请求。

      MII / RMII 有该线。

    • ENET_1588EVENT2_IN:捕获/比较块输入/输出事件总线信号。当被配置为捕捉并检测到上升沿时,当前定时器值被锁定并传送到相应的ENET_TCRN 寄存器中以供软件检查。当配置为比较时,当定时器达到在寄存器ENET_TCRN 中编程的比较值时,对应的信号1588_EVENT 被断言一个周期。如果设置了ENET TCSRN[TIE]或ENETTCSRN[TDRE]中的相应位,则可以触发中断或DMA 请求。

      MII / RMII 有该线。

    • ENET_1588EVENT3_OUT:捕获/比较块输入/输出事件总线信号。当被配置为捕捉并检测到上升沿时,当前定时器值被锁定并传送到相应的ENET_TCRN 寄存器中以供软件检查。当配置为比较时,当定时器达到在寄存器ENET_TCRN 中编程的比较值时,对应的信号1588_EVENT 被断言一个周期。如果设置了ENET TCSRN[TIE]或ENETTCSRN[TDRE]中的相应位,则可以触发中断或DMA 请求。

      MII / RMII 有该线。

    • ENET_1588EVENT3_IN:捕获/比较块输入/输出事件总线信号。当配置为捕获并检测到上升沿时,当前计时器值被锁存并传送到相应的ENET TCCRN 寄存器中,以供软件检查。当配置为比较时,当定时器达到在寄存器ENET_TCRN 中编程的比较值时,对应的信号1588_EVENT 被断言一个周期。如果设置了ENET TCSRN[TIE]或ENETTCSRN[TDRE]中的相应位,则可以触发中断或DMA 请求。

      MII / RMII 有该线。


    网络接口:

    MII: Media Independent Interface

    MII接口信号包括三类,分别为:

    • 发送端信号:TXCLK,***TXD[0-***3]TXENTXER
    • 接收端信号:RXCLKRXD[0-3]RXDVRXERCRSCOL
    • 配置信号:MDIOMDC

    信号方向如下图所示,其中 TXER 为选配。MII 共计 18 根信号线,只有 MDIO/MDC 信号可以在不同 PHY 间级联。假定系统中有 8 个 PHY,则 MII 信号总数为 8 * 16 + 2 = 130 根!

    因此为减少信号数,RMII 接口应运而生(下一个点有说)。

    在这里插入图片描述

    Transmitter signals:

    Signal nameDescriptionDirection
    TX_CLKTransmit clockPHY to MAC
    TXD0Transmit data bit 0 (transmitted first)MAC to PHY
    TXD1Transmit data bit 1MAC to PHY
    TXD2Transmit data bit 2MAC to PHY
    TXD3Transmit data bit 3MAC to PHY
    TX_ENTransmit enableMAC to PHY
    TX_ERTransmit error (optional)MAC to PHY

    Receiver signals:

    Signal nameDescriptionDirection
    RX_CLKReceive clockPHY to MAC
    RXD0Receive data bit 0 (received first)PHY to MAC
    RXD1Receive data bit 1PHY to MAC
    RXD2Receive data bit 2PHY to MAC
    RXD3Receive data bit 3PHY to MAC
    RX_DVReceive data validPHY to MAC
    RX_ERReceive errorPHY to MAC
    CRSCarrier sensePHY to MAC
    COLCollision detectPHY to MAC

    Management signals:

    Signal nameDescriptionDirection
    MDIOManagement dataBidirectional
    MDCManagement data clockMAC to PHY

    RMII: Reduced Media Independent Interface

    相比于MII接口,RMII有以下四处变化:

    • TXCLKRXCLK 两个时钟信号,合并为一个时钟 REFCLK
    • 时钟速率由 25MHz 上升到 50MHz,单向数据由 4 bits 变为 2 bits
    • CRSRXDV 合并为一个信号 CRSDV
    • 取消了 COL 信号

    RMII信号如下图所示。RMII只要 9 根信号线,相比于MII的 18 根信号可谓有不少的删减,在同一个系统中的多个设备可以共享 MDIO, MDCREFCLK 信号线,每个端口仅留 67 个引脚。

    在这里插入图片描述

    RMII signals:

    Signal nameDescriptionDirection
    REF_CLKContinuous 50 MHz reference clockReference clock may be an input on both devices from an external clock source, or may be driven from the MAC to the PHY
    TXD0Transmit data bit 0 (transmitted first)MAC to PHY
    TXD1Transmit data bit 1MAC to PHY
    TX_ENWhen high, clock data on TXD0 and TXD1 to the transmitterMAC to PHY
    RXD0Receive data bit 0 (received first)PHY to MAC
    RXD1Receive data bit 1PHY to MAC
    CRS_DVCarrier Sense (CRS) and RX_Data Valid (RX_DV) multiplexed on alternate clock cycles. In 10 Mbit/s mode, it alternates every 10 clock cycles.PHY to MAC
    RX_ERReceive error (optional on switches)PHY to MAC
    MDIOManagement dataBidirectional
    MDCManagement data clock.MAC to PHY

    更多的接口信息可看:https://en.wikipedia.org/wiki/Media-independent_interface

    LwIP移植操作:

    基础移植

    下载 LwIP源码,这里使用 v2.1.2版本:http://download.savannah.nongnu.org/releases/lwip/

    要知道在 LwIP协议套件里是支持 OS操作和裸机操作,一般要用到这种网络协议栈都会使用 OS,因此这里也是以带 OS的为例。
    首先,准备移植好带 FreeRTOS的工程模板,然后把下载下来的 LwIP源码放到我们的工程文件夹里面:
    在这里插入图片描述
    另外,还需要下载 contrib文件包,选择 v2.1.0就好了,因为 contrib中包含了一些和平台移植相关的代码,到时候要提取一些代码:
    在这里插入图片描述
    接着再把刚下载的 contrib文件夹里的 ./apps 文件夹也同样移植到工程中的中间件文件夹 LwIP里面,然后得到这样的目录(这里先不用看 port接口文件先,而 test文件夹是一些协议栈内核测试程序,在提取完 lwipopts.h 之后就可直接删除了。):
    在这里插入图片描述
    文件分析:

    • 当前主目录文件

      • CHANGELOG ---- 版本更新记录,从中可以看到 LwIP不同版本的变化
      • COPYING ---- 版权说明
      • FEATURES ---- LwIP特征 /特点功能说明
      • FILES ---- 其中说明了其所在目录下的各目录或文件的用途。在不同的目录下会有不同的该文件
      • README ---- 简介文档
      • UPGRADING ---- 版本升级后可能出现不兼容,该文档记录了从老版本升级需要修改的地方。对于升级自己使用的 LwIP版本时很有用处。
    • src(核心文件部分)

      src
       ├─api		// 高级包装器 API的代码。如果使用低级回调 /原始 API,则不需要。
       ├─apps		// 用 LwIP低级 /原始 API专门编写的更高级的应用程序。
       │  ├─altcp_tls
       │  ├─http
       │  │  ├─fs
       │  │  │  └─img
       │  │  └─makefsdata
       │  ├─lwiperf
       │  ├─mdns
       │  ├─mqtt
       │  ├─netbiosns
       │  ├─smtp
       │  ├─snmp
       │  ├─sntp
       │  └─tftp
       ├─core		// TPC /IP栈的核心;协议的实现,内存和缓冲区管理,以及底层的原始 API。
       │  ├─ipv4
       │  └─ipv6
       ├─include	// lwIP include files.
       │  ├─compat
       │  │  ├─posix
       │  │  │  ├─arpa
       │  │  │  ├─net
       │  │  │  └─sys
       │  │  └─stdc
       │  ├─lwip
       │  │  ├─apps
       │  │  ├─priv
       │  │  └─prot
       │  └─netif
       │      └─ppp
       │          └─polarssl
       └─netif	// 通用网络接口设备驱动程序保存在这里。
           └─ppp
               └─polarssl
      

    port接口移植

    以下部分需要根据相应的底层编写对应的驱动处理文件。

    系统处理

    1、添加 lwipopts.h :在源码文件夹 ...\lwip-2.1.2\test\fuzz 下可以找到该文件,该文件主要用于 Lwip参数的配置,供用户修改,部分参数配置依赖于 ...\lwip-2.1.2\src\include\lwip\opt.h 文件。
    2、添加 sys_arch.c :在 contrib文件夹的 ...\contrib-2.1.0\ports\freertos 里可以找到该文件,这个主要用来与操作系统对接的接口源文件。
    3、添加对应上面 sys_arch.c 所需的头文件 cc.h、perf.h、sys_arch.h:通用平台移植,适用于 NO_SYS的两种状态。(将调试映射到 printf,从系统时间提供 sys_now和 co功能等),这些文件可以在 ...\contrib-2.1.0\ports\unix\port\include\arch 中提取出来。

    物理层处理

    一般来说,要进行网络通讯,从硬件的角度看,以太网接口电路主要由MAC(Media Access Control)控制器和物理层接口PHY(Physical Layer,PHY)两大部分构成,如下图所示;而软件上就是基于硬件上面编写相应的驱动程序:
    在这里插入图片描述
    对于上述的三部分,并不一定都是独立的芯片,根据组合形式,可分为下列几种类型:

    • 方案一:CPU集成 MAC与 PHY:
      在这里插入图片描述

    • 方案二:CPU集成MAC,PHY采用独立芯片:
      在这里插入图片描述

    • 方案三:CPU不集成MAC与PHY,MAC与PHY采用集成芯片;
      在这里插入图片描述


    添加 PHY驱动

    官方 board使用的物理层驱动芯片:KSZ8081RNB
    在这里插入图片描述
    如果使用的是官方一样的 PHY驱动芯片,那么可以在 \SDK_2.8.0_EVKB-IMXRT1050\components\phy\device\phyksz8081 中找到驱动文件。

    添加 MAC驱动

    在 rt1052中,芯片上是集成了 MAC驱动,看下图:
    在这里插入图片描述
    因此这部分我们是不用管的,全程交给其内部自行处理。

    添加 MDIO处理

    从下图可以看出来,MDIO用于处理外部 PHY和媒体访问控制器之间传输控制信息,属于 PHY驱动接口的一部分:
    在这里插入图片描述
    其处理文件可以在 ...\SDK_2.8.0_EVKB-IMXRT1050\components\phy\mdio\enet 找到。

    网卡驱动处理

    网卡驱动部分比较特别,这些文件需要在包含了 Lwip middleware的官方 SDK文件中找到 .../SDK_2.8.0_MIMXRT1052xxxxB module\middleware\lwip\port
    在这里插入图片描述

    然后,移植完成后,port文件结构如下:

    port
     │  lwipopts.h
     │  sys_arch.c
     │  
     ├─arch
     │      cc.h
     │      perf.h
     │      sys_arch.h
     │      
     ├─ethernetif
     │      enet_ethernetif.c
     │      enet_ethernetif.h
     │      enet_ethernetif_kinetis.c
     │      enet_ethernetif_priv.h
     │      
     └─temp
         │  lwipopts.h
         │  sys_arch.c
         │  
         └─arch
                cc.h
                perf.h
                sys_arch.h
    

    最终添加到工程里面如下:
    在这里插入图片描述


    工程文件说明:

    通过上面的移植,这里简单分析一下与 LwIP相关的要操作的文件

    在这里插入图片描述

    • slipif.c - SLIP组件文件

      SLIP即串行链路IP,它提供了一种在串行链路上传送 IP 数据包的函数定义。SLIP 协议比较简单,它只是定义了一系列的字符,以实现对链路上的 IP数据包封装和发送,除此之外,它不提供任何寻址、错误检测、包类型识别机制,因此相关驱动程序的实现也比较简单。它需要一个sio(串行 I / O)模块才能工作。(这里并不需要,所以编译屏蔽掉)

    • port文件夹(注意,需要根据平台进行相应的修改)

      这个文件夹中主要是针对 TCP/IP 规约的各种定义。

      • sys_arch.c文件 - 一般用在有操作系统的移植上
      • cc.h文件 - 包含处理器相关的变量类型、数据结构及字节对齐的相关宏
      • perf.h文件 - 与系统统计与测量相关的头文件
    • ethernetif文件夹 - 存放着底层的网卡驱动函数

      对应的网卡驱动程序,请根据相应的设备进行移植或修改

    • components\lwip文件夹 - 存放着对应的以太网芯片的底层处理程序

      对于不同的 PHY to MAC 芯片,请根据相应的底层驱动进行移植或修改

    • lwipopt.h - 该文件主要用于 Lwip 参数的配置(This file is based on …\src\include\lwip\opt.h

      移植时需要根据自己的需要,进行相关的配置,其默认参数配置在 opt.h 文件中配置

    1、重写 cc.h、perf.h、sys_arch.h 文件。其实也不算是重写吧,直接把带有 Lwip middleware的官方 SDK文件中 ...\SDK_2.8.0_MIMXRT1052xxxxB module\middleware\lwip\port\archcc.h、perf.h、sys_arch.h 的内容复制过来或者直接替换。

    2、重写 sys_arch.c 文件。同样的,在带有 Lwip middleware的官方 SDK文件中 ...\SDK_2.8.0_MIMXRT1052xxxxB module\middleware\lwip\portsys_arch.c 的内容复制过来或者直接替换。

    3、重写 lwipopts.h 文件。修改为以下内容:

    /**
     ******************************************************************************
     * @file    lwipopts.h
     * This file is based on \src\include\lwip\opt.h
     ******************************************************************************
     * Copyright (c) 2013-2016, Freescale Semiconductor, Inc.
     * Copyright 2016-2018 NXP
     * All rights reserved.
     *
     * SPDX-License-Identifier: BSD-3-Clause
     */
    
    #ifndef __LWIPOPTS_H__
    #define __LWIPOPTS_H__
    
    #if USE_RTOS
    
    /**
     * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain
     * critical regions during buffer allocation, deallocation and memory
     * allocation and deallocation.
     */
    #define SYS_LIGHTWEIGHT_PROT 1
    
    /**
     * NO_SYS==0: Use RTOS
     */
    #define NO_SYS 0
    /**
     * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c)
     */
    #define LWIP_NETCONN 1
    /**
     * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c)
     */
    #define LWIP_SOCKET 1
    
    /**
     * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and
     * SO_RCVTIMEO processing.
     */
    #define LWIP_SO_RCVTIMEO 1
    
    #else
    /**
     * NO_SYS==1: Bare metal lwIP
     */
    #define NO_SYS       1
    /**
     * LWIP_NETCONN==0: Disable Netconn API (require to use api_lib.c)
     */
    #define LWIP_NETCONN 0
    /**
     * LWIP_SOCKET==0: Disable Socket API (require to use sockets.c)
     */
    #define LWIP_SOCKET  0
    
    #endif
    
    /* ---------- ENET Priority options ---------- */
    
    /* 不打开则使用默认值,基于 enet_ethernetif.h文件修改
       注意 configMAX_SYSCALL_INTERRUPT_PRIORITY配置 */
    //#define ENET_PRIORITY 13U
    //#define ENET_1588_PRIORITY 12U
    
    /* ---------- Core locking ---------- */
    
    #define LWIP_TCPIP_CORE_LOCKING 1		// ../include/lwip/opt.h文件有默认定义
    
    /* ../include/lwip/tcpip.h文件中约 52行默认有定义 */
    #if LWIP_TCPIP_CORE_LOCKING
    /* 核心互斥操作 */
    void sys_lock_tcpip_core(void);
    #define LOCK_TCPIP_CORE() sys_lock_tcpip_core()		// 相对的加入了线程保护
    
    void sys_unlock_tcpip_core(void);
    #define UNLOCK_TCPIP_CORE() sys_unlock_tcpip_core()	// 相对的加入了线程保护
    
    
    void sys_check_core_locking(void);
    #define LWIP_ASSERT_CORE_LOCKED() sys_check_core_locking()	// 判定是否线程化,原 #define为空
    
    void sys_mark_tcpip_thread(void);
    #define LWIP_MARK_TCPIP_THREAD() sys_mark_tcpip_thread()	// 检查核心锁定
    
    #endif /* LWIP_TCPIP_CORE_LOCKING */
    
    /* ---------- Memory options ---------- */
    /**
     * MEM_ALIGNMENT: should be set to the alignment of the CPU
     *    4 byte alignment -> #define MEM_ALIGNMENT 4
     *    2 byte alignment -> #define MEM_ALIGNMENT 2
     */
    #ifndef MEM_ALIGNMENT
    #define MEM_ALIGNMENT 4
    #endif
    
    /**
     * MEM_SIZE: the size of the heap memory. If the application will send
     * a lot of data that needs to be copied, this should be set high.
     */
    #ifndef MEM_SIZE
    #define MEM_SIZE (22 * 1024)
    #endif
    
    /* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application
       sends a lot of data out of ROM (or other static memory), this
       should be set high. */
    #ifndef MEMP_NUM_PBUF
    #define MEMP_NUM_PBUF 15
    #endif
    /* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
       per active UDP "connection". */
    #ifndef MEMP_NUM_UDP_PCB
    #define MEMP_NUM_UDP_PCB 6
    #endif
    /* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP
       connections. */
    #ifndef MEMP_NUM_TCP_PCB
    #define MEMP_NUM_TCP_PCB 10
    #endif
    /* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP
       connections. */
    #ifndef MEMP_NUM_TCP_PCB_LISTEN
    #define MEMP_NUM_TCP_PCB_LISTEN 6
    #endif
    /* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP
       segments. */
    #ifndef MEMP_NUM_TCP_SEG
    #define MEMP_NUM_TCP_SEG 22
    #endif
    /* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active
       timeouts. */
    #ifndef MEMP_NUM_SYS_TIMEOUT
    #define MEMP_NUM_SYS_TIMEOUT 10
    #endif
    
    /* ---------- Pbuf options ---------- */
    /* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
    #ifndef PBUF_POOL_SIZE
    #define PBUF_POOL_SIZE 9
    #endif
    
    /* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */
    /* Default value is defined in lwip\src\include\lwip\opt.h as
     * LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN)*/
    
    /* ---------- TCP options ---------- */
    #ifndef LWIP_TCP
    #define LWIP_TCP 1
    #endif
    
    #ifndef TCP_TTL
    #define TCP_TTL 255
    #endif
    
    /* Controls if TCP should queue segments that arrive out of
       order. Define to 0 if your device is low on memory. */
    #ifndef TCP_QUEUE_OOSEQ
    #define TCP_QUEUE_OOSEQ 0
    #endif
    
    /* TCP Maximum segment size. */
    #ifndef TCP_MSS
    #define TCP_MSS (1500 - 40) /* TCP_MSS = (Ethernet MTU - IP header size - TCP header size) */
    #endif
    
    /* TCP sender buffer space (bytes). */
    #ifndef TCP_SND_BUF
    #define TCP_SND_BUF (6 * TCP_MSS) // 2
    #endif
    
    /* TCP sender buffer space (pbufs). This must be at least = 2 *
       TCP_SND_BUF/TCP_MSS for things to work. */
    #ifndef TCP_SND_QUEUELEN
    #define TCP_SND_QUEUELEN (3 * TCP_SND_BUF) / TCP_MSS // 6
    #endif
    
    /* TCP receive window. */
    #ifndef TCP_WND
    #define TCP_WND (2 * TCP_MSS)
    #endif
    
    /* Enable backlog*/
    #ifndef TCP_LISTEN_BACKLOG
    #define TCP_LISTEN_BACKLOG 1
    #endif
    
    /* ---------- Network Interfaces options ---------- */
    /* Support netif api (in netifapi.c). */
    #ifndef LWIP_NETIF_API
    #define LWIP_NETIF_API 1
    #endif
    
    /* ---------- ICMP options ---------- */
    #ifndef LWIP_ICMP
    #define LWIP_ICMP 1
    #endif
    
    /* ---------- RAW options ---------- */
    #if !defined LWIP_RAW
    #define LWIP_RAW 0
    #endif
    
    /* ---------- DHCP options ---------- */
    /* Define LWIP_DHCP to 1 if you want DHCP configuration of
       interfaces. DHCP is not implemented in lwIP 0.5.1, however, so
       turning this on does currently not work. */
    #ifndef LWIP_DHCP
    #define LWIP_DHCP 0
    #endif
    
    /* ---------- UDP options ---------- */
    #ifndef LWIP_UDP
    #define LWIP_UDP 1
    #endif
    #ifndef UDP_TTL
    #define UDP_TTL 255
    #endif
    
    /* ---------- Statistics options ---------- */
    #ifndef LWIP_STATS
    #define LWIP_STATS 0
    #endif
    #ifndef LWIP_PROVIDE_ERRNO
    #define LWIP_PROVIDE_ERRNO 1
    #endif
    
    /* ---------- DNS options ---------- */
    #ifndef LWIP_DNS
    #define LWIP_DNS 0
    #endif
    
    /*
       --------------------------------------
       ---------- Checksum options ----------
       --------------------------------------
    */
    
    /*
    Some MCU allow computing and verifying the IP, UDP, TCP and ICMP checksums by hardware:
     - To use this feature let the following define uncommented.
     - To disable it and process by CPU comment the  the checksum.
    */
    //#define CHECKSUM_BY_HARDWARE
    
    #ifdef CHECKSUM_BY_HARDWARE
    /* CHECKSUM_GEN_IP==0: Generate checksums by hardware for outgoing IP packets.*/
    #define CHECKSUM_GEN_IP 0
    /* CHECKSUM_GEN_UDP==0: Generate checksums by hardware for outgoing UDP packets.*/
    #define CHECKSUM_GEN_UDP 0
    /* CHECKSUM_GEN_TCP==0: Generate checksums by hardware for outgoing TCP packets.*/
    #define CHECKSUM_GEN_TCP 0
    /* CHECKSUM_CHECK_IP==0: Check checksums by hardware for incoming IP packets.*/
    #define CHECKSUM_CHECK_IP 0
    /* CHECKSUM_CHECK_UDP==0: Check checksums by hardware for incoming UDP packets.*/
    #define CHECKSUM_CHECK_UDP 0
    /* CHECKSUM_CHECK_TCP==0: Check checksums by hardware for incoming TCP packets.*/
    #define CHECKSUM_CHECK_TCP 0
    #else
    /* CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets.*/
    #define CHECKSUM_GEN_IP    1
    /* CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets.*/
    #define CHECKSUM_GEN_UDP   1
    /* CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets.*/
    #define CHECKSUM_GEN_TCP   1
    /* CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.*/
    #define CHECKSUM_CHECK_IP  1
    /* CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets.*/
    #define CHECKSUM_CHECK_UDP 1
    /* CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets.*/
    #define CHECKSUM_CHECK_TCP 1
    #endif
    
    /**
     * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread.
     * The stack size value itself is platform-dependent, but is passed to
     * sys_thread_new() when the thread is created.
     */
    #ifndef DEFAULT_THREAD_STACKSIZE
    #define DEFAULT_THREAD_STACKSIZE (6 * 128)
    #endif
    
    /**
     * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread.
     * The priority value itself is platform-dependent, but is passed to
     * sys_thread_new() when the thread is created.
     */
    #ifndef DEFAULT_THREAD_PRIO
    #define DEFAULT_THREAD_PRIO 3
    #endif
    
    /*
       ------------------------------------
       ---------- Debugging options ----------
       ------------------------------------
    */
    
    #define LWIP_DEBUG
    
    #ifdef LWIP_DEBUG
    #define U8_F  "c"
    #define S8_F  "c"
    #define X8_F  "02x"
    #define U16_F "u"
    #define S16_F "d"
    #define X16_F "x"
    #define U32_F "u"
    #define S32_F "d"
    #define X32_F "x"
    #define SZT_F "u"
    #endif
    
    #define TCPIP_MBOX_SIZE        32
    #define TCPIP_THREAD_STACKSIZE 1024
    #define TCPIP_THREAD_PRIO      8
    
    /**
     * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a
     * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed
     * to sys_mbox_new() when the recvmbox is created.
     */
    #define DEFAULT_RAW_RECVMBOX_SIZE 12
    
    /**
     * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a
     * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed
     * to sys_mbox_new() when the recvmbox is created.
     */
    #define DEFAULT_UDP_RECVMBOX_SIZE 12
    
    /**
     * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a
     * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed
     * to sys_mbox_new() when the recvmbox is created.
     */
    #define DEFAULT_TCP_RECVMBOX_SIZE 12
    
    /**
     * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections.
     * The queue size value itself is platform-dependent, but is passed to
     * sys_mbox_new() when the acceptmbox is created.
     */
    #define DEFAULT_ACCEPTMBOX_SIZE 12
    
    #if (LWIP_DNS || LWIP_IGMP || LWIP_IPV6) && !defined(LWIP_RAND)
    /* When using IGMP or IPv6, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value*/
    #include "lwip/arch.h"
    u32_t lwip_rand(void);
    #define LWIP_RAND() lwip_rand()
    #endif
    
    #endif /* __LWIPOPTS_H__ */
    
    /*****END OF FILE****/
    
    

    然后,值得注意的是,上面有写到:

    /* 不打开则使用默认值,基于 enet_ethernetif.h文件修改
       注意 configMAX_SYSCALL_INTERRUPT_PRIORITY配置 */
    //#define ENET_PRIORITY 13U
    //#define ENET_1588_PRIORITY 12U
    

    这两个宏是用来配置网卡驱动的中断优先级的,所以,宏 ENET_PRIORITYENET_1588_PRIORITY 定义的中断等级大小必须在 FreeRTOS配置的 configMAX_SYSCALL_INTERRUPT_PRIORITYconfigKERNEL_INTERRUPT_PRIORITY优先级之间,否则就会出现错误,其原因是由于任务中断控制不受 FreeRTOS的管理了,具体的 FreeRTOS配置文件分析可看:FreeRTOS篇章之 FreeRTOSConfig.h分析

    TCP回显测试:

    复制带有 Lwip middleware的官方 SDK文件中 ...\SDK_2.8.0_MIMXRT1052xxxxB module\middleware\lwip\contrib\apps\tcpecho 的文件以及提取 SDK_2.8.0_MIMXRT1052xxxxB module\boards\evkbimxrt1050\lwip_examples\lwip_tcpecho\freertoslwip_tcpecho_freertos.c 文件中的部分代码。
    其中,从 lwip_tcpecho_freertos.c 提取出来的代码变更为:

    #include "./ENET/enet.h"
    
    #include "lwip/netifapi.h"
    #include "enet_ethernetif.h"
    
    #include "board.h"
    #include "fsl_iomuxc.h"
    #include "pin_mux.h"
    
    #include "fsl_phyksz8081.h"
    #include "fsl_enet_mdio.h"
    
    
    /* IP address configuration. */
    #define configIP_ADDR0 192
    #define configIP_ADDR1 168
    #define configIP_ADDR2 0
    #define configIP_ADDR3 102
    
    /* Netmask configuration. */
    #define configNET_MASK0 255
    #define configNET_MASK1 255
    #define configNET_MASK2 255
    #define configNET_MASK3 0
    
    /* Gateway address configuration. */
    #define configGW_ADDR0 192
    #define configGW_ADDR1 168
    #define configGW_ADDR2 0
    #define configGW_ADDR3 100
    
    /* MAC address configuration. */
    #define configMAC_ADDR                     \
        {                                      \
            0x02, 0x12, 0x13, 0x10, 0x15, 0x11 \
        }
    
    /* Address of PHY interface. */
    #define EXAMPLE_PHY_ADDRESS BOARD_ENET0_PHY_ADDRESS
    
    /* MDIO operations. */
    #define EXAMPLE_MDIO_OPS enet_ops
    
    /* PHY operations. */
    #define EXAMPLE_PHY_OPS phyksz8081_ops
    
    /* ENET clock frequency. */
    #define EXAMPLE_CLOCK_FREQ CLOCK_GetFreq(kCLOCK_IpgClk)
    
    #ifndef EXAMPLE_NETIF_INIT_FN
    /*! @brief Network interface initialization function. */
    #define EXAMPLE_NETIF_INIT_FN ethernetif0_init
    #endif /* EXAMPLE_NETIF_INIT_FN */
    
    
    static mdio_handle_t mdioHandle = {.ops = &EXAMPLE_MDIO_OPS};
    static phy_handle_t phyHandle   = {.phyAddr = EXAMPLE_PHY_ADDRESS, .mdioHandle = &mdioHandle, .ops = &EXAMPLE_PHY_OPS};
    
    static void BOARD_InitModuleClock(void)
    {
        const clock_enet_pll_config_t config = {.enableClkOutput = true, .enableClkOutput25M = false, .loopDivider = 1};
        CLOCK_InitEnetPll(&config);
    }
    
    static void delay(void)
    {
        volatile uint32_t i = 0;
        for (i = 0; i < 1000000; ++i)
        {
            __asm("NOP"); /* delay */
        }
    }
    
    void User_IP_Config(void)
    {
        static struct netif netif;
    #if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0)
        static mem_range_t non_dma_memory[] = NON_DMA_MEMORY_ARRAY;
    #endif /* FSL_FEATURE_SOC_LPC_ENET_COUNT */
        ip4_addr_t netif_ipaddr, netif_netmask, netif_gw;
        ethernetif_config_t enet_config = {
            .phyHandle  = &phyHandle,
            .macAddress = configMAC_ADDR,
    #if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0)
            .non_dma_memory = non_dma_memory,
    #endif /* FSL_FEATURE_SOC_LPC_ENET_COUNT */
        };
    
        gpio_pin_config_t gpio_config = {kGPIO_DigitalOutput, 0, kGPIO_NoIntmode};
    	
    	BOARD_InitModuleClock();
    
        IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1TxClkOutputDir, true);
    
        GPIO_PinInit(BOARD_INITPINS_ENET_INT_GPIO, BOARD_INITPINS_ENET_INT_GPIO_PIN, &gpio_config);
        GPIO_PinInit(BOARD_INITPINS_ENET_RST_GPIO, BOARD_INITPINS_ENET_RST_GPIO_PIN, &gpio_config);
        /* pull up the ENET_INT before RESET. */
        GPIO_WritePinOutput(BOARD_INITPINS_ENET_INT_GPIO, BOARD_INITPINS_ENET_INT_GPIO_PIN, 1);
        GPIO_WritePinOutput(BOARD_INITPINS_ENET_RST_GPIO, BOARD_INITPINS_ENET_RST_GPIO_PIN, 0);
        delay();
        GPIO_WritePinOutput(BOARD_INITPINS_ENET_RST_GPIO, BOARD_INITPINS_ENET_RST_GPIO_PIN, 1);
    
        mdioHandle.resource.csrClock_Hz = EXAMPLE_CLOCK_FREQ;
    
        IP4_ADDR(&netif_ipaddr, configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3);
        IP4_ADDR(&netif_netmask, configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3);
        IP4_ADDR(&netif_gw, configGW_ADDR0, configGW_ADDR1, configGW_ADDR2, configGW_ADDR3);
    
        tcpip_init(NULL, NULL);
    
        netifapi_netif_add(&netif, &netif_ipaddr, &netif_netmask, &netif_gw, &enet_config, EXAMPLE_NETIF_INIT_FN,
                           tcpip_input);
        netifapi_netif_set_default(&netif);
        netifapi_netif_set_up(&netif);
    
        PRINTF("\r\n************************************************\r\n");
        PRINTF(" TCP Echo example\r\n");
        PRINTF("************************************************\r\n");
        PRINTF(" IPv4 Address     : %u.%u.%u.%u\r\n", ((u8_t *)&netif_ipaddr)[0], ((u8_t *)&netif_ipaddr)[1],
               ((u8_t *)&netif_ipaddr)[2], ((u8_t *)&netif_ipaddr)[3]);
        PRINTF(" IPv4 Subnet mask : %u.%u.%u.%u\r\n", ((u8_t *)&netif_netmask)[0], ((u8_t *)&netif_netmask)[1],
               ((u8_t *)&netif_netmask)[2], ((u8_t *)&netif_netmask)[3]);
        PRINTF(" IPv4 Gateway     : %u.%u.%u.%u\r\n", ((u8_t *)&netif_gw)[0], ((u8_t *)&netif_gw)[1],
               ((u8_t *)&netif_gw)[2], ((u8_t *)&netif_gw)[3]);
        PRINTF("************************************************\r\n");
    }
    
    
    /*---------------------------- END ----------------------------*/
    
    
    
    

    最后,调用 User_IP_Config();函数和 tcpecho_init();,另外,tcpecho_init()函数其实已经内部定向创建了任务了,所以没必要再单独放到任务中执行,只需要先执行 User_IP_Config();函数再到 tcpecho_init();函数的执行就好了。

    参考:

    https://blog.csdn.net/ZCShouCSDN/article/details/79229728
    https://blog.csdn.net/baidu_18848209/article/details/103956031
    https://www.jianshu.com/p/dba15e62bcbf
    https://www.cnblogs.com/jason-lu/tag/%E7%BD%91%E5%8F%A3/

    展开全文
  • UCOSIII+LWIP移植

    2017-11-16 09:20:15
    UCOSIII+LWIP移植,基于原子STM32F429开发板(阿波罗底板)
  • 在STM32F407IG开发板上移植了最新的FreeRTOS 10.0.1和LWIP 2.1.0成功,开发板当服务器,电脑当客户端,客户端发送数据,服务器收到了全部返回。连续长时间收发数据无问题。
  • LwIP移植和使用

    2019-07-17 17:09:12
    LwIP移植和使用 本手册基于lwip-1.4.x编写,本人没有移植过1.4.0之前的版本,更早的版本或许有差别。如果看官发现问题欢迎联系<QQ:937431539email:937431539@qq.com> 本文系个人原创,你可以转载,修改,...

    原文地址:https://www.cnblogs.com/electron/p/3546508.html

    LwIP移植和使用

    本手册基于lwip-1.4.x编写,本人没有移植过1.4.0之前的版本,更早的版本或许有差别。如果看官发现问题欢迎联系<QQ: 937431539  email: 937431539@qq.com>

     

    本文系个人原创,你可以转载,修改,重新发布,但请保留作者信息。

     

    LwIP官网是:http://savannah.nongnu.org/projects/lwip/

    你可以从这里获取源代码。当然也可以从Git获取源代码:

    git clone git://git.savannah.nongnu.org/lwip.git

     

    LwIP以BSD协议发布源代码,我们可以自由的使用,修改,发布或不发布源代码。

     

    附件中有我移植的文件,可以用来参考。祝你移植顺利。

     

    移植

    1)新建几个头文件:

    include/lwipopts.h         // lwip配置文件

    include/arch/cc.h          // 平台相关。类型定义,大小端设置,内存对齐等

    include/arch/perf.h        // 平台相关的性能测量实现(没用)

    include/arch/sys_arch.h    // RTOS抽象层。信号量,mbox等类型定义,函数声明

     

    lwipopts.h                // lwip配置文件,详见附件

     

    cc.h                      //类型定义,大小端设置,内存对齐等

    复制代码

    #ifndef __CC_H__ 
    #define __CC_H__ 
    
    #include <stdint.h>
    
    /* Types based on stdint.h */
    typedef uint8_t            u8_t; 
    typedef int8_t             s8_t; 
    typedef uint16_t           u16_t; 
    typedef int16_t            s16_t; 
    typedef uint32_t           u32_t; 
    typedef int32_t            s32_t; 
    typedef uintptr_t          mem_ptr_t; 
     
    /* Define (sn)printf formatters for these lwIP types */
    #define U16_F "hu"
    #define S16_F "hd"
    #define X16_F "hx"
    #define U32_F "lu"
    #define S32_F "ld"
    #define X32_F "lx"
    #define SZT_F "uz"
     
    /* 选择小端模式 */
    #define BYTE_ORDER LITTLE_ENDIAN
     
    /* Use LWIP error codes */
    #define LWIP_PROVIDE_ERRNO
    
    /* 内存对齐 */
    #if defined(__arm__) && defined(__ARMCC_VERSION) 
    /* Keil uVision4 tools */
        #define PACK_STRUCT_BEGIN __packed
        #define PACK_STRUCT_STRUCT
        #define PACK_STRUCT_END
        #define PACK_STRUCT_FIELD(fld) fld
    #define ALIGNED(n)  __align(n)
    
    #endif

    复制代码

     

    perf.h                     // 两个宏定义为空即可

    复制代码

    #ifndef __PERF_H__
    #define __PERF_H__
    
    #define PERF_START    /* null definition */
    #define PERF_STOP(x)  /* null definition */
    
    #endif /* END __PERF_H__ */

    复制代码

     

    sys_arch.h 

    RTOS抽象层的类型定义,函数声明,详细内容见 doc/sys_arch.h

     

    2)建立RTOS抽象层文件:

    port/sys_arch.c            // RTOS抽象层实现

    为了屏蔽不同RTOS在信号量,互斥锁,消息,任务创建等OS原语使用上的差别,lwip构造了一个RTOS的抽象层,规定了OS原语的数据类型名称和对应方法名称。我们要做的就是根据所用RTOS的api去实现这些原语。

    比如移植lwip到raw-os上,信号量的移植:

     

    类型定义,宏定义在sys_arch.h中 

    复制代码

    struct _sys_sem 
    {
        RAW_SEMAPHORE *sem;
    };
    
    typedef struct _sys_sem sys_sem_t; // sys_sem_t是lwip的信号量类型名 
    #define SYS_SEM_NULL NULL 
    #define sys_sem_valid(sema) (((sema) != NULL) && ((sema)->sem != NULL)) 
    #define sys_sem_set_invalid(sema) ((sema)->sem = NULL) 
    err_t sys_sem_new(sys_sem_t *sem, u8_t count)
    { 
        RAW_SEMAPHORE *semaphore_ptr = 0;
        if (sem == NULL) 
        {
            RAW_ASSERT(0); 
        }
    
        semaphore_ptr = port_malloc(sizeof(RAW_SEMAPHORE));
        if(semaphore_ptr == 0)
        {
            RAW_ASSERT(0);
        }
    
        //这是raw-os的API 
        raw_semaphore_create(semaphore_ptr, (RAW_U8 *)"name_ptr", count);
        sem->sem = semaphore_ptr;
    
        return ERR_OK;
    } 
    
    void sys_sem_free(sys_sem_t *sem)
    {
        if((sem == NULL) || (sem->sem == NULL)) 
        {
            RAW_ASSERT(0);
        }
    
        raw_semaphore_delete(sem->sem); //这是raw-os的API 
    
        raw_memset(sem->sem, sizeof(RAW_SEMAPHORE), 0); 
        port_free(sem->sem);
        sem->sem = NULL;
    }
    

    复制代码

     

    还有几个函数就不一一列举了,如有疑问看doc/sys_arch.txt

     

    3)修改网卡框架文件:

    netif/ethernetif.c

     

    该文件是作者提供的网卡驱动和lwip的接口框架。

    该文件中要改动的函数只有3个:

    static void   low_level_init(struct netif *netif);

    static err_t  low_level_output(struct netif *netif, struct pbuf *p);

    static struct pbuf *low_level_input(struct netif *netif);

     

    复制代码

    /* 你可以给网卡起个名字 */
    /* Define those to better describe your network interface. */
    #define IFNAME0 'e'
    #define IFNAME1 '0'
    
    /**
     * Helper struct to hold private data used to operate your ethernet
     * interface.
     * Keeping the ethernet address of the MAC in this struct is not
     * necessary as it is already kept in the struct netif.
     * But this is only an example, anyway...
     */
    struct ethernetif 
    {
        struct eth_addr *ethaddr;
        // Add whatever per-interface state that is needed here.
        // 在这里添加网卡的私有数据,比如和网卡相关的信号量,互斥锁,
        // 网卡状态等等,这不是必须的
    };

    复制代码

     

    3个网卡相关的函数只要改动红色部分,需根据具体的网卡驱动函数改动

    复制代码

    static void low_level_init(struct netif *netif)
    {
        struct ethernetif *ethernetif = netif->state;
    
        /* set MAC hardware address length */
        netif->hwaddr_len = ETHARP_HWADDR_LEN;
    
        /* 设置MAC地址, 必须与网卡初始化的地址相同 */
        netif->hwaddr[0] = ;
        netif->hwaddr[1] = ;
        netif->hwaddr[2] = ;
        netif->hwaddr[3] = ;
        netif->hwaddr[4] = ;
        netif->hwaddr[5] = ;
    
        /* maximum transfer unit */
        netif->mtu = 1500;
    
        /* device capabilities */
        /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
        netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
    
        /* 在这里添加其他初始化代码(如真正的网卡初始化, phy初始化等) */ 
    }
    
     
    
    static err_t low_level_output(struct netif *netif, struct pbuf *p)
    {
        struct ethernetif *ethernetif = netif->state;
        struct pbuf *q;
     
        initiate transfer();
    
    #if ETH_PAD_SIZE
        pbuf_header(p, -ETH_PAD_SIZE);   /* drop the padding word */
    #endif
     
        for(q = p; q != NULL; q = q->next){
            /* Send the data from the pbuf to the interface, one pbuf at a
                time. The size of the data in each pbuf is kept in the ->len
                variable. */
            send data from(q->payload, q->len);
        }
    
        signal that packet should be sent();
    
    #if ETH_PAD_SIZE
        pbuf_header(p, ETH_PAD_SIZE);   /* reclaim the padding word */
    #endif
    
        LINK_STATS_INC(link.xmit);
     
        return ERR_OK;
    }
    
    static struct pbuf * low_level_input(struct netif *netif)
    {
        struct ethernetif *ethernetif = netif->state;
        struct pbuf *p, *q;
        u16_t len;
    
        /* Obtain the size of the packet and put it into the "len" variable. */
        len = ;  // 获取将要接收的数据长度
    
    #if ETH_PAD_SIZE
        len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
    #endif
    
        /* We allocate a pbuf chain of pbufs from the pool. */
        p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
    
        if (p != NULL){ 
    #if ETH_PAD_SIZE
            pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
    #endif
    
            /* We iterate over the pbuf chain until we have read the entire
             * packet into the pbuf. */
            for(q = p; q != NULL; q = q->next) {
                /* Read enough bytes to fill this pbuf in the chain. The
                 * available data in the pbuf is given by the q->len
                 * variable.
                 * This does not necessarily have to be a memcpy, you can also 
                 * preallocate pbufs for a DMA-enabled MAC and after receiving truncate 
                 * it to the actually received size. In this case, ensure the tot_len 
                 * member of the pbuf is the sum of the chained pbuf len members.
                 */
                read data into(q->payload, q->len);
            }
    
            acknowledge that packet has been read();
    
    #if ETH_PAD_SIZE
            pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
    #endif
    
            LINK_STATS_INC(link.recv); 
        } 
        else 
        {
            drop packet();
            LINK_STATS_INC(link.memerr);
            LINK_STATS_INC(link.drop);
        }
    
        return p;  
    }

    复制代码


    LwIP的使用

    LwIP的初始化:

     

    LwIP的初始化必须在RTOS启动之后才可以进行, 因为它的初始化代码使用了一些OS提供的功能!!!

     

    初始化代码示例:

    复制代码

    extern err_t ethernetif_init(struct netif *netif);
    struct netif lpc1788_netif;
    ip_addr_t e0ip, e0mask, e0gw;
    
    /* tcpip_init使用的回调函数,用于判断tcpip_init初始化完成 */
    static void tcpip_init_done(void *pdat)
    {
        *(int *)pdat = 0;
    }
    
    void  ethernetif_input(struct netif *netif);
    // 一直调用ethernetif_input函数,从网卡读取数据
    static void lwip_read_task(void *netif)
    {
        while(1)
        {
            ethernetif_input(netif);
        }
    }
     
    void init_lwip()
    {
        struct netif *pnetif = NULL;
        int flag = 1;
    
        tcpip_init(tcpip_init_done, &flag);  // lwip协议栈的初始化
        while(flag);
    
        IP4_ADDR(&e0ip, 192,168,6,188);      // 设置网卡ip
        IP4_ADDR(&e0mask, 255,255,255,0);    // 设置子网掩码
        IP4_ADDR(&e0gw, 192,168,6,1);        // 设置网关
    
        //给lwip添加网卡
        pnetif = netif_add(&lpc1788_netif, &e0ip, &e0mask, &e0gw,
                           NULL, ethernetif_init, tcpip_input);
        netif_set_default(pnetif);     // 设置该网卡为默认网卡
        netif_set_up(&lpc1788_netif);  // 启动网卡,可以唤醒DHCP等服务
    
        // 创建一个任务。这个任务负责不停的调用ethernetif_input函数从网卡读取数据
        raw_task_create(&lwip_read_obj, (RAW_U8  *)"lwip_read", &lpc1788_netif,
                        CONFIG_RAW_PRIO_MAX - 25, 0,  lwip_read_stk, 
                        LWIP_READ_STK_SIZE ,  lwip_read_task, 1);  
    }

    复制代码

     

    附件:

    http://pan.baidu.com/s/1gdfz1zd

    分类: 单片机,网络

    标签: lwip移植

    好文要顶 关注我 收藏该文  

    electron
    关注 - 9
    粉丝 - 7

    +加关注

    2

    0

    « 上一篇:Linux上进行单片机开发
    » 下一篇:ubuntu ping响应慢的解决方法

    posted @ 2014-02-12 20:12 electron 阅读(9810) 评论(4) 编辑 收藏

     

    评论列表

      

    #1楼 2014-02-13 10:10 cronus象牙塔  

    请问你是在什么平台上移植的,加操作系统了吗?

    支持(0)反对(0)

      

    #2楼[楼主] 2014-02-13 10:11 electron  

    @ cronus象牙塔
    在raw-os上移植的,整个系统跑在lpc1788, lpc4337上

    支持(0)反对(0)

      

    #3楼 2014-02-13 10:15 cronus象牙塔  

    移植操作系统后, low_level_input(struct netif *netif)函数里加信号量了吗?就这个为什么在这里加信号量,请指教!

    支持(0)反对(0)

      

    #4楼[楼主] 2014-02-13 10:20 electron  

    @ cronus象牙塔
    加了。在low_level_input函数里会调用真正从网卡读取数据的函数,假定是eth_read。在eth_read中加了信号量的P操作,尝试获取信号量。然后再网卡中断中会有信号量的V操作,发送一个信号量。我在移植中就使用了计数信号量。这样做的目的是为了实现异步运行。

    展开全文
  • lwip移植

    2018-04-07 14:01:13
    请问我要用synopsys的三速以太网卡做lwip移植,但是现在找不到它的驱动文件(好像有的是.v文件的?)然后也找不到完整的教程或lwip例程,导致我现在卡壳在了ethernetif.c文件的编写上,后续怎么做完全不知道啊,我看...
  • lwip 移植

    千次阅读 2016-09-13 20:51:10
    一、源码目录结构  api 、 core、netif、 include  core下又有IPV4 、 IPV6 、 ... include下又有IPV4、IPV6、LWIP、netif  netif下的文件有  1. ethernetif.c这里主要涉及到具体的硬件  2.etharp
  • FreeRTOS和LwIP联合移植

    2017-09-01 09:38:10
    FreeRTOS和LwIP联合移植,针对移植部分书籍截取篇
  • ucos+lwip移植

    2013-07-15 23:21:53
    最近需要在lpc2378上移植ucos+lwip因此在这里吧下载的一些资料分享出来,希望对需要的人有用
  • 文章主要介绍基于windows环境下的lwip协议栈的移植方法,分析了移植过程中需要注意的各种关键点,讨论了内存,线程,通知和保护机制的适配方法,最终实现了lwip在windows平台下的移植
  • stm32107 LWIP移植范例

    2010-08-28 09:24:18
    这是stm32107VC的LWIP协议栈移植范例,内附说明
  • Lwip移植和使用

    2018-09-14 11:35:39
    一份LWIP移植过程说明及相关代码,涉及移植框架修改说明,类型重定义等
  • lwip 移植 stm32

    2018-01-05 21:32:40
    lwip移植,建立客户端,服务器端。 rawapi编程模式,绝对可用
  • 基于STM32F429平台的DM9161C的LWIP移植实现UDP服务器的操作,基本标准库文件开发,文档含详细流程。操作流程在ST官方提供的STM32F4x7 lwip例程的基础上移植而来,亲测可用。
  • uCOS平台下的LwIP移植笔记,内容详细,步骤清晰。
  • STM32以太网通信-FreeRTOS + LwIP移植

    千次阅读 2021-01-25 15:07:41
    移植:FreeRTOS + LwIP实现以太网通信。 简要 LwIP 不仅能在裸机上开发,也能在操作系统环境下运行,而且在操作系统环境下,用户能使用 NETCONN API 与 Socket API 编程。相比于 RAW API 编程会更加简便。使用操作...
  • 本程序是基于STM32F107芯片,DM9161为以太网PHY芯片的Lwip裸板移植,借助于网络调试助手可以实现客户端与服务端之间的通信。其以STM32为服务端,电脑为客户端,STM32默认IP为192.168.0.30,端口为23,调试的时候若...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,086
精华内容 1,234
关键字:

lwip移植