文章目录
- 一、LAN8720A简介
- 二、引脚说明
- 芯片管脚配置
- 示例演示
一、LAN8720A简介
LAN8720A是低功耗的10/100M以太网PHY芯片,支持通过RMII接口和MAC层通信。它包含一个全双工10-BASE-T/100BASE-TX收发器,支持10Mbps和100Mbps操作。可以自动协商以自动确定最佳速度和双工操作模式。支持 HPAuto-MDIX 自动翻转功能,无需更换网线即可将连接更改为直连或交又连接。特性如下:
- 10/100M
- 支持RMII接口
- 支持全双工和半双工
- 使用外部25M晶振,LAN8720A内部集成 PLL可以将25M倍频到50MHz参考时钟给MAC层使用
- 支持自协商模式 支持HPAuto-MDIX自动翻转
- 支持SMI串行管理接口
LAN8720A内部框图:
LAN8720A系统框图:左边10/100M网络控制器。 右边的RJ45就是网口。 下边框图说明需要一个外部晶振。
二、引脚说明
引脚 | 描述 |
---|---|
TX1 | PHY收发器发送的两位数据第1位数据发送引脚 |
NC | 不连接 |
TX_EN | 数据发送使能指示TXD[1:0]上存在有效的发送数据,用于控制发送数据的使能 |
TX0 | PHY收发器发送的两位数据第0位数据发送引脚 |
RX0 | PHY收发器接收的两位数据第0位数据接收引脚 |
RX1 | PHY收发器接收的两位数据第1位数据接收引脚 |
nINT/RETCLK | 中断输出低有效/参考时钟信号輸出 |
CRS | 载波侦听/接收数据有效,用于指示是否检测到网络上的载波 |
MDIO | 串行管理接口的输入输出引脚,用于读写PHY寄存器 |
MDC | 串行管理接口的时钟引脚,用于同步数据传输 |
VCC | 3.3V |
芯片管脚配置
PHY地址配置:PHYAD[0]引脚用于配置 SMI通信的 LAN8720A 地址,在芯片内部该引脚已经自带下拉电阻,默认认为 0(即外部悬空不接),在系统上电时会检测该引脚获取得到 LAN8720A的地址为 0 或者 1,并保存在特殊模式寄存器(R18)的 PHYAD位中,该寄存器的 PHYAD有 5个位,在需要超过 2个 LAN8720A 时可以通过软件设置不同 SMI通信地址。模块的硬件设计PHYAD[0]引脚默认上拉到高电平,即PHY address为1。
nINT/REFCLKO参考时钟配置:配置REF_CLK输入模式(nINT)和REF_CLK输出模式。配置模式决定了nINT/REFCLKO引脚的功能。nINTSEL配置带锁定在POR和nRST的上升沿。默认情况下,nINTSEL通过内部上拉电阻器配置为nINT模式。
当 nINTSEL引脚为低电平时,REF_CLK输出模式,设备会倍频到50MHz RMII REF_CLK,nINT中断不可用。REF_CLK输出模式允许使用低成本的25MHz晶体作为REF_CLK的参考。这种配置可能会降低系统成本。
当 nINTSEL引脚为高电平时,50MHz REF_CLK在XTAL1/CLKIN引脚上被驱动。即需要外部提供50MHz参考时钟给CLKIN引脚。
MODE[2:0]模式配置:选择网络通信速率和工作模式,可选10Mbps 或 100Mbps 通信速度,半双工或全双工工作模式。将MODE引脚都设置为1,让 LAN8720A 启动自适应功能,它会自动寻找最优工作方式。其中,复用引脚如下:
配置MODE[2:0] 引脚,支持以下几种模式:
REGOFF内部+1.2V稳压器配置:配置是否使用内部稳压器,当REGOFF引脚为高电平时选择外部+1.2V稳压器,通过VDDCR引脚输入+1.2V 电压提供。当REGOFF引脚为低电平时选择内部+1.2V稳压器。注意,由于REGOFF与 LED1 引脚复用,必须适当考虑LED的极性。模块的VDDCR引脚位置如下:
示例演示
- 引脚接线
ESP32 | LAN8720模块 |
---|---|
GPIO21 | TX_EN |
GPIO19 | TX0 |
GPIO22 | TX1 |
GPIO25 | RX0 |
GPIO26 | RX1 |
GPIO27 | CRS |
GPIO23 | MDC |
GPIO18 | MDIO |
- 示例代码
#include <ETH.h> //引用以使用ETH
#include <WiFiUdp.h>
#define ETH_ADDR 1
#define ETH_POWER_PIN -1
#define ETH_MDC_PIN 23
#define ETH_MDIO_PIN 18
#define ETH_TYPE ETH_PHY_LAN8720
#define ETH_CLK_MODE ETH_CLOCK_GPIO17_OUT
WiFiUDP Udp; //创建UDP对象
unsigned int localUdpPort = 2333; //本地端口号
void setup()
{
Serial.begin(115200);
Serial.println();
ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE, ETH_CLK_MODE); //启用ETH
while(!((uint32_t)ETH.localIP())) //等待获取到IP
{
}
Serial.println("Connected");
Serial.print("IP Address:");
Serial.println(ETH.localIP());
Udp.begin(localUdpPort); //启用UDP监听以接收数据
}
void loop()
{
int packetSize = Udp.parsePacket(); //获取当前队首数据包长度
if (packetSize) //如果有数据可用
{
char buf[packetSize];
Udp.read(buf, packetSize); //读取当前包数据
Serial.println();
Serial.print("Received: ");
Serial.println(buf);
Serial.print("From IP: ");
Serial.println(Udp.remoteIP());
Serial.print("From Port: ");
Serial.println(Udp.remotePort());
Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); //准备发送数据
Udp.print("Received: "); //复制数据到发送缓存
Udp.write((const uint8_t*)buf, packetSize); //复制数据到发送缓存
Udp.endPacket(); //发送数据
}
}
- 示例结果