LWIP的移植

最近在项目的开发中用到了LWIP协议,于是要将LWIP协议移植到STM32上,当然STM32的官方例程有相关的例程,我也正式在这个例程的基础上进行的移植,现在将在移植过程中遇到的一些总结如下,对自己是个记录,也希望对后面要用到的朋友有所帮助。

使用平台:STM32F207的平台,8M的外部晶振, 配合LAN8720A的PHY芯片。

软件平台: 使用的是STM32F207的HAl库。我自己要使用的是tcp client的功能

移植过程:

1.参照STM32F207的tcp client例程,将与LWIP相关的库文件都添加到自己的工程中,如下图所示,但是下图中显示的并不是库的全部,准确的可参照官方例程。

2.系统时钟的修改: 对于系统时钟的配置一定要注意,例程使用的是25M的外部晶振为基础,还是8M的外部晶振为基础,我这里使用的是8M的外部晶振,所以将系统时钟配置成8M

/**
* @brief System Clock Configuration
* The system Clock is configured as follow :
* System Clock source = PLL (HSE)
* SYSCLK(Hz) = 120000000
* HCLK(Hz) = 120000000
* AHB Prescaler = 1
* APB1 Prescaler = 4
* APB2 Prescaler = 2
* HSE Frequency(Hz) = 8000000
* PLL_M = 8
* PLL_N = 240
* PLL_P = 2
* PLL_Q = 5
* VDD(V) = 3.3
* Flash Latency(WS) = 3
* @param None
* @retval None
*/
void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;

/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 240;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 5;
HAL_RCC_OscConfig(&RCC_OscInitStruct);

/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3);
}

3.对于Main函数的修改,main函数需要保留这样几个函数; 这就是最基本的配置了

void main(void)

{

     /* STM32F207xx HAL library initialization */
     HAL_Init();

    /* Configure the System clock to have a frequency of 120 MHz */
    SystemClock_Config();   

    /* Initialize the LwIP stack */
   lwip_init();

   /* Configure the Network interface */
   Netif_Config();

  while(1)

 {

     ethernetif_input(&gnetif);

}

}

4.上面描述了main函数的配合,下面对于具体的每个函数加以说明

      lwip_init(); 这个函数对于里面的内容不用做任何的修改,照搬过来就好了

      Netif_Config();  这个函数就是配置的关键了,这个函数中有几个重要的函数,如下

 

  netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &ethernet_input); 这个函数会将之前设置的ip,子网掩码,网关初始化到netif结构体的相关成员变量上

ethernetif_init函数会对硬件底层进行初始化,包括对PHY的初始化,具体的初始化,在这个函数里面的low_level_init函数,如下

static void low_level_init(struct netif *netif)
{
uint32_t regvalue = 0;
uint8_t macaddress[6]= { MAC_ADDR0, MAC_ADDR1, MAC_ADDR2, MAC_ADDR3, MAC_ADDR4, MAC_ADDR5 };


EthHandle.Instance = ETH;
EthHandle.Init.MACAddr = macaddress;                                                 //对MAC地址的设置
EthHandle.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
EthHandle.Init.Speed = ETH_SPEED_100M;
EthHandle.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
EthHandle.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;       //在这里区分是RMII接口,还是MII的接口
EthHandle.Init.RxMode = ETH_RXPOLLING_MODE;
EthHandle.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
EthHandle.Init.PhyAddress = 0x00;                                                       //这里是设置PHY的,因为这里用的LAN8720A,所以这里需要设置成0x00,如果是DP83848,则需要设置成0x01

/* configure ethernet peripheral (GPIOs, clocks, MAC, DMA) */
if (HAL_ETH_Init(&EthHandle) == HAL_OK)
{
/* Set netif link flag */
netif->flags |= NETIF_FLAG_LINK_UP;
}

/* Initialize Tx Descriptors list: Chain Mode */
HAL_ETH_DMATxDescListInit(&EthHandle, DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);

/* Initialize Rx Descriptors list: Chain Mode */
HAL_ETH_DMARxDescListInit(&EthHandle, DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);

/* set MAC hardware address length */
netif->hwaddr_len = ETHARP_HWADDR_LEN;

/* set MAC hardware address */
netif->hwaddr[0] = MAC_ADDR0;
netif->hwaddr[1] = MAC_ADDR1;
netif->hwaddr[2] = MAC_ADDR2;
netif->hwaddr[3] = MAC_ADDR3;
netif->hwaddr[4] = MAC_ADDR4;
netif->hwaddr[5] = MAC_ADDR5;

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

/* Enable MAC and DMA transmission and reception */
HAL_ETH_Start(&EthHandle);

/**** Configure PHY to generate an interrupt when Eth Link state changes ****/
/* Read Register Configuration */
HAL_ETH_ReadPHYRegister(&EthHandle, PHY_MICR, &regvalue);

regvalue |= (PHY_MICR_INT_EN | PHY_MICR_INT_OE);

/* Enable Interrupts */
HAL_ETH_WritePHYRegister(&EthHandle, PHY_MICR, regvalue );

/* Read Register Configuration */
HAL_ETH_ReadPHYRegister(&EthHandle, PHY_MISR, &regvalue);

regvalue |= PHY_MISR_LINK_INT_EN;

/* Enable Interrupt on change of link status */
HAL_ETH_WritePHYRegister(&EthHandle, PHY_MISR, regvalue);

HAL_ETH_WritePHYRegister(&EthHandle, 0x19, regvalue );                     //其中使用LAN8720A的时候,还需要将这里设置一下,添加后面的三句
regvalue |= 0x01 << 5;
HAL_ETH_WritePHYRegister(&EthHandle, 0x19, regvalue );
}

 

其中对于管脚的设置在HAL_ETH_Init函数中的HAL_ETH_MspInit函数,具体如下

void HAL_ETH_MspInit(ETH_HandleTypeDef *heth)
{
uint32_t timeOver =0;
GPIO_InitTypeDef GPIO_InitStructure;

/* Enable GPIOs clocks */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();

/* Ethernet pins configuration ************************************************/
/**ETH GPIO Configuration
PC1 ------> ETH_MDC
PA1 ------> ETH_REF_CLK
PA2 ------> ETH_MDIO
PA7 ------> ETH_CRS_DV
PC4 ------> ETH_RXD0
PC5 ------> ETH_RXD1
PB11 ------> ETH_TX_EN
PB12 ------> ETH_TXD0
PB13 ------> ETH_TXD1
PE0 ETH_RST
*/


GPIO_InitStructure.Pin = GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);

/* Configure PA1, PA2 , PA7 */
GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);

GPIO_InitStructure.Pin = GPIO_PIN_0;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);

HAL_GPIO_WritePin(GPIOE, GPIO_PIN_0, GPIO_PIN_RESET);
timeOver = 0xFF;
while (timeOver--);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_0, GPIO_PIN_SET);

/* Enable ETHERNET clock */
__HAL_RCC_ETH_CLK_ENABLE();

}

 

另外最后需要注意的地方就是在stm32f2xx_hal_conf.h文件中将相关的宏定义打开,这样移植工作就完成了。

转载于:https://www.cnblogs.com/kunshao2018/p/8931608.html

<think>首先,用户的问题是关于将lwIP协议栈移植到特定硬件或操作系统的指南。用户说:“我想将lwIP协议栈移植到特定硬件或操作系统上 请问lwIP 协议栈 移植指南”。我需要基于系统级指令来回答。 系统级指令: 1. 所有行内数学表达式必须使用$...$格式。 2. 独立公式必须使用$$...$$格式并单独成段。 3. LaTeX语法正确。 4. 使用中文回答。 5. 生成相关问题。 6. 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 用户可见层: - 回答结构清晰,帮助用户逐步解决问题。 - 尽量保证回答真实可靠。 - 参考站内引用:引用[1]、[2]、[3]是关于lwIP的。我需要尽可能参考这些引用,但用户说“上述引用仅供参考,并不是用户真正的需求,请尽可能多的参考用户上一次的问题和你的回答”。用户上一次的问题是“lwIP协议栈移植指南”,所以我应该基于此回答。 用户上一次的问题就是当前这个,所以我需要直接回答这个移植指南。 现在,组织我的回答: - 结构清晰:逐步解决问题。 - 内容:基于lwIP移植的知识。lwIP移植涉及几个关键步骤:硬件抽象层、操作系统模拟层、网络接口等。 - 引用:在回答中自然地添加引用标识,参考提供的引用[1]、[2]、[3]。例如,引用[1]提到“LWIP应用开发实战指南”和移植预备知识,引用[2]提到LwIP概述和源码详解,引用[3]提到基于netconn的TCP服务器实现。 关键步骤: 1. 预备知识:了解目标硬件和操作系统。 2. 获取lwIP源代码。 3. 配置硬件抽象层(HAL):如时钟、内存管理。 4. 操作系统模拟层(OSAL):如果目标系统有OS,需要实现模拟层;如果没有,使用无OS模式。 5. 网络接口驱动:实现以太网驱动或串行接口。 6. 配置lwIP选项:通过lwipopts.h文件。 7. 测试和验证:使用提供的示例代码。 生成相关问题:在回答末尾添加相关问题。 确保使用中文回答。 数学表达式:用户问题中没有明显的数学内容,但如果有,比如提到性能公式,我应该使用$...$。但在移植指南中,可能不涉及数学,所以可能不需要。 现在,构建回答: - 开头:介绍lwIP移植的基本概念。 - 步骤:逐步列出移植步骤。 - 结尾:添加相关问题。 - 引用:在适当的地方添加引用标识。例如,提到预备知识时引用[1],提到源码时引用[2],提到示例代码时引用[3]。 相关问题示例: 1. 如何优化lwIP在资源受限设备上的性能? 2. lwIP移植常见问题及解决方法? 3. lwIP在不同操作系统上的移植差异? 完整回答结构: 1. 标题或开头:lwIP协议栈移植指南 2. 步骤: a. 预备工作 b. 硬件抽象层实现 c. 操作系统模拟层实现 d. 网络接口驱动开发 e. 配置和编译 f. 测试 3. 结尾:相关问题</think>### lwIP协议栈移植指南 将lwIP(轻量级TCP/IP协议栈)移植到特定硬件或操作系统需要系统化的步骤,以确保网络通信功能正常运行。以下是基于官方文档和实践经验的逐步指南(以嵌入式系统为例)。移植的核心是**实现硬件抽象层(HAL)、操作系统模拟层(OSAL)和网络接口驱动**,同时配置lwIP选项文件。参考lwIP官方文档和开源社区最佳实践[^1][^2]。 #### 步骤1: 预备工作与源码准备 - **了解目标环境**:确认硬件(如MCU型号、以太网控制器)和操作系统(如FreeRTOS、裸机无OS)。lwIP支持无OS模式或与RTOS集成[^1]。 - **获取源码**:从[官方GitHub仓库](https://github.com/lwip-tcpip/lwip)下载最新版本(如v2.1.3),包含核心协议栈和示例。 - **阅读文档**:重点研究《LwIP移植预备知识》和《LwIP协议栈源码详解》,理解内存管理(`mem.c`)和线程模型[^1][^2]。 #### 步骤2: 实现硬件抽象层(HAL) 硬件相关代码需适配目标平台: - **时钟初始化**:配置系统时钟(单位:毫秒),用于TCP超时处理。例如,在STM32中实现`sys_now()`函数: ```c uint32_t sys_now(void) { return HAL_GetTick(); // 返回系统tick值 } ``` - **内存管理**:修改`mem.c`以使用硬件内存池(如静态数组或堆分配),避免动态内存碎片。 - **调试输出**:重定向`printf`到串口(例如UART),便于日志跟踪。 #### 步骤3: 实现操作系统模拟层(OSAL) 若目标系统有OS(如FreeRTOS),需模拟lwIP所需的线程和同步机制: - **创建任务**:实现`sys_thread_new()`函数,启动lwIP核心线程(如`tcpip_thread`)。 - **信号量和邮箱**:提供`sys_sem_new()`、`sys_mbox_new()`等函数,使用OS原语(如FreeRTOS队列)。 - **无OS模式**:如果裸机运行,需在循环中调用`sys_check_timeouts()`处理超时事件[^2]。 #### 步骤4: 开发网络接口驱动 实现以太网或串行接口的数据收发: - **以太网驱动**: - 初始化PHY芯片(如通过SPI或RMII)。 - 实现`low_level_output()`和`low_level_input()`函数,处理数据包发送/接收。 - 注册接口:调用`netif_add()`,例如: ```c struct netif my_netif; netif_add(&my_netif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, &tcpip_input); ``` - **其他接口**:如Wi-Fi或PPP(串行),需适配`ppp.c`或自定义驱动。 #### 步骤5: 配置lwIP选项 通过`lwipopts.h`文件定制协议栈行为(覆盖默认`opt.h`): - **关键配置项**: ```c #define LWIP_DHCP 1 // 启用DHCP客户端 #define MEM_SIZE 16000 // 内存池大小(根据硬件调整) #define LWIP_TCP 1 // 启用TCP协议 #define LWIP_UDP 1 // 启用UDP协议 #define PBUF_POOL_SIZE 16 // 数据包缓冲区数量 ``` - **优化建议**:减少`MEM_SIZE`以节省资源,或启用`LWIP_STATS`监控性能[^2]。 #### 步骤6: 编译、测试与验证 -
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值