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, ®value) < 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 寄存器
其他函数类似,这里就不一一解析了。
