zoukankan      html  css  js  c++  java
  • gpio模拟mdio代码

    MDIO接口包括两根信号线:MDC和MDIO,通过它,MAC层芯片(或其它控制芯片)可以访问物理层芯片的寄存器。作为MA和PHY之间的控制总线,数据总线是RMII/MII。、

    其实mdio和I2C接口非常类似,是为了规避专利,特意重新命名了一种总线。

    下面是使用gpio模拟mdc/mdio通信,经过验证,此代码可行。

    #include <string.h>
    #include <stddef.h>
    #include <stdint.h>
    #include "soc.h"
    #include "irq.h"
    #include "bios.h"
    #include "gpio.h"
    
    /* bb:bit-bang,通过gpio引脚,用软件模拟通信*/
    #define MDIO_PORT			GPIO7
    #define MDIO_PIN 			GPIO_Pin_9
    #define MDC_PORT 			GPIO7
    #define MDC_PIN 			GPIO_Pin_10
    
    #define MDIO_DELAY 			10			// us
    #define MDIO_READ_DELAY 	10			// us
    
    /*  Or MII_ADDR_C45 into regnum for read/write on mii_bus to enable the 21 bit
    *   IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips.
    */
    #define MII_ADDR_C45 (1<<30)
    
    #define MDIO_READ 2
    #define MDIO_WRITE 1
    
    #define MDIO_C45 (1<<15)
    #define MDIO_C45_ADDR (MDIO_C45 | 0)
    #define MDIO_C45_READ (MDIO_C45 | 3)
    #define MDIO_C45_WRITE (MDIO_C45 | 1)
    
    
    
    //#define READ_REG 0x37
    //#define WRITE_REG 0x38
    
    
    #define MDIO_C45_TEST 0
    
    
    typedef struct gpio_ctrl_blk{
        int pin;
        int value;
    }gpio_cblk_t;
    
    typedef struct phy_reg_blk{
        unsigned int phy_address;
        unsigned int reg_address;
        unsigned int reg_value;
    }phy_reg_cblk_t;
    
    
    #define MDIO_DEV_ID 't'
    #define READ_REG             _IOWR (MDIO_DEV_ID,0x37,phy_reg_cblk_t)
    #define WRITE_REG            _IOWR (MDIO_DEV_ID,0x38,phy_reg_cblk_t)
    static void MDC_OUT(void);
    static void MDIO_OUT(void);
    static void MDIO_IN(void);
    static void MDC_H(void);
    static void MDC_L(void);
    static int GET_MDIO(void);
    static void SET_MDIO(int val);
    
    
    /* 设置MDC为输出引脚,在MDC输出时钟之前设置 */
    static void MDC_OUT(void)
    {
    	struct gpio_cfg cfg;
    
    	cfg.pins = MDC_PIN;
    	cfg.dir = GPIO_OUT;
    	cfg.irq_mode = GPIO_IRQ_DISABLE;
    	gpio_init(MDC_PORT, &cfg);
    }
    
    /* 设置MDIO的gpio引脚为输出引脚 */
    static void MDIO_OUT(void)
    {
    	struct gpio_cfg cfg;
    
    	cfg.pins = MDIO_PIN;
    	cfg.dir = GPIO_OUT;
    	cfg.irq_mode = GPIO_IRQ_DISABLE;
    	gpio_init(MDIO_PORT, &cfg);
    }
    
    /* 设置MDIO的gpio引脚为输入引脚 */
    static void MDIO_IN(void)
    {
    	struct gpio_cfg cfg;
    
    	cfg.pins = MDIO_PIN;
    	cfg.dir = GPIO_IN;
    	cfg.irq_mode = GPIO_IRQ_DISABLE;
    	gpio_init(MDIO_PORT, &cfg);
    }
    
    /* MDC输出高电平,在MDC设置为输出后调用 */
    static void MDC_H(void)
    {
    	gpio_write_pin(MDC_PORT, MDC_PIN, GPIO_OUTPUT_HIGH);
    }
    
    /* MDC输出低电平,在MDC设置为输出后调用 */
    static void MDC_L(void)
    {
    	gpio_write_pin(MDC_PORT, MDC_PIN, GPIO_OUTPUT_LOW);
    }
    
    /* 获得MDIO的数据,只获得一个bit */
    static int GET_MDIO(void)
    {
    	return gpio_read_input_pin(MDIO_PORT, MDIO_PIN);
    }
    
    /* 设置MDIO的数据,一个bit */
    static void SET_MDIO(int val)
    {
    	gpio_write_pin(MDIO_PORT, MDIO_PIN, val);
    }
    
    
    /* MDIO发送一个bit的数据,MDIO必须已经被配置为输出 */
    static void mdio_bb_send_bit(int val)
    {
        MDC_OUT();
        SET_MDIO(val);
        bios_udelay(MDIO_DELAY);
        MDC_H();
        bios_udelay(MDIO_DELAY);
        MDC_L();
        //bios_udelay(MDIO_DELAY);
    }
    
    /*  MDIO 获取一个bit的数据,MDIO必须已经被配置为输入. */
    static int mdio_bb_get_bit(void)
    {
        int value;
    
        MDC_OUT();
        bios_udelay(MDIO_DELAY);
        MDC_H();
        bios_udelay(MDIO_READ_DELAY);
        value = GET_MDIO();
    //  bios_udelay(MDIO_DELAY);
        MDC_L();
    
        return value;
    }
    
     /*
      *  MDIO发送一个数据,MDIO 必须被配置为输出模式.
      *  value:要发送的数据
      *  bits:数据的位数
      *
      *  */
    static void mdio_bb_send_num(unsigned int value ,int bits)
    {
        int i;
        MDIO_OUT();
    
        for(i = bits - 1; i >= 0; i--)
            mdio_bb_send_bit((value >> i) & 1);
    }
    
    /*
      *  MDIO获取一个数据,MDIO 必须被配置为输入模式.
      *  bits:获取数据的位数
      *
      *  */
    static int mdio_bb_get_num(int bits)
    {
        int i;
        int ret = 0;
        for(i = bits - 1; i >= 0; i--)
        {
            ret <<= 1;
            ret |= mdio_bb_get_bit();
        }
    
        return ret;
    }
    
    /*  Utility to send the preamble, address, and
     *   register (common to read and write).
     */
    static void mdio_bb_cmd(int op,int phy,int reg)
    {
        int i = 0 ;
        MDIO_OUT();  //设置MDIO引脚为输出引脚
    
        /*发送32bit的1,这个帧前缀域不是必须的,某些物理层芯片的MDIO操作就没有这个域*/
        for(i = 0; i < 32; i++)
            mdio_bb_send_bit(1);
    
    
        /* 发送开始位(01),和读操作码(10),写操作码(01)
         * Clause 45 操作,开始位是(00),(11)为读,(10)为写
        */
    
    #if MDIO_C45_TEST
        mdio_bb_send_bit(0);
       if(op & MDIO_C45)
            mdio_bb_send_bit(0);
        else
            mdio_bb_send_bit(1);
    
    #else
        mdio_bb_send_bit(0);
        mdio_bb_send_bit(1);
    
    #endif
        mdio_bb_send_bit((op >> 1) & 1);
        mdio_bb_send_bit((op >> 0) & 1);
    
        mdio_bb_send_num(phy,5);
        mdio_bb_send_num(reg,5);
    
    }
    
    static int mdio_bb_cmd_addr(int phy,int addr)
    {
        unsigned int dev_addr = (addr >> 16) & 0x1F;
        unsigned int reg = addr & 0xFFFF;
    
        mdio_bb_cmd(MDIO_C45_ADDR,phy,dev_addr);
    
        /*  send the turnaround (10) */
        mdio_bb_send_bit(1);
        mdio_bb_send_bit(0);
    
        mdio_bb_send_num(reg,16);
    
        MDIO_IN();
        mdio_bb_get_bit();
    
        return dev_addr;
    }
    
    void mdio_set_turnaround(void)
    {
        int i = 0;
    
        MDIO_IN();
        MDC_OUT();
        for(i=0;i<1;i++)
        {
            bios_udelay(MDIO_DELAY);
            MDC_H();
            bios_udelay(MDIO_DELAY);
            MDC_L();
        }
    }
    
    unsigned int mdio_bb_read(int phy,int reg)
    {
        unsigned int ret,i;
    
    #if MDIO_C45_TEST
        /* 寄存器是否满足有C45标志 */
        if(reg & MII_ADDR_C45)
        {
            reg = mdio_bb_cmd_addr(phy,reg);
            mdio_bb_cmd(MDIO_C45_READ,phy,reg);
        }
        else
            mdio_bb_cmd(MDIO_READ,phy,reg);
    #else
            mdio_bb_cmd(MDIO_READ,phy,reg);
    #endif
    
        MDIO_IN();
        //mdio_set_turnaround();
    #if 1
        /*  check the turnaround bit: the PHY should be driving it to zero */
        if(mdio_bb_get_bit() != 0)
        {
            /* PHY didn't driver TA low -- flush any bits it may be trying to send*/
            for(i = 0; i < 32; i++)
                mdio_bb_get_bit();
            //bios_log("PHY didn't driver TA low! 
    ");
            return 0xFFFF;
        }
    #endif
        ret = mdio_bb_get_num(16);
        mdio_bb_get_bit();
    
        return ret;
    }
    
    
    
    int mdio_bb_write(unsigned int phy,unsigned int reg,unsigned int val)
    {
    #if MDIO_C45_TEST
        if(reg & MII_ADDR_C45)
        {
            reg = mdio_bb_cmd_addr(phy,reg);
            mdio_bb_cmd(MDIO_C45_WRITE,phy,reg);
        }
        else
            mdio_bb_cmd(MDIO_WRITE,phy,reg);
    #else
            mdio_bb_cmd(MDIO_WRITE,phy,reg);
    #endif
    
    
    #if 1
        /*  send the turnaround (10) */
        mdio_bb_send_bit(1);
        mdio_bb_send_bit(0);
    #else
        mdio_set_turnaround();
    #endif
        mdio_bb_send_num(val,16);
    
        MDIO_IN();
        //mdio_bb_get_bit();
    
        return 0;
    }
    
    int mdio_init(int id)
    {
    	// set PAD49/PAD50 as gpio
    	*(volatile uint32_t *)(SYSCTL_BASE + 0x78) &= ~(0xF << 8);
    	*(volatile uint32_t *)(SYSCTL_BASE + 0x78) &= ~(0xF << 4);
    }
    

      

  • 相关阅读:
    1602液晶显示实验
    LNMP安装(二)
    LNMP安装(一)
    vim插件安装
    资料下载
    建表的sql
    time
    计算机里的加减乘除
    branch
    存储过程
  • 原文地址:https://www.cnblogs.com/mic-chen/p/14717709.html
Copyright © 2011-2022 走看看