[综合信息] HC32L190 实现模拟MDIO协议

[复制链接]
214|0
Xiashiqi 发表于 2025-10-9 21:49 | 显示全部楼层 |阅读模式
一、MDIO协议原理

1.硬件连接(控制引脚只有两个,一路MDC,一路MDIO)类似模拟iic 一路时钟线一路数据线

993968e7697308429.png

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芯片驱动

9735068e7696d6f2b2.png

        读操作:TA第一个bit mac和phy都必须将mdio驱动成高阻态 外部上拉高电平

                        TA第二个bit 由PHY驱动MDIO 为低电平,驱动转移给PHY芯片

2674668e7696797c67.png

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

8952168e76949a61e9.png

————————————————
版权声明:本文为CSDN博主「chem4111」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_46286415/article/details/148060125

您需要登录后才可以回帖 登录 | 注册

本版积分规则

97

主题

282

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部