FreeRTOS+TCP for STM32H7?

Thank you for the time giving your help !
API between STM32F7 and STM32H7 seems to be quiet different but I will try to inspire on that. If I manage, i will give my STM32H7 API with great pleasure !

1 Like

I found the original driver: NetworkInterface_STM32H7.c (8.4 KB) !

It was updated in January 2019. It is using the HAL from STM32H7. If I find a later version, it will be posted here.

If you have any questions about it, you can ask them here.

Appreciate it if somebody could create a PR to upstream this. https://github.com/FreeRTOS/FreeRTOS/tree/master/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface

Sure I will prepare a PR for the STM32H7 network driver, after checking the source code once more.
Hein

I prepared a PR #48 called:

FreeRTOS+TCP : Adding a Network Interface for STM32H7

Please feel free to use it and report any problems that you encounter in this thread.

PS. the adapted NetworkInterface.c can be found here

1 Like

Thank you so much for your responsiveness and your help, I really appreciate it ! I’m going to check on what you have posted

@htibosch

Could you clarify something for me regarding the intent for xNetworkInterfaceInitialise() ?

I get that there is a one-time initialization of the EMAC/PHY and task creation.

I’m confused about subsequent calls to xNetworkInterfaceInitialise(). In this case…

Is the intent that it simply return link status?

… OR…

Is the intent that it check link status and attempt to restore the link if down?

The following piece of code is taken from the STM32Fxx driver:

if( xMacInitStatus == eMACPass )
{
    if( xPhyObject.ulLinkStatusMask != 0uL )
    {
        /* Enable interrupts. */
        xETH.Instance->DMAIER |= ETH_DMA_ALL_INTS;
        xReturn = pdPASS;
        FreeRTOS_printf( ( "Link Status is high\n" ) ) ;
    }
    else
    {
        /* For now pdFAIL will be returned. But prvEMACHandlerTask() is running
        and it will keep on checking the PHY and set 'ulLinkStatusMask' when
        necessary. */
        xReturn = pdFAIL;
    }
}
else
{
    xReturn = pdFAIL;
}

It fact it only returns the PHY Link Status.
This function xNetworkInterfaceInitialise() is called from the IP-task and therefor it may not initialise the PHY.
The deferred interrupt handler task “owns” the PHY and it may re-start a negotiation when necessary.
The other driver has this code:

if( xPhyCheckLinkStatus( &xPhyObject, xResult ) != 0 )
{
    /* Something has changed to a Link Status, need re-check. */
    prvEthernetUpdateConfig( pdFALSE );
}
1 Like

I adopted the network interface which you have provided a year ago. It worked on STM32H7 in normal cases, but when I plugged out the ethernet cable and plugged it in again after ca. 30 seconds, it was not able to receive any data again.

After a lot of debugging, I figured out, that I have to reinitialize the MAC after the PHY link got done (I check the PHY link state in a cycling thread and call there FreeRTOS_NetworkDown() if needed). I changed the code to the one below and now all is working as expected:

BaseType_t xNetworkInterfaceInitialise( void ) {
if (eth_input_task_handle == NULL) {
	xTaskCreate(eth_input_task, "eth_input", 1024, NULL, 0, &eth_input_task_handle);
}

// restart MAC if it was already started
if(HAL_ETH_GetState(&heth) & HAL_ETH_STATE_BUSY_RX)	{
	if(HAL_ETH_Stop_IT(&heth) != HAL_OK) {
		return pdFAIL;
	}

	/* Disable global ethernet interrupt */
	HAL_NVIC_DisableIRQ(ETH_IRQn);

	if(HAL_ETH_DeInit(&heth) != HAL_OK) {
		return pdFAIL;
	}
}

/* Init MAC */
if(HAL_ETH_Init(&heth) != HAL_OK) {
	return pdFAIL;
}

/* Set IRQ priority and enable global ethernet interrupt */
HAL_NVIC_SetPriority(ETH_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(ETH_IRQn);

// Assign memory buffers to DMA Rx descriptor
for(uint32_t idx = 0; idx < ETH_RX_DESC_CNT; idx ++)
{
	if(HAL_ETH_DescAssignMemory(&heth, idx, (uint8_t*) ethRxBuffer[idx], NULL) != HAL_OK)
	{
		return pdFAIL;
	}
}

/* Start MAC and DMA */
if (HAL_ETH_Start_IT(&heth) != HAL_OK) {
	return pdFAIL;
}

/* check PHY status */
if(phy_isLinkUp()) {
	return pdPASS;
}
else {
	return pdFAIL;
}

}

Thank you very much for your template, that was a big help for me!

Good to hear, and thank you for reporting.

Maybe it is still good to also look at this NetworkInterface.c from my PR.

I would recommend to use these stages:

    eMACInit,   /* Must initialise MAC. */
    eMACPass,   /* Initialisation was successful. */
    eMACFailed, /* Initialisation failed. */

You said that the ETH needs a new initialisation after the Link Status comes up again.
In the STM32Fxx driver I did the same: whenever Link Status comes up, the function prvEthernetUpdateConfig() is called. One of the reasons is that the ETH must be updated with the new negotiated network parameters (speed, duplex, etc).

@htibosch Thanks once again!

@htibosch Another lingering question I have is about the intent of phyHandling.c / .h.

Are PHYs basically compliant to “standard” or “defacto” register definitions and thus phyHandling is meant to eliminate the need for a phy-specific / device-specific “driver”?

In my case, I have a vendor supplied PHY “driver”. Should I go through the bother of mapping that to FreeRTOS+TCP phyHandling.c, or ignore phyHandling.c?

I guess what I’m trying to really understand is how intertwined is phyHandling.c into the rest of the FreeRTOS+TCP code.

Your comments would be greatly appreciated!

There is a standard among the different Ethernet PHY’s, but there are also many deviations.
When I worked with boards from many different vendors, and on various platforms, I thought of developing one solution that should work on every platform and for all 100Mbps Ethernet PHY’s that I have seen.

What it needs is the address of 2 access functions:

BaseType_t xRead( BaseType_t xAddress, BaseType_t xRegister, uint32_t *pulValue );
BaseType_t xWrite( BaseType_t xAddress, BaseType_t xRegister, uint32_t ulValue );

in order to communicate with the RMII or MII bus.

It will detect all Ethernet PHY’s connected to the bus and initialise them. Normally there is only 1 PHY connected.
It will initialise the PHY and keep on polling its Link Status.

You can see in the existing STM32Fxx driver which methods of xPhyObject are called.

Here is the PHY initialisation:

    void vMACBProbePhy( void )
    {
        /* Bind the 2 access functions. */
        vPhyInitialise( &xPhyObject, xSTM32_PhyRead, xSTM32_PhyWrite );
        /* Poll the bus for all connected PHY's. */
        xPhyDiscover( &xPhyObject );
        /* Configure them using the properties provided. */
        xPhyConfigure( &xPhyObject, &xPHYProperties );
    }

And in the task, called in every iteration:

    if( xPhyCheckLinkStatus( &xPhyObject, xResult ) != 0 )
    {
        /* Something has changed to a Link Status, need re-check. */
        prvEthernetUpdateConfig( pdFALSE );
    }

I would recommend using phyHandling.c

1 Like

Hi everyone,

Thanks to the PR #48 prepared by @htibosch and the STM32F7 Network Interface which already exists, I now have a NetworkInterface working for the STM32H7 correctly. It’s maybe not optimized but it works : NetworkInterface.c (18.9 KB)
I also attach the MSP file in order to configure the Ethernet clock and gpio for a STM32H745 MCU : hal_msp.c (3.2 KB)

Ps: PhyHandling file can be used with this NetworkInterface file
Ps2: Thank you so much again for the help gived the last few days :slight_smile: !

Hello Alex,

Thank you very much for working on this network interface!
Later on I will have a detailed look, but it looks good!

and the STM32F7 Network Interface

Correction: earlier there was a STM32F4xx and a STM32F7xx driver. Later I merged these two into an STM32Fxx driver which works for both.

STM32H is very different so it will get its own NetworkInterface. I think that there is also an STM32H4?

PhyHandling file can be used with this NetworkInterface file

That is great, thank you!

Thank you so much again for the help gived the last few days :slight_smile: !

You are welcome

FYI… randomly noticed that the comment closing out the the if-clause … if( xMacInitStatus == eMACInit )… needs to be updated. It still refers to xEMACTaskHandle == NULL.

2 Likes

Yes, I see! I changed it and will update it in the repo.
Thanks, Hein

1 Like

Hello Hein and Alex - A couple questions:

  1. From the ST forum and painful experience here, the ST-delivered drivers had lots of bugs. Have you reviewed+fixed the bugs posted on the ST forum?
  2. Have you looked at lwIP integration or only FreeRTOS TCP?
    Thanks!
    Best Regards, Dave

i have looked at and used lwIP, but not with regards to their STM32xx network interfaces.

When I developed the STM32Fxx network interface for FreeRTOS+TCP, I took a copy of stm32fxx_hal_eth.c. I changed it so it can be used by all STM32Fxx parts. I did change a lot to this HAL driver, especially to enable zero-copy and to get a high performance.

I didn’t make use of the PHY driver provided by ST, but I wrote a new generic phyHandler.c

Are you using F or H?

The new STM32H7 driver is very new, and it uses the HAL driver as-it-is, without changes.

Hi Dave, I finally have an STM32H747 board here. I am also looking at a HAL driver that is far from perfect.

I found a new version of stm32h7xx_hal_eth.c, but it is incompatible with the NetworkInterface as it is now.

In the STM32Fx driver, I adapted and integrated a version of stm32h7xx_hal_eth.c.
I would like to do for the STM32Hxx driver.

Have you found a good version stm32h7xx_hal_eth.c that works well?
Thanks