接口定义
也被称作MII管理接口(MII Management Interface),包括MDC和MDIO两条信号线。MDIO是一个PHY的管理接口,用来读/写PHY的寄存器,以控制PHY的行为或获取PHY的状态,MDC为MDIO提供时钟
MDIO是双向的,只支持一个MAC连接最多32个PHY的连接方式,且MAC作为master,PHY作为slave。在写PHY寄存器的时候,由MAC驱动MDIO向PHY写入数据;在读PHY寄存器时,前半段由MAC驱动发送寄存器地址,后半段由PHY驱动回复寄存器的值。
MDC要求由MAC输出,是非周期性的,即不要求提供固定频率的时钟,对于PHY芯片则作为输入,以在上升沿触发MDIO的读写。MDC的时钟频率可以是DC-2.5MHz,即最小的时钟周期为400ns。MDC支持的最大时钟频率根据具体PHY决定。
时序图
读写的帧如下图所示
Preamble+Start:32bits的前导码以及2bit的开始位。
OP Code:2bits的操作码,10表示读,01表示写。
PHYAD:5bits的PHY地址,一般PHY地址从0开始顺序编号,例如6口switch中PHY地址为0-5。
REGAD:5bits的寄存器地址,即要读或写的寄存器。
Turn Around:2bits的TA,在读命令中,MDIO在此时由MAC驱动改为PHY驱动,并等待一个时钟周期准备发送数据。在写命令中,不需要MDIO方向发生变化,则只是等待两个时钟周期准备写入数据。
Data:16bits数据,在读命令中,PHY芯片将读到的对应PHYAD的REGAD寄存器的数据写到Data中,在写命令中,MAC将要写入对应PHYAD的REGAD寄存器的值写入Data中。
Idle:空闲状态,此时MDIO无源驱动,处高阻状态,但一般用上拉电阻使其处在高电平,上拉电阻一般为1.5K
时序如下图所示
GPIO模拟时序
模拟读写
对于没有mdio控制器的soc;可以使用i2c,或者使用gpio来模拟mdio总线
uint32_t smi_cl22_write(uint8_t phy_addr, uint8_t reg_addr, uint16_t rData)
{
_smi_writeBit(0xffff, 16);/*pre code*/
_smi_writeBit(0xffff, 16);/*pre code*/
_smi_writeBit(ST_CODE, 2);
_smi_writeBit(OP_WRITE, 2);/*write*/
_smi_writeBit(phy_addr, 5);/*phy addr*/
_smi_writeBit(reg_addr, 5);/*reg addr*/
_smi_writeBit(TA_CODE, 2);
_smi_writeBit(rData, 16);
return 0;
}
uint32_t smi_cl22_read(uint8_t phy_addr, uint8_t reg_addr, uint16_t *pRData)
{
uint32_t rData;
_smi_writeBit(0xffff, 16);/*pre code*/
_smi_writeBit(0xffff, 16);/*pre code*/
_smi_writeBit(ST_CODE, 2);
_smi_writeBit(OP_READ, 2);/*read*/
_smi_writeBit(phy_addr, 5);/*phy addr*/
_smi_writeBit(reg_addr, 5);/*reg addr*/
_smi_writeBit(0, 1); /* */
_smi_readBit(16, &rData);
*pRData = (uint32_t)rData;
return 0;
}
时序异常
结果发现读出来的数据,第一次总是错的;然后抓波形
发现没拉高的这两位换算成1,刚好就是准确的寄存器数据,怀疑是外部上拉能力不够,加上拉电阻解决;虽然还不太完美,但已经能够保证代码里读的时序了