W5500 phy stuck at 10mbps / 1/2 Duplex

Greetings,

My W5500 is stuck in 10MBPS 1/2 Duplex mode. When it auto negotiates with my switch, it won’t choose 100MBPS / Full Duplex. Further, Even if I set the phy to 100mbit it just falls back to 10mbps immediately.

Thanks in advance for your help!

Here’s my source code:

void initWizchip()
{
wiz_NetInfo netInfo;
wiz_PhyConf phyConf;

getRunningNetConfig(&netInfo);  


ETH_CS_set_level(true);	// high select.
ETH_RST_set_level(false); // hold the chip in reset.

reg_wizchip_cris_cbfunc(wizCritEnter, wizCritExit);
reg_wizchip_cs_cbfunc(wizChipSelect, wizChipDeselect);
reg_wizchip_spi_cbfunc(wizReadByte, wizWriteByte);
reg_wizchip_spiburst_cbfunc(wizSpiRead, wizSpiWrite);

_delay_ms(50);			// wait for the chip to reset.
ETH_RST_set_level(true);
_delay_ms(50);

phyConf.by = PHY_CONFBY_SW;
phyConf.duplex = PHY_DUPLEX_FULL;
phyConf.mode = PHY_MODE_MANUAL;
phyConf.speed = PHY_SPEED_100;	

wizphy_setphyconf(&phyConf);

ctlnetwork(CN_SET_NETINFO, (void*)&netInfo);

}

hello,

Are you really half-duplex at 10mbps?
If you do not configure phy, the W5500 will work with auto negoation, which is the default setting.

If you set it to 100mbps, the link is caught at 100mbps or not caught.
So I think that you are not doing the right thing, or might be wrong.

I have the exact same issue. I set it up:

    phyConf.by = PHY_CONFBY_SW;
    phyConf.speed = PHY_SPEED_100;
    phyConf.duplex = PHY_DUPLEX_FULL;
    phyConf.mode = PHY_MODE_MANUAL;
    wizphy_setphyconf(&phyConf);

But it keeps defaulting to 10 half. On all routers and networks. @becky any advice?

I notice there hasn’t been any action on this topic for a while and disappointingly there has also been no resolution.

I have the same issue when setting PHY_MODE_AUTONEGO using the github libraries.

When PHY configuration is set as per below, I get 100M Full duplex.

static wiz_PhyConf phyConf =
{
PHY_CONFBY_SW,
PHY_MODE_MANUAL,
PHY_SPEED_100,
PHY_DUPLEX_FULL,
};

however, when I set as follows, it drops down to 10M Half Duplex

static wiz_PhyConf phyConf =
{
PHY_CONFBY_SW,
PHY_MODE_AUTONEGO,
PHY_SPEED_100,
PHY_DUPLEX_FULL,
};

It seems PHY_MODE_AUTONEGO overrides all other settings and causes chip to auto-negotiate, and it can only auto-negotiate at 10M/H. Why? No idea… probably other device is set to auto-negotiate too, and they start with 10M/H and find connection and even do not try higher speeds and full duplex. Check and play with other device’s settings.

I’ve verified the issues directly on a switch that I know works properly. Auto negotiation does not start at the slowest speed, it will agree on the fastest speed (bandwidth actually) that both sides support and configure for that.

Basically, when set to auto negotiate or HW controlled it will connect at 10M Half duplex, whereas if I force it to 100M Full, it works there as well.

UPDATE: OK, I think it is negotiating correctly to 100M however this doesn’t seem to be reflected when calling the function “void wizphy_getphyconf(wiz_PhyConf* phyconf)” and I’m not sure that the function is even correct looking at how it works.

If I call the following function I appear to get the results I expect so whilst not being a huge issue, I’d still like to get to the bottom of why the above function works in the way it does.

void wizphy_getphystat(wiz_PhyConf* phyconf)
{
uint8_t tmp = getPHYCFGR();
phyconf->duplex = (tmp & PHYCFGR_DPX_FULL) ? PHY_DUPLEX_FULL : PHY_DUPLEX_HALF;
phyconf->speed = (tmp & PHYCFGR_SPD_100) ? PHY_SPEED_100 : PHY_SPEED_10;
}

#define PHYCFGR_DPX_FULL             (1<<2)
#define PHYCFGR_DPX_HALF             (0<<2)
#define PHYCFGR_SPD_100              (1<<1)
#define PHYCFGR_SPD_10               (0<<1)

Seems to be correct bit assignment according to W5500’s PHYCFGR register.

#define PHY_SPEED_10             0     ///< Link Speed 10
#define PHY_SPEED_100            1     ///< Link Speed 100
#define PHY_DUPLEX_HALF          0     ///< Link Half-Duplex
#define PHY_DUPLEX_FULL          1     ///< Link Full-Duplex

The ultimate truth is the value of the PHYCFGR register. Read it using

uint8_t tmp = getPHYCFGR();

and check its bits according to the description in the datasheet. Does its reading look incorrect?

Yes, I am getting the correct return from getPHYCFGR(), the problem seems to be with that I was using function void wizphy_getphyconf(wiz_PhyConf* phyconf) to read the results. Looking at this function, and based on getPHYCFGR returning a value of 255 for 100M Full, Auto Negotiation the function is loading the following into the phyconf structure.

void wizphy_getphyconf(wiz_PhyConf* phyconf)
{
    uint8_t tmp = 0;
    tmp = getPHYCFGR();
    
    phyconf->by   = (tmp & PHYCFGR_OPMD) ? PHY_CONFBY_SW : PHY_CONFBY_HW;

255 & (1<<6) = 64 → PHY_CONFBY_SW → Correct

    switch(tmp & PHYCFGR_OPMDC_ALLA)
    {
        case PHYCFGR_OPMDC_ALLA:
        case PHYCFGR_OPMDC_100FA:
        {
            phyconf->mode = PHY_MODE_AUTONEGO;
            break;
        }
        
        default:
        {
            phyconf->mode = PHY_MODE_MANUAL;
            break;
        }

255 & (7<<3) = 56 → Goes to default, this is incorrect and will never match the first two cases.

    switch(tmp & PHYCFGR_OPMDC_ALLA)
    {
        case PHYCFGR_OPMDC_100FA:
        case PHYCFGR_OPMDC_100F:
        case PHYCFGR_OPMDC_100H:
        {
            phyconf->speed = PHY_SPEED_100;
            break;
        }
        
        default:
        {
            phyconf->speed = PHY_SPEED_10;
            break;
        }
    }

Again, 255 & (7<<3) = 56 → Goes to default, this is incorrect and will never match the first three cases.

This is where I’m getting the incorrect result from. As you suggested, if I just look at the bit result from getPHYCFGR() then I guess that will give me the correct result. Just think that the above function I highlighted needs to be looked at.

1 Like