Appearance
启动流程
旧版
- 申请内存, 获取四个缓冲区ethernet_mem_malloc
- 初始化一下静态的ip, 实际是一个自己定义的信息结构体lwip_comm_default_ip_set
c
/*lwip控制结构体*/
typedef struct
{
uint8_t mac[6]; /* MAC地址 */
uint8_t remoteip[4]; /* 远端主机IP地址 */
uint8_t ip[4]; /* 本机IP地址 */
uint8_t netmask[4]; /* 子网掩码 */
uint8_t gateway[4]; /* 默认网关的IP地址 */
uint8_t dhcpstatus; /* dhcp状态 */
/* 0, 未获取DHCP地址;*/
/* 1, 进入DHCP获取状态*/
/* 2, 成功获取DHCP地址*/
/* 0XFF,获取失败 */
}__lwip_dev;
之后会使用这一个结构体里面的信息进行初始化lwIP
- ethernet_init初始化一下HAL库的MAC驱动, 间接调用HAL_ETH_MspInit这一个函数
在HAL_ETH_MspInit里面初始化各种IO, 以及使用硬件复位一下PHY芯片, 以及设置网络的中断优先级
- lwip_init初始化一下lwIP的内核, 使用不同的宏定义初始化不同的部件, tcpip_init = >建立处理任务
- netif_add添加一个网口, 这一个函数设置以太网的IP地址, 以及传进去两个函数, 一个是网卡初始化, 另一个是以太网数据包输入的函数
c
netif_init_flag = netif_add(&lwip_netif, (const ip_addr_t *)&ipaddr, (const ip_addr_t *)&netmask, (const ip_addr_t *)&gw, NULL, ðernetif_init, ðernet_input);
ethernetif_init: 会在这一个函数里面记录虚拟网卡的名字, 使用的函数(如下), 最后调用low_level_init初始化缓冲区链表以及使能ETH
比如etharp_output函数, 会使用这一个函数判断IP地址有没有对应的Mac地址, 没有的话使用ARP获取, low_level_output函数, 这一个函数把pbuf里面的数据复制到缓冲区里面, 然后启动DMA
ethernet_input: 会把pbuf里面的信息发送到网络层里面
- 收数据的处理
中断里面判断是获取了数据, lwip_pkt_handle->ethernetif_input->low_level_input, 在这一个函数把DMA获取的数据复制到pbuf里面, 返回的是puf链表的第一个pbuf
之后会调用ethernet_input(netif->input)函数把数据包提交到网络层
新版
- 初始化缓冲区, 使用一个数组
- 初始化lwIP的内核lwip_init
- 初始化默认的信息lwip_comm_default_ip_set
c
/*lwip控制结构体*/
typedef struct
{
uint8_t mac[6]; /* MAC地址 */
uint8_t remoteip[4]; /* 远端主机IP地址 */
uint8_t ip[4]; /* 本机IP地址 */
uint8_t netmask[4]; /* 子网掩码 */
uint8_t gateway[4]; /* 默认网关的IP地址 */
uint8_t dhcpstatus; /* dhcp状态
0, 未获取DHCP地址
1, 进入DHCP获取状态
2, 成功获取DHCP地址
0XFF,获取失败 */
}__lwip_dev;
实际是对这一个结构体的填充
- netif_add添加网络驱动
在添加的时候调用ethernetif_init这一个函数进行初始化, 以及设置一下输出函数
最后调用low_level_init函数下面是这一个函数的作用
里面的函数会在eth_chip_init里面进行初始化函数调用, 同时在里面遍历所有的地址, 获取实际有用的地址, 之后使用获取的这一个地址进行一次软件复位
eth_chip_start_auto_nego函数里面使用之前获取的地址, 以及写寄存器的函数进行设置, 启用自动协商
eth_chip_get_link_state获取一下使用速度以及是否使用全双工, 使用获取的参数使能ETH, 开启虚拟网卡, 使能ETH的时候会初始化GPIO, 软件复位以及启动中断, 在eth_chip_regster_bus_io里面设置io对应的函数, 设置一下初始化(设置时钟), 读写寄存器, 获取时钟的函数
- pcf8574_init在这一个里面初始化PHY芯片
有操作系统
- 在任务里面调用lwip_comm_init函数
- tcpip_init, 会在这一个里面调用lwip_init函数, 以及建立一个tcpip_thread线程(会使用lvipopt.h里面的配置), 以及建立一个用于传递数据的邮箱tcpip_mbox, 之后pbuf的传递也会使用这一个
- netif_add, 在里面调用ethernetif_init函数, 以及初始化netif, ethernetif_init函数里面会调用low_level_init, 以及设置netif的战术, low_level_init会进行ethernetif_input任务的创建, 以及两个二值信号量
- lwip_comm_default_ip_set, 记录一下初始化的信息
- 创建lwip_link_thread任务, 通过读取PHY芯片的寄存器, 判断是不是连接, 不是的话进行处理
- 创建lwip_periodic_handle任务, 通过DHCP获取ip
把里面的操作改为使用任务实现
start_task初始化
起始任务, 初始化的时候开启的第一个任务, 会在这一个函数里面调用lwip_comm_init函数, 之后通过读取寄存器的方式进行获取是不是链接成功, 之后通过DHCP获取IP, 然后创建lwip_demo_task任务
ethernetif_input接收数据
在这一个任务里面获取信号量, s_xSemaphore, 这一个信号量是在获取数据的中断里面进行释放的, 使用low_level_input获取信息, 返回一个pbuf, 进一步调用tcpip_input等函数把这一个信息交给网络层, 使用tcpip_inpkt函数构建一个msg结构体, 把信息交给队列tcpip_thread函数进行处理, 使用邮箱tcpip_mbox
input_fn 指向函数 ethernet_input
LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS这一个宏定义设置为1的时候会使用word作为申请任务的时候栈的大小, 在sys_srch.c
tcpip_thread数据分类
获等待获取邮箱发送过来的信息, tcpip_input=>tcpip_inpkt=>sys_mbox_trypost
获取邮箱里面的消息(阻塞), 根据获取的信息进行判断, 使用tcpip_thread_handle_msg进行处理消息, 根据不同类别的消息进行不同的处理, 如果是TCPIP_MSG_INPKT这一个类型的话, 会把这一个消息传出去
这一个消息最后会到达ethernet_input这一个函数, 判断获取的包的类型, 如果是一个ARP类型的数据, 使用etharp_input函数进行处理, 否则使用ipv4_input函数进行处理
lwip_link_thread
读取PHY芯片的状态寄存器, 获取连接的信息, 查看网线是不是接入了, 有的话打开网络中断以及启动虚拟网卡, 否则的话关闭
lwip_periodic_handle
通过DHCP的状态机获取DHCP分配的ip地址
发送数据
low_level_output函数里面进行底层的发送数据, 把pbuf里面的数据移动到缓冲区里面, 发送以后会等待信号量g_TxSemaphore, 会在中断的HAL_ETH_TxCpltCallback回调函数里面进行释放, 获取到这一个信号量以后说明信息已经发送出去了, 这时候可以释放pbuf