cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H750B - TouchGFX and Ethernet

Garnett.Robert
Senior III

Hi

Using the following tools:

TouchGFX Designer 4.24.0

CubeIDE 1.16.1 and

CubeMx 6.11.0

 

I have attempted to build a system with ethernet capability.

 

I added the ethernet peripheral, LwIP compiled it without any errors, but the ethernet does not work.  The router it is connected to does not "see" the MAC address and fails to assign an IP address. I have DHCP enabled.

 

I bolted Adam Berlinger's code into one of my projects

Adams Ethernet

 

and that worked fine, with DHCP but the I cannot get the latest CubeMX build to work.

 

I have used the same board and cable that I used with Adams ethernet code for the new build so it's not the hardware.

Is the latest CubeMX build supposed to at least connect to a router and allow a ping test or do I have to do something else. The touchGFX code is working fine.

To be quite frank I find the ST Ethernet firmware and builds to be a nightmare.  You basically have to be an experienced network engineer first to understand the jargon. SMTP, DHCP etc which is never spelled out in full in the cube help panel and secondly to work your way through the code which is like spaghetti to find out what is going wrong.  LwIP is very clever, but its documentation is a joke considering how widely it is used.  Compared to a system like FreeRTOS which has excellent documentation, a vibrant forum and heap and heaps (pardon the pun) of examples, LwIP is more like a hackers bad dream. Its been around for over twenty years yet the documentation is sparse to say the least.

The Wiki content for the socket API is just a regurgitation of the header file for the macro or function. Here is the entry for setsocketopt:

 

Snag_15592871.png

Now I'm guessing that setsockopt sets some options for the socket the application programmer is trying to instantiate. But it doesn't explain that, or what the various macro parameters do and what valid inputs they can be.

I am guessing that s is the socket handle, but what the rest of them are is beyond me. An application Programming Interface needs a lot more than code it needs an explanation of what the function does, when you should use it and what its parameters are.

Surely someone in ST could come up with some code that would provide simple things like ubiquitous for ethernet such as  DHCP, mDNS, SNTP and a simple socket interface without the applications programmer needing to do a PhD in advanced network engineering. The hardware works fine, but the software...

From my little rant the perceptive among you probably sense I am just a little frustrated. I reckon I have spent more time trying to get ethernet to work than I have spent on all the other peripherals combined.

Am I being silly, am I missing something? What do others think?

 

Kind regards

Rob

 

1 ACCEPTED SOLUTION

Accepted Solutions

Hello @Garnett.Robert ,

Did you try to implement the second suggestion on the FreeRTOS forum other than the first workaround. 

Can you share with us the project version with FreeRTOS only reproducing the issue as on a fresh project with the same setting for FreeRTOS as yours I'm unable to reproduce this problem the rand function is working as expected. 
Regards 

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

View solution in original post

13 REPLIES 13
STea
ST Employee

Hello @Garnett.Robert ,

Thank you for sharing your experience. I get that it can be quite challenging with Ethernet and related Middleware such as LWIP for the first time without initialization to basic networking concepts .i also agree with you on the basis that LWIP documentation lacks some details in the functions description but we try to explain its basics and ways of using it with our own documentation such as this AN3966 UM1713  AN3102 with LWIP concepts applicable on all STM32 series and a lot of examples using LWIP in community knowledge base such as the article you tried written by Adam and other example present in CubeFirmwareH7.and we are continently working on making the Ethernet Programming easier thro examples and documentation so any suggestions would be appreciated.
From your problem description I don't get exactly where you get stuck at and what is not working exactly.
If you could share with us more details about your software environment your IOC file and the relevant code changes apported to the generated it will help us investigate this issue.
Regards 

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Hi, ST

 

Thankyou for your reply.

 

I will arc up the example I created and trace the program flow with the debugger to attempt to find the issue.  The problem is that this is a very time consuming process.  I will also have a look at the documents you listed although I am pretty sure I have read at least one of them.

 

I have got the ethernet to work with an F7 board with a very old version of Cube, probably ten years or more ago but as I remember that was quite a struggle to. One of the problems I encountered since was that the ethernet driver has changed so much. Some functions that were provided in the older versions are no incorporated in new releases.  it is such a moving target.

 

I think ST should work with AWS's Richard Barry and port in FreeRTOS+TCP.  Some people have got this working on STF4 and H7 platforms.  FreeRTOS+TCP may not have everything that LwIP does, but it is simpler and the documentation is much better.  Also the support by Richard and his colleagues is excellent. In my view developers  are never going to use an ST micro as the basis for some complex communications application, all you need is basic functions, DHCP, mDNS, sockets, SNTP, SMTP and IGCP and these should be set up to work out of the box.

You should be able to ping the thing, get date and time, bring up a web page and move data around at modest rates.

The reason I want to use ethernet is to for remote time stamped logging data  and to set the RTC so time-stamping can use network time to set the clock so that clock setting functions don't have to be provided to the user.  No one has to set the time on their mobile phone anymore or worry about IP addresses.

 

I did think of trying ThreadX as a number of people claim that LwIP works better with this, however my understanding is that TouchGFX only works with FreeRTOs so ThreadX is only an option for headless systems.

 

On another topic. A lot of people complain about the HAL_Drivers, I like them. With the exception of the ethernet driver they are generally easy to follow and if they don't provide the exact functionality you need you can clone and modify them.  You can speed them up by stripping out unused functionality and doing small optimisations. I also like the CubeMX suite and TouchGFX.  CuibeIDE has some great features, rtos aware, profiling, the Build analyser etc which are easy to use and very powerful.  I started embedded programming using Keil uVision which was robust, but the analytical functions were lacking.  I had to write a .map analyser for uVision to do the same thing that the Build Analyser does. Nobody wants to wade through fifty or more pages of a map file to get the info they want.

 

Kind regards

Rob

Hi , i agree, that MX not prepare working peripheral code , but this is normal , it create only first hw level init.

Too @STea appnotes have zero lines about MX setup to do it simpler.

You need forget , that this exist here. But when you preffer realy worked envi choice for example GitHub - stm32duino/STM32Ethernet: Arduino library to support Ethernet for STM32 based board 

Hi Again ST

 

I ran traced the program flow of MX_LWIP_Init() to determine where things were going wrong.  It didn't take long to find as the error occurs in the  tcpip_init( NULL, NULL );  function in the tcpip.c file function lwip_init(void) and more precisely in the udp_init() function. This may be found in file udp,c,

 

 

/**
 * Initialize this module.
 */
#pragma GCC push_options
#pragma GCC optimize ("O0")
void udp_init(void)
{
#ifdef LWIP_RAND
	uint32_t randNo = LWIP_RAND();	/* <==  Fails in the rand function rjg debug */  

  udp_port = UDP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND());
#endif /* LWIP_RAND */
}
#pragma GCC pop_options

 

The call to the stdlib, rand() function fails at the assert function:

 

 

          rand:
90033524:   ldr     r3, [pc, #88]   @ (0x90033580 <rand+92>)
90033526:   push    {r4, lr}
90033528:   ldr     r4, [r3, #0]
9003352a:   ldr     r3, [r4, #48]   @ 0x30
9003352c:   cbnz    r3, 0x9003355c <rand+56>
9003352e:   movs    r0, #24
90033530:   bl      0x900333a8 <malloc>
90033534:   mov     r2, r0
90033536:   str     r0, [r4, #48]   @ 0x30
90033538:   cbnz    r0, 0x90033544 <rand+32>
9003353a:   ldr     r3, [pc, #72]   @ (0x90033584 <rand+96>)
9003353c:   ldr     r0, [pc, #72]   @ (0x90033588 <rand+100>)
9003353e:   movs    r1, #82 @ 0x52
90033540:   bl      0x90033360 <__assert_func> ;<== Fails here program hangs no hard fault
90033544:   ldr     r1, [pc, #68]   @ (0x9003358c <rand+104>)
90033546:   ldr     r3, [pc, #72]   @ (0x90033590 <rand+108>)
90033548:   strd    r1, r3, [r0]
9003354c:   ldr     r3, [pc, #68]   @ (0x90033594 <rand+112>)
9003354e:   str     r3, [r0, #8]
90033550:   movs    r3, #11
90033552:   strh    r3, [r0, #12]

 

The program ends in the while(1) loop in syscalls

 

 

void _exit (int status)
{
	_kill(status, -1);
	while (1) {}		/* Make sure we hang here */
}

 

This is weird so I tried the rand function in main.c. and it worked.

 

I call the MX_LWIP_Init from the default task that i renamed monitorTask so I checked the stack assignment, it was only 128 words so I increased it to 4096 thinking it might be a stack problem. This didn't fix the problem.  I looked at the heap allocation as rand calls malloc.  My heap in FreeRTOS is set to 100000 and the system heap set in the linker script is 0x1000 (4k) which seems OK.

The rand function is not guaranteed thread safe so i disabled interrupts before ran is called, but it still failed at the

_exit function.

 

I removed the call to rand and made the number a constant 0xCOAD1234. Viz.

 

 

/**
 * Initialize this module.
 */
#pragma GCC push_options
#pragma GCC optimize ("O0")
void udp_init(void)
{
#ifdef LWIP_RAND
	taskDISABLE_INTERRUPTS();
//	uint32_t randNo = LWIP_RAND();	/* rjg debug */

//  udp_port = UDP_ENSURE_LOCAL_PORT_RANGE(59876);
	udp_port = 59876;
	taskENABLE_INTERRUPTS();
#endif /* LWIP_RAND */
}
#pragma GCC pop_options

 

This fixed the call to udp_init, but then the program crashed on the following call to tcp_init on the same macro:

 

void
tcp_init(void)
{
#ifdef LWIP_RAND
  tcp_port = TCP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); 
#endif /* LWIP_RAND */
}

 

I replaced the call to rand with a fixed value:

 

 

void
tcp_init(void)
{
#ifdef LWIP_RAND
//  tcp_port = TCP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND());
tcp_port = 59123;
#endif /* LWIP_RAND */
}

 

This allowed the tcp_init function to complete without crashing, but sadly something else went wrong in the DHCP module in the dhcp_discover function. And yes, you guessed it, the lead in the saddlebags was our old friend rand(), line 1913 of the dhcp,c module! viz:

 

 

  /* DHCP_REQUEST should reuse 'xid' from DHCPOFFER */
  if ((message_type != DHCP_REQUEST) || (dhcp->state == DHCP_STATE_REBOOTING)) {
    /* reuse transaction identifier in retransmissions */
    if (dhcp->tries == 0) {
#if DHCP_CREATE_RAND_XID && defined(LWIP_RAND)
      xid = LWIP_RAND();  /* <==  ****************** This one **********/
#else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */
      xid++;
#endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */
    }
    dhcp->xid = xid;
  }
  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
              ("transaction id xid(%"X32_F")\n", xid));

 

I did a search for LWIP_RAND and found it is sprinkelrd liberally around the LWIP code:

 

Snag_b106514.png

That's it for now it is lunch time.

I will make my own rand code and tackle the problem on a full stomach. Fixing this is not for the mal-nourished!

Hello @Garnett.Robert ,

can you share your IOC file generating this code after some examination it seems like you are running from address space 90000000 meaning you are executing from external memory.

are you using an external clock source other then systick as you are using FreeRTOS ?

are you configuring the Ethernet in MII mode with the correct pins assigned to the board.

a don't see why you should be stuck in a call from the standard library this is most probably a miss configuration, or we are missing something to get the full picture. 
if you are using external memory, it is to note the following mentioned in UM2488

STea_0-1729518971373.png

Regards

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Hi ST,

 

I have configured for 100Mb full duplex and have checked this.  I also checked the solder bridges and resistors and they are in the default configuration. I am using the same config as Adams i.e. MII not RMII.

 

I will check the pinout and config again just to be certain and will get back to you.  Like you I don't understand why rand() works in main, but not in a task. 

 

Kind Regards

Rob

Hello again,

I replaced all of the calls to LWIP_RAND aka rand() with some "magic numbers" which allowed the Ethernet initialisation to complete and viola it works.

I went on to the FreeRTOS forum and asked why rand() is failing from within tasks. Like me they thought it was a malloc - heap problem as rand calls malloc but returns with invalid addresses in the registers which causes the error at the assembler

<__assert_func> 

 

They made a few suggestions.

Ihttps://forums.freertos.org 

 

The reason I'm using external flash is that this processor has only limited on-board flash and as the project was started from TouchGFX the program has a bootloader that uses the 2 MByte of external flash.

I have attached my IOC and the linker script to assist you.

I will let you know if the FreeRTOS boys come up with anything else.

 

Kind regards

Rob

 

I have attached the IOC file.

 

Hello @Garnett.Robert ,

Did you try to implement the second suggestion on the FreeRTOS forum other than the first workaround. 

Can you share with us the project version with FreeRTOS only reproducing the issue as on a fresh project with the same setting for FreeRTOS as yours I'm unable to reproduce this problem the rand function is working as expected. 
Regards 

In order to give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Hi Stea,

I failed to inform you that I produced the project from TouchGFX. (4.24.0) To assist you I go through the steps I used below ( Iwrote these down as I progressed)

1. Initial build from TouchGFX for an STM32H750B

2. Use the cube IOC file embedded in the project to add ethernet and LwIP. On opening the CubeMX window the IDE asks if I wish to migrate the project to the newer CubeMX version (6.12.1). I pushed yes migrate.

3. I Select Eth in the CubeMX peripheral tree and set it to MII Full Duplex Only and I activate the Rx and Tx error signals

4. I then set all of the 16 Ethernet I/O Pins to Speed Very High

5. I set the Ethernet global interrupt to enabled. I leave the wake-up interrupt disabled.

6. I then enable LwIP in the cube Middleware and Software pack tree.

7. I set the Ethernet parameters thus:

- Platform LAN8742
- Set LWIP_DNS module = Enabled
- Set LWIP_MULTICAST_TX_OPTIONS = enabled (for IGMP)
- Check that memP_NUM_IGMP_GROUP > 1 (it is 8)
- Set LWIP_SNTP to enabled
- Set SNTP_MAX_SERVERS = 2
- Set SNTP_GET_SERVERS_FROM_DHCP = 1
- Set SNTP_COMP_ROUNDTRIP = enabled

8. Saved the IOC file from within CubeIDE then answered "Yes" to the do you wish to generate code dialog.

9. I then do a full clean and build of the project

10. Under the debugger I run the project on my board and the LWIP_RAND function rand() from stdlib errors into syscalls _exit(int status) with status equal to 1.

11. On the advice of the FreewRTOS team I changed the caddr_t _sbrk(int incr) function to

#include <errno.h>
#include <stdio.h>

#include <sys/types.h> // Added as a workaround for Bugzilla 158966

/* Variables */
extern int errno;

/* Functions */

/**
 _sbrk
 Increase program data space. Malloc and related functions depend on this
**/
caddr_t _sbrk(int incr)
{
	extern char end asm("end");
	static char *heap_end;
	char *prev_heap_end;
	char * stack_ptr;

	if (heap_end == 0)
		heap_end = &end;

	__asm volatile ("MRS %0, msp" : "=r" (stack_ptr) );

	prev_heap_end = heap_end;
	if (heap_end + incr > stack_ptr)
	{
		errno = ENOMEM;
		return (caddr_t) -1;
	}

	heap_end += incr;

	return (caddr_t) prev_heap_end;
}

 

The code then runs without the rand() error, the TouchGFX responds to screen touches, but no ethernet port appears on my network monitor (Linksys Modem or Advanced IP Scanner.)

12. GPIO examination. I checked the GPIO's assigned for the ether net peripheral against Adams working version and I found a difference. viz.

    /**Adams ETH GPIO Configuration
    PG11     ------> ETH_TX_EN
    PE2     ------> ETH_TXD3
    PG12     ------> ETH_TXD1
    PG13     ------> ETH_TXD0
    PA9     ------> ETH_TX_ER
    PI10     ------> ETH_RX_ER
    PC1     ------> ETH_MDC
    PC2     ------> ETH_TXD2
    PC3     ------> ETH_TX_CLK
    PA2     ------> ETH_MDIO
    PA1     ------> ETH_RX_CLK
    PA0     ------> ETH_CRS
    PA7     ------> ETH_RX_DV
    PC4     ------> ETH_RXD0
    PB1     ------> ETH_RXD3
    PA3     ------> ETH_COL
    PC5     ------> ETH_RXD1
    PB0     ------> ETH_RXD2

   /**Cube MX ETH GPIO Configuration
    PG11     ------> ETH_TX_EN
    PE2     ------> ETH_TXD3
    PG12     ------> ETH_TXD1
    PG13     ------> ETH_TXD0
    PA9     ------> ETH_TX_ER
    PI10     ------> ETH_RX_ER
    PC1     ------> ETH_MDC
    PC2     ------> ETH_TXD2
    PC3     ------> ETH_TX_CLK
    PA2     ------> ETH_MDIO
    PA1     ------> ETH_RX_CLK
    PA7     ------> ETH_RX_DV
    PC4     ------> ETH_RXD0
    PB1     ------> ETH_RXD3
    PC5     ------> ETH_RXD1
    PB0     ------> ETH_RXD2
    */

 

13. to make it easier to identify the board in my network maps I changed the MAC ADDRESS TO

uint8_t MACAddr[6] ;
heth.Instance = ETH;
MACAddr[0] = 0xE0;
MACAddr[1] = 0xE1;
MACAddr[2] = 0xE2;
MACAddr[3] = 0xE3;
MACAddr[4] = 0xE4;
MACAddr[5] = 0xE5;

i.e "E0 E1 E2 E3 E4 E5"

I then compiled and ran the code, but still no IP address appeared for that MAC Address.

14. I then edited the GPIO initialisation to match Adam's. I did a full clean and build and ran the program under the debugger again. I waiter ten minutes for the router to identify and connect to myboard, but again no internet connection.

15. I added a breakpoint after the RxPktSemaphore in the ethernetif_input function to observe whether valis packets were being recieved but the program never hit that interrupt. I checked the ETH_DMACIER register and the following interrupts were enabled: TIE, RIE, RBUE, FBEE, AIE and NIE. I compared this with Adams working version and found after the HAL_ETH_Start_IT(&heth); has executed the same interrupts with the exception of the RBUE interrupt were set.

16. I then added some linker script code consistant with Adam's example viz:

/*********************************************************************/
/* Ethernet Buffers */
.lwip_sec (NOLOAD) : {
. = ABSOLUTE(0x30040000);
*(.RxDecripSection)

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

. = ABSOLUTE(0x30040200);
*(.RxArraySection)
} >RAM_D2

This did not fix the problem.

17. Added in additional options in lwipopts.h, but still did not work.

                                                 *************************************************

 

I think that if you are building without TouchGFX and just using CubeMX perhaps it does work.  The rand() problem may be a conseqeunce of the sysmem.c code produced under TouchGFX being different from that produced with CubeMX alone.  I will try this.

I would would like to try the system with no TouchGFX, just using FreeRTOS and LWIP. The problem I have is that I need the external flash and bootloader provided by the TouchGFX build to fit LwIP in and I haven't a clue how to do that and I don't have the time to learn as I need to get on with my current project.  I have spent about 24 hours work time on this.

 

I will try the rand() function on a project generated by CubeMX and see if it is different from that produced by TouchGFX.

 

Kind regards

Rob