cancel
Showing results for 
Search instead for 
Did you mean: 

LAN8742 Issue DuplexMode

AGP_29
Associate III

Hello everyone,

I'm currently using  Nucleo-H743ZI2  but this aim to go on a custum PCB. LWIP (2.1.2) is activated without FREERTOS and my TCP server is working. I'm also using HAL function with CubeIDE (1.16.1). And I'm using an Aruba 2530-8G switch to visualize the Speed and Duplex Mode
But I'm having issues with the LAN8742A. Especially with the Duplex Mode of the LAN8742. I can't manage to make the duplex mode to Full Duplex . I already manage the speed and autonegociation well, but the Full Duplex mode is not working without AutoNegociation.

What I did in order to manually configure the LAN8742 ? 

- Writing in the SMR (Special Modes Register) of the LAN8742 which mode I wanted (Bit 5->7)
- Writing in the BCR (Basic Control Register) of the LAN8742 the speed (Bit 13), the Auto-Negotiation (Bit 12), and the Duplex Mode (Bit 8)
- Specify the Link State via lan8742.c function given by ST

 

// Function that write the configuration for the LAN8742
void appMain_initLAN8742(void) {
    // Read the current mode configuration 	
    LAN8742.IO.ReadReg(LAN8742.DevAddr, LAN8742_SMR, &readWriteVal);
    readWriteVal |= (1 << 5) | (1 << 6); // Change mode to 011 AKA AKA 100BASE-TX Full Duplex
    readWriteVal &= ~((1 << 7)); // Change mode to 011 AKA AKA 100BASE-T Full Duplex
    // Writing in SMR (Special Mode Register) the mode that we want
    rc = LAN8742.IO.WriteReg(LAN8742.DevAddr, LAN8742_SMR, readWriteVal);

    // Read current value in register
    LAN8742.IO.ReadReg(LAN8742.DevAddr, LAN8742_BCR, &writeVal);
    // Deactivate AutoNegoce
    writeVal = (writeVal & ~(1 << 12));
    // Set Speed to 100Mb
    writeVal = (writeVal | (1 << 13));
    // Set DuplexMode to Full Duplex
    writeVal = (writeVal | (1 << 8));
    // Writing in BCR the speed, Duplex and AutoNegoce
    rc = LAN8742.IO.WriteReg(LAN8742.DevAddr, LAN8742_BCR, writeVal);
    printf("[appMain_initLAN8742] - Writing LAN8742 : %s\n", (rc == 0) ? "SUCCESS" : "FAIL");

    // Specify the Link State via lan8742.c function given by ST
    rc = LAN8742_SetLinkState(&LAN8742, LAN8742_STATUS_100MBITS_FULLDUPLEX);
    if (rc != LAN8742_STATUS_OK) // Error Case
        printf("[appMain_handleLAN8742] - ERROR in LAN8742_SetLinkState()\n");
}
// Function that print value from LAN8742 register (BCR, PHYSCR, SMR)
void appMain_logLAN8742(void) {
	static uint32_t tickDebug = 0;
	char duplexMode = 0;
	uint32_t readBCRVal = 0, readPHYSCSRVal = 0, readSMR = 0, speed = 0, tmpVar = 0;
	char speedIndicator[25] = { 0 };
	char speedIndicator2[25] = { 0 };
	char modeIndicator[30] = { 0 };
	bool autoDone = false;
	int32_t PHYLinkState = 0;
	bool autoNegoce, speedBool, duplexModeBool, restartAutoNegoce, softReset, powerDown, loopBack;
	LAN8742.IO.ReadReg(LAN8742.DevAddr, LAN8742_BCR, &readBCRVal);
	LAN8742.IO.ReadReg(LAN8742.DevAddr, LAN8742_PHYSCSR, &readPHYSCSRVal);
	LAN8742.IO.ReadReg(LAN8742.DevAddr, LAN8742_SMR, &readSMR);

	autoDone = (readPHYSCSRVal & (1 << 12)) ? true : false;
	tmpVar = (readPHYSCSRVal >> 2) & 0x7; // Extract only 2->4 bit.

	// Parse PHY STATUS CONTROL Regster
	if (tmpVar == 0b001) {
		strncpy(speedIndicator, "10BASE-T HalfDuplex", sizeof(speedIndicator) - 1);
	} else if (tmpVar == 0b010) {
		strncpy(speedIndicator, "100BASE-T HalfDuplex", sizeof(speedIndicator) - 1);
	} else if (tmpVar == 0b101) {
		strncpy(speedIndicator, "10BASE-T FullDuplex", sizeof(speedIndicator) - 1);
	} else if (tmpVar == 0b110) {
		strncpy(speedIndicator, "100BASE-T FullDuplex", sizeof(speedIndicator) - 1);
	} else {
		strncpy(speedIndicator, "Unknown Duplex", sizeof(speedIndicator) - 1);
	}

	autoNegoce = (readBCRVal & (1 << 12)) ? true : false;
	speedBool = (readBCRVal & (1 << 13)) ? true : false;
	speed = speedBool == 1 ? 100 : 10;
	duplexModeBool = (readBCRVal & (1 << 8)) ? true : false;
	duplexMode = duplexModeBool == 1 ? 'F' : 'H';
	restartAutoNegoce = (readBCRVal & (1 << 9)) ? true : false;
	softReset = (readBCRVal & (1 << 15)) ? true : false;
	powerDown = (readBCRVal & (1 << 11)) ? true : false;
	loopBack = (readBCRVal & (1 << 11)) ? true : false;

	// Parse Special Modes Register
	tmpVar = (readSMR >> 5) & 0x7;
	if (tmpVar == 0b000) {
		strncpy(modeIndicator, "10BASE-T HalfDuplex", sizeof(modeIndicator) - 1);
	} else if (tmpVar == 0b001) {
		strncpy(modeIndicator, "10BASE-T FullDuplex", sizeof(modeIndicator) - 1);
	} else if (tmpVar == 0b010) {
		strncpy(modeIndicator, "100BASE-T HalfDuplex", sizeof(modeIndicator) - 1);
	} else if (tmpVar == 0b011) {
		strncpy(modeIndicator, "100BASE-T FullDuplex", sizeof(modeIndicator) - 1);
	} else if (tmpVar == 0b100) {
		strncpy(modeIndicator, "100BASE-T HalfDuplex (AN)", sizeof(modeIndicator) - 1);
	} else if (tmpVar == 0b101) {
		strncpy(modeIndicator, "100BASE-T HalfDuplex (AN)", sizeof(modeIndicator) - 1);
	} else if (tmpVar == 0b110) {
		strncpy(modeIndicator, "PowerDown Mode", sizeof(modeIndicator) - 1);
	} else if (tmpVar == 0b111) {
		strncpy(modeIndicator, "All Capable (AN)", sizeof(modeIndicator) - 1);
	} else {
		strncpy(speedIndicator, "Unknown Duplex", sizeof(speedIndicator) - 1);
	}

	// Parse LAN8742_GetLinkState()
	PHYLinkState = LAN8742_GetLinkState(&LAN8742);
	if (PHYLinkState == 5) {
		strncpy(speedIndicator2, "10Mb HD", sizeof(speedIndicator2) - 1);
	} else if (PHYLinkState == 4) {
		strncpy(speedIndicator2, "10Mb FD", sizeof(speedIndicator2) - 1);
	} else if (PHYLinkState == 3) {
		strncpy(speedIndicator2, "100Mb HD", sizeof(speedIndicator2) - 1);
	} else if (PHYLinkState == 2) {
		strncpy(speedIndicator2, "100Mb FD", sizeof(speedIndicator2) - 1);
	} else {
		strncpy(speedIndicator2, "Error in LINK", sizeof(speedIndicator2) - 1);
	}

	if ((HAL_GetTick() - tickDebug) > TICK_LOG_LAN8742) {
		tickDebug = HAL_GetTick();
		printf("############## LOG START ##############\n");
		printf(
				"[appMain_logLAN8742] - [BCR] Restart AutoNegotiate : %d, AutoNegoce : %d, DuplexMode : %c, Speed : %ld, SoftReset : %d, powerDown : %d, LoopBack : %d\n",
				restartAutoNegoce, autoNegoce, duplexMode, speed, softReset, powerDown, loopBack);
		printf("[appMain_logLAN8742] - [PHYSCSR] AutoDone : %d, Speed Indication : %s (%ld), SI2 : %s \n", autoDone,
				speedIndicator, tmpVar, speedIndicator2);
		printf("[appMain_logLAN8742] - [SMR] Mode indicator : %s\n", modeIndicator);
	}

}

 

I also have some code that handles the MACConfig to match the configuration I'm currently in (Speed and DuplexMode).
The weird thing is that my log function for the lan8742 ("appMain_logLAN8742") returns the state that I want (AKA full duplex), even though the switch sees the link as Half Duplex. I also try with an other switch but I had the same result.

Log from appMain_logLAN8742()

############## LOG START ##############
[appMain_logLAN8742] - [BCR] Restart AutoNegotiate : 0, AutoNegoce : 0, DuplexMode : F, Speed : 100, SoftReset : 0, powerDown : 0, LoopBack : 0
[appMain_logLAN8742] - [PHYSCSR] AutoDone : 0, Speed Indication : 100BASE-T FullDuplex (3), SI2 : 100Mb FD
[appMain_logLAN8742] - [SMR] Mode indicator : 100BASE-T FullDuplex
[appMain_logMACConfig] - duplexMode : F, Speed : 100
############## LOG STOP ##############

View of the switch where the nucleo is connected to Port 7 

switch(config)# show interfaces brief

Status and Counters - Port Status

| Intrusion MDI Flow
Port Type | Alert Enabled Status Mode Mode Ctrl
----- ---------- + --------- ------- ------ ---------- ---- ----
1 100/1000T | No Yes Down 100FDx MDIX on
2 100/1000T | No Yes Down 1000FDx MDI on
3 100/1000T | No Yes Down 1000FDx MDIX on
4 100/1000T | No Yes Down 1000FDx MDI on
5 100/1000T | No Yes Down 1000FDx MDI on
6 100/1000T | No Yes Down 1000FDx MDIX on
7 100/1000T | No Yes Up 100HDx MDI on
8 100/1000T | No Yes Down 1000FDx MDIX on
9 100/1000T | No Yes Up 1000FDx MDIX on
10 100/1000T | No Yes Up 1000FDx MDI on

I have the same problem for 10Mb Full Duplex and 100Mb Full duplex. I also try with a Soft Reset (Bit 15 from BRC) but didn't work.

Datasheet from LAN8742 : https://ww1.microchip.com/downloads/en/DeviceDoc/DS_LAN8742_00001989A.pdf

1 ACCEPTED SOLUTION

Accepted Solutions

for reference see Duplex mismatch - Wikipedia

"

When a device set to autonegotiation is connected to a device that is not using autonegotiation, the autonegotiation process fails. The autonegotiating end of the connection is still able to correctly detect the speed of the other end, but cannot correctly detect the duplex mode. For backward compatibility with Ethernet hubs, the standard requires the autonegotiating device to use half duplex in these conditions. Therefore, the autonegotiating end of the connection uses half duplex while the non-negotiating peer is locked at full duplex, and this is a duplex mismatch.

The Ethernet standards and major Ethernet equipment manufacturers recommend enabling autonegotiation."

View solution in original post

9 REPLIES 9
Pavel A.
Evangelist III

> Full Duplex mode is not working without AutoNegociation.

AFAIK this is normal. Some time ago I asked about this professional Ethernet engineers and they stated that full duplex works only when auto-negotiated with the peer. I haven't understood the explanation, only the bottom line.

 

Do you have any source or paper that say that ?

Unfortunately I don't. But I had this question too, googled a lot and have not found other answers.

 

AGP_29
Associate III

I forgot to mention, but the switch is in full auto 

Any update ? 

AGP_29
Associate III

Update from my side.

I try to set an ETH interface of two different computers to  100Mb and 10Mb full duplex without autoNegociation and a switch in full AUTO.
Both computers (one is windows 7, the other one is a Raspberry PI 5 with Ubuntu 22 Desktop) are viewed by the switch in 100Mb/10Mb Half Duplex. 

It appears that @Pavel A.  is right but I would appreciate some source or paper that said so.

Hi

Did you try with the board configured in "full duplex without auto-negotiation" AND the ethernet switch port configured in "full duplex without auto-negotiation" ? Does it work ?

 

 

for reference see Duplex mismatch - Wikipedia

"

When a device set to autonegotiation is connected to a device that is not using autonegotiation, the autonegotiation process fails. The autonegotiating end of the connection is still able to correctly detect the speed of the other end, but cannot correctly detect the duplex mode. For backward compatibility with Ethernet hubs, the standard requires the autonegotiating device to use half duplex in these conditions. Therefore, the autonegotiating end of the connection uses half duplex while the non-negotiating peer is locked at full duplex, and this is a duplex mismatch.

The Ethernet standards and major Ethernet equipment manufacturers recommend enabling autonegotiation."

Yes I did, and it work