Debug f107+lan8720 code generated by cube

Posted by Ryan Sanders on Wed, 29 Dec 2021 02:17:20 +0100

The w5500 used before, but the chip is becoming more and more expensive. There are about 100 lan8720a on hand. Change the scheme directly.

Previously, when working in Shenzhen, the company's gateway just used this scheme. Copy it directly.

Hardware design: the network port has no crystal oscillator. It is output by the mco pin of mcu. It is in 50Mhz mode. Others are universal connection modes

Next, let's get to the point: as the standard library used before, now try hal library. Open cubemx. After one operation, the configuration is completed and the code is generated.

The first problem is the debugging port. The official default is to close swd and jtag if it is not set, resulting in the inability to download the program twice. You need to change the system core - > sys - > debug to the corresponding mode. I use serial wire, that is, swd.

Next, you can debug normally. Only dhcp is enabled functionally, but the code fails completely.

The second problem is address setting. You need to change eth - > parameter settings - > General: Ethernet configuration - > PHY address to the corresponding value. My side is 0

OK, try again. It still doesn't work. Next, I looked at the mco pin with an oscilloscope. It does have 50mhz

The third problem is that the code uses default parameters. Some parameters are too small. For the modified part, the default task stack space is increased, and the operating system heap space is increased. Of course, this may have nothing to do with the result, and the process has to be recorded

Still can't. I have no choice but to try the previous standard library code. There's no problem at all.

Compare the code and add several print information to determine whether the chip id can be recognized. Because cubemx does not generate its id register offset address, it is written dead here

    uint32_t id_0,id_1;
    HAL_ETH_ReadPHYRegister(&heth,2,&id_0);
    HAL_ETH_ReadPHYRegister(&heth,3,&id_1);
    printf("PHY_ID = %X\n", (id_0<<16) | (id_1)); 

Register addresses 2 and 3 respectively correspond to the following description in the document

Finally, I read it out. It's no problem at all.

So the fourth question starts from lwip, but I haven't seen how cubemx can turn on the debug function of lwip for a long time. It can only turn on the global function. There are no functional modules at all, so I found lwipopts H file, add the following

#define DHCP_DEBUG            0xf7
#define UDP_DEBUG            0xf7
#define NETIF_DEBUG            0xf7

Don't let the 4th bit be 1, that is 0x08, because this bit blocks the function. See the following code segment

Well, let's continue to see the results. In general, dhcp has been broadcasting and timed out without receiving a reply.

Then you can only compare the previous code. Finally found

Finally, the key issues. The generated code reads the result of register 1 after the automatic negotiation rate is completed. Then I see that some on the Internet say 31, and I see that 31 can be read in the manual

Here, I checked the read value for breakpoint debugging, and the result is 0x04 (00000 100), that is, the speed is 001, which corresponds to 10m half duplex, which is wrong.

Conversely, when I look at the previous code, I read address 1, and there is indeed a speed indication

So I changed to the previous way and tried again. Sure enough, I succeeded.

File stm32f1xx_hal_eth.c

Function HAL_ETH_Init

After auto negotiation is completed

    /* Read the result of the auto-negotiation */
    if ((HAL_ETH_ReadPHYRegister(heth, PHY_BSR, &phyreg)) != HAL_OK)
    {
      /* In case of write timeout */
      err = ETH_ERROR;

      /* Config MAC and DMA */
      ETH_MACDMAConfig(heth, err);

      /* Set the ETH peripheral state to READY */
      heth->State = HAL_ETH_STATE_READY;

      /* Return HAL_ERROR */
      return HAL_ERROR;
    }
    //The above is the original generated code
	 //HAL_ETH_ReadPHYRegister(&heth, PHY_BSR, &regvalue);
	if((phyreg & PHY_100M_T4) != (uint32_t)RESET)
    {
      /* Set Ethernet duplex mode to FullDuplex following the autonegotiation */
      (heth->Init).DuplexMode = ETH_MODE_FULLDUPLEX;
	  (heth->Init).Speed = ETH_SPEED_100M;
    }
    else if((phyreg & PHY_100M_Duplex) != (uint32_t)RESET)
    {
      /* Set Ethernet duplex mode to FullDuplex following the autonegotiation */
      (heth->Init).DuplexMode = ETH_MODE_FULLDUPLEX;
	  (heth->Init).Speed = ETH_SPEED_100M;
    }
    else if((phyreg & PHY_100M_Half) != (uint32_t)RESET)
    {
      /* Set Ethernet duplex mode to FullDuplex following the autonegotiation */
      (heth->Init).DuplexMode = ETH_MODE_HALFDUPLEX;
	  (heth->Init).Speed = ETH_SPEED_100M;
    }
    else if((phyreg & PHY_10M_Duplex) != (uint32_t)RESET)
    {
      /* Set Ethernet duplex mode to FullDuplex following the autonegotiation */
      (heth->Init).DuplexMode = ETH_MODE_FULLDUPLEX;
	  (heth->Init).Speed = ETH_SPEED_10M;
    }
    else if((phyreg & PHY_10M_Half) != (uint32_t)RESET)
    {
      /* Set Ethernet duplex mode to FullDuplex following the autonegotiation */
      (heth->Init).DuplexMode = ETH_MODE_HALFDUPLEX;
	  (heth->Init).Speed = ETH_SPEED_10M;
    }


	 #if 0 / / original generated code
    /* Configure the MAC with the Duplex Mode fixed by the auto-negotiation process */
    if ((phyreg & PHY_DUPLEX_STATUS) != (uint32_t)RESET)
    {
      /* Set Ethernet duplex mode to Full-duplex following the auto-negotiation */
      (heth->Init).DuplexMode = ETH_MODE_FULLDUPLEX;
    }
    else
    {
      /* Set Ethernet duplex mode to Half-duplex following the auto-negotiation */
      (heth->Init).DuplexMode = ETH_MODE_HALFDUPLEX;
    }
    /* Configure the MAC with the speed fixed by the auto-negotiation process */
    if ((phyreg & PHY_SPEED_STATUS) == PHY_SPEED_STATUS)
    {
      /* Set Ethernet speed to 10M following the auto-negotiation */
      (heth->Init).Speed = ETH_SPEED_10M;
    }
    else
    {
      /* Set Ethernet speed to 100M following the auto-negotiation */
      (heth->Init).Speed = ETH_SPEED_100M;
    }
	 #endif

Several of these macros are defined as follows

#define PHY_100M_Duplex            (0x4000)
#define PHY_100M_Half            (0x2000)
#define PHY_10M_Duplex            (0x1000)
#define PHY_10M_Half            (0x0800)
#define PHY_100M_T4                (0x8000)

In addition, there is not only this modification, but also the connection status update. I won't elaborate on this

Looking back, in fact, register 31 is OK, but why is it wrong? It is worth noting that this is special ly modified. Is it difficult to enter a certain mode? I don't understand this anyway

In addition, you can consider modifying the following definitions to avoid touching the native library file

According to code analysis, it should not be difficult, and it is no longer studied here

Topics: stm32