AnsweredAssumed Answered

SDK 2.6 on RT1050 - ENET input clock incorrect

Question asked by David Rodgers on Sep 10, 2019
Latest reply on Sep 13, 2019 by Victor Jimenez

TL;DR - The "lwip_tcpecho_freertos" SDK example for RT1050 uses "kCLOCK_CoreSysClk" when initializing the driver and PHY, but it should instead use "kCLOCK_IpgClk" per the datasheet (and based on empirical testing).


So I'm trying to get Ethernet working on my custom RT1050 board.  To check out my hardware, I created a copy of the "lwip_tcpecho_freertos" project and modified it to use QSPI flash and alternate I/O pins for MDIO, UART, and ENET_INT and ENET_RST.  The PHY wasn't responding during startup; the program would hit the assert() in enet_ethernetif.c line 101.  So I started probing the MDIO bus to see what was happening there.  (Note: I have probed ENET_TX_CLK and verified that it is sending a 50 MHz waveform to the XI input of the KSZ8081 on our board.)


I could see that there was a continuous clock on MDC as expected, measuring 1.31578 MHz on my scope.  Thinking I could turn down the MDIO clock to help with capturing a scope trace, I investigated the function PHY_Init(), and specifically ENET_SetSMI(), which sets the MDIO timing parameters by calculating and setting the ENET_MSCR register.


What I found was that ENET_SetSMI() was being passed a srcClock_Hz value of 600 MHz.  Given that the target frequency of MDC is 2.5 MHz, and the MII_SPEED divider maxes out at (2 * 64), I could see it would be impossible to achieve 2.5 MHz with such a high input clock.  Indeed, the calculated "speed" variable was 120, meaning that (120 % 64) = 56 was actually put into MSCR[MII_SPEED].  Also, clkCycle was calculated to be 9, which is out of range of the HOLDTIME field (0-7).


So I instead tried to reverse-engineer what the input clock to the module actually is, based on the observed MDC clock rate.  The value of ENET_MSCR was 0x0170, meaning MII_SPEED (bits 6-1) was 111000 or 56 decimal.  The MDC clock rate is (input_clock / ((MII_SPEED + 1) * 2), or (input_clock / 114) in this case.  Thus, to achieve an MDC of 1.31578 MHz, the input clock must be (1.31578 * 114) = 150 MHz.


Reading the RT1050 manual, it states in "40.5 Clocks" that the module clock is "ipg_clk_root", which is in fact 150 MHz.  I verified that my IPG clock was running at 150 MHz inside my test program by calling CLOCK_GetFreq(kCLOCK_IpgClk).  So I changed EXAMPLE_CLOCK_NAME to kCLOCK_IpgClk and re-ran the example.  Now much more reasonable values are calculated in ENET_SetSMI() (speed = 30, clkCycle = 1), yielding an MDC much closer to 2.5 MHz (2.41935 MHz).  The example still initializes the PHY correctly, and the unit responds to ping.  Basically, it was dumb luck that the MDC frequency worked out to a usable value when supplying 600 MHz as the source clock frequency.


Also, your code for ENET_SetSMI() is not entirely correct.  The value for MII_SPEED is one greater than intended if the divisor is even, and the delay cycles could be calculated more precisely.  Here is a corrected version:

#define ENET_MDIO_HOLD_TIME_NS    10

void ENET_SetSMI(ENET_Type *base, uint32_t srcClock_Hz, bool isPreambleDisabled)

    uint32_t clkCycle = 0;
    uint32_t speed    = 0;
    uint32_t mscr     = 0;

    /* MDC = CLKIN / ((SPEED + 1) * 2)
     * (SPEED + 1) * 2 = CLKIN / MDC
     * SPEED + 1 = CLKIN / (MDC * 2)
     * SPEED = (CLKIN / (MDC * 2)) - 1
     * Hold cycle count = (hold_time_ns * input_clock_hz) / 10^9 */

    /* Calculate the MII speed which controls the frequency of the MDC. */
    speed = (srcClock_Hz + (2 * ENET_MDC_FREQUENCY - 1)) / (2 * ENET_MDC_FREQUENCY) - 1;
    /* Calculate the hold time on the MDIO output. */
    clkCycle = (ENET_MDIO_HOLD_TIME_NS * (srcClock_Hz / 1000) + 999999) / 1000000 - 1;
    /* Build the configuration for MDC/MDIO control. */
    mscr = ENET_MSCR_MII_SPEED(speed) | ENET_MSCR_HOLDTIME(clkCycle) | (isPreambleDisabled ? ENET_MSCR_DIS_PRE_MASK : 0);
    base->MSCR = mscr;


NXP, please verify that EXAMPLE_CLOCK_NAME should be kCLOCK_IpgClk when initializing Ethernet and the PHY on RT1050/1060; you should make sure that all instances of this value are fixed for all i.MX RT Ethernet examples.  Also please consider using my corrected version of ENET_SetSMI().  I've attached my modified version of the demo program, which contains code to verify the frequencies of the system clocks, as well as the corrected clock index.  Thanks.


David R.