cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H723ZG TCP/IP with lwIP - setting ethernet RxBuffer location in CubeMX giving hardfault

GGODA
Associate II

Edit : see this post for answers :

https://www.reddit.com/r/embedded/comments/13rcrqf/stm32h723zg_creating_tcpip_with_lwip_but_cannot/

reddit dot com /r/embedded/comments/13rcrqf/stm32h723zg_creating_tcpip_with_lwip_but_cannot/

 

Hello

 

Summary

  • what I want to do
  • what I have done
  • question

 

##### WHAT I WANT TO DO #####

I want to send protobuf message from my STM32H723ZG (as a client) to a Raspberry using ethernet communication.

So far I am just trying to create an ethernet connection and to ping the adress of the stm.

 

##### WHAT I HAVE DONE #####

I looked at ressources online.

The most ineteresting seemed to be this set of videos from controllersTech expaining hwo to do a bunch of ethernet thin on stm32H7xxx:

as well as this github repo + video of a polish person doing a HTTPd project ont the exact same card as me stm32h723zg:

this tutoriel from ST on how to use MPU:

honorable mention to user manual lwIP (um1713) but it doesn't talk about cubeMx so not interesting for now.

 

I tried initializing a simple lwIp project on cubeMx

Following the controllersTech's videos I :

  • enabled ETH (had to force PB0 to ETH_RXD2)


_legacyfs_online_stmicro_images_0693W00000bkmJBQAY.png 

  • checked the size of the descriptors (96B => 0x60)


_legacyfs_online_stmicro_images_0693W00000bkmIEQAY.png 

  • set the right memory address c.f. image 1 (0x3000 0000 for 1st descriptor [beginning of SRAM 1] 0x3000 0060 for second descripto)
  • enabled cortex7 data and instruction cache
  • enable lwIP
  • select LAN8742 in "platform settings"
  • keep the DHCP enabled (I also tried setting a static ip adress and it was inverted so now I keep the DHCP on)
  • set the heap size to 10KB and start it at 0x3000 4000 (SRAM2)


_legacyfs_online_stmicro_images_0693W00000bkmSDQAY.png 

  • enable MPU
  • set base address at 0x3000 000 (SRAM1)
  • set the size to 32KB (SRAM 1 et 2)
  • set memory type to non-shareable device (c.f. youtube.com/watch?v=6IUfxSAFhlw) basicaly put TEX 1 disable everything the most important is that it's not cacheable

From there I can generate the project.

I add "extern struct netif gnetif;" in the main and "ethernetif_input(&gnetif);" and "sys_check_timeouts();" to the super loop (while(1)).

I should now be able to build and run my program and ping the IP address but when debugging it I instantly get a hardfault.

When debugging using "step over", I notice that the programm/thread is stuck during "SCB_EnableDCache();"

 

I added

 

 .lwip_sec (NOLOAD) : {

 . = ABSOLUTE(0x30000000);

 *(.RxDescripSection)

  

 . = ABSOLUTE(0x30000060);

 *(.TxDescripSection)

  

 . = ABSOLUTE(0x300000C0);

 *(.RxArraySection)

 } >RAM_D2

 

In the flash script and i added the lines regarding the RxBuff

 

__attribute__((at(0x30000000))) ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */

__attribute__((at(0x30000060))) ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */

__attribute__((at(0x300000C0))) uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_RX_BUFFER_SIZE]; /* Ethernet Receive Buffer */

 

#elif defined ( __GNUC__ ) /* GNU Compiler */

 

ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT] __attribute__((section(".RxDecripSection"))); /* Ethernet Rx DMA Descriptors */

ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT] __attribute__((section(".TxDecripSection")));  /* Ethernet Tx DMA Descriptors */

uint8_t Rx_Buff[ETH_RX_DESC_CNT][ETH_RX_BUFFER_SIZE] __attribute__((section(".RxArraySection"))); /* Ethernet Receive Buffer */

 

in the ethernetif.c (only the 2 lines regarding RxBuff, the otehr one already existed).

 

No change in behavior.

I can see that the domaine 2 now have lwip_sec however it is only 192Kb (the descriptors but not the buffer) and I cannot click it in the memory details window to show what is inside (on the controllersTech video he can click on it to show what is inside).


_legacyfs_online_stmicro_images_0693W00000bkmfHQAQ.png 

I tried using the cubeMx files from the github repo mentionned earlier

The github repo seems to have everything working well.

Since I cannot specify the buffer memory address I looked at his cubeMx file.

It uses an older version of cubeMx so I had the choice to continue or to migrate, I tried both and migrate worked.

Indeed his cubeMx file is different than mine: in ETH, he can specify the memory address of the buffer! (at the time I am writting that i cannot reproduce this but I clearly remember it)

 

The rest of the setup is similar.

However, I added some print on the console through UART to send the ip address (as decimal).

The whole project can be found here : https://drive.google.com/drive/folders/1GFPTB1tn3KoMvoncMS5x6Oi6IVztdZYd?usp=sharing

 

In that project I am able to run the project for about 2 seconds the first time I launch it before it gets stuck into hardfault.

When i run it after that it run for .5 second.

 

##### Question #####

If you can answer one of those that would greatly help me:

 

1) Do you see a problem in my cubeMx setup?

2) Do you see a problem in my code?

3) Do you have an exemple of a working TCP/IP client or server ?

4) Do you know why I cannot set the memory address of the buffer in cubeMx?

5) Do you know why I get hardfaults?

6) Why do I only get 192KB in lwip_sec (no buffer)?

7) Why can't I see what is inside lwip_sec?

 

Golden question ) How to make it work? 

 

Thanks in advance for you response.

If something isn't clear, feel free to ask.

 

Regards

2 REPLIES 2
GGODA
Associate II

:)

Wilfrith
Associate

Hello. Thank you for your post because you helped me figure out my problems. I had the same issue on STM32H750VBT6 but solved.
You must pay attention to every detail because I had little mistakes that prevented my project from working. For example, one of my mistakes was configuring one of adreses missing one zero. Another time, I forgot to give all permissions in MPU according to the youtube video you provided. Another time I forgot to enable MPU to exclude the ethernet ram regions from cache. If it get cached, then the ethernet and LWIP software would not know if new data was written on the buffer by someone like the ethernet DMA. Another problem was signal integrity because I'm using an external module and wired with some clumsy board to board wires with poor shilding and grounding. That RMII digital signal is 50MHz by the way! But it worked after I cut those wires short enough. Now I'm using 10cm board to board wires again with no shilding and proper transmission line impedance control (line impedance, impedance matching, termination). It is a good idea to check if the communication with LAN8742 using that MDIO is ok. I'm not an exert but I think it serves as an auxiliary communication for configuration and some other perposes. You can check if Link is Up and speed is 10 or 100MB/s using the code I provide you in the end. Pay attention is some LWIP software package versions, the name "RxArraySection" is different. for me it is "Rx_PoolSection". My flash linker code in the sections part is as follows:
.lwip_sec (NOLOAD) :
{
. = ABSOLUTE(0x30000000);
*(.RxDecripSection)

. = ABSOLUTE(0x30000080);
*(.TxDecripSection)

. = ABSOLUTE(0x30000100);
*(.Rx_PoolSection)

} >RAM_D2
My last problem was that I thought it is not neccessary to read the buffer by my self manually for only ICMP (ping) protocol. But it seems like to be mandatory. You should check the buffer frequently using the code provided in that video you addressed:

  ethernetif_input(&gnetif);
  sys_check_timeouts();

finally if everything is ok you can use the command "arp -a" in a command window in windows to see if your device is visible in the ip map of your local network. Also I suggest you not to use DHCP in the beginning. Use a static IP first and then move on to DHCP. I also set the MPU for ethernet region as sharable. I don't know if it has any effect.
Another problem I was facing was that the first time after MCU boot or reset, it would transmit an ARP packet to my laptop and it would appear in the list but ping did not respond at all. I mean you should check ping and do not rely on arp command alone because I think somewhere in LWIP or ethernet interrupt routine,  some flags were not cleared properly. It only interrupted one time. I also checked if you do not read the buffer frequently this probelm would happen. I connected the LAN8742 directly to my laptop using static IP. Another problem you might face is windows firewall. As of my last attempt, windows 11 does not let you easily change the type of this direct ethernet network to a secure one and always count it as public unsafe and firewall rules apply. There are various solutions available but simplest is to disable firewall or configure special rule for the specific static IP adress of your device. It is a good practice to check your ethernet packets using wireshark.


My test codes for RMII and LWIP are as follows:

  uint32_t phy_id1 = 0, phy_id2 = 0;
     //Read PHY ID Register (PHYIDR1 and PHYIDR2)
    if (HAL_ETH_ReadPHYRegister(&heth, 0x01, 0x02, &phy_id1) == HAL_OK) {  // Read PHY ID1 Register
        printf("PHY ID1: 0x%X\n", phy_id1);
    } else {
        printf("Failed to read PHY ID1\n");
    }
    if (HAL_ETH_ReadPHYRegister(&heth, 0x01, 0x03, &phy_id2) == HAL_OK) {  // Read PHY ID2 Register
        printf("PHY ID2: 0x%X\n", phy_id2);
    } else {
        printf("Failed to read PHY ID2\n");
    }
    uint32_t phy_id = 0;
    for (uint8_t addr = 0; addr <= 31; addr++) {
        if (HAL_ETH_ReadPHYRegister(&heth, addr, 2, &phy_id) == HAL_OK) {
            printf(":white_heavy_check_mark: Found PHY at address: 0x%02X\n", addr);
            break;
        }
        HAL_Delay(10);
    }
    uint32_t phy_status = 0;
    if (HAL_ETH_ReadPHYRegister(&heth, 0x00, 0x01, &phy_status) == HAL_OK) {  // Read Basic Status Register (BSR)
        if (phy_status & 0x0004) {
            printf(":white_heavy_check_mark: Ethernet Link is UP\n");
        } else {
            printf(":cross_mark: Ethernet Link is DOWN\n");
        }
    } else {
        printf(":cross_mark: Failed to read PHY Status Register\n");
    }
    if (HAL_ETH_ReadPHYRegister(&heth, 0x00, 0x1F, &phy_status) == HAL_OK) {  // LAN8720 Special Status Register
printf("PHY Special Status Register: 0x%X\n", phy_status);
if (phy_status & (1 << 4)) {
printf(":white_heavy_check_mark: 100 Mbps Mode\n");
} else {
printf(":white_heavy_check_mark: 10 Mbps Mode\n");
}
if (phy_status & (1 << 3)) {
printf(":white_heavy_check_mark: Full Duplex Mode\n");
} else {
printf(":white_heavy_check_mark: Half Duplex Mode\n");
}
} else {
printf(":cross_mark: Failed to read PHY Special Status Register\n");
}
    uint32_t phy_status = 0;
    if (HAL_ETH_ReadPHYRegister(&heth, 0,1, &phy_status) == HAL_OK) {  // Read Basic Status Register (BSR)
        if (phy_status & 0x0004) {
            printf(":white_heavy_check_mark: Ethernet Link is UP\r\n");
        } else {
            printf(":cross_mark: Ethernet Link is DOWN (Check Cable!)\r\n");
        }
    } else {
        printf(":cross_mark: Failed to read PHY Status Register\r\n");
    }
    HAL_Delay(1);
    extern struct netif gnetif;
    if (!netif_is_up(&gnetif)) {
        printf(":cross_mark: LwIP network interface is DOWN!\r\n");
    } else {
        printf(":white_heavy_check_mark: LwIP network interface is UP\r\n");
    }
    HAL_Delay(1);
    struct netif *netif = &gnetif;  // Global network interface (from lwip.c)
    if (netif_is_up(netif) && netif->ip_addr.addr != 0) {
        printf("STM32 IP Address: %s \r\n", ip4addr_ntoa(&netif->ip_addr));
    } else {
        printf("No IP assigned yet (Waiting for DHCP...)\r\n");
    }
    HAL_Delay(1);
    printf(":white_heavy_check_mark: STM32 MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n",
            gnetif.hwaddr[0], gnetif.hwaddr[1], gnetif.hwaddr[2],
            gnetif.hwaddr[3], gnetif.hwaddr[4], gnetif.hwaddr[5]);
    HAL_Delay(1);
    if (NVIC_GetEnableIRQ(ETH_IRQn)) {
        printf(":white_heavy_check_mark: ETH Interrupt is ENABLED in NVIC!\n");
    } else {
        printf(":cross_mark: ETH Interrupt is DISABLED in NVIC!\n");
    }
    HAL_Delay(1);
    printf("\n\n\n");
        HAL_Delay(1);
 
        HAL_Delay(10000);