Lan8720 网线插拔状态检测

目的:能够实时的检测网线的插拔状态。并能够根据网线的插拔状态通知到到应用层,让应用层做相应的处理。

1.解决问题的根本方法就是看lan8720的数据手册!!!!

如果说你用过一款芯片,而没有去研究过它的数据手册时,可以说你没有用过这个芯片。

在Lan8720数据手册的第48页给出了这个芯片的控制和状态寄存器资料。因为我们是要用来检测lan8720连接网线的状态,所以这个状态应该是属于Basic Status Register这个类别的。

我们跳转到这个寄存器的说明:

Lan8720 网线插拔状态检测_第1张图片Lan8720 网线插拔状态检测_第2张图片

红色框框圈出来的是Lan8720的速度以及状态,因为这个是一款10/100M自适应的以太网芯片,所以就有了10M和100M的速度模式的检测。我们可以看到LinK Status状态位是这个寄存器的第2位,我们只需要读取这个寄存器得到的值,然后对这个值的第二位进行与1运算,该位与1得到1则说明网线连接正常,该位与1得到0则说明网线连接断开。

在刚开始验证RTT的这部分代码时,没有细看这个功能,后来想到这个问题的时候,重新看了一遍代码,发现RTT也做了这部分的检测,只是我们没有把调试日志打开,所以没有看到这部分的功能。

检测的代码如下:[摘自RTT]

/* PHY: LAN8720 */
static uint8_t phy_speed = 0;
#define PHY_LINK_MASK       (1<<0)    //1左移0位,结果还是1
#define PHY_100M_MASK       (1<<1)    //1左移1位,结果是2
#define PHY_DUPLEX_MASK     (1<<2)    //1左移2位,结果是4
static void phy_monitor_thread_entry(void *parameter)
{
    uint8_t phy_addr = 0xFF;
    uint8_t phy_speed_new = 0;

    /* phy search */
    {
        rt_uint32_t i;
        rt_uint16_t temp;

        for(i=0; i<=0x1F; i++)
        {
            temp = ETH_ReadPHYRegister(i, 0x02);

            if( temp != 0xFFFF )
            {
                phy_addr = i;
                break;
            }
        }
    } /* phy search */

    if(phy_addr == 0xFF)
    {
        STM32_ETH_PRINTF("phy not probe!\r\n");
        return;
    }
    else
    {
        STM32_ETH_PRINTF("found a phy, address:0x%02X\r\n", phy_addr);
    }

    /* RESET PHY */
    STM32_ETH_PRINTF("RESET PHY!\r\n");
    ETH_WritePHYRegister(phy_addr, PHY_BCR, PHY_Reset);
    rt_thread_delay(RT_TICK_PER_SECOND * 2);
    ETH_WritePHYRegister(phy_addr, PHY_BCR, PHY_AutoNegotiation);

    while(1)
    {
        uint16_t status  = ETH_ReadPHYRegister(phy_addr, PHY_BSR);//读取Basic Status Register的值
        STM32_ETH_PRINTF("LAN8720 status:0x%04X\r\n", status);

        phy_speed_new = 0;

        if(status & (PHY_AutoNego_Complete | PHY_Linked_Status))
        {
            uint16_t SR;

            SR = ETH_ReadPHYRegister(phy_addr, 31);
            STM32_ETH_PRINTF("LAN8720 REG 31:0x%04X\r\n", SR);

            SR = (SR >> 2) & 0x07; /* LAN8720, REG31[4:2], Speed Indication. */
            phy_speed_new = PHY_LINK_MASK;

            if((SR & 0x03) == 2)
            {
                phy_speed_new |= PHY_100M_MASK;
            }

            if(SR & 0x04)
            {
                phy_speed_new |= PHY_DUPLEX_MASK;
            }
        }

        /* linkchange */
        if(phy_speed_new != phy_speed)
        {
            if(phy_speed_new & PHY_LINK_MASK)//和1进行&运算,得1,则代表连接。否则,断开
            {
                STM32_ETH_PRINTF("link up ");

                if(phy_speed_new & PHY_100M_MASK)
                {
                    STM32_ETH_PRINTF("100Mbps");
                    stm32_eth_device.ETH_Speed = ETH_Speed_100M;
                }
                else
                {
                    stm32_eth_device.ETH_Speed = ETH_Speed_10M;
                    STM32_ETH_PRINTF("10Mbps");
                }

                if(phy_speed_new & PHY_DUPLEX_MASK)
                {
                    STM32_ETH_PRINTF(" full-duplex\r\n");
                    stm32_eth_device.ETH_Mode = ETH_Mode_FullDuplex;
                }
                else
                {
                    STM32_ETH_PRINTF(" half-duplex\r\n");
                    stm32_eth_device.ETH_Mode = ETH_Mode_HalfDuplex;
                }
                rt_stm32_eth_init((rt_device_t)&stm32_eth_device);

                /* send link up. */
                //网线正常连接,通知上层应用
                //可以根据自己的需求进行修改
                eth_device_linkchange(&stm32_eth_device.parent, RT_TRUE);
            } /* link up. */
            else
            {
                STM32_ETH_PRINTF("link down\r\n");
                /* send link down. */
                //网线断开,通知上层应用
                ////可以根据自己的需求进行修改
                eth_device_linkchange(&stm32_eth_device.parent, RT_FALSE);
            } /* link down. */

            phy_speed = phy_speed_new;
        } /* linkchange */

        rt_thread_delay(RT_TICK_PER_SECOND);
    } /* while(1) */
}

只需要其一个线程来实时监测即可。

如果是裸机代码,把while循环去掉,里面相关延时去掉。将其放入主程序的大循环中,定时器起一个标志定时检测即可。

你可能感兴趣的:(Lwip学习)