导读:
本文移植是以STM32F4开发板为例,PHY物理层采用的LAN8720。除了少数代码需要更改之外,对于其他的开发板是通用的步骤。
详细内容可以参考 STM32F4 LWIP开发手册
第一部分:移植前准备
第二部分:移植过程
移植前准备 |
1.准备好基础工程
我选择具有内存管理功能的模板。在ST以太网驱动库中 DMA缓存区 采用数组实现,数组实现存放与RAM中太浪费内存,而我采用了内存管理使用外部SRAM来分配空间。
如下:(stm324x7_eth.c)中就是数组,可以注释掉。
ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB] __attribute__ ((aligned (4))); /* Ethernet Rx DMA Descriptor */
ETH_DMADESCTypeDef DMATxDscrTab[ETH_TXBUFNB] __attribute__ ((aligned (4))); /* Ethernet Tx DMA Descriptor */
uint8_t Rx_Buff[ETH_RXBUFNB][ETH_RX_BUF_SIZE] __attribute__ ((aligned (4))); /* Ethernet Receive Buffer */
uint8_t Tx_Buff[ETH_TXBUFNB][ETH_TX_BUF_SIZE] __attribute__ ((aligned (4))); /* Ethernet Transmit Buffer */
2.下载ST以太网驱动库
STM32F4x7_ETH_LwIP_v1.1.0中的STM32F4x7_ETH_Driver里面一共三个文件:
1.stm32f4x7_eth.h 头文件
2.stm32f4x7_eth.c 驱动
3.stm32f4x7_eth_conf.h 以太网配置文件(需要重命名,原名:stm32f4x7_eth_conf_template.h)
3.下载LWIP文件
lwip-1.4.1.zip 是LWIP源码
contrib-1.4.1.zip 含官方例程和一些头文件
移植 |
1.st以太网驱动库的移植 |
- 将以太网库的3个文件包含进工程。
- 遇到找不到main.h直接注释掉
- 因为我们采用默认的软件延时函数,所以直接注释掉USE_Delay
//#define USE_DELAY
- 将官方对于DP83848 PHY改为LAN8720(用户使用的PHY)
下面将讲解一下需要的配置conf.h
//前部分和原来的内容一致,最下面PHY方面是关于LAN8720的,ST驱动库需要读取外部PHY来读取速度和双工状态
#ifndef __STM32F4x7_ETH_CONF_H
#define __STM32F4x7_ETH_CONF_H
#include "stm32f4xx.h"
#define USE_ENHANCED_DMA_DESCRIPTORS
//如果使用自己定义的延时函数的话就注销掉下面一行代码,否则使用
//默认的低精度延时函数
//#define USE_Delay //使用默认延时函数,因此注销掉
#ifdef USE_Delay
#include "main.h"
#define _eth_delay_ Delay //Delay为用户自己提供的高精度延时函数
#else
#define _eth_delay_ ETH_Delay //默认的_eth_delay功能函数延时精度差
#endif
#ifdef CUSTOM_DRIVER_BUFFERS_CONFIG
//重新定义以太网接收和发送缓冲区的大小和数量
#define ETH_RX_BUF_SIZE ETH_MAX_PACKET_SIZE //接收缓冲区的大小
#define ETH_TX_BUF_SIZE ETH_MAX_PACKET_SIZE //发送缓冲区的大小
#define ETH_RXBUFNB 20 //接收缓冲区数量
#define ETH_TXBUFNB 5 //发送缓冲区数量
#endif
//*******************PHY配置块*******************
#ifdef USE_Delay
#define PHY_RESET_DELAY ((uint32_t)0x000000FF) //PHY复位延时
#define PHY_CONFIG_DELAY ((uint32_t)0x00000FFF) //PHY配置延时
#define ETH_REG_WRITE_DELAY ((uint32_t)0x00000001) //向以太网寄存器写数据时的延时
#else
#define PHY_RESET_DELAY ((uint32_t)0x000FFFFF) //PHY复位延时
#define PHY_CONFIG_DELAY ((uint32_t)0x00FFFFFF) //PHY配置延时
#define ETH_REG_WRITE_DELAY ((uint32_t)0x0000FFFF) //向以太网寄存器写数据时的延时
#endif
//LAN8720 PHY芯片的状态寄存器
#define PHY_SR ((uint16_t)31) //LAN8720的PHY状态寄存器地址
#define PHY_SPEED_STATUS ((uint16_t)0x0004) //LAN8720 PHY速度值掩码
#define PHY_DUPLEX_STATUS ((uint16_t)0x00010) //LAN8720 PHY连接状态值掩码
#endif
修改eth.c
注释掉四个数组,采用内存分配使用外部SRAM
2.添加LAN8720和MAC/DMA驱动 |
- LAN8720.c复制到工程中
出现错误:..\OBJ\MALLOC.axf: Error: L6218E: Undefined symbol lwip_pkt_handle (referred from lan8720.o).
这个函数在后面添加的文件中,暂时提示没有定义,不要心急!
3.添加LWIP源文件 |
- 工程中创建LWIP文件夹,复制lwip-1.4.1文件夹来
- 工程中增加文件分组 LWIP-API,LWIP-NETIF,LWIP-CORE
- 添加源文件和头路径
4.添加中间文件(起桥梁作用) |
以上几个步骤仅仅是添加了LWIP源文件和st以太网驱动。将以太网驱动和st驱动连接起来需要一种中间文件。
1. 添加arch,添加5个文件。其中cc.h根据组件定义了一些变量 u8_t。LWIP内部也采用printf来调试信息。cpu.h 定义大小端模式,stm32为小端。 perf.h。sys_arch.c .h全局变量获取当前系统时间。
2. 添加LWIP通用文件-ALLETEK编写的。
3. 添加ethernetif.h文件(LWIP源码是没有的ALIENTEK提供)
5.修改LWIP源码 |
中间文件连接底层驱动和LWIP,需要进行一些修改。
1.修改LWIP文件名
core中的sys.c和sys.h与原来的文件重名,这里修改为lwip_sys。注意修改.c中#include “lwip_sys.h”
修改完毕后报错:..\LWIP\arch\sys_arch.c(37): error: #5: cannot open source input file “timer.h”: No such file or directory
- lwip需要提供一种系统时钟,有一些周期性事务来处理。因为现在没有操作系统,则需要自己实现定时器,并且添加到HARDWARE中。 所以这里我们使用定时器3,并且设置周期为10ms。添加“timer.c”文件到工程中,内容为定时器3。中断服务函数中,进行lwip_loacltime+=10;//10ms中断,所以+10。具体代码看DEMO
添加timer后报错:..\OBJ\MALLOC.axf: Error: L6407E: Sections of aggregate size 0x3524 bytes could not fit into .ANY selector(s).
- 这里提示空间不足,解决办法在malloc.h中,修改可以管理的内部Ram的大小
#define MEM1_MAX_SIZE 60*1024 //从100k修改为60k,这里是malloc可以管理的大小,不宜过大。
- 之后会报错一些函数没有定义,暂时不去管它。
2.修改ethernetif.c
暂时不讲解源代码,所以直接用例程的替代。
3.修改mem.c memp.c
在LWIP内部采用动态内存管理技术,LWIP内存堆ram_heap和内存池memp_memory。我们用MALLOC进行动态内存分配(也可以使用attribute),注释掉数组。
* mem.c 注释181,182行。定义一个指针
/** the heap. we need one struct mem at the end and some room for alignment */
u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT];
u8_t * ram_heap; //定义指针
- memp.c中是169~173
- memp_get_memorysize()用于获取memp_memory数组的大小。memp_memory会在lwip_comm.c中使用动态内存管理来分配内存
4.修改icmp.c, ping使用的icmp协议
- st有一个默认硬件帧校验
6.LWIP的裁剪与配置 |
- LWIP中opt.h是可以裁剪和配置LWIP的。但是不建议opt.h中修改,其中的配置都是条件编译。那么在其他地方定义就行了。
- 在lwip_common下的lwipopts.h进行了配置。
- 开发板连接路由器是会DHCP自动分配地址的。如果DHCP设置为0,是使用静态IP地址的。