| 
 
| 一、MDIO协议原理 
 1.硬件连接(控制引脚只有两个,一路MDC,一路MDIO)类似模拟iic 一路时钟线一路数据线
 
 
   
 2.协议帧
 
 (1)双向传输
 
 (2)先传高位,再传低位
 
 (3)MDIO相关管理寄存器  clause-22  总共32个寄存器 ,每个寄存器16bit
 
 IDLE: 空闲状态下MDIO总线是高阻态(中间态),外部上拉至高电平状态
 
 PRE:preamble前导码,32个连续的高电平bit位
 
 ST : 固定发送两bit 01表示数据传输开始
 
 OP:操作码,表示不同的操作类型 读(10)  写(01)
 
 PHYAD:5个bit位组成的32个地址,先传高位
 
 REGAD:  5个bit位组成的32个地址,先传高位
 
 TA :TurnAround 。介于寄存器地址和寄存器数据之间的两个bit位用来转换数据方向
 
 写操作:TA 由MAC芯片驱动成 10  ,写操作都是由MAC芯片驱动
 
 
   
 读操作:TA第一个bit mac和phy都必须将mdio驱动成高阻态 外部上拉高电平
 
 TA第二个bit 由PHY驱动MDIO 为低电平,驱动转移给PHY芯片
 
 
   
 DATA:16bit数据位
 
 写操作:MAC芯片驱动
 
 读操作:phy芯片驱动
 
 二、代码
 
 hd_mdio.c
 
 #include "hd_mdio.h"
 #include "gpio.h"
 #include "hd_gpt_timer.h"
 
 
 // 1us延时
 void delay_us(uint32_t us) {
 volatile uint32_t i;
 for (i = 0; i < us * (48 / 2); i++);
 }
 
 /**
 * @brief  Initialize GPIO pins for MDIO interface
 * @NOTE   Configures MDC as output and MDIO as bidirectional
 */
 void mdio_gpio_init(void) {
 stc_gpio_cfg_t stcGpioCfg;
 
 // Enable GPIO peripheral clock
 Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);
 
 // Configure MDC pin (always output)
 stcGpioCfg.enDir = GpioDirOut;
 stcGpioCfg.enPu = GpioPuDisable;
 stcGpioCfg.enPd = GpioPdDisable;
 stcGpioCfg.enDrv = GpioDrvH;       // High drive capability for MDC
 stcGpioCfg.enOD = GpioOdDisable;
 stcGpioCfg.enCtrlMode = GpioAHB;    // AHB control mode
 Gpio_Init(MDC_GPIO_PORT, MDC_PIN, &stcGpioCfg);
 
 // Configure MDIO pin (initial direction set to output)
 Gpio_Init(MDIO_GPIO_PORT, MDIO_PIN, &stcGpioCfg);
 }
 
 /**
 * @brief  Set MDIO pin as output
 * @note   Re-initializes the pin with output direction
 */
 void mdio_set_output(void) {
 stc_gpio_cfg_t stcGpioCfg;
 
 stcGpioCfg.enDir = GpioDirOut;
 stcGpioCfg.enPu = GpioPuDisable;
 stcGpioCfg.enPd = GpioPdDisable;
 stcGpioCfg.enDrv = GpioDrvH;
 stcGpioCfg.enOD = GpioOdDisable;
 stcGpioCfg.enCtrlMode = GpioAHB;
 
 Gpio_Init(MDIO_GPIO_PORT, MDIO_PIN, &stcGpioCfg);
 }
 
 /**
 * @brief  Set MDIO pin as input
 * @note   Re-initializes the pin with input direction
 */
 void mdio_set_input(void) {
 stc_gpio_cfg_t stcGpioCfg;
 
 stcGpioCfg.enDir = GpioDirIn;
 stcGpioCfg.enPu = GpioPuDisable;
 stcGpioCfg.enPd = GpioPdDisable;
 stcGpioCfg.enDrv = GpioDrvH;
 stcGpioCfg.enOD = GpioOdDisable;
 stcGpioCfg.enCtrlMode = GpioAHB;
 
 Gpio_Init(MDIO_GPIO_PORT, MDIO_PIN, &stcGpioCfg);
 }
 
 
 void mdio_write_bit(uint8_t bit) {
 mdio_set_output();
 if (bit) MDIO_HIGH(); else MDIO_LOW();
 delay_us(1);
 MDC_HIGH(); delay_us(1);
 MDC_LOW();  delay_us(1);
 }
 
 uint8_t mdio_read_bit(void) {
 uint8_t bit;
 mdio_set_input();
 delay_us(1);
 MDC_HIGH(); delay_us(1);
 bit = MDIO_READ();
 MDC_LOW(); delay_us(1);
 return bit;
 }
 
 void mdio_send_bits(uint16_t data, uint8_t len) {
 for (int i = len - 1; i >= 0; i--) {
 mdio_write_bit((data >> i) & 1);
 }
 }
 
 uint16_t mdio_read_bits(uint8_t len) {
 uint16_t val = 0;
 for (int i = len - 1; i >= 0; i--) {
 if (mdio_read_bit()) val |= (1 << i);
 }
 return val;
 }
 
 
 
 uint16_t mdio_read(uint8_t phy_addr, uint8_t reg_addr) {
 uint16_t val = 0;
 
 // 发送前导码(32个1)
 mdio_set_output();
 for(int i=0; i<32; i++) {
 mdio_write_bit(1);
 }
 
 // 发送读命令
 mdio_send_bits(0x06, 4); // 01(start) + 10(read)
 mdio_send_bits(phy_addr, 5);
 mdio_send_bits(reg_addr, 5);
 
 // 读取数据
 mdio_set_input();
 mdio_read_bit(); // 跳过turnaround
 val = mdio_read_bits(16);
 
 mdio_set_output();
 MDIO_HIGH(); // 释放总线
 
 return val;
 }
 
 void mdio_write(uint8_t phy_addr, uint8_t reg_addr, uint16_t data) {
 // 发送前导码(32个1)
 mdio_set_output();
 for(int i=0; i<32; i++) {
 mdio_write_bit(1);
 }
 
 // 发送写命令
 mdio_send_bits(0x05, 4); // 01(start) + 01(write)
 mdio_send_bits(phy_addr, 5);
 mdio_send_bits(reg_addr, 5);
 mdio_send_bits(0x02, 2); // turnaround
 mdio_send_bits(data, 16);
 
 MDIO_HIGH(); // 释放总线
 }
 
 
 hd_mdio.h
 
 #ifndef HD_MDIO_H
 #define HD_MDIO_H
 
 #include <stdbool.h>
 #include "gpio.h"
 
 
 #define MDC_GPIO_PORT     GpioPortA
 #define MDC_PIN           GpioPin0
 
 #define MDIO_GPIO_PORT    GpioPortA
 #define MDIO_PIN          GpioPin1
 
 #define MDC_HIGH() Gpio_SetIO(MDC_GPIO_PORT, MDC_PIN)
 #define MDC_LOW()  Gpio_ClrIO(MDC_GPIO_PORT, MDC_PIN)
 
 #define MDIO_HIGH() Gpio_SetIO(MDIO_GPIO_PORT, MDIO_PIN)
 #define MDIO_LOW()  Gpio_ClrIO(MDIO_GPIO_PORT, MDIO_PIN)
 #define MDIO_READ() Gpio_GetInputIO(MDIO_GPIO_PORT, MDIO_PIN)
 
 
 // PHY地址定义(根据硬件连接设置)
 #define PHY_ADDR_YT8531  0x01
 #define PHY_ADDR_YT8011  0x02
 
 
 void mdio_gpio_init(void);
 uint16_t mdio_read(uint8_t phy_addr, uint8_t reg_addr);
 void mdio_write(uint8_t phy_addr, uint8_t reg_addr, uint16_t data);
 
 #endif
 
 
 
 三、效果
 
 写时序  mdio_write(0x01, 0x03, 0x5555);
 
 
   
 ————————————————
 版权声明:本文为CSDN博主「chem4111」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
 原文链接:https://blog.csdn.net/weixin_46286415/article/details/148060125
 
 
 | 
 |