cancel
Showing results for 
Search instead for 
Did you mean: 

32F417 to LAN8742 very slow configuration data link

PHolt.1
Senior III

Can anyone explain why there is a 1ms delay here

/**
  * @brief  Disables the MAC transmission.
  * @param  heth pointer to a ETH_HandleTypeDef structure that contains
  *         the configuration information for ETHERNET module  
  * @retval None
  */
static void ETH_MACTransmissionDisable(ETH_HandleTypeDef *heth)
{ 
  __IO uint32_t tmpreg1 = 0U;
  
  /* Disable the MAC transmission */
  (heth->Instance)->MACCR &= ~ETH_MACCR_TE;
  
  /* Wait until the write operation will be taken into account:
     at least four TX_CLK/RX_CLK clock cycles */
  tmpreg1 = (heth->Instance)->MACCR;
  ETH_Delay(ETH_REG_WRITE_DELAY);
  (heth->Instance)->MACCR = tmpreg1;
}

I am trying to power down the LAN8742 PHY, ahead of putting the CPU in Standby. I have tried the obvious like

ETH->MACCR = 0x00008000;

but the above code snippet shows one has to then read back MACCR and write it back in after a long delay. That delay above is actually 1ms, which is way too long for my purpose.

I can see there is some sort of "USART" link along which this stuff gets sent. The 8742 data sheet describes the registers. Its SMI timing shows a max clock of ~2MHz.

11 REPLIES 11

ETH_MACCR.TE has nothing to do with PHY, it enables/disables transmitter in MAC.

JW

PHolt.1
Senior III

I am looking for a way to shut down the PHY (LAN8742).

It needs to be done via the interface in the CPU.

The CPU is then put into Standby.

I can see that a write to ETH->MACCR is translated to some sort of "UART" transmission (a part of the RMII interface) and this writes register bits in the PHY chip. There is a .h file in the ST code which defines the mapping, and e.g. HAL_ETH_Stop()

ETH_DMATransmissionDisable(heth);
  
  /* Stop DMA reception */
  ETH_DMAReceptionDisable(heth);
  
  /* Disable receive state machine of the MAC for reception from the MII */
  ETH_MACReceptionDisable(heth);
  
  /* Flush Transmit FIFO */
  ETH_FlushTransmitFIFO(heth);
  
  /* Disable transmit state machine of the MAC for transmission on the MII */
  ETH_MACTransmissionDisable(heth);

writes to these registers. For example ETH_MACTransmissionDisable:

static void ETH_MACTransmissionDisable(ETH_HandleTypeDef *heth)
{ 
  __IO uint32_t tmpreg1 = 0U;
  
  /* Disable the MAC transmission */
  (heth->Instance)->MACCR &= ~ETH_MACCR_TE;
  
  /* Wait until the write operation will be taken into account:
     at least four TX_CLK/RX_CLK clock cycles */
  tmpreg1 = (heth->Instance)->MACCR;
  ETH_Delay(ETH_REG_WRITE_DELAY);
  (heth->Instance)->MACCR = tmpreg1;
}

writes to MACCR and when one looks up the PHY data sheet one finds that ETH_MACCR_TE is the TX shutdown bit.

The immediate issue I have is with the above code

(heth->Instance)->MACCR &= ~ETH_MACCR_TE;
  
  /* Wait until the write operation will be taken into account:
     at least four TX_CLK/RX_CLK clock cycles */
  tmpreg1 = (heth->Instance)->MACCR;
  ETH_Delay(ETH_REG_WRITE_DELAY);
  (heth->Instance)->MACCR = tmpreg1;

which as you can see does a MACCR write (clearing the TE bit), then it reads it back, then waits for 1ms, and then it writes is back again. A google on some of this shows this code replicated all over the plane (hundreds of hits) but nobody questions WHY, and why that 1ms delay is needed.

I can see there is some (perhaps undocumented) issue with the LAN87xx PHY, but there seems to be a separate issue that this "serial interface" is running very slowly. The comment "at least four TX_CLK/RX_CLK clock cycles" is also repeated all over the internet but a 1ms delay does not relate in any way to say PCLK1/2. Taken literally, it suggests this serial interface is running at 5-10kHz.

The 8742 data sheet describes it. Two wires: MDIO (data i/o) and MDC (clock). The two 32F4 registers which control which PHY register is being accessed are MACMIIAR and MACMIIDR. There are 3 bits which control the MDC clock speed and the options on those are all pretty fast (above 1MHz) so that comment makes no sense.

Anyway, stepping through the ETH init code, I find that the clock field in MACMIIAR is set to 100 which with a 168MHz clock is a MDC clock of ~1.6MHz. So I reckon the comment in the above ST code above the 1ms delay is BS. And nobody ever discovered it...

Pavel A.
Evangelist III

>  So I reckon the comment in the above ST code above the 1ms delay is BS. And nobody ever discovered it...

Many issues have been accumulated for this driver, it is going to be updated (or already is, I do not follow the F4 lib anymore). Please check the latest version here.

PHolt.1
Senior III

It is still there, the same

/**
  * @brief  Clears the ETHERNET transmit FIFO.
  * @param  heth pointer to a ETH_HandleTypeDef structure that contains
  *         the configuration information for ETHERNET module
  * @retval None
  */
static void ETH_FlushTransmitFIFO(ETH_HandleTypeDef *heth)
{
  __IO uint32_t tmpreg = 0;
 
  /* Set the Flush Transmit FIFO bit */
  (heth->Instance)->DMAOMR |= ETH_DMAOMR_FTF;
 
  /* Wait until the write operation will be taken into account:
     at least four TX_CLK/RX_CLK clock cycles */
  tmpreg = (heth->Instance)->DMAOMR;
  HAL_Delay(ETH_REG_WRITE_DELAY);
  (heth->Instance)->DMAOMR = tmpreg;
}

 In case anyone is interested, this drops the current draw by almost 100mA

// Shut down LAN8742 ETH PHY chip
// This shifts out 32 bits at 1.6MHz to the LAN8742 so needs to be done
// well before CPU shutdown
 
uint32_t tmpreg1 = 0U;			// point at phy=0 reg=0
tmpreg1 = ETH->MACMIIAR;		// get existing MACMIIAR value
tmpreg1 &= ~ETH_MACMIIAR_CR_MASK;	// mask off 3 clock divider bits
tmpreg1 |= 3;					// WR=1 BUSY=1
ETH->MACMIIDR = 1 << 11;		// data reg = SHUTDOWN bit set
ETH->MACMIIAR = tmpreg1;		// write it back

Pavel A.
Evangelist III

Is is necessary to flush TX?

PHolt.1
Senior III

AFAICT looking at the other HAL code, the way this "USART" works is

load DR

load AR and that load starts the clocking out of the 32 bits

I have not checked it with a scope, but given there is no "start bit" etc or other means of sync, the clock must stop, like with I2C or SPI. There is no "transmit buffer" like in a UART.

Also the 1ms delay makes no sense, given the tx clock is ~1.6MHz. The data is gone in ~20us.

The comment about "four TX_CLK/RX_CLK clock cycles" makes no sense either.

PHolt.1
Senior III

The details of this "USART" are in the RM, under the heading "SMI write operation" (page 1128).

It is a 64 bit USART. The first 32 bits are a sync pattern - all 1s - then you have 16 address+etc bits, then you have 16 data bits. This seems to be a standard ETH PHY chip serial config protocol.

The shifting starts when the WR bit in MACMIIAR is set to 1. There is no buffering like a normal UART has, so loading MACMIIAR must be the last thing you do.

So, no evidence I can see supporting the above code, especially the 1ms delay (I actually measured that delay). Maybe it is a workaround for some hardware bug? Is there anyone here from ST?

The problem is that there are scenarios where that 1ms delay is way too long.

/* Wait until the write operation will be taken into account:
     at least four TX_CLK/RX_CLK clock cycles */
  tmpreg = (heth->Instance)->DMAOMR;
  HAL_Delay(ETH_REG_WRITE_DELAY);
  (heth->Instance)->DMAOMR = tmpreg;

The other end of this can be seen on page 26 of the LAN8742A/LAN8742Ai data sheet as Serial Management Interface (SMI). No clue there either.

Piranha
Chief II

Oh, dear...

When you look at schematics, you see RMII pins, two of which are named MDIO and MDC. You are talking about some "mythical USART", but, searching a Google or Wikipedia, immediately finds these articles:

https://en.wikipedia.org/wiki/Media-independent_interface

https://en.wikipedia.org/wiki/Management_Data_Input/Output

You say MDIO doesn't have a synchronization, which, of course, it does have. Then you try to relate MDIO interface frequency to some HAL delay function, which is a complete nonsense. And a PHY register mapping to MAC registers - even greater nonsense.

> The comment "at least four TX_CLK/RX_CLK clock cycles" is also repeated all over the internet but a 1ms delay does not relate in any way to say PCLK1/2.

Noone said it must be related to PCLK. TX_CLK/RX_CLK are MII/RMII pins and run at 25/50 MHz respectively. And the comment is repeated all over the internet, but you still haven't read the words "at least"!

> So, no evidence I can see supporting the above code, especially the 1ms delay (I actually measured that delay). Maybe it is a workaround for some hardware bug?

So, maybe it's worth at last looking where the hardware bugs are documented - MCU's errata sheet? This issue among some other issues is well documented there long ago...

> The problem is that there are scenarios where that 1ms delay is way too long.

ST's STM32 software developers cannot implement a working Ethernet and lwIP code for 15 years and counting... Objectively analyzing all of the HAL/Cube code the answer to most of the "Why?" questions is - incompetence. The actual required delay even with the slower MII 25 MHz interface is at least 160 ns plus some % to compensate for a potential inaccuracy of clocks, especially if HSI is used. Such a short delay with an "at least" (not an exact time) logic can easily be implemented with a trivial busy-loop with a number of iterations calculated from SystemCoreClock variable and the errata requirements, but...

PHolt.1
Senior III

Hello Piranha I profusely apologise for not matching up to your intellectual level : - )

" This issue among some other issues is well documented there long ago..."

Could you point me to where this issue is mentioned?

Specifically:

/* Wait until the write operation will be taken into account:
     at least four TX_CLK/RX_CLK clock cycles */
  tmpreg = (heth->Instance)->DMAOMR;
  HAL_Delay(ETH_REG_WRITE_DELAY);
  (heth->Instance)->DMAOMR = tmpreg;

which I don't appear to need to do.