这里写目录标题
前言
最近在学习zynq中的lwip协议族,找不到很好的记笔记的地方,所以就用csdn记录一下自己的学习过程。现在对lwip不熟悉,只是把官方的lwip echo server例程跑了一下,能跑通就一点点的照着学了,笔记都是根据自己的理解写的,而且部分内容可能也只针对lwip echo server例程有效,笔记可以供有缘人参考,但不敢保证全对,有不对的地方也期待有高人指点一二。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_40356705/article/details/136824649
一、概述
- 原型
static err_t low_level_init(struct netif *netif)
- 参数
struct netif *netif :结构体的指针,该结构体包含了网络接口的各种信息,如名称、输出函数、链路层输出函数等。 - 作用
- 网络接口初始化函数
二、函数体
static err_t low_level_init(struct netif *netif)
{
/* 将网络接口的状态(MAC地址)转换为无符号整数指针 */
UINTPTR mac_address = (UINTPTR)(netif->state);
/* 定义指向xemac结构体和xemacpsif结构体的指针 */
struct xemac_s *xemac;
xemacpsif_s *xemacpsif;
/* 定义DMA控制寄存器变量 */
u32 dmacrreg;
/* 定义状态变量,用于记录函数执行状态 */
s32_t status = XST_SUCCESS;
/* 将全局变量NetIf指向当前网络接口 */
NetIf = netif;
/* 为xemacpsif结构体分配内存 */
xemacpsif = mem_malloc(sizeof *xemacpsif);
if (xemacpsif == NULL) {
/* 如果内存分配失败,则打印调试信息并返回内存错误 */
LWIP_DEBUGF(NETIF_DEBUG, ("xemacpsif_init: out of memory\r\n"));
return ERR_MEM;
}
/* 为xemac结构体分配内存 */
xemac = mem_malloc(sizeof *xemac);
if (xemac == NULL) {
/* 如果内存分配失败,则释放之前为xemacpsif分配的内存,并返回内存错误 */
mem_free(xemacpsif);
LWIP_DEBUGF(NETIF_DEBUG, ("xemacpsif_init: out of memory\r\n"));
return ERR_MEM;
}
/* 设置xemac结构体的状态字段为xemacpsif结构体的地址 */
xemac->state = (void *)xemacpsif;
/* 根据MAC地址查找拓扑索引 */
xemac->topology_index = xtopology_find_index(mac_address);
/* 设置xemac结构体的类型为xemacps */
xemac->type = xemac_type_emacps;
/* 初始化xemacpsif结构体的发送队列为空 */
xemacpsif->send_q = NULL;
/* 创建接收队列 */
xemacpsif->recv_q = pq_create_queue();
if (!xemacpsif->recv_q) {
/* 如果队列创建失败,则释放之前分配的内存,并返回内存错误 */
mem_free(xemac);
mem_free(xemacpsif);
return ERR_MEM;
}
/* 设置网络接口的最大传输单元(MTU) */
#ifdef ZYNQMP_USE_JUMBO
/* 如果定义了ZYNQMP_USE_JUMBO,则使用更大的MTU */
netif->mtu = XEMACPS_MTU_JUMBO - XEMACPS_HDR_SIZE;
#else
/* 否则使用默认的MTU */
netif->mtu = XEMACPS_MTU - XEMACPS_HDR_SIZE;
#endif
/* 设置网络接口支持的IGMP和MLD过滤函数 */
#if LWIP_IGMP
netif->igmp_mac_filter = xemacpsif_mac_filter_update;
#endif
#if LWIP_IPV6 && LWIP_IPV6_MLD
netif->mld_mac_filter = xemacpsif_mld6_mac_filter_update;
#endif
/* 设置网络接口的标志位 */
netif->flags = NETIF
NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP |
NETIF_FLAG_LINK_UP;
/* 如果支持IPv6和MLD,则设置相应的标志位 */
#if LWIP_IPV6 && LWIP_IPV6_MLD
netif->flags |= NETIF_FLAG_MLD6;
#endif
/* 如果支持IGMP,则设置相应的标志位 */
#if LWIP_IGMP
netif->flags |= NETIF_FLAG_IGMP;
#endif
/* 在没有操作系统的环境下,创建用于接收数据可用的信号量 */
#if !NO_SYS
sys_sem_new(&xemac->sem_rx_data_available, 0);
#endif
/* 获取该EMAC的配置信息 */
mac_config = (XEmacPs_Config *)xemacps_lookup_config((unsigned)(UINTPTR)netif->state);
/* 在EL1非安全模式下,请求设备以指示此库正在使用它 */
#if EL1_NONSECURE
if (mac_config->BaseAddress == VERSAL_EMACPS_0_BASEADDR) {
Xil_Smc(PM_REQUEST_DEVICE_SMC_FID, DEV_GEM_0, 1, 0, 100, 1, 0, 0);
}
if (mac_config->BaseAddress == VERSAL_EMACPS_1_BASEADDR) {
Xil_Smc(PM_REQUEST_DEVICE_SMC_FID, DEV_GEM_1, 1, 0, 100, 1, 0, 0);
}
#endif
// 初始化EMACPS硬件
status = XEmacPs_CfgInitialize(&xemacpsif->emacps, mac_config, mac_config->BaseAddress);
// 检查初始化是否成功
if (status != XST_SUCCESS) {
// 如果初始化失败,则打印错误信息
xil_printf("In %s:EmacPs Configuration Failed....\r\n", __func__);
}
// 调用函数来进一步初始化EMACPS
init_emacps(xemacpsif, netif);
// 读取EMACPS的DMA控制寄存器的内容
dmacrreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET);
// 修改DMA控制寄存器的值,这里通过或运算设置特定的位
dmacrreg = dmacrreg | (0x00000010);
// 将修改后的值写回DMA控制寄存器
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET, dmacrreg);
// 条件编译,只有当定义了FreeRTOS操作系统,并且是ARM架构且不是ARMR5时,以下代码才会被编译
#if defined(OS_IS_FREERTOS) && defined(__arm__) && !defined(ARMR5)
// 创建一个FreeRTOS定时器,周期为10ms,回调函数为vTimerCallback
xemac->xTimer = xTimerCreate("Timer", 10, pdTRUE, ( void * ) 1, vTimerCallback);
// 检查定时器是否创建成功
if (xemac->xTimer == NULL) {
// 如果定时器创建失败,则打印错误信息
xil_printf("In %s:Timer creation failed....\r\n", __func__);
} else {
// 启动定时器
if(xTimerStart(xemac->xTimer, 0) != pdPASS) {
// 如果定时器启动失败,则打印错误信息
xil_printf("In %s:Timer start failed....\r\n", __func__);
}
}
#endif
// 设置EMACPS的中断服务例程
setup_isr(xemac);
// 初始化EMACPS的DMA功能
init_dma(xemac);
// 启动EMACPS硬件
start_emacps(xemacpsif);
// 将网络接口的状态更新为EMAC实例的指针
// 这样其他与网络接口相关的函数可以通过netif->state来访问EMAC实例
netif->state = (void *)xemac;
// 返回成功状态
return ERR_OK;
}
三、调用关系
被xemacpsif_init调用,重点调用了setup_isr,init_dma,start_emacps函数。其中setup_isr为关键调用。其主要作用是注册以太网数据接受与发送的中断函数。
标签:Lwip,netif,level,网络接口,mac,init,xemac,xemacpsif From: https://blog.csdn.net/weixin_40356705/article/details/137412632