LinY 发表于 2024-3-6 17:13:37

千兆交换机LAN8720A手动协商只能到10M

难搞哦 自动协商连不上网,手动协商只能到10M全双工
想问下有没有解决办法。


交换机是锐捷的S2910V2-48GT4SFP-L 千兆交换机

电脑连上测速500-800M带宽


开发环境:
STM32CubeMX(V6.10.0)和 Keil(V5.38.0) ARM版本5.06
用的STM32F429IGT6和LAN8720A
本地测试环境正常100M全双工,生产环境出现10M的情况,用的上面提到的锐捷交换机。


代码:
main中正常调用MX_LWIP_Init(), while(1)主循环中调用MX_LWIP_Process()
其他的设置MAC,IP,掩码,网关都确定没问题。

// STM32CubeMX生成的自协商代码 只有自协商 这个锐捷交换机会有一定概率连不上网

void ethernet_link_check_state_1(struct netif *netif)
{
ETH_MACConfigTypeDef MACConf = {0};
int32_t PHYLinkState = 0;
uint32_t linkchanged = 0U, speed = 0U, duplex = 0U;

PHYLinkState = LAN8742_GetLinkState(&LAN8742);

if(netif_is_link_up(netif) && (PHYLinkState <= LAN8742_STATUS_LINK_DOWN))
{
    HAL_ETH_Stop(&heth);
    netif_set_down(netif);
    netif_set_link_down(netif);
}
else if(!netif_is_link_up(netif) && (PHYLinkState > LAN8742_STATUS_LINK_DOWN))
{
    switch (PHYLinkState)
    {
    case LAN8742_STATUS_100MBITS_FULLDUPLEX:
      duplex = ETH_FULLDUPLEX_MODE;
      speed = ETH_SPEED_100M;
      linkchanged = 1;
      break;
    case LAN8742_STATUS_100MBITS_HALFDUPLEX:
      duplex = ETH_HALFDUPLEX_MODE;
      speed = ETH_SPEED_100M;
      linkchanged = 1;
      break;
    case LAN8742_STATUS_10MBITS_FULLDUPLEX:
      duplex = ETH_FULLDUPLEX_MODE;
      speed = ETH_SPEED_10M;
      linkchanged = 1;
      break;
    case LAN8742_STATUS_10MBITS_HALFDUPLEX:
      duplex = ETH_HALFDUPLEX_MODE;
      speed = ETH_SPEED_10M;
      linkchanged = 1;
      break;
    default:
      break;
    }

    if(linkchanged)
    {
      /* Get MAC Config MAC */
      HAL_ETH_GetMACConfig(&heth, &MACConf);
      MACConf.DuplexMode = duplex;
      MACConf.Speed = speed;
      HAL_ETH_SetMACConfig(&heth, &MACConf);
      HAL_ETH_Start(&heth);
      netif_set_up(netif);
      netif_set_link_up(netif);
    }
}

}

// 自己在原有基础上改的先自协商 没成功就手动协商 按照100M,10M的先后尝试。只有10M才能成功。强制100M后续没网

void ethernet_link_check_state(struct netif *netif)
{
ETH_MACConfigTypeDef MACConf = {0};
int32_t PHYLinkState = 0;
uint32_t linkchanged = 0U, speed = 0U, duplex = 0U;

PHYLinkState = LAN8742_GetLinkState(&LAN8742);

static uint32_t last_time = 0;
static int32_t last_linkstate = 0;

//printf("netif_is_link_up:%u, PHYLinkState:%d\n", netif_is_link_up(netif), PHYLinkState);

if(netif_is_link_up(netif) && (PHYLinkState <= LAN8742_STATUS_LINK_DOWN))
{
    printf("1.netif_is_link_up:%u, PHYLinkState:%d\n", netif_is_link_up(netif), PHYLinkState);
    printf("1.eth stop and set down.\n");
    last_linkstate = LAN8742_STATUS_LINK_DOWN;
    HAL_ETH_Stop(&heth);
    netif_set_down(netif);
    netif_set_link_down(netif);
}
else if(!netif_is_link_up(netif) && (PHYLinkState > LAN8742_STATUS_LINK_DOWN))
{
    printf("2.netif_is_link_up:%u, PHYLinkState:%d\n", netif_is_link_up(netif), PHYLinkState);
//    if (PHYLinkState == LAN8742_STATUS_10MBITS_FULLDUPLEX)
//      {
//            PHYLinkState = LAN8742_STATUS_100MBITS_FULLDUPLEX;
//      }
//      else
//      if (PHYLinkState == LAN8742_STATUS_10MBITS_HALFDUPLEX)
//      {
//            PHYLinkState = LAN8742_STATUS_100MBITS_HALFDUPLEX;
//      }
    switch (PHYLinkState)
    {
    case LAN8742_STATUS_100MBITS_FULLDUPLEX:
      duplex = ETH_FULLDUPLEX_MODE;
      speed = ETH_SPEED_100M;
      linkchanged = 1;
      break;
    case LAN8742_STATUS_100MBITS_HALFDUPLEX:
      duplex = ETH_HALFDUPLEX_MODE;
      speed = ETH_SPEED_100M;
      linkchanged = 1;
      break;
    case LAN8742_STATUS_10MBITS_FULLDUPLEX:
      duplex = ETH_FULLDUPLEX_MODE;
      speed = ETH_SPEED_10M;
      linkchanged = 1;
      break;
    case LAN8742_STATUS_10MBITS_HALFDUPLEX:
      duplex = ETH_HALFDUPLEX_MODE;
      speed = ETH_SPEED_10M;
      linkchanged = 1;
      break;
//      case LAN8742_STATUS_10MBITS_FULLDUPLEX:
//      duplex = ETH_FULLDUPLEX_MODE;
//      speed = ETH_SPEED_100M;
//      linkchanged = 1;
//      break;
//    case LAN8742_STATUS_10MBITS_HALFDUPLEX:
//      duplex = ETH_HALFDUPLEX_MODE;
//      speed = ETH_SPEED_100M;
//      linkchanged = 1;
//      break;
    default:
      break;
    }

    if(linkchanged)
    {
      printf("2.eth changed.\n");
      /* Get MAC Config MAC */
      HAL_ETH_GetMACConfig(&heth, &MACConf);
      MACConf.DuplexMode = duplex;
      MACConf.Speed = speed;
      HAL_ETH_SetMACConfig(&heth, &MACConf);
      HAL_ETH_Start(&heth);
      netif_set_up(netif);
      netif_set_link_up(netif);
    }
}
else if(!netif_is_link_up(netif) && (HAL_GetTick() - last_time > 5000))
{
    // printf("3netif_is_link_up:%u, PHYLinkState:%d\n", netif_is_link_up(netif), PHYLinkState);
    if (last_linkstate == LAN8742_STATUS_LINK_DOWN) {
      last_time = HAL_GetTick();
      printf("3.set eth mode auto ");
      int32_t status = LAN8742_StartAutoNego(&LAN8742);
      if(status == LAN8742_STATUS_OK) {
      printf("successfully.\n");
      } else if (status == LAN8742_STATUS_READ_ERROR){
      printf("but read bcr failed.\n");
      } else if (status == LAN8742_STATUS_WRITE_ERROR){
      printf("but write bcr failed.\n");
      } else if (status == LAN8742_STATUS_ERROR){
      printf("but status err.\n");
      }
      last_linkstate = LAN8742_STATUS_AUTONEGO_NOTDONE;
    } else if (last_linkstate == LAN8742_STATUS_AUTONEGO_NOTDONE && (HAL_GetTick() - last_time < 10000)) {
    } else {
      last_time = HAL_GetTick();
      PHYLinkState = last_linkstate;
      PHYLinkState++;
      if ( PHYLinkState < LAN8742_STATUS_100MBITS_FULLDUPLEX || PHYLinkState > LAN8742_STATUS_10MBITS_HALFDUPLEX) {
//          if ( PHYLinkState < LAN8742_STATUS_100MBITS_FULLDUPLEX || PHYLinkState > LAN8742_STATUS_100MBITS_HALFDUPLEX) {
      PHYLinkState = LAN8742_STATUS_100MBITS_FULLDUPLEX;
      }
      printf("3.set eth mode %d ", PHYLinkState);
      int32_t status = LAN8742_SetLinkState(&LAN8742, PHYLinkState);
      if(status == LAN8742_STATUS_OK) {
      printf("successfully.\n");
      } else if (status == LAN8742_STATUS_READ_ERROR){
      printf("but read bcr failed.\n");
      } else if (status == LAN8742_STATUS_WRITE_ERROR){
      printf("but write bcr failed.\n");
      } else if (status == LAN8742_STATUS_ERROR){
      printf("but status err.\n");
      }
      last_linkstate = PHYLinkState;
    }
    HAL_ETH_Stop(&heth);
    netif_set_down(netif);
    netif_set_link_down(netif);
}
}





LinY 发表于 2024-3-6 17:27:18

硬汉哥 帮忙看下呗

参考1.说是因为寄存器没有配置对,所以HAL框架读取了错误的寄存器地址,所以自动协商失败。
地址:https://community.st.com/t5/stm32-mcus-products/configuring-lan8742-possible-bug-issues-using-cubemx-tool-for/td-p/569142
说明:这个寄存器地址我多确认过了 代码没用到的我甚至给他注释掉了
/** @defgroup LAN8742_Registers_Mapping LAN8742 Registers Mapping
* @{
*/
#define LAN8742_BCR      ((uint16_t)0x0000U)
#define LAN8742_BSR      ((uint16_t)0x0001U)
//#define LAN8742_PHYI1R   ((uint16_t)0x0002U)
//#define LAN8742_PHYI2R   ((uint16_t)0x0003U)
//#define LAN8742_ANAR   ((uint16_t)0x0004U)
//#define LAN8742_ANLPAR   ((uint16_t)0x0005U)
//#define LAN8742_ANER   ((uint16_t)0x0006U)
////#define LAN8742_ANNPTR   ((uint16_t)0x0007U)
////#define LAN8742_ANNPRR   ((uint16_t)0x0008U)
////#define LAN8742_MMDACR   ((uint16_t)0x000DU)
////#define LAN8742_MMDAADR((uint16_t)0x000EU)
////#define LAN8742_ENCTR    ((uint16_t)0x0010U)
//#define LAN8742_MCSR   ((uint16_t)0x0011U)
#define LAN8742_SMR      ((uint16_t)0x0012U)
////#define LAN8742_TPDCR    ((uint16_t)0x0018U)
////#define LAN8742_TCSR   ((uint16_t)0x0019U)
//#define LAN8742_SECR   ((uint16_t)0x001AU)
//#define LAN8742_SCSIR    ((uint16_t)0x001BU)
////#define LAN8742_CLR      ((uint16_t)0x001CU)
#define LAN8742_ISFR   ((uint16_t)0x001DU)
#define LAN8742_IMR      ((uint16_t)0x001EU)
#define LAN8742_PHYSCSR((uint16_t)0x001FU)


参考2.另一个人说他把自动协商关闭了,直接初始化为100兆全双工也行。
low_level_init()函数里面:
heth.Init.AutoNegotiation = ETH_AUTONEGOTIATION_DISABLE;
heth.Init.Speed = ETH_SPEED_100M;
heth.Init.DuplexMode = ETH_MODE_FULLDUPLEX;

并且把MX_LWIP_Process()函数中读寄存器相关的代码注释掉了

// HAL_ETH_ReadPHYRegister(&heth, PHY_MICR, ®value);
// regvalue |= (PHY_MICR_INT_EN | PHY_MICR_INT_OE);
// /* Enable Interrupts */
// HAL_ETH_WritePHYRegister(&heth, PHY_MICR, regvalue );
// /* Read Register Configuration */
// HAL_ETH_ReadPHYRegister(&heth, PHY_MISR, ®value);
// regvalue |= PHY_MISR_LINK_INT_EN;
// /* Enable Interrupt on change of link status */
// HAL_ETH_WritePHYRegister(&heth, PHY_MISR, regvalue)

地址:https://community.st.com/t5/stm32-mcus-embedded-software/ethernet-lwip-on-stm32f407-board-with-hal-lib/td-p/456812
说明:我这边cubemx生产的结构体heth.Init就没这几个变量。而且他这个也是设置手动协商,我的那边设置手动协商应该也能达到一样的效果,但是不生效



参考3.这个贴子里面大意是从CMSIS中获得正确的LAN8720驱动,而不是用LAN8742的,第二步,修改CubeMX中的bug(最后一个回贴)
地址:https://community.st.com/t5/stm32cubemx-mcus/how-to-add-a-quot-lan8720-quot-driver/td-p/146547
说明:这个正在看,估计改起来比较麻烦。

目前开发都是STM32CubeMX生成用Keil HAL库开发的,发现HAL问题不少,而且都不好找到原因和处理。有的坑


eric2013 发表于 2024-3-7 00:32:35

强制配置100M,不做自动协商,是否正常。

LinY 发表于 2024-3-7 09:33:02

eric2013 发表于 2024-3-7 00:32
强制配置100M,不做自动协商,是否正常。

强制100M 连不上网

LinY 发表于 2024-3-7 10:22:09


// 输出了下几个寄存器值的变化
// LAN8742_BCR, LAN8742_BSR, LAN8742_SMR, LAN8742_ISFR, LAN8742_IMR, LAN8742_PHYSCSR
xxx.set eth mode 2 successfully.
reg-0000>>0000000000000000->0010000100000000
reg-0001>>0000000000000000->0111100000001001
reg-0012>>0000000000000000->0110000011100000
reg-001D>>0000000000000000->0000000000010000
reg-001F>>0000000000000000->0000000001011000
3.set eth mode 2 successfully.
3.set eth mode 3 successfully.
reg-0000>>0010000100000000->0010000000000000
reg-001F>>0000000001011000->0000000001001000
3.set eth mode 4 successfully.
reg-0000>>0010000000000000->0000000100000000
reg-001F>>0000000001001000->0000000001010100
reg-001D>>0000000000010000->0000000010000000
reg-0001>>0111100000001001->0111100000001101
2.netif_is_link_up:0, PHYLinkState:4
2.eth changed.
reg-0001>>0111100000001101->0111100000001001
reg-001D>>0000000010000000->0000000010010000
1.netif_is_link_up:1, PHYLinkState:1
1.eth stop and set down.
reg-0001>>0111100000001001->0111100000001101
reg-001D>>0000000010010000->0000000010000000
2.netif_is_link_up:0, PHYLinkState:4
2.eth changed.
reg-0001>>0111100000001101->0111100000001001
reg-001D>>0000000010000000->0000000010010000
1.netif_is_link_up:1, PHYLinkState:1
1.eth stop and set down.
reg-0001>>0111100000001001->0111100000001101
reg-001D>>0000000010010000->0000000010000000
2.netif_is_link_up:0, PHYLinkState:4
2.eth changed.
reg-0001>>0111100000001101->0111100000001001
reg-001D>>0000000010000000->0000000010010000
1.netif_is_link_up:1, PHYLinkState:1
1.eth stop and set down.
reg-0001>>0111100000001001->0111100000001101
reg-001D>>0000000010010000->0000000010000000
2.netif_is_link_up:0, PHYLinkState:4
2.eth changed.
reg-001D>>0000000010000000->0000000010010000
reg-0001>>0111100000001101->0111100000001001
1.netif_is_link_up:1, PHYLinkState:1
1.eth stop and set down.
reg-0001>>0111100000001001->0111100000001101
reg-001D>>0000000010010000->0000000010000000
2.netif_is_link_up:0, PHYLinkState:4
2.eth changed.
reg-001D>>0000000010000000->0000000010010000
reg-0001>>0111100000001101->0111100000001001
1.netif_is_link_up:1, PHYLinkState:1
1.eth stop and set down.
reg-0001>>0111100000001001->0111100000001101
reg-001D>>0000000010010000->0000000010000000
2.netif_is_link_up:0, PHYLinkState:4
2.eth changed.
reg-0001>>0111100000001101->0111100000001001
reg-001D>>0000000010000000->0000000010010000
1.netif_is_link_up:1, PHYLinkState:1
1.eth stop and set down.
reg-001D>>0000000010010000->0000000000010000
reg-001D>>0000000000010000->0000000000000000
reg-0001>>0111100000001001->0111100000001101
reg-001D>>0000000000000000->0000000010000000
2.netif_is_link_up:0, PHYLinkState:4
2.eth changed.

eric2013 发表于 2024-3-7 11:14:03

LinY 发表于 2024-3-7 10:22

// 输出了下几个寄存器值的变化
// LAN8742_BCR, LAN8742_BSR, LAN8742_SMR, LAN87 ...
不排除估计是有干扰,这样试试,你的8720做外置硬件复位还是GPIO控制的复位,可以先硬件复位下,然后软件命令再复位一次,等待1秒后操作试试。

还有就是设置你的RMII所涉及到GPIO速度等级降低下。

LinY 发表于 2024-3-7 16:07:24

eric2013 发表于 2024-3-7 11:14
不排除估计是有干扰,这样试试,你的8720做外置硬件复位还是GPIO控制的复位,可以先硬件复位下,然后软件 ...

试了 没效果

hpdell 发表于 2024-3-7 17:29:48

LinY 发表于 2024-3-7 16:07
试了 没效果

st 貌似有提供 lan4872 的驱动吗 ?

可以参考一下,或者更换 8742 芯片试试看

eric2013 发表于 2024-3-8 00:33:01

LinY 发表于 2024-3-7 16:07
试了 没效果

还有个问题,使用路由器或者换个交换机有测试过没。或者找个其它带网络的板子测试。

难道是板子的硬件设计问题或者交换机的问题。想办法锁定下问题方向,排除法。

LinY 发表于 2024-3-11 14:05:10

第一个方案用LAN8742替换LAN8720 测试可以解决问题。
准备试下第二个方案 原来给LAN8720用的是扬兴25MHz无源晶振(X322525MOB4SI),准备换爱普生或扬兴的有源晶振+LAN8720试试。
页: [1]
查看完整版本: 千兆交换机LAN8720A手动协商只能到10M