LwIP 介绍
LwIP 全名:Light weight IP,意思是轻量化的 TCP/IP 协议
LwIP 的设计初衷是:用少量的资源消耗实现一个较为完整的 TCP/IP 协议栈,其中“完整”主要指的是 TCP 协议的完整性,实现的重点是在保持 TCP 协议主要功能的基础上减少对 RAM 的占用。此外 LwIP 既可以移植到操作系统上运行,也可以在无操作系统的情况下独立运行。
LwIP 的代码已经交给 Savannah 托管,LwIP 的项目主页是:http://savannah.nongnu.org/projects/lwip/
LwIP编程接口
LwIP 提供了三种编程接口,分别为 RAW/Callback API、NETCONN API、SOCKET API。它们的易用性从左到右依次提高,而执行效率从左到右依次降低,用户可以根据实 际情况,平衡利弊,选择合适的 API 进行网络应用程序的开发。
- RAW/Callback API: 使用回调来实现,没有操作系统也能实现
- NETCONN API : 使用了操作系统的 IPC 机制,对网络连接进行了抽象,用户可以像操 作文件一样操作网络连接(打开/关闭、读/写数据)。但是 NETCONN API 并不如操作文 件的 API 那样简单易用。
- SOCKET API : Socket,即套接字,它对网络连接进行了高级的抽象,使得用户可以像操作文件一样 操作网络连接。
ETH 介绍
PHY 层
在物理层,由 IEEE 802.3 标准规定了以太网使用的传输介质、传输速度、数据编码方 式和冲突检测机制,物理层一般是通过一个 PHY 芯片实现其功能的。
常用的PHY芯片有LAN8720A。
MAC 子层
它主要负责与物理层进行数据交接,如是否
可以发送数据,发送的数据是否正确,对数据流进行控制等。它自动对来自上层的数据包
加上一些控制信号,交给物理层。接收方得到正常数据时,自动去除 MAC 控制信号,把
该数据包交给上层。
STM32 的ETH外设
STM32 的 ETH 内部自带专用的 DMA 控制器用于 MAC, ETH 支持两个工业标准接口介质独立
接口(MII)和简化介质独立接口(RMII)用于与外部 PHY 芯片连接。
MII 和 RMII 接口
MII 需要 16 根通信线, RMII 只需 7 根通信,在功能上是相同的。
STM32F407ZGT6 CUBEMX ETH与LwIP配置
1、RCC
2、SYS
3、ETH
4、RTOS
5、LWIP
这里为了方便测试,关闭了DHCP
6、时钟
7、堆栈
8、生成工程后修改代码
a、加入初始化代码
初始化调用步骤如下:
MX_LWIP_Init 初始化网卡 (IP地址、子网掩码、网关IP)
MX_LWIP_Init 调用netif_add函数,添加带RTOS的网络接口(IPv4/IPv6)
netif_add函数会调用ethernetif_init,ethernetif_init内将调用low_level_init(netif);
low_level_init内会进行eth的初始化(通过初始化heth句柄,与调用HAL_ETH_Init)
HAL_ETH_Init 会调用 HAL_ETH_MspInit (初始化ETH相关的时钟、GPIO与中断)
b、添加复位引脚代码
在调用HAL_ETH_Init 前,应当手动编写代码硬件翻转PHY的RESET引脚来复位PHY,同时加入下面2局代码:
HAL_ETH_DeInit(&heth);
ETH->DMABMR |= ETH_DMABMR_SR;
c、修改ETH配置
并将stm32f4xx_hal_conf.h 里面的
从4 改为8 否则HAL_ETH_Init将返回HAL_TIMEOUT,导致初始化失败。
d、修改配置
在low_level_init函数内,还会调用osSemaphoreNew函数,官方的注释解释是:
创建一个用于通知ethernetif帧接收的二进制信号量
默认是s_xSemaphore = osSemaphoreNew(1, 1, NULL);
需要改为s_xSemaphore = osSemaphoreNew(40, 1, NULL);
否则代码完成后无法ping通,原因未知,暂时无法理解。
e、新增ETH句柄的配置
heth.Init.Speed = ETH_SPEED_100M; //speed
heth.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
f、修改中断优先级
freertos的例程,优先级不能默认为0,否则卡死
测试
ping
插上和电脑同一个路由器测试一下
联网发送数据测试
设置花生壳内网映射,DEST_IP 与 DEST_PORT 填写未花生壳映射的IP与PORT。
添加代码并放入TASK中运行
#include "opt.h"
#include "sys.h"
#include "api.h"
#define DEST_IP_ADDR0 xxx
#define DEST_IP_ADDR1 xxx
#define DEST_IP_ADDR2 xxx
#define DEST_IP_ADDR3 xxx
#define DEST_PORT 43457
void App_process(void)
{
struct netconn *conn;
int ret;
ip4_addr_t ipaddr;
uint8_t send_buf[]= "This is a TCP Client test...\n";
printf("目地IP地址:%d.%d.%d.%d \t 端口号:%d\n\n", \
DEST_IP_ADDR0,DEST_IP_ADDR1,DEST_IP_ADDR2,DEST_IP_ADDR3,DEST_PORT);
while(1)
{
conn = netconn_new(NETCONN_TCP);
if (conn == NULL)
{
printf("create conn failed!\n");
vTaskDelay(10);
continue;
}
IP4_ADDR(&ipaddr,DEST_IP_ADDR0,DEST_IP_ADDR1,DEST_IP_ADDR2,DEST_IP_ADDR3);
ret = netconn_connect(conn,&ipaddr,DEST_PORT);
if (ret == -1)
{
printf("Connect failed!");
netconn_close(conn);
vTaskDelay(10);
continue;
}
printf("Connect to server successful!\n");
while (1)
{
ret = netconn_write(conn,send_buf,sizeof(send_buf),0);
vTaskDelay(1000);
}
}
}
测试结果: