十五、STM32——移植lwip
我这里移植的lwip,都是通过STM32CubeMX直接生成,同时含有FreeRTOS系统。以下是对CubeMX生成的文件直接描述。
1 架构描述
关于源代码文件分为两部分:
-
中间层文件,跟STM32和PHY芯片有关。STM32芯片不同,PHY芯片不同,这部分文件都会变化。
-
lwip源文件,不进行修改部分,这部分是直接复制lwip。
中间层文件:
-
lwip.c:
MX_LWIP_Init
初始化函数,tcp_init
,netif_add
,网卡连接状态线程创建。 -
lan8742.c:PHY芯片寄存器读写函数,设置自动协商,获取网口连接状态,开启关闭PHY中断。
-
ethernetif.c:所有跟STM32 ETH有关的函数,ETH初始化,ETH的读和写,ETH中断。
主要是 netif.c
,这是有关网口描述符定义和相关函数的文件,STM32 ETH的读和写都会在这里赋值给网口描述符对象,从而使用lwip库。
1.1 netif 结构体
-
netif
是网口的抽象描述符。netif 结构体是在netif.c
文件中定义的。netif 描述一个网络接口 network interface(网卡)。 -
单网卡只需要一个netif即可,lwip也实现了多个netif单链表连接的结构,以实现多网卡功能。
netif.c
定义了struct netif *netif_list
。
struct netif {
/* 指向下一块网卡 */
struct netif *next;
/* 该网口的ip地址、子网掩码、默认网关配置 */
ip_addr_t ip_addr;
ip_addr_t netmask;
ip_addr_t gw;
/* 网卡数据的输入(接收),实际指向的是 tcpip_input */
netif_input_fn input;
/* 把网络层数据,包装成链路层数据,负责IP->MAC的转换(ARP),实际指向的是 etharp_output */
netif_output_fn output;
/* 网卡数据底层(物理层)发送,实际指向的是 low_level_output */
netif_linkoutput_fn linkoutput;
/* 当网络接口的 "IP 配置状态" 发生变化时触发。通常打印新IP地址,在界面上更新网络连接信息 */
netif_status_callback_fn status_callback;
/* 当网络接口的 "物理链路状态" 发生变化时触发:网线插拔,PHY 链路状态改变(Link Up / Down) */
netif_status_callback_fn link_callback;
/**
* 表示网络接口的主机名(hostname),主要用于:
* DHCP 协议中的 DHCP Hostname 选项(Option 12)
* 有些路由器在 DHCP 客户端连接时,会显示主机名
*/
const char* hostname;
/**
* 是 LwIP 内部用于标识网络接口的两个字符的“接口简名”
* 配合接口号(num)形成接口标识,例如:en0、st1、et0、lw0 等
*/
char name[2];
/* 如果你设备上有多个网络接口(如多个以太网/WiFi/PPP),每个接口会有一个唯一的 num 值(从 0 开始递增)。 */
u8_t num; /* netif_num赋值给num, netif_num 由 netif_add 函数进行加一,每调用一次 netif_num 加一 */
}
netif 相关函数
netif_init() /* 网卡抽象描述符(netif)初始化 */
netif_add() /* 添加一个虚拟网卡(netif) */
netif_remove() /* 移除一个虚拟网卡(netif) */
netif_set_default() /* 设置默认虚拟网卡(用于未知的数据包) */
1.2 lwip.c
调用所有相关功能进行初始化
1.3 ethernetif.c
1.4 lan8742.c
-
LAN8742_Init初始化,并不是初始化PHY芯片的,是对PHY对象(lan8742_Objct_t *pObj)的地址号进行赋值。
-
实现了PHY读写寄存器相关函数,自动协商,开启和关闭PHY中断函数。
2 lwip自动创建的3个线程
2.1 ethernet_link_thread
该线程周期性检测以太网物理链路状态,并在网线插拔时动态配置 MAC 和更新 LwIP 网络接口的上下线状态。
确保网络断开或重新连接后能自动响应。
2.2 ethernetif_input
-
STM32以太网中断,发出
RxPktSemaphore
信号量 -
ethernetif_input
循环等待该RxPktSemaphore
信号量可用,调用tcpip_input
函数,把以太网数据放入tcpip_mbox
邮箱,可以让tcpip_thread
处理以太网输入数据。
2.3 tcpip_thread
以太网数据读取流程
3 以太网问题分析和移植总结
-
PHY芯片复位问题,如果PHY模块没有复位引脚或者复位后,需要等待一定时间,判断PHY是否复位成功。
例如:我使用的LAN8720芯片,没有复位引脚,复位后,LANxxx_Init直接读取phy地址,可以就会失败。
-
PHY芯片地址。由于PHY芯片寄存器可能不一样,地址可能读取失败。
-
MPU配置问题,STM32H7系列,以太网DMA描述符和lwip内存池的SRAM空间需要配置。否则会有内存问题。
-
FreeRTOS默认任务会进行LWIP初始化,所以任务栈大小需要设置为大一些,比如
2048
。
2 PHY芯片之DM9161
汉泰科兴项目中使用的是该芯片,下面是该芯片电路图:
-
CubeMX生成的
lan7842.c
中,LAN8742_Init
初始化函数可能无法找到正确的PHY设备地址,可以直接指定PHY地址。(因为两款芯片读取PHY地址寄存器不一样)