当前位置: 首页 > news >正文

PHY——LAN8720A 代码解析 (三)

文章目录

  • PHY——LAN8720A 代码解析 (三)
    • PHY 源码解析
      • ETH_PHY_IO_Init
      • ETH_PHY_IO_DeInit
      • ETH_PHY_IO_WriteReg
      • ETH_PHY_IO_ReadReg
      • ETH_PHY_IO_GetTick
    • LAN8720 源码解析
      • LAN8720_RegisterBusIO
      • LAN8720_Init
      • LAN8720_DisablePowerDownMode
      • LAN8720_EnablePowerDownMode

PHY——LAN8720A 代码解析 (三)

PHY 源码解析

这里 PHY 的操作是通过函数指针实现的。

PHY 结构体定义如下:

typedef int32_t  (*lan8720_Init_Func) (void); 
typedef int32_t  (*lan8720_DeInit_Func) (void);
typedef int32_t  (*lan8720_ReadReg_Func)   (uint32_t, uint32_t, uint32_t *);
typedef int32_t  (*lan8720_WriteReg_Func)  (uint32_t, uint32_t, uint32_t);
typedef int32_t  (*lan8720_GetTick_Func)  (void);

typedef struct 
{                   
  lan8720_Init_Func      Init; 
  lan8720_DeInit_Func    DeInit;
  lan8720_WriteReg_Func  WriteReg;
  lan8720_ReadReg_Func   ReadReg; 
  lan8720_GetTick_Func   GetTick;   
} lan8720_IOCtx_t;  

  
typedef struct 
{
  uint32_t            DevAddr;
  uint32_t            Is_Initialized;
  lan8720_IOCtx_t     IO;
  void               *pData;
}lan8720_Object_t;
  • lan8720_IOCtx_t 结构体实现 PHY 操作的方法
  • lan8720_Object_t 结构体是 PHY 操作的对象

PHY 操作方法的实现

int32_t ETH_PHY_IO_Init(void);
int32_t ETH_PHY_IO_DeInit (void);
int32_t ETH_PHY_IO_ReadReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal);
int32_t ETH_PHY_IO_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal);
int32_t ETH_PHY_IO_GetTick(void);

lan8720_Object_t LAN8720;
lan8720_IOCtx_t  LAN8720_IOCtx = {ETH_PHY_IO_Init,
                                  ETH_PHY_IO_DeInit,
                                  ETH_PHY_IO_WriteReg,
                                  ETH_PHY_IO_ReadReg,
                                  ETH_PHY_IO_GetTick};

ETH_PHY_IO_Init

ETH_PHY_IO_Init 函数用于初始化 PHY 接口。这里主要用于初始化 MDIO 的时钟。

int32_t ETH_PHY_IO_Init(void)
{
  /* We assume that MDIO GPIO configuration is already done
     in the ETH_MspInit() else it should be done here
  */

  /* Configure the MDIO Clock */
  HAL_ETH_SetMDIOClockRange(&heth);

  return 0;
}

ETH_PHY_IO_DeInit

ETH_PHY_IO_DeInit 函数用于反初始化 PHY 接口。这里暂未实现。

ETH_PHY_IO_WriteReg

ETH_PHY_IO_WriteReg 函数用于向 PHY 写入寄存器。这里其实就是封装了 HAL_ETH_WritePHYRegister 函数,并对返回值进行判断。

int32_t ETH_PHY_IO_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal)
{
  if(HAL_ETH_WritePHYRegister(&heth, DevAddr, RegAddr, RegVal) != HAL_OK)
  {
    return -1;
  }

  return 0;
}

ETH_PHY_IO_ReadReg

ETH_PHY_IO_ReadReg 函数用于从 PHY 读取寄存器。这里其实也是封装了 ETH_PHY_IO_ReadReg 函数,并对返回值进行判断。

int32_t ETH_PHY_IO_ReadReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal)
{
  if(HAL_ETH_ReadPHYRegister(&heth, DevAddr, RegAddr, pRegVal) != HAL_OK)
  {
    return -1;
  }

  return 0;
}

ETH_PHY_IO_GetTick

ETH_PHY_IO_GetTick 函数用于获取当前的 tick 值。对 HAL_GetTick 进行了封装。

int32_t ETH_PHY_IO_GetTick(void)
{
  return HAL_GetTick();
}

最终将函数指针赋值给 LAN8720_IOCtx 这个变量

LAN8720 源码解析

LAN8720 的接口其实就是调用 PHY 的一系列接口来控制 LAN8720,或者获取 LAN8720 的状态。

LAN8720_RegisterBusIO

LAN8720_RegisterBusIO 函数用于注册 PHY 接口。这里主要是对 lan8720_Object_t 结构体中的 IO 成员进行赋值。

int32_t  LAN8720_RegisterBusIO(lan8720_Object_t *pObj, lan8720_IOCtx_t *ioctx)
{
  if(!pObj || !ioctx->ReadReg || !ioctx->WriteReg || !ioctx->GetTick)
  {
    return LAN8720_STATUS_ERROR;
  }

  pObj->IO.Init = ioctx->Init;
  pObj->IO.DeInit = ioctx->DeInit;
  pObj->IO.ReadReg = ioctx->ReadReg;
  pObj->IO.WriteReg = ioctx->WriteReg;
  pObj->IO.GetTick = ioctx->GetTick;

  return LAN8720_STATUS_OK;
}

函数调用

  /* Set PHY IO functions */
  LAN8720_RegisterBusIO(&LAN8720, &LAN8720_IOCtx);

  /* Initialize the LAN8742 ETH PHY */
  if(LAN8720_Init(&LAN8720) != LAN8720_STATUS_OK)
  {
    printf("init lan8720 error\r\n");
    while(1);
  }

这样 LAN8720 这个变量的结构体成员就被赋值了。操作 PHY 的使用调用 LAN8720 对应的函数指针即可。

LAN8720_Init

这个函数其实就是从 0 遍历 PHY 的地址,找到一个可用的 PHY 地址。

int32_t LAN8720_Init(lan8720_Object_t *pObj)
{
   uint32_t regvalue = 0, addr = 0;
   int32_t status = LAN8720_STATUS_OK;

   if(pObj->Is_Initialized == 0)
   {
     if(pObj->IO.Init != 0)
     {
       /* GPIO and Clocks initialization */
       pObj->IO.Init();
     }

     /* for later check */
     pObj->DevAddr = LAN8720_MAX_DEV_ADDR + 1;

     /* Get the device address from special mode register */
     for(addr = 0; addr <= LAN8720_MAX_DEV_ADDR; addr ++)
     {
       if(pObj->IO.ReadReg(addr, LAN8720_SMR, &regvalue) < 0)
       {
         status = LAN8720_STATUS_READ_ERROR;
         /* Can't read from this device address
            continue with next address */
         continue;
       }

       if((regvalue & LAN8720_SMR_PHY_ADDR) == addr)
       {
         pObj->DevAddr = addr;
         status = LAN8720_STATUS_OK;
         break;
       }
     }

     if(pObj->DevAddr > LAN8720_MAX_DEV_ADDR)
     {
       status = LAN8720_STATUS_ADDRESS_ERROR;
     }

     /* if device address is matched */
     if(status == LAN8720_STATUS_OK)
     {
       pObj->Is_Initialized = 1;
     }
   }

   return status;
 }

这个函数主要是读取 LAN8720_SMR 寄存器,并获取 PHY 的地址

  • LAN8720_SMR 寄存器偏移是 0x12
  • bit4:0 是 PHY 的地址。

LAN8720_DisablePowerDownMode

这个函数用于禁用 PHY 的 Power Down 模式。

int32_t LAN8720_DisablePowerDownMode(lan8720_Object_t *pObj)
{
  uint32_t readval = 0;
  int32_t status = LAN8720_STATUS_OK;

  if(pObj->IO.ReadReg(pObj->DevAddr, LAN8720_BCR, &readval) >= 0)
  {
    readval &= ~LAN8720_BCR_POWER_DOWN;

    /* Apply configuration */
    if(pObj->IO.WriteReg(pObj->DevAddr, LAN8720_BCR, readval) < 0)
    {
      status =  LAN8720_STATUS_WRITE_ERROR;
    }
  }
  else
  {
    status = LAN8720_STATUS_READ_ERROR;
  }

  return status;
}

这个函数其实就是实现 读-改-写

  • 读 LAN8720_BCR 寄存器,也就是偏移地址是 0
  • 将 bit11 清零,也就是禁用 Power Down 即 normal operation 模式
  • 写入 LAN8720_BCR 寄存器

LAN8720_EnablePowerDownMode

这个函数用于启用 PHY 的 Power Down 模式。

int32_t LAN8720_EnablePowerDownMode(lan8720_Object_t *pObj)
{
  uint32_t readval = 0;
  int32_t status = LAN8720_STATUS_OK;

  if(pObj->IO.ReadReg(pObj->DevAddr, LAN8720_BCR, &readval) >= 0)
  {
    readval |= LAN8720_BCR_POWER_DOWN;

    /* Apply configuration */
    if(pObj->IO.WriteReg(pObj->DevAddr, LAN8720_BCR, readval) < 0)
    {
      status =  LAN8720_STATUS_WRITE_ERROR;
    }
  }
  else
  {
    status = LAN8720_STATUS_READ_ERROR;
  }

  return status;
}

这个函数其实就是实现 读-改-写

  • 读 LAN8720_BCR 寄存器,也就是偏移地址是 0
  • 将 bit11 设置为 1,也就是 General power down mode 模式
  • 写入 LAN8720_BCR 寄存器

其他函数类似,这里就不一一解析了。

相关文章:

  • HttpClient-01.介绍
  • Libevent UDP开发指南
  • 基于动态渲染与反检测技术的爬虫框架设计
  • Spring笔记05-面向切面编程
  • 每日一题(小白)暴力娱乐篇9
  • 【AI4CODE】4 Trae 锤一个数据搬运工的小应用
  • fpga:分秒计时器
  • 创建虚拟机
  • ChatGPT 的新图像生成器非常擅长伪造收据
  • 3dmax批量转glb/gltf/fbx/osgb/stl/3ds/dae/obj/skp格式导出转换插件,无需一个个打开max,材质贴图在
  • vue实现俄罗斯方块
  • MMD 转 STL,拓宽 3D 模型应用边界:方法与门道
  • 《JVM考古现场(十五):熵火燎原——从量子递归到热寂晶壁的代码涅槃》
  • 二分答案 + P8800 [蓝桥杯 2022 国 B] 卡牌 - 题解
  • 网络安全设备介绍:防火墙、堡垒机、入侵检测、入侵防御
  • UniApp集成极光推送详细教程
  • 多模态大语言模型arxiv论文略读(三)
  • Python - 爬虫-网页抓取数据-库urllib
  • 机器视觉之光源选型
  • 微服务的简单认识
  • 北京2025年住房发展计划:供应商品住房用地240-300公顷,建设筹集保租房5万套
  • 欧盟决意与俄罗斯能源彻底决裂之际,美国谋划新生意:进口俄气对欧转售
  • 新华时评:直播间里“家人”成“韭菜”,得好好管!
  • 马上评|孩子亲近自然只能靠公园露营了吗
  • 中国人民银行:5月8日起降息,15日起降准
  • 黄仁勋:中国AI市场将达500亿美元,美国企业若无法参与是巨大损失