HC32L190 实现模拟MDIO协议

一、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);

### 设置YT8511芯片以100Mbps速率运行 为了使YT8511芯片工作在100Mbps速率下,可以通过配置其寄存器来设定所需的工作参数。具体操作涉及以下几个方面: #### 配置基本设置 确保硬件连接正确无误之后,需要初始化PHY设备并进入特定的操作模式。通常情况下,默认会启用自协商功能,这允许两端设备自行决定最优的数据传输速率和双工模式。 如果希望强制指定为100Mbps全双工模式,则需禁用自协商过程,并直接写入相应的控制位到MII管理接口中的Basic Mode Control Register (BMCR)[^1]。 ```c // 假设已经定义好了MDIO访问函数mdio_write() void set_phy_to_100mbps_full_duplex(uint8_t phy_addr){ // Disable auto-negotiation and force 100Mbps full-duplex mode. mdio_write(phy_addr, MII_BMCR, BMCR_SPEED100 | BMCR_FULLDPLX); } ``` 上述代码片段展示了如何通过编程方式将PHY芯片固定在一个预选的速度上而不是依赖于自动协商的结果。这里假设存在一个用于执行MDIO读写的辅助函数`mdio_write()`以及一些必要的宏定义如`MII_BMCR`, `BMCR_SPEED100` 和 `BMCR_FULLDPLX`. 需要注意的是,在实际开发环境中可能还需要考虑其他因素比如链路伙伴的能力以及其他高级特性的影响,因此建议参照具体的器件数据表来进行更详细的配置[^2]. 对于某些特殊的应用场景而言,除了简单的速度切换外,还应该关注信号质量优化等问题,例如调整接收灵敏度或是发射功率等参数,这些都可以通过对内部寄存器的不同字段进行适当调节来完成[^3]. 最后值得注意的一点是在嵌入式系统中集成此类第三方组件时可能会遇到兼容性挑战,特别是当涉及到不同厂商提供的软件栈或中间件时。针对这种情况可以参考相关解决方案文档获取更多指导信息[^4].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chem4111

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值