Skip to content

启动流程

旧版

image-20240701172602037

  1. 申请内存, 获取四个缓冲区ethernet_mem_malloc
  2. 初始化一下静态的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

  1. ethernet_init初始化一下HAL库的MAC驱动, 间接调用HAL_ETH_MspInit这一个函数

在HAL_ETH_MspInit里面初始化各种IO, 以及使用硬件复位一下PHY芯片, 以及设置网络的中断优先级

  1. lwip_init初始化一下lwIP的内核, 使用不同的宏定义初始化不同的部件, tcpip_init = >建立处理任务
  2. 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, &ethernetif_init, &ethernet_input);

ethernetif_init: 会在这一个函数里面记录虚拟网卡的名字, 使用的函数(如下), 最后调用low_level_init初始化缓冲区链表以及使能ETH

比如etharp_output函数, 会使用这一个函数判断IP地址有没有对应的Mac地址, 没有的话使用ARP获取, low_level_output函数, 这一个函数把pbuf里面的数据复制到缓冲区里面, 然后启动DMA

ethernet_input: 会把pbuf里面的信息发送到网络层里面

image-20240701183942729

  1. 收数据的处理

中断里面判断是获取了数据, lwip_pkt_handle->ethernetif_input->low_level_input, 在这一个函数把DMA获取的数据复制到pbuf里面, 返回的是puf链表的第一个pbuf

之后会调用ethernet_input(netif->input)函数把数据包提交到网络层

image-20240701185526340

image-20240701185653526

新版

image-20240701171437347

  1. 初始化缓冲区, 使用一个数组
  2. 初始化lwIP的内核lwip_init
  3. 初始化默认的信息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;

实际是对这一个结构体的填充

  1. 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对应的函数, 设置一下初始化(设置时钟), 读写寄存器, 获取时钟的函数

image-20240701215923315

  1. pcf8574_init在这一个里面初始化PHY芯片

image-20240701215950873

有操作系统

image-20240702153518793

image-20240702153700490

  1. 在任务里面调用lwip_comm_init函数
  2. tcpip_init, 会在这一个里面调用lwip_init函数, 以及建立一个tcpip_thread线程(会使用lvipopt.h里面的配置), 以及建立一个用于传递数据的邮箱tcpip_mbox, 之后pbuf的传递也会使用这一个
  3. netif_add, 在里面调用ethernetif_init函数, 以及初始化netif, ethernetif_init函数里面会调用low_level_init, 以及设置netif的战术, low_level_init会进行ethernetif_input任务的创建, 以及两个二值信号量
  4. lwip_comm_default_ip_set, 记录一下初始化的信息
  5. 创建lwip_link_thread任务, 通过读取PHY芯片的寄存器, 判断是不是连接, 不是的话进行处理
  6. 创建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

image-20240702182018246

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函数进行处理

读取PHY芯片的状态寄存器, 获取连接的信息, 查看网线是不是接入了, 有的话打开网络中断以及启动虚拟网卡, 否则的话关闭

image-20240702183722104

lwip_periodic_handle

通过DHCP的状态机获取DHCP分配的ip地址

发送数据

image-20240702184447900

low_level_output函数里面进行底层的发送数据, 把pbuf里面的数据移动到缓冲区里面, 发送以后会等待信号量g_TxSemaphore, 会在中断的HAL_ETH_TxCpltCallback回调函数里面进行释放, 获取到这一个信号量以后说明信息已经发送出去了, 这时候可以释放pbuf