RTthread 网络之 8720A DP83848

发布于 2020-11-20 10:04:14

项目背景

  • 公司有个项目做UWB精准室内定位,需要用到网络通讯功能,在开始做之前我直接买了两个开发板上面的网络是 8720A 和 DP83848,我直接移植通过后,网络测试ping通正常,后期自己也参照8720A画了一个板子,正常使用。但是到了项目中后期,我测试稳定性的时候现在出现了问题,请允许我求助,分享,希望大佬们有遇到过的给予帮助,小弟在此万分感谢!!!

8720A

  • 先上原理图和引脚设置

8720A原理图.png
8720A引脚初始化.png
上面这部分直接在CubeMx中生成的。

  • 配置1-自适应关闭 + 100M + 全双工
  1. 配置代码

8720A网络自适应100M全双工.png

  1. Hal库函数调用,这里我们只关心寄存器配置方面

a.png
b.png
c.png

  1. 关于寄存器,这里面涉及到几个Phy芯片的寄存器,我们对照手册看一下

d.png
bcr.png
bsr.png
physr.png
8720寄存器bit.png
gg.png

  1. Rtthread 后面启动一个线程时刻观测Phy状态,我们可以看到这里复位了一下,然后开启自适应,执行一次phy_linkchange,接下来通过软件定时器不停的执行.

phylinkchange.png

  1. 这里面看一下这部分代码

phylinkchange-2.png

  1. 这里面的寄存器配置又换成了RTthread中的寄存器配置

phylinkchange-3.png

  • 观测现象
  1. 这个时候状态寄存器,BSR(01) == 0x782D; PSR(1F)= 0

现象1.png
比较奇怪为什么 PSR 会等于 0 呢?

  1. ping通状态,这时候可以ping通,时间比较久是因为开启了调试,但是Frame Failed

现象2.png
现象2-1.png

  1. Debug 查看进入中断

现象3.png

  • 结论
  1. 这个时候我可以知道,开启自适应模式,芯片自适应到了 10M 半双工模式,正常触发中断,可以ping通。
  • 修改
  1. 修改rtthread线程,关闭自适应功能

hh.png

  • 观测现象

1.这个时候状态寄存器,BSR(01) == 0x782D; PSR(1F)= 0
现象1-1.png

  1. ping通状态,这时候可以ping通,时间比较久是因为开启了调试,但是Frame Failed
  2. 中断正常触发
  • 疑问

1.配置修改自适应, 依旧是10M,Half

EthHandle.Init.AutoNegotiation = ETH_AUTONEGOTIATION_DISABLE;

2.线程中屏蔽自适应,依旧是10M,Half

    /* RESET PHY */
    LOG_D("RESET PHY!");
    HAL_ETH_WritePHYRegister(&EthHandle, PHY_BASIC_CONTROL_REG, PHY_RESET_MASK);
    rt_thread_mdelay(2000);
    HAL_ETH_WritePHYRegister(&EthHandle, PHY_BASIC_CONTROL_REG, PHY_AUTO_NEGOTIATION_MASK);
  1. PSR(1F) 读取为什么一直都是0
  2. 为什么Frame Failed

关于DP83848 问题我追贴描述,现在要开会啦。。。

查看更多

关注者
0
被浏览
105
2 个回答
aozima
aozima 2020-11-20
拒绝白嫖,拒绝键盘侠!
开启自适应模式,芯片自适应到了 10M 半双工模式

感觉板子硬件设计没达标,建议换个开发板来验证下。

分析总结步骤不错的,赞一个。
代码标签不要用全角字符,帮你修改了一下。

zhujie
zhujie 2020-11-20

DP83848

  • 先上原理图

Dp83848原理图.png

  1. 也是用的RMII接口,但是应该注意这个开发板选用的是有源晶振
  2. 开发板上的Reset 引脚是和单片机 复位连接在一起的,不受我控制
  • 配置代码及寄存器设置代码
  1. 配置代码同8720A
  2. 寄存器配置代码这里面需要对照DataSheet看一下

Reg-1.png
Reg-2.png
Reg2-1.png
Reg2-2.png
Reg2-3.1.png
Reg2-3.2.png

  1. 对应修改 Hal 中的寄存器配置位 和 drv_eth.h 中的配置位
/* DP83848_PHY_ADDRESS Address*/
#define DP83848_PHY_ADDRESS           1U
/* PHY Reset delay these values are based on a 1 ms Systick interrupt*/
#define PHY_RESET_DELAY                 ((uint32_t)0x00FFFFFFU)
/* PHY Configuration delay */
#define PHY_CONFIG_DELAY                ((uint32_t)0x00000FFFU)

#define PHY_READ_TO                     ((uint32_t)0x0000FFFFU)
#define PHY_WRITE_TO                    ((uint32_t)0x0000FFFFU)

/* Section 3: Common PHY Registers */

#define PHY_BCR                         ((uint16_t)0x00U)    /*!< Transceiver Basic Control Register   */
#define PHY_BSR                         ((uint16_t)0x01U)    /*!< Transceiver Basic Status Register    */

#define PHY_RESET                       ((uint16_t)0x8000U)  /*!< PHY Reset */
#define PHY_LOOPBACK                    ((uint16_t)0x4000U)  /*!< Select loop-back mode */
#define PHY_FULLDUPLEX_100M             ((uint16_t)0x2100U)  /*!< Set the full-duplex mode at 100 Mb/s */
#define PHY_HALFDUPLEX_100M             ((uint16_t)0x2000U)  /*!< Set the half-duplex mode at 100 Mb/s */
#define PHY_FULLDUPLEX_10M              ((uint16_t)0x0100U)  /*!< Set the full-duplex mode at 10 Mb/s  */
#define PHY_HALFDUPLEX_10M              ((uint16_t)0x0000U)  /*!< Set the half-duplex mode at 10 Mb/s  */
#define PHY_AUTONEGOTIATION             ((uint16_t)0x1000U)  /*!< Enable auto-negotiation function     */
#define PHY_RESTART_AUTONEGOTIATION     ((uint16_t)0x0200U)  /*!< Restart auto-negotiation function    */
#define PHY_POWERDOWN                   ((uint16_t)0x0800U)  /*!< Select the power down mode           */
#define PHY_ISOLATE                     ((uint16_t)0x0400U)  /*!< Isolate PHY from MII                 */

#define PHY_AUTONEGO_COMPLETE           ((uint16_t)0x0020U)  /*!< Auto-Negotiation process completed   */
#define PHY_LINKED_STATUS               ((uint16_t)0x0004U)  /*!< Valid link established               */
#define PHY_JABBER_DETECTION            ((uint16_t)0x0002U)  /*!< Jabber condition detected            */

/* Section 4: Extended PHY Registers */
#define PHY_SR                          ((uint16_t)0x10U)    /*!< PHY status register Offset           */

#define PHY_LINK_STATUS                 ((uint16_t)0x0001U)  /*!< PHY Link mask                        */
#define PHY_SPEED_STATUS                ((uint16_t)0x0002U)  /*!< PHY Speed mask                       */
#define PHY_DUPLEX_STATUS               ((uint16_t)0x0004U)  /*!< PHY Duplex mask                      */
// 为了防止寄存器配置错误,我把不使用的配置寄存器都屏蔽了
/* The PHY basic control register */
#define PHY_BASIC_CONTROL_REG       0x00U
#define PHY_RESET_MASK              (1<<15)
#define PHY_AUTO_NEGOTIATION_MASK   (1<<12)

/* The PHY basic status register */
#define PHY_BASIC_STATUS_REG        0x01U
#define PHY_LINKED_STATUS_MASK      (1<<2)
#define PHY_AUTONEGO_COMPLETE_MASK  (1<<5)

/* The PHY ID one register */
#define PHY_ID1_REG                 0x02U

///* The PHY ID two register */
//#define PHY_ID2_REG                 0x03U

///* The PHY auto-negotiate advertise register */
//#define PHY_AUTONEG_ADVERTISE_REG   0x04U


#ifdef PHY_USING_DP83848C
#define PHY_Status_REG              0x10U
#define PHY_10M_MASK                (1<<1)
#define PHY_FULL_DUPLEX_MASK        (1<<2)
#define PHY_Status_SPEED_10M(sr)    ((sr) & PHY_10M_MASK)
#define PHY_Status_SPEED_100M(sr)   (!PHY_Status_SPEED_10M(sr))
#define PHY_Status_FULL_DUPLEX(sr)  ((sr) & PHY_FULL_DUPLEX_MASK)

/*  The PHY interrupt source flag register. */
//#define PHY_INTERRUPT_FLAG_REG      0x12U
//#define PHY_LINK_CHANGE_FLAG        (1<<13)
///*  The PHY interrupt control register. */
//#define PHY_INTERRUPT_CTRL_REG      0x11U
//#define PHY_INTERRUPT_EN            ((1<<0)|(1<<1))
///*  The PHY interrupt mask register. */
//#define PHY_INTERRUPT_MASK_REG      0x12U
//#define PHY_INT_MASK                (1<<5)
#endif /* PHY_USING_DP83848C */
  • 修改 1
  1. 配置代码关闭自适应
    __HAL_RCC_ETH_CLK_ENABLE();

    /* ETHERNET Configuration */
    EthHandle.Instance = ETH;
    EthHandle.Init.MACAddr = (rt_uint8_t *)&stm32_eth_device.dev_addr[0];
    EthHandle.Init.AutoNegotiation = ETH_AUTONEGOTIATION_DISABLE;
    EthHandle.Init.Speed = ETH_SPEED_100M;
    EthHandle.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
    EthHandle.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
    EthHandle.Init.RxMode = ETH_RXINTERRUPT_MODE;
#ifdef RT_LWIP_USING_HW_CHECKSUM
    EthHandle.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
#else
    EthHandle.Init.ChecksumMode = ETH_CHECKSUM_BY_SOFTWARE;
#endif
  1. Rtthread 线程中关闭自适应
static void phy_monitor_thread_entry(void *parameter)
{
    uint8_t phy_addr = 0xFF;
    uint8_t detected_count = 0;

    while(phy_addr == 0xFF)
    {
        /* phy search */
        rt_uint32_t i, temp;
        for (i = 0; i <= 0x1F; i++)
        {
            EthHandle.Init.PhyAddress = i;
            HAL_ETH_ReadPHYRegister(&EthHandle, PHY_ID1_REG, (uint32_t *)&temp);

            if (temp != 0xFFFF && temp != 0x00)
            {
                phy_addr = i;
                break;
            }
        }

        detected_count++;
        rt_thread_mdelay(1000);

        if (detected_count > 10)
        {
            LOG_E("No PHY device was detected, please check hardware!");
        }
    }

    LOG_D("Found a phy, address:0x%02X", phy_addr);

//    /* RESET PHY */
//    LOG_D("RESET PHY!");
//    HAL_ETH_WritePHYRegister(&EthHandle, PHY_BASIC_CONTROL_REG, PHY_RESET_MASK);
//    rt_thread_mdelay(2000);
//    HAL_ETH_WritePHYRegister(&EthHandle, PHY_BASIC_CONTROL_REG, PHY_AUTO_NEGOTIATION_MASK);

    phy_linkchange();
#ifdef PHY_USING_INTERRUPT_MODE
    /* configuration intterrupt pin */
    rt_pin_mode(PHY_INT_PIN, PIN_MODE_INPUT_PULLUP);
    rt_pin_attach_irq(PHY_INT_PIN, PIN_IRQ_MODE_FALLING, eth_phy_isr, (void *)"callbackargs");
    rt_pin_irq_enable(PHY_INT_PIN, PIN_IRQ_ENABLE);

    /* enable phy interrupt */
    HAL_ETH_WritePHYRegister(&EthHandle, PHY_INTERRUPT_MASK_REG, PHY_INT_MASK);
#if defined(PHY_INTERRUPT_CTRL_REG)
    HAL_ETH_WritePHYRegister(&EthHandle, PHY_INTERRUPT_CTRL_REG, PHY_INTERRUPT_EN);
#endif
#else /* PHY_USING_INTERRUPT_MODE */
    stm32_eth_device.poll_link_timer = rt_timer_create("phylnk", (void (*)(void*))phy_linkchange,
                                        NULL, RT_TICK_PER_SECOND, RT_TIMER_FLAG_PERIODIC);
    if (!stm32_eth_device.poll_link_timer || rt_timer_start(stm32_eth_device.poll_link_timer) != RT_EOK)
    {
        LOG_E("Start link change detection timer failed");
    }
#endif /* PHY_USING_INTERRUPT_MODE */
}
  • 修改1-实验结果

结果1.png

  1. 此时可以发现 100M 半双工
  2. BSR(01) = 0x786D; PHY_Status_REG(10) = 0
  3. 正常触发中断
  4. 可以ping通
  • 修改 2
  1. 修改配置代码为 自适应
    __HAL_RCC_ETH_CLK_ENABLE();

    /* ETHERNET Configuration */
    EthHandle.Instance = ETH;
    EthHandle.Init.MACAddr = (rt_uint8_t *)&stm32_eth_device.dev_addr[0];
    EthHandle.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;
    EthHandle.Init.Speed = ETH_SPEED_100M;
    EthHandle.Init.DuplexMode = ETH_MODE_FULLDUPLEX;
    EthHandle.Init.MediaInterface = ETH_MEDIA_INTERFACE_RMII;
    EthHandle.Init.RxMode = ETH_RXINTERRUPT_MODE;
#ifdef RT_LWIP_USING_HW_CHECKSUM
    EthHandle.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
#else
    EthHandle.Init.ChecksumMode = ETH_CHECKSUM_BY_SOFTWARE;
#endif
  1. 开启 Rtthread 线程中的Reset 和自适应

static void phy_monitor_thread_entry(void *parameter)
{
    uint8_t phy_addr = 0xFF;
    uint8_t detected_count = 0;

    while(phy_addr == 0xFF)
    {
        /* phy search */
        rt_uint32_t i, temp;
        for (i = 0; i <= 0x1F; i++)
        {
            EthHandle.Init.PhyAddress = i;
            HAL_ETH_ReadPHYRegister(&EthHandle, PHY_ID1_REG, (uint32_t *)&temp);

            if (temp != 0xFFFF && temp != 0x00)
            {
                phy_addr = i;
                break;
            }
        }

        detected_count++;
        rt_thread_mdelay(1000);

        if (detected_count > 10)
        {
            LOG_E("No PHY device was detected, please check hardware!");
        }
    }

    LOG_D("Found a phy, address:0x%02X", phy_addr);

    /* RESET PHY */
    LOG_D("RESET PHY!");
    HAL_ETH_WritePHYRegister(&EthHandle, PHY_BASIC_CONTROL_REG, PHY_RESET_MASK);
    rt_thread_mdelay(2000);
    HAL_ETH_WritePHYRegister(&EthHandle, PHY_BASIC_CONTROL_REG, PHY_AUTO_NEGOTIATION_MASK);

    phy_linkchange();
#ifdef PHY_USING_INTERRUPT_MODE
    /* configuration intterrupt pin */
    rt_pin_mode(PHY_INT_PIN, PIN_MODE_INPUT_PULLUP);
    rt_pin_attach_irq(PHY_INT_PIN, PIN_IRQ_MODE_FALLING, eth_phy_isr, (void *)"callbackargs");
    rt_pin_irq_enable(PHY_INT_PIN, PIN_IRQ_ENABLE);

    /* enable phy interrupt */
    HAL_ETH_WritePHYRegister(&EthHandle, PHY_INTERRUPT_MASK_REG, PHY_INT_MASK);
#if defined(PHY_INTERRUPT_CTRL_REG)
    HAL_ETH_WritePHYRegister(&EthHandle, PHY_INTERRUPT_CTRL_REG, PHY_INTERRUPT_EN);
#endif
#else /* PHY_USING_INTERRUPT_MODE */
    stm32_eth_device.poll_link_timer = rt_timer_create("phylnk", (void (*)(void*))phy_linkchange,
                                        NULL, RT_TICK_PER_SECOND, RT_TIMER_FLAG_PERIODIC);
    if (!stm32_eth_device.poll_link_timer || rt_timer_start(stm32_eth_device.poll_link_timer) != RT_EOK)
    {
        LOG_E("Start link change detection timer failed");
    }
#endif /* PHY_USING_INTERRUPT_MODE */
}
  • 修改2 实验结果

结果2.png

  1. 此时可以发现 100M 半双工
  2. BSR(01) = 0x786D; PHY_Status_REG(10) = 0
  3. 这个时候 无法触发中断
  4. 这个时候 不可以ping通
  • 后期修改
  1. 我思考了一下,在配置中我已经开启了自适应,后面应该就不需要了呀,我修改了,将Rtthread 线程中,的芯片复位和开启 自适应,可惜实验结果同上,不触发中断无法ping通。
  2. 后面我发现只要将配置代码中的
 EthHandle.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE;

修改为

 EthHandle.Init.AutoNegotiation = ETH_AUTONEGOTIATION_DISABLE;

就可以正常触发中断,正常ping通,无论Rtthread线程中的 phy 寄存器是否配置位自适应。

疑问

  1. 无论是 8720A 还是 83848,我再读取 PHY_Status_REG() 时为啥都是0;当然8720 寄存器地址是1F;83848 是 10;
  2. 8720 无论是否开启自适应都能ping通,正常触发中断,即使是100M,可能是硬件没达标等。
  3. 为啥 我的83848 配置中是否开启自适应,会影响最终的联网成功失败。

恳请 各位大佬 各位大神指点。。。。

测试环境

  1. 计算机发送数据帧,MCU电路板回应,查看发送数与接收数看是否丢包
  2. 从左至右分别是 83848 启明开发板;8720A自己画的电路板;8720A EC20Plus 开发板;
  3. 测试结果表现为,83848 老是掉线;两块8720A 不掉线,不丢包

恳请 大神 大佬们指点,项目比较急,万分感谢!!!

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友

手机
浏览

扫码手机浏览