Zynq-Linux移植学习笔记之67- 国产ZYNQ上通过GPIO模拟MDC/MDIO协议

news2024/9/22 17:38:33

1、背景介绍

模块上有9个PHY,其中两个PHY通过ZYNQ PS端的MDIO总线连接,其余7个PHY单独通过GPIO进行控制,需要实现GPIO模拟MDC/MDIO协议。

2、vivado工程设计

vivado工程内为每个PHY建立两个GPIO IP核,分别用来代表MDC和MDIO(虽然有点浪费)

MDC配置为默认输出

MDIO配置为双向

MDIO管脚默认上拉

3、MDIO时序介绍

MDIO接口包括两条线,MDIO和MDC,其中MDIO是双向数据线,而MDC是由STA驱动的时钟线。MDC时钟的最高速率一般为2.5MHz,MDC也可以是非固定频率,甚至可以是非周期的。MDIO接口只是会在MDC时钟的上升沿进行采样,而并不在意MDC时钟的频率(类似于I2C接口)。MDIO是一个PHY的管理接口,用来读/写PHY的寄存器,以控制PHY的行为或获取PHY的状态,MDC为MDIO提供时钟。

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。(空闲电平是低电平)

逻辑分析上抓到的示意图如下:

4、应用程序设计

参考上面的时序,采用GPIO翻转实现,注意AXI GPIO IP核0x4写0为输出,写1为输入,主要是用来操作MDIO方向

代码如下:

/*
 * Copyright (c) 2012 Xilinx, Inc.  All rights reserved.
 *
 * Xilinx, Inc.
 * XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
 * COURTESY TO YOU.  BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
 * ONE POSSIBLE   IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
 * STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
 * IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
 * FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
 * XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
 * THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
 * ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
 * FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <linux/mii.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/sockios.h>
#include <linux/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include "xil_io.h"


#define  PHY2_YT8521_ADDR                             0x01
#define  PHY3_YT8521_ADDR                             0x02
#define  PHY5_YT8521_ADDR                             0x04
#define  PHY6_YT8521_ADDR                             0x05
#define  PHY7_YT8521_ADDR                             0x06
#define  PHY8_YT8521_ADDR                             0x07
#define  PHY9_YT8521_ADDR                             0x00

#define  PHY_YT8521_ID_REG_ADDR                      0x03
#define  PHY_YT8521_REG_DEBUG_ADDR_OFFSET            0x1E
#define  PHY_YT8521_REG_DEBUG_DATA                   0x1F
#define  PHY_YT8521_EXT_REG_ADDR                     0xa00d

#define MDC2_GPIO_ADDR 0x412B0000
#define MDC3_GPIO_ADDR 0x412D0000
#define MDC5_GPIO_ADDR 0x412F0000
#define MDC6_GPIO_ADDR 0x41310000
#define MDC7_GPIO_ADDR 0x41330000
#define MDC8_GPIO_ADDR 0x41350000
#define MDC9_GPIO_ADDR 0x41370000

#define MDIO2_GPIO_ADDR 0x412C0000
#define MDIO3_GPIO_ADDR 0x412E0000
#define MDIO5_GPIO_ADDR 0x41300000
#define MDIO6_GPIO_ADDR 0x41320000
#define MDIO7_GPIO_ADDR 0x41340000
#define MDIO8_GPIO_ADDR 0x41360000
#define MDIO9_GPIO_ADDR 0x41380000



#define PHY2_SOFT_SMI_MDIO_READ Xil_In32(MDIO2_GPIO_ADDR)
#define PHY3_SOFT_SMI_MDIO_READ Xil_In32(MDIO3_GPIO_ADDR)
#define PHY5_SOFT_SMI_MDIO_READ Xil_In32(MDIO5_GPIO_ADDR)
#define PHY6_SOFT_SMI_MDIO_READ Xil_In32(MDIO6_GPIO_ADDR)
#define PHY7_SOFT_SMI_MDIO_READ Xil_In32(MDIO7_GPIO_ADDR)
#define PHY8_SOFT_SMI_MDIO_READ Xil_In32(MDIO8_GPIO_ADDR)
#define PHY9_SOFT_SMI_MDIO_READ Xil_In32(MDIO9_GPIO_ADDR)

typedef unsigned char u8;
typedef unsigned short u16;

void mdio_out(int index)
{
	switch(index)
	{
	case 2:
		Xil_Out32(MDIO2_GPIO_ADDR+0x4,0x0);
		break;
	case 3:
		Xil_Out32(MDIO3_GPIO_ADDR+0x4,0x0);
		break;
	case 5:
		Xil_Out32(MDIO5_GPIO_ADDR+0x4,0x0);
		break;
	case 6:
		Xil_Out32(MDIO6_GPIO_ADDR+0x4,0x0);
		break;
	case 7:
		Xil_Out32(MDIO7_GPIO_ADDR+0x4,0x0);
		break;
	case 8:
		Xil_Out32(MDIO8_GPIO_ADDR+0x4,0x0);
		break;
	case 9:
		Xil_Out32(MDIO9_GPIO_ADDR+0x4,0x0);
		break;
	default:
		break;
	}

}

void mdio_in(int index)
{
	switch(index)
	{
	case 2:
		Xil_Out32(MDIO2_GPIO_ADDR+0x4,0x1);
		break;
	case 3:
		Xil_Out32(MDIO3_GPIO_ADDR+0x4,0x1);
		break;
	case 5:
		Xil_Out32(MDIO5_GPIO_ADDR+0x4,0x1);
		break;
	case 6:
		Xil_Out32(MDIO6_GPIO_ADDR+0x4,0x1);
		break;
	case 7:
		Xil_Out32(MDIO7_GPIO_ADDR+0x4,0x1);
		break;
	case 8:
		Xil_Out32(MDIO8_GPIO_ADDR+0x4,0x1);
		break;
	case 9:
		Xil_Out32(MDIO9_GPIO_ADDR+0x4,0x1);
		break;
	default:
		break;
	}

}

void mdc_low(int index)
{
	switch(index)
	{
	case 2:
		Xil_Out32(MDC2_GPIO_ADDR,0x0);
		break;
	case 3:
		Xil_Out32(MDC3_GPIO_ADDR,0x0);
		break;
	case 5:
		Xil_Out32(MDC5_GPIO_ADDR,0x0);
		break;
	case 6:
		Xil_Out32(MDC6_GPIO_ADDR,0x0);
		break;
	case 7:
		Xil_Out32(MDC7_GPIO_ADDR,0x0);
		break;
	case 8:
		Xil_Out32(MDC8_GPIO_ADDR,0x0);
		break;
	case 9:
		Xil_Out32(MDC9_GPIO_ADDR,0x0);
		break;
	default:
		break;
	}

}

void mdc_high(int index)
{
	switch(index)
	{
	case 2:
		Xil_Out32(MDC2_GPIO_ADDR,0xffffffff);
		break;
	case 3:
		Xil_Out32(MDC3_GPIO_ADDR,0xffffffff);
		break;
	case 5:
		Xil_Out32(MDC5_GPIO_ADDR,0xffffffff);
		break;
	case 6:
		Xil_Out32(MDC6_GPIO_ADDR,0xffffffff);
		break;
	case 7:
		Xil_Out32(MDC7_GPIO_ADDR,0xffffffff);
		break;
	case 8:
		Xil_Out32(MDC8_GPIO_ADDR,0xffffffff);
		break;
	case 9:
		Xil_Out32(MDC9_GPIO_ADDR,0xffffffff);
		break;
	default:
		break;
	}

}

void mdio_low(int index)
{
	switch(index)
	{
	case 2:
		Xil_Out32(MDIO2_GPIO_ADDR,0x0);
		break;
	case 3:
		Xil_Out32(MDIO3_GPIO_ADDR,0x0);
		break;
	case 5:
		Xil_Out32(MDIO5_GPIO_ADDR,0x0);
		break;
	case 6:
		Xil_Out32(MDIO6_GPIO_ADDR,0x0);
		break;
	case 7:
		Xil_Out32(MDIO7_GPIO_ADDR,0x0);
		break;
	case 8:
		Xil_Out32(MDIO8_GPIO_ADDR,0x0);
		break;
	case 9:
		Xil_Out32(MDIO9_GPIO_ADDR,0x0);
		break;
	default:
		break;
	}

}

void mdio_high(int index)
{
	switch(index)
	{
	case 2:
		Xil_Out32(MDIO2_GPIO_ADDR,0xffffffff);
		break;
	case 3:
		Xil_Out32(MDIO3_GPIO_ADDR,0xffffffff);
		break;
	case 5:
		Xil_Out32(MDIO5_GPIO_ADDR,0xffffffff);
		break;
	case 6:
		Xil_Out32(MDIO6_GPIO_ADDR,0xffffffff);
		break;
	case 7:
		Xil_Out32(MDIO7_GPIO_ADDR,0xffffffff);
		break;
	case 8:
		Xil_Out32(MDIO8_GPIO_ADDR,0xffffffff);
		break;
	case 9:
		Xil_Out32(MDIO9_GPIO_ADDR,0xffffffff);
		break;
	default:
		break;
	}


}


void Mcu_Yt8521_Soft_Smi_Bit_Set(int index,u8 bit)
{
    // set mdio dir out
    // set mdio
	mdio_out(index);
	if(bit) mdio_high(index);
	else mdio_low(index);

    // set clk.
	mdc_low(index);
	mdc_high(index);
}

void Mcu_Yt8521_Soft_Smi_Bit_Get(int index,u8 *bit)
{
    // set mdio dir in
    // get mdio
	mdio_in(index);      //MDIO线设置为输入

	switch(index)
	{
	case 2:
		*bit = !!PHY2_SOFT_SMI_MDIO_READ;
		break;
	case 3:
		*bit = !!PHY3_SOFT_SMI_MDIO_READ;
		break;
	case 5:
		*bit = !!PHY5_SOFT_SMI_MDIO_READ;
		break;
	case 6:
		*bit = !!PHY6_SOFT_SMI_MDIO_READ;
		break;
	case 7:
		*bit = !!PHY7_SOFT_SMI_MDIO_READ;
		break;
	case 8:
		*bit = !!PHY8_SOFT_SMI_MDIO_READ;
		break;
	case 9:
		*bit = !!PHY9_SOFT_SMI_MDIO_READ;
		break;
	default:
		break;
	}


    // set clk.
	mdc_low(index);
	mdc_high(index);

}

u16 Srv_Yt8521_Soft_I2c_Device_Write(int index,u8 phy_addr, u8 reg_addr, u16 data)
{
	u16 i = 0;

    //idel
	for(i = 0; i < 32; i++)
	{
		Mcu_Yt8521_Soft_Smi_Bit_Set(index,1);
	}

	//start
	Mcu_Yt8521_Soft_Smi_Bit_Set(index,0);
	Mcu_Yt8521_Soft_Smi_Bit_Set(index,1);

	//op code
	Mcu_Yt8521_Soft_Smi_Bit_Set(index,0);
	Mcu_Yt8521_Soft_Smi_Bit_Set(index,1);

	//phy address
	for(i = 0; i < 5; i++)
	{
		if( phy_addr & (0x10 >> i) )
		{
			Mcu_Yt8521_Soft_Smi_Bit_Set(index,1);
		}
		else
		{
			Mcu_Yt8521_Soft_Smi_Bit_Set(index,0);
		}
	}

	//register address
	for(i = 0; i < 5; i++)
	{
		if( reg_addr & (0x10 >> i) )
		{
			Mcu_Yt8521_Soft_Smi_Bit_Set(index,1);
		}
		else
		{
			Mcu_Yt8521_Soft_Smi_Bit_Set(index,0);
		}
	}

	//TA翻转状态(ack)
	Mcu_Yt8521_Soft_Smi_Bit_Set(index,1);
	Mcu_Yt8521_Soft_Smi_Bit_Set(index,0);

	//register data
	for(i = 0; i < 16; i++)
	{
		if( data & (0x8000 >> i) )
		{
			Mcu_Yt8521_Soft_Smi_Bit_Set(index,1);
		}
		else
		{
			Mcu_Yt8521_Soft_Smi_Bit_Set(index,0);
		}
	}

	return 0;
}

u16 Srv_Yt8521_Soft_I2c_Device_Read(int index,u8 phy_addr, u8 reg_addr)
{
	u16 i = 0;
	u16 data = 0;     //待获取的数据
	u8  bit  = 0;

	//idel
	for(i = 0; i < 32; i++)
	{
		Mcu_Yt8521_Soft_Smi_Bit_Set(index,1);
	}

	//start
	Mcu_Yt8521_Soft_Smi_Bit_Set(index,0);
	Mcu_Yt8521_Soft_Smi_Bit_Set(index,1);

	//op code
	Mcu_Yt8521_Soft_Smi_Bit_Set(index,1);
	Mcu_Yt8521_Soft_Smi_Bit_Set(index,0);

	//phy address
	for(i = 0; i < 5; i++)
	{
		if( phy_addr & (0x10 >> i) )
		{
			Mcu_Yt8521_Soft_Smi_Bit_Set(index,1);
		}
		else
		{
			Mcu_Yt8521_Soft_Smi_Bit_Set(index,0);
		}
	}

	//register address
	for(i = 0; i < 5; i++)
	{
		if( reg_addr & (0x10 >> i) )
		{
			Mcu_Yt8521_Soft_Smi_Bit_Set(index,1);
		}
		else
		{
			Mcu_Yt8521_Soft_Smi_Bit_Set(index,0);
		}
	}

	//TA翻转状态(ack)
	Mcu_Yt8521_Soft_Smi_Bit_Get(index,&bit);
	Mcu_Yt8521_Soft_Smi_Bit_Get(index,&bit);

	//register data
	for(i = 0; i < 16; i++)
	{
		data<<=1;
		Mcu_Yt8521_Soft_Smi_Bit_Get(index,&bit);

		if(bit)
		{
			data |= 0x1;
		}
	}

	return data;
}

int main(int argc, char *argv[])
{
	int phy_index=0;
	int reg_addr=0;
	int value=0;
	u16 Reg_Value;
	if(argc<4)
	{
		printf("Usage mdio_test w/r phy_index[2,3,5,6,7,8,9] reg_addr [value]\n ");
		return 0;
	}

	if(argc==4)
	{
		phy_index=(uint16_t) strtoul(argv[2], NULL, 0);
		reg_addr=(uint16_t) strtoul(argv[3], NULL, 0);

		switch(phy_index)
		{
		case 2:
			Reg_Value=Srv_Yt8521_Soft_I2c_Device_Read(2,PHY2_YT8521_ADDR, reg_addr);
			printf("[READ]phy_index %d reg_addr 0x%x value is 0x%x\n",phy_index,reg_addr,Reg_Value);
			break;
		case 3:
			Reg_Value=Srv_Yt8521_Soft_I2c_Device_Read(3,PHY3_YT8521_ADDR, reg_addr);
			printf("[READ]phy_index %d reg_addr 0x%x value is 0x%x\n",phy_index,reg_addr,Reg_Value);
			break;
		case 5:
			Reg_Value=Srv_Yt8521_Soft_I2c_Device_Read(5,PHY5_YT8521_ADDR, reg_addr);
			printf("[READ]phy_index %d reg_addr 0x%x value is 0x%x\n",phy_index,reg_addr,Reg_Value);
			break;
		case 6:
			Reg_Value=Srv_Yt8521_Soft_I2c_Device_Read(6,PHY6_YT8521_ADDR, reg_addr);
			printf("[READ]phy_index %d reg_addr 0x%x value is 0x%x\n",phy_index,reg_addr,Reg_Value);
			break;
		case 7:
			Reg_Value=Srv_Yt8521_Soft_I2c_Device_Read(7,PHY7_YT8521_ADDR, reg_addr);
			printf("[READ]phy_index %d reg_addr 0x%x value is 0x%x\n",phy_index,reg_addr,Reg_Value);
			break;
		case 8:
			Reg_Value=Srv_Yt8521_Soft_I2c_Device_Read(8,PHY8_YT8521_ADDR, reg_addr);
			printf("[READ]phy_index %d reg_addr 0x%x value is 0x%x\n",phy_index,reg_addr,Reg_Value);
			break;
		case 9:
			Reg_Value=Srv_Yt8521_Soft_I2c_Device_Read(9,PHY9_YT8521_ADDR, reg_addr);
			printf("[READ]phy_index %d reg_addr 0x%x value is 0x%x\n",phy_index,reg_addr,Reg_Value);
			break;
		default:
			break;
		}


	}
	else if(argc==5)
	{
		phy_index=(uint16_t) strtoul(argv[2], NULL, 0);
		reg_addr=(uint16_t) strtoul(argv[3], NULL, 0);
		value=(uint16_t) strtoul(argv[4], NULL, 0);
		printf("[WRITE] phy_index is %d reg_addr is 0x%x value is 0x%x\n",phy_index,reg_addr,value);
		switch(phy_index)
		{
		case 2:
			Srv_Yt8521_Soft_I2c_Device_Write(2,PHY2_YT8521_ADDR, reg_addr,value);
			break;
		case 3:
			Srv_Yt8521_Soft_I2c_Device_Write(3,PHY3_YT8521_ADDR, reg_addr,value);
			break;
		case 5:
			Srv_Yt8521_Soft_I2c_Device_Write(5,PHY5_YT8521_ADDR, reg_addr,value);
			break;
		case 6:
			Srv_Yt8521_Soft_I2c_Device_Write(6,PHY6_YT8521_ADDR, reg_addr,value);
			break;
		case 7:
			Srv_Yt8521_Soft_I2c_Device_Write(7,PHY7_YT8521_ADDR, reg_addr,value);
			break;
		case 8:
			Srv_Yt8521_Soft_I2c_Device_Write(8,PHY8_YT8521_ADDR, reg_addr,value);
			break;
		case 9:
			Srv_Yt8521_Soft_I2c_Device_Write(9,PHY9_YT8521_ADDR, reg_addr,value);
			break;
		default:
			break;
		}
	}






#if 0
	u16 id = 0;

	printf("//***************** Read SMI Reg of YT8521 ******************//\r\n");
	printf("------ PHY Identification Registers ------\r\n");

	id = Srv_Yt8521_Soft_I2c_Device_Read(2,PHY2_YT8521_ADDR, PHY_YT8521_ID_REG_ADDR);   //reg_addr:0x03  读取的值应为0x11a
	printf("PHY2_YT8521 id = 0x%x\n", id);


	id = Srv_Yt8521_Soft_I2c_Device_Read(3,PHY3_YT8521_ADDR, PHY_YT8521_ID_REG_ADDR);   //reg_addr:0x03  读取的值应为0x11a
	printf("PHY3_YT8521 id = 0x%x\n", id);

	id = Srv_Yt8521_Soft_I2c_Device_Read(5,PHY5_YT8521_ADDR, PHY_YT8521_ID_REG_ADDR);   //reg_addr:0x03  读取的值应为0x11a
	printf("PHY5_YT8521 id = 0x%x\n", id);

	id = Srv_Yt8521_Soft_I2c_Device_Read(6,PHY6_YT8521_ADDR, PHY_YT8521_ID_REG_ADDR);   //reg_addr:0x03  读取的值应为0x11a
	printf("PHY6_YT8521 id = 0x%x\n", id);

	id = Srv_Yt8521_Soft_I2c_Device_Read(7,PHY7_YT8521_ADDR, PHY_YT8521_ID_REG_ADDR);   //reg_addr:0x03  读取的值应为0x11a
	printf("PHY7_YT8521 id = 0x%x\n", id);

	id = Srv_Yt8521_Soft_I2c_Device_Read(8,PHY8_YT8521_ADDR, PHY_YT8521_ID_REG_ADDR);   //reg_addr:0x03  读取的值应为0x11a
	printf("PHY8_YT8521 id = 0x%x\n", id);

	id = Srv_Yt8521_Soft_I2c_Device_Read(9,PHY9_YT8521_ADDR, PHY_YT8521_ID_REG_ADDR);   //reg_addr:0x03  读取的值应为0x11a
	printf("PHY9_YT8521 id = 0x%x\n", id);


    printf("Setting PHY2\n");
    Srv_Yt8521_Soft_I2c_Device_Write(2,PHY2_YT8521_ADDR, PHY_YT8521_REG_DEBUG_ADDR_OFFSET, PHY_YT8521_EXT_REG_ADDR);
    Srv_Yt8521_Soft_I2c_Device_Write(2,PHY2_YT8521_ADDR, PHY_YT8521_REG_DEBUG_DATA,0x604);

    printf("Setting PHY3\n");
    Srv_Yt8521_Soft_I2c_Device_Write(3,PHY3_YT8521_ADDR, PHY_YT8521_REG_DEBUG_ADDR_OFFSET, PHY_YT8521_EXT_REG_ADDR);
    Srv_Yt8521_Soft_I2c_Device_Write(3,PHY3_YT8521_ADDR, PHY_YT8521_REG_DEBUG_DATA,0x604);

    printf("Setting PHY5\n");
    Srv_Yt8521_Soft_I2c_Device_Write(5,PHY5_YT8521_ADDR, PHY_YT8521_REG_DEBUG_ADDR_OFFSET, PHY_YT8521_EXT_REG_ADDR);
    Srv_Yt8521_Soft_I2c_Device_Write(5,PHY5_YT8521_ADDR, PHY_YT8521_REG_DEBUG_DATA,0x604);

    printf("Setting PHY6\n");
    Srv_Yt8521_Soft_I2c_Device_Write(6,PHY6_YT8521_ADDR, PHY_YT8521_REG_DEBUG_ADDR_OFFSET, PHY_YT8521_EXT_REG_ADDR);
    Srv_Yt8521_Soft_I2c_Device_Write(6,PHY6_YT8521_ADDR, PHY_YT8521_REG_DEBUG_DATA,0x604);

    printf("Setting PHY7\n");
    Srv_Yt8521_Soft_I2c_Device_Write(7,PHY7_YT8521_ADDR, PHY_YT8521_REG_DEBUG_ADDR_OFFSET, PHY_YT8521_EXT_REG_ADDR);
    Srv_Yt8521_Soft_I2c_Device_Write(7,PHY7_YT8521_ADDR, PHY_YT8521_REG_DEBUG_DATA,0x604);

    printf("Setting PHY8\n");
    Srv_Yt8521_Soft_I2c_Device_Write(8,PHY8_YT8521_ADDR, PHY_YT8521_REG_DEBUG_ADDR_OFFSET, PHY_YT8521_EXT_REG_ADDR);
    Srv_Yt8521_Soft_I2c_Device_Write(8,PHY8_YT8521_ADDR, PHY_YT8521_REG_DEBUG_DATA,0x604);

    printf("Setting PHY9\n");
    Srv_Yt8521_Soft_I2c_Device_Write(9,PHY9_YT8521_ADDR, PHY_YT8521_REG_DEBUG_ADDR_OFFSET, PHY_YT8521_EXT_REG_ADDR);
    Srv_Yt8521_Soft_I2c_Device_Write(9,PHY9_YT8521_ADDR, PHY_YT8521_REG_DEBUG_DATA,0x604);
#endif


    return 0;
}

5、测试验证

读取裕太8521的PHY ID

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1249265.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue 2.0源码分析-Virtual DOM

Virtual DOM 这个概念相信大部分人都不会陌生&#xff0c;它产生的前提是浏览器中的 DOM 是很“昂贵"的&#xff0c;为了更直观的感受&#xff0c;我们可以简单的把一个简单的 div 元素的属性都打印出来&#xff0c;如图所示&#xff1a; 可以看到&#xff0c;真正的 DOM …

IDEA中的Postman?完全免费!

Postman是大家最常用的API调试工具&#xff0c;那么有没有一种方法可以不用手动写入接口到Postman&#xff0c;即可进行接口调试操作&#xff1f;今天给大家推荐一款IDEA插件&#xff1a;Apipost Helper&#xff0c;写完代码就可以调试接口并一键生成接口文档&#xff01;而且还…

用Python写一个浏览器集群框架

更多Python学习内容&#xff1a;ipengtao.com 在分布式爬虫和大规模数据采集的场景中&#xff0c;使用浏览器集群是一种有效的方式&#xff0c;可以提高数据采集的速度和效率。本文将介绍如何用Python编写一个简单但强大的浏览器集群框架&#xff0c;以应对需要使用多个浏览器实…

个人财务管理软件CheckBook Pro mac中文版特点介绍

CheckBook Pro mac是一款Mac平台的个人财务管理软件&#xff0c;主要用于跟踪个人收入、支出和账户余额等信息。 CheckBook Pro mac 软件特点 简单易用&#xff1a;该软件的用户界面非常简洁明了&#xff0c;即使您是初学者也可以轻松上手。 多账户管理&#xff1a;该软件支持…

一文彻底看懂Python切片,Python切片理解与操作

1.什么是切片 切片是Python中一种用于操作序列类型(如列表、字符串和元组)的方法。它通过指定起始索引和结束索引来截取出序列的一部分,形成一个新的序列。切片是访问特定范围内的元素,就是一个Area。 说个笑话:切片不是切片,而是切片,但是又是切片。大家理解下呢(末…

Shell循环:for(二)

一、通过用户列表文件创建用户 需求&#xff1a;通过用户列表文件创建用户 [rootlocalhost ~]# cat user.txt qian yoa huang演示&#xff1a; [rootlocalhost ~]# vim foruser.sh #编写脚本 #!/bin/bash for i in cat user.txt do useradd $i if [ $? -eq 0 ] thenech…

ErphpdownV16.21插件 安装教程和插件下载

ErphpdownV16.21插件下载_新版本 上传插件并解压 登入后台插件管理启动ErphpdownV16.21插件即可 启动后设置即可使用此版本为学习版插件 功能介绍&#xff1a; Erphpdown会员推广下载专业版 经过完美测试运行于wordpress 3.x-6.x版本。后续会增加更多实用的功能。已针对此插件…

多功能智能灯杆主要功能有哪些?

多功能智能灯杆这个词相信大家都不陌生&#xff0c;最近几年多功能智能灯杆行业发展迅速&#xff0c;迅速取代了传统路灯&#xff0c;那么多功能智能灯杆相比传统照明路灯好在哪里呢&#xff0c;为什么大家都选择使用叁仟智慧多功能智能灯杆呢&#xff1f;所谓多功能智能灯杆着…

电机应用-直流有刷电机多环控制实现

目录 直流有刷电机多环控制实现 硬件设计 直流电机三环&#xff08;速度环、电流环、位置环&#xff09;串级PID控制-位置式PID 编程要点 配置ADC可读取电流值 配置基本定时器6产生定时中断读取当前电路中驱动电机的电流值并执行PID运算 配置定时器1输出PWM控制电机 配…

nodejs微信小程序+python+PHP-书吧租阅管理系统的设计与实现-安卓-计算机毕业设计

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

canvas高级动画001:文字瀑布流

canvas实例应用100 专栏提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。 canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重要的帮助。 文章目录 示例…

什么是强化学习

1 概况 1.1 定义 强化学习&#xff08;Reinforcement Learning, RL&#xff09;是机器学习的一个重要分支&#xff0c;与监督学习和无监督学习并列。它主要涉及智能体&#xff08;agent&#xff09;在环境中通过学习如何做出决策。与监督学习的主动指导和无监督学习的数据探索…

volatile 关键字的作用是什么?它的实现原理是什么?

文章目录 volatile 关键字的作用是什么&#xff1f;它的实现原理是什么&#xff1f; 今天来聊一聊 volatile 这个关键字在java中的作用是什么&#xff0c;经常看到却不知道原理是什么&#xff0c;今天就带大家看看&#xff0c;开干。。。。 volatile 关键字的作用是什么&#x…

鸿蒙4.0开发笔记之DevEco Studio如何使用低代码开发模板进行开发的详细流程(六)

鸿蒙低代码开发 一、什么是低代码二、如何进行鸿蒙低代码开发1、 创建低代码开发工程&#xff08;方式壹&#xff09;2、已有工程则创建Visual文件&#xff08;方拾贰&#xff09; 三、低代码开发界面介绍四、低代码实现页面跳转五、低代码开发建议 一、什么是低代码 所谓低代码…

点大商城V2.5.3分包小程序端+小程序上传提示限制分包制作教程

这几天很多播播资源会员反馈点大商城V2.5.3小程序端上传时提示大小超限&#xff0c;官方默认单个包都不能超过2M&#xff0c;总分包不能超20M。如下图提示超了93KB&#xff0c;如果出现超的不多情况下可采用手动删除一些images目录下不使用的图片&#xff0c;只要删除超过100KB…

导入PIL时报错

在导入PIL时,报以下错误: 查找原因 参考博客 Could not find a version that satisfies the requirement PIL (from versions: ) No matching distributi-CSDN博客,按照wheel后,安装PIL时,报如下的错误。 查找说是python版本与wheel文件版本不同,确认本机python版本 …

仿 美图 / 饿了么,店铺详情页功能

前言 UI有所不同&#xff0c;但功能差不多&#xff0c;商品添加购物车功能 正在写&#xff0c;写完会提交仓库。 效果图一&#xff1a;左右RecyclerView 联动 效果图二&#xff1a;通过点击 向上偏移至最大值 效果图三&#xff1a;通过点击 或 拖动 展开收缩公告 效果图四&…

晨控CK-FR03-EIP读卡器与欧姆龙NX/NJ系列EtherNet/IP通讯手册

晨控CK-FR03-EIP读卡器与欧姆龙NX/NJ系列EtherNet/IP通讯手册 CK-FR03-EIP是一款基于射频识别技术的高频RFID标签读卡器&#xff0c;读卡器工作频率为13.56MHZ&#xff0c;支持对I-CODE 2、I-CODE SLI等符合ISO15693国际标准协议格式标签的读取。 读卡器同时支持标准工业通讯…

如何用低代码的思路设计文字描边渐变组件

前言 文字特效设计一直是困扰 Web 前端 Css 世界多年的问题, 比如如何用纯 Css 实现文字描边, 渐变, 阴影等, 由于受限于浏览器兼容性的问题, 我们不得不使用其他替代方案来实现. 平时工作中我们使用 PS 等设计工具能很容易的实现文字渐变等特效, 但是随着可视化技术的成熟, 我…

《Effective Modern C++》全书内容提炼总结

个人博客地址: https://cxx001.gitee.io 前言 C程序员都应该是对性能执着的人&#xff0c;想要彻底理解C11和C14&#xff0c;不可止步于熟悉它们引入的语言特性&#xff08;例如&#xff0c;auto型别推导、移动语义、lambda表达式&#xff0c;以及并发支持&#xff09;。挑战在…