Search code examples
stm32tcpclientethernetlwip

NUCLEO-H743ZI2 lwIP TCP Connection


How can I establish a TCP Connection with an NUCLEO-H743ZI2 ?

I managed to establish a simple TCP Connection with a NUCLEO-F429ZI and my PC using the lwIP stack (without FreeRTOS). The NUCLEO-F429ZI was the client and connected to a server, which was running on my pc using hercules. This worked without any problems. Now I tried to use a NUCLEO-H743ZI2 instead, because I needed more RAM for my application. I implemented basecally the same application but the tcp connection is never established. After calling tcp_connect(...) the callback is never called.

I tried multiple different firmwares and configurations but nothing worked for me.

I followed this guide: https://community.st.com/s/article/FAQ-Ethernet-not-working-on-STM32H7x3

And used the linkerscript and the MPU_Config() function from the example project but it still doesn't work.

I also tried to use this answer: STM32H7 LAN8742 LwIP only works fine after power-up, not after reset I looked through the github repository and tried to match my code but this didn't work either.

Does anybody have an idea what I might be doing wrong ?

If you need any code just ask and I'll provide it as fast as possible.

Thank you for taking the time to read (and hopefully answer) this :)


Solution

  • Okay so what worked for me was to ensure 3 thinks:

    1. Use the right Linkerscript
    2. Configure the MPU
    3. Add SCB_CleanInvalidateDCache(); in low_level_output(...)

    Linkerscript:

    It is important that the Data for Ethernet is stored in the right locations. Therefore you can simply use the linkerscript from the example: https://github.com/bkht/Nucleo-H743ZI_LAN8742_LwIP_NO-SYS/blob/master/TrueSTUDIO/Nucleo-H743ZI_Jack_012_tcp_LAN8742_gh/STM32H743ZI_FLASH.ld

    STM32H743ZI_FLASH.ld:

    /*
    *****************************************************************************
    **
    
    **  File        : stm32_flash.ld
    **
    **  Abstract    : Linker script for STM32H743ZI Device with
    **                2048KByte FLASH, 1056KByte RAM
    **
    **                Set heap size, stack size and stack location according
    **                to application requirements.
    **
    **                Set memory bank area and size if external memory is used.
    **
    **  Target      : STMicroelectronics STM32
    **
    **  Environment : Atollic TrueSTUDIO(R)
    **
    **  Distribution: The file is distributed as is, without any warranty
    **                of any kind.
    **
    **  (c)Copyright Atollic AB.
    **  You may use this file as-is or modify it according to the needs of your
    **  project. This file may only be built (assembled or compiled and linked)
    **  using the Atollic TrueSTUDIO(R) product. The use of this file together
    **  with other tools than Atollic TrueSTUDIO(R) is not permitted.
    **
    *****************************************************************************
    */
    
    /* Entry Point */
    ENTRY(Reset_Handler)
    
    /* Highest address of the user mode stack */
    _estack = 0x24080000;    /* end of RAM was 0x20020000 */
    /* Generate a link error if heap and stack don't fit into RAM */
    _Min_Heap_Size = 0x2000;      /* required amount of heap  was 0x1000 */
    _Min_Stack_Size = 0x4000; /* required amount of stack  was 0x1000 */
    
    /* Specify the memory areas */
    MEMORY
    {
    DTCMRAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 128K
    RAM_D1 (xrw)      : ORIGIN = 0x24000000, LENGTH = 512K
    RAM_D2 (xrw)      : ORIGIN = 0x30000000, LENGTH = 288K
    RAM_D3 (xrw)      : ORIGIN = 0x38000000, LENGTH = 64K
    ITCMRAM (xrw)      : ORIGIN = 0x00000000, LENGTH = 64K
    FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 2048K
    }
    
    /* Define output sections */
    SECTIONS
    {
      /* The startup code goes first into FLASH */
      .isr_vector :
      {
        . = ALIGN(4);
        KEEP(*(.isr_vector)) /* Startup code */
        . = ALIGN(4);
      } >FLASH
    
      /* The program code and other data goes into FLASH */
      .text :
      {
        . = ALIGN(4);
        *(.text)           /* .text sections (code) */
        *(.text*)          /* .text* sections (code) */
        *(.glue_7)         /* glue arm to thumb code */
        *(.glue_7t)        /* glue thumb to arm code */
        *(.eh_frame)
    
        KEEP (*(.init))
        KEEP (*(.fini))
    
        . = ALIGN(4);
        _etext = .;        /* define a global symbols at end of code */
      } >FLASH
    
      /* Constant data goes into FLASH */
      .rodata :
      {
        . = ALIGN(4);
        *(.rodata)         /* .rodata sections (constants, strings, etc.) */
        *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
        . = ALIGN(4);
      } >FLASH
    
      .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
      .ARM : {
        __exidx_start = .;
        *(.ARM.exidx*)
        __exidx_end = .;
      } >FLASH
    
      .preinit_array     :
      {
        PROVIDE_HIDDEN (__preinit_array_start = .);
        KEEP (*(.preinit_array*))
        PROVIDE_HIDDEN (__preinit_array_end = .);
      } >FLASH
      .init_array :
      {
        PROVIDE_HIDDEN (__init_array_start = .);
        KEEP (*(SORT(.init_array.*)))
        KEEP (*(.init_array*))
        PROVIDE_HIDDEN (__init_array_end = .);
      } >FLASH
      .fini_array :
      {
        PROVIDE_HIDDEN (__fini_array_start = .);
        KEEP (*(SORT(.fini_array.*)))
        KEEP (*(.fini_array*))
        PROVIDE_HIDDEN (__fini_array_end = .);
      } >FLASH
    
      /* used by the startup to initialize data */
      _sidata = LOADADDR(.data);
    
      /* Initialized data sections goes into RAM, load LMA copy after code */
      .data : 
      {
        . = ALIGN(4);
        _sdata = .;        /* create a global symbol at data start */
        *(.data)           /* .data sections */
        *(.data*)          /* .data* sections */
    
        . = ALIGN(4);
        _edata = .;        /* define a global symbol at data end */
      /* } >DTCMRAM AT> FLASH */
      } >RAM_D1 AT> FLASH
    
    
      /* Uninitialized data section */
      . = ALIGN(4);
      .bss :
      {
        /* This is used by the startup in order to initialize the .bss secion */
        _sbss = .;         /* define a global symbol at bss start */
        __bss_start__ = _sbss;
        *(.bss)
        *(.bss*)
        *(COMMON)
    
        . = ALIGN(4);
        _ebss = .;         /* define a global symbol at bss end */
        __bss_end__ = _ebss;
      /* } >DTCMRAM */
      } >RAM_D1
    
    
      /* User_heap_stack section, used to check that there is enough RAM left */
      ._user_heap_stack :
      {
        . = ALIGN(4);
        PROVIDE ( end = . );
        PROVIDE ( _end = . );
        . = . + _Min_Heap_Size;
        . = . + _Min_Stack_Size;
        . = ALIGN(4);
      } >DTCMRAM
    
    
    
    
      .lwip_sec (NOLOAD) : {
        . = ABSOLUTE(0x30040000);
        *(.RxDecripSection) 
    
        . = ABSOLUTE(0x30040060);
        *(.TxDecripSection)
    
        . = ABSOLUTE(0x30040200);
        *(.RxArraySection) 
      } >RAM_D2 AT> FLASH
    
    
      /* Remove information from the standard libraries */
      /DISCARD/ :
      {
        libc.a ( * )
        libm.a ( * )
        libgcc.a ( * )
      }
    
      .ARM.attributes 0 : { *(.ARM.attributes) }
    }
    

    MPU Config:

    Also you should use the same MPU_Config() as the example project which is defined here:https://github.com/bkht/Nucleo-H743ZI_LAN8742_LwIP_NO-SYS/blob/master/Src/main.c

    void MPU_Config(void)
    {
      MPU_Region_InitTypeDef MPU_InitStruct = {0};
    
      /* Disables the MPU */
      HAL_MPU_Disable();
      /**Initializes and configures the Region and the memory to be protected
      */
      MPU_InitStruct.Enable = MPU_REGION_ENABLE;
      MPU_InitStruct.Number = MPU_REGION_NUMBER0;
      MPU_InitStruct.BaseAddress = 0x30040000;
      MPU_InitStruct.Size = MPU_REGION_SIZE_256B;
      MPU_InitStruct.SubRegionDisable = 0x0;
      MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
      MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
      MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
      MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
      MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
      MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
    
      HAL_MPU_ConfigRegion(&MPU_InitStruct);
      /**Initializes and configures the Region and the memory to be protected
      */
      MPU_InitStruct.Enable = MPU_REGION_ENABLE;
      MPU_InitStruct.Number = MPU_REGION_NUMBER1;
      MPU_InitStruct.BaseAddress = 0x30044000;
      MPU_InitStruct.Size = MPU_REGION_SIZE_16KB;
      MPU_InitStruct.SubRegionDisable = 0x0;
      MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
      MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
      MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
      MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
      MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
      MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
    
      HAL_MPU_ConfigRegion(&MPU_InitStruct);
      /* Enables the MPU */
      HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
    
    }
    

    Call it at the start of main:

    int main(void)
    {
    
      MPU_Config();
      ...
    
    }
    

    Add SCB_CleanInvalidateDCache(); in low_level_output(...):

    The function static err_t low_level_output(struct netif *netif, struct pbuf *p) is located in ethernetif.c. You have to add the function SCB_CleanInvalidateDCache(); near the end like this:

    static err_t low_level_output(struct netif *netif, struct pbuf *p)
    {
      ...  
    
      SCB_CleanInvalidateDCache(); //<-- Add this line if it is missing
      HAL_ETH_Transmit(&heth, &TxConfig, ETH_DMA_TRANSMIT_TIMEOUT);
    
      return errval;
    }