Lwip移植过程(基于FreeRTOS)
程序员文章站
2024-01-23 12:16:34
...
Lwip移植过程(基于FreeRTOS)
准备过程
-
首先准备带FreeRTOS的工程模板,如下图所示;
-
下载LWIP源码,这里使用2.1.2版本,官网下载地址,拷贝源码到工程中去,如下图所示;
将LwIP源文件添加到工程中去
- LWIP/api
- LWIP/core
- LWIP/core/ipv4
- LWIP/netif
添加头文件信息
移植修改
-
编译后发现很多error,如下图所示
-
添加lwipopts.h,在源码文件夹test\fuzz下可以找到该文件,如下图所示,该文件主要用于Lwip参数的配置,供用户修改,默认参数配置在opt.h文件中配置;
-
在lwip-2.1.2文件夹下创建user文件夹,放置网络相关的用户配置文件,如下图所示
-
添加lwipopts.h头文件路径,如下图所示
-
再次编译,缺少arch/cc.h文件,如下图所示
-
添加arch/cc.h文件,将下图文件夹下的两个*.h拷到lwip-2.1.2/user/arch*文件夹下
-
修改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 <aaa@qq.com>
*
*/
#ifndef LWIP_ARCH_CC_H
#define LWIP_ARCH_CC_H
#include <stdio.h>
#include <stdlib.h>
#if defined (__CC_ARM ) || \
(defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
#include <errno.h>
#undef EDOM
#undef ERANGE
#undef EILSEQ
#undef ESIGNUM
#undef EINVAL
#undef ENOMEM
#define LWIP_PROVIDE_ERRNO
#else
#define LWIP_PROVIDE_ERRNO
#endif
/* Define platform endianness (might already be defined) */
#ifndef BYTE_ORDER
#define BYTE_ORDER LITTLE_ENDIAN
#endif /* BYTE_ORDER */
/* 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 "lu"
/* Compiler hints for packing structures */
#if defined(__ICCARM__)
#define PACK_STRUCT_STRUCT __packed
#else
#define PACK_STRUCT_STRUCT __attribute__((packed))
#endif
/* Platform specific diagnostic output */
#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0)
#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_RAND() ((u32_t)rand())
#endif /* LWIP_ARCH_CC_H */
- 修改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_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__ */
- 添加带操作系统的网络接口文件sys_arch.c和sys_arch.h
10. 在工程中添加sys_arch.c
- LWIP/arch
- 在sys_arch.c文件中增加宏定义,如下
#define configSTACK_DEPTH_TYPE uint16_t
- 再次编译,出现错误,是因为在网络接口的文件下添加了slipif.c SLIP组件文件,这里屏蔽掉就好,再次编译就好;其实在lwipopt.h中也可以删除了ipv6的宏定义,工程文件中的很多网络接口都可以屏蔽掉,根据使用情况添加即可。
添加PHY驱动
物理层驱动芯片:DM9161
驱动参考MDK的例程进行修改,若采用的芯片与官方提供的一致,可直接使用,仅需更改物理地址即可;
MDK下的驱动路径如下图所示,在ETH文件夹内;
也可以使用MDK官方提供的模板,在MDK安装路径下可以找到。
- 在工程文件的user目录下添加以太网驱动文件夹ETH_driver,并添加MDK文件夹下的驱动,这里我们复制如下图所示的文件,并修改文件名为自己的驱动芯片,该文件内容一般不需要做任何改动即可使用
- 添加文件到工程中去,并添加头文件路径
- 修改驱动芯片相应的寄存器映射地址,在PHY_XXXX.h中修改,这里根据字节使用的芯片手册进行更改即可。
添加MAC驱动
说明:MAC驱动在MDK安装包里也有,在D:\Keil_v5\ARM\PACK\Keil路径下,如下图所示,选择相应文件下的驱动即可
- 我这里使用的是STM32H7xx的芯片,复制下图中的文件到user/ETH_Driver目录下,并添加到工程中去
- 编译会发现缺少MX_Device.h文件,如下图所示
- 添加MX_Device.h文件,我们需要到MDK的目录下去搜索,比如我这里用的STM32H7xx,那么就再如下图文件夹下搜索,其实都是官方开发板下的demo,检索完,单开任意一个复制其文件就行
- 修改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 */
-
重新编译,发现缺少定义
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进行配置。
- 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);
}
- 再次编译,一般情况就没有错误了。
添加网卡驱动接口
为了便于移植,这里直接使用MDK提供的*ethernetif.c*文件进行移植操作,文件路径如下;
同时还需要拷贝*ethif_config.h*文件,路径见下图
- 添加文件到工程中去,如下所示
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, ðernetif_init, ðernet_input);
/* 注册默认网络接口 */
netif_set_default(&netif);
netif_set_up(&netif);
#if LWIP_DHCP
dhcp_start (&netif);
#endif
}
- 通过FreeRTOS创建一个eth任务,代码如下:
void vTaskEthCheck(void *pvParameters)
{
/* 初始化网络 */
printf("开始初始化网络.....");
net_init();
printf("初始化网络完成");
while(1)
{
vTaskDelay(300);
}
- 编译运行,打开串口调试助手,发现有断言错误,如下图所示:
- 这是由于lwip使用了FreeRTOS,因此在tcpip.c里面会调用sys_thread_new创建一个TCP任务,如下图所示
- 在lwipopt.h中添加上图中用到的宏定义,如下图所示
- 继续编译、下载,能够正常初始化网络,但无法ping通,如下图所示
- 这是由于没加添加网卡接收任务,导致下位机未对接收的网卡数据产生反应,需要在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通