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

6 REPLIES 6
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.