cancel
Showing results for 
Search instead for 
Did you mean: 

NUCLEO-H743ZI (STM32H743ZI) no Ethernet DMA transfer

Joerg Wagner
Senior III
Posted on October 08, 2017 at 15:11

Hi all.

Does anyone have a working example for Ethernet?

I tried to build one wih CubeMX (HAL 1.1.0) with and without FreeRTOS.

I did it many times for F746, F767 (A and Z) and F769 (A) but Ethernet with STM32H743ZI (Ver. Y) will not work.

- IDE is OpenSTM32 (GNU C)

- RAM is AXI SRAM in Domain D1 or AHB SRAM1 in Domain D2

- no DTCM RAM is used (in linker script: i.e. RAM_D1 >AT FLASH, _estack is adapted)

- Instruction Cache enabled and Data Cache is disabled

- no MPU

- ethernetif.c line 421 is commented out: // SCB_CleanInvalidateDCache();

- ethernetif.c line 443 is commented out: // SCB_CleanInvalidateDCache();

Another options:

- using 0x30040000 and MPU for DMARxDscrTab[ETH_RX_DESC_CNT] and DMATxDscrTab[ETH_TX_DESC_CNT]

- DHCP or static IP

- Data cache enabled and using original SCB_CleanIvalidDCache();

The result:

stm32h7xx_hal_eth.c : HAL_ETH_Transmit(...) throws a timeout in line 708 and returns HAL_ERROR

which is not recognized by low_level_output() in ethernetif.c

Using a different timeout value (>0) in the HAL_ETH_Transmit( &heth, &TxConfig, myTimeOutVal) throws a timeout as well.

When I enable MPUETHADDR16_COPY(&ethhdr->src, src); in ethernet.c it will end in Infinite_Loop. (Edited: wrong MPU settings)

Using AHB SRAM2 in Domain D2, the software cannot be debugged. I hope not to forget something: payload is in domain D2, LAN8742 is activated in CubeMX (Platform settings), ...

In conclusion: The DMA transfer does not work.

I spent so many hours to find a solution and I'm thankful for any advice.

Note: this post was migrated and contained many threaded conversations, some content may be missing.
1 ACCEPTED SOLUTION

Accepted Solutions
Joerg Wagner
Senior III
Posted on October 23, 2017 at 15:13

Using HAL only works.

The next CubeMX release should fix this. There are many differences in the produced code.

A good starting point to use HAL only and to get mature.

- Joerg -

View solution in original post

36 REPLIES 36
Oussema Hajjem_O
Associate III
Posted on October 09, 2017 at 15:30

Hello Joerg,

When the HAL_ETH_Transmit(...) throws a timeout, it doesn't mean that the DMA transfer failed, it means that the Transmit function returned without waiting for the Tx status (Transmission is ongoing)

Please ensure that your DMA descriptors are configured by MPU as Device (not cacheable).

For more information, please refer to the HTTP server application in the STM32Cube H7 FW package: 

..\Projects\STM32H743ZI-Nucleo\Applications\LwIP\LwIP_HTTP_Server_Netconn_RTOS\

Best regards,

Oussema

Posted on October 09, 2017 at 18:39

Hello Oussema.

I connected a scope to the signals RMII_TXD0 and RM_TXD1. There is no traffic anytime!

This is a note in the original hal driver:

@Note: This interface is implemented to operate in zero-copy mode only:

        - Rx buffers are allocated statically and passed directly to the LwIP stack

          they will return back to DMA after been processed by the stack.

        - Tx Buffers will be allocated from LwIP stack memory heap,

          then passed to ETH HAL driver.

Why are Tx Buffers allocated from heap? If your data is in DTCMRAM there is no interconnect to the DMA. Anyway, but I tried it also to put TxBuffer in 0x3400XXXX and somewhere else except DTCM, not cacheable.

Using SW4STM32, I prepared the linker script to have the ETH descriptors like in LwIP (0x34000000, 0x34000060) with this in MPU_Config():

  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_SHAREABLE;

  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;

  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);

I visited a friend with the board to use KEIL and we adopted a sample MDK project from H743-EVAL to NUCLEO-H743, because the __attribute__ sections are already prepared. Same result: no traffic.

In the reference manual RM0433 on page 2679 cont'd is an explanation of the DMA flow. This means in my case the Own bit is set but not resetted by the controller.

Thank you, Joerg

Posted on October 09, 2017 at 19:28

Hello Joerg,

To ensure zero-copy, the ETH driver needs to send buffers allocated by the LwIP stack and not copy them in any other shadow buffers.

If you are using 

DTCMRAM, it is obvious that Tx buffers will be allocated in this memory, so you have to relocate the LWIP heap to D1 or D2 SRAM by defining LWIP_RAM_HEAP_POINTER in the lwipopts.h file.

Could you please check the Fatal Bus Error bit of the DMACSR register, after trying to send data, if it's SET, so it's clear that the Tx buffers are in DTCMRAM.

also please try to run the application with RAM starting from 0x24000000 (don't use theDTCMRAM)

Hope this will help you,

Best regards,

Oussema.

Posted on October 09, 2017 at 19:59

Hello Oussema.

ETH_DMACSR_FBE is not set anytime. It means I do not have DMA memory trouble.

I tried your advice to reallocate the LwIP with LWIP_RAM_HEAP_Pointer, no success.

The descriptor tables and buffers are located here:

.RxDecripSection

                0x0000000030040000       0x60 load address 0x000000000800da08

 *(.RxDecripSection)

 .RxDecripSection

                0x0000000030040000       0x60 Src/ethernetif.o

                0x0000000030040000                DMARxDscrTab

 *(.RxDecripSection*)

.TxDecripSection

                0x0000000030040060       0x60 load address 0x000000000800da68

 *(.TxDecripSection)

 .TxDecripSection

                0x0000000030040060       0x60 Src/ethernetif.o

                0x0000000030040060                DMATxDscrTab

 *(.TxDecripSection*)

.ETH_Fill       0x00000000300400c0      0x140 load address 0x000000000800dac8

                0x0000000000000140                . = 0x140

 *fill*         0x00000000300400c0      0x140

.RxArraySection

                0x0000000030040200     0x17e0 load address 0x000000000800dac8

                0x0000000030040200                . = ALIGN (0x20)

 *(.RxArraySection)

 .RxArraySection

                0x0000000030040200     0x17e0 Src/ethernetif.o

                0x0000000030040200                Rx_Buff

 *(.RxArraySection*)

.TxArraySection

                0x00000000300419e0        0x0 load address 0x000000000800f2a8

                0x00000000300419e0                . = ALIGN (0x20)

 *(.TxArraySection)

 *(.TxArraySection*)

I do not use SCB_EnableDCache() to avoid trouble.

If you have a little working example that would be awesome.

Thank you, Joerg

Posted on October 10, 2017 at 11:53

Hello Oussema.

Today I built with CubeMX two tiny projects (SW4STM32) for you to analyze.

I attached the files to my original question.

App &sharp1 is developed for NUCLEO-F767ZI and App &sharp2 is created for NUCLEO-H743ZI.

Both have just ETH Init only, no RTOS, no LwIP. The purpose is to transfer data (dummy values) via Ethernet_DMA

to the LAN8742 PHY. I connected an oscilloscope to PG13 and PB13 (RMII_TXD0 and RMII_TXD1)

to visualize the traffic to the PHY.

There is traffic on the F767 board but there is no data sent on the H743 board.

Thank you, Joerg

Posted on October 10, 2017 at 15:19

Hello Joerg,

I will test your project and I'll return to as soon as possible.

BR,

Oussema

Posted on October 11, 2017 at 19:07

Hello Joerg,

I reviewed your code, and I found that you are not enabling the ETH MAC and DMA transmission and reception.

So could you please add the call to HAL_ETH_Start(&heth); after the ETH initialization.

Also I see that the ETH GPIO speed configuration is set GPIO_SPEED_FREQ_LOW so could you please replace it by GPIO_SPEED_FREQ_HIGH, because in RMII mode the IO communication frequency is 50 MHz

When I did the test I can see that the OWN bit is set to 0 after frame each frame transmission

BR,

Oussema.

Posted on October 11, 2017 at 21:45

Hello Oussema,

First, thank you for your time. You are right, I forgot to call HAL_ETH_Start(&heth);

The setting

GPIO_SPEED_FREQ_LOW

comes from CubeMX generation and I corrected this by hand.

If found 2 other mistakes:

CubeMX connects RMII_TXD0 to PB12 and this is totally wrong. It must be PG13 like with the NUCLEO-F767 board.

Close to the PG13 pin at the Morpho connector is the resistor SB182 and he is physically connected to the PG13 at the die, like in the current schematics V1.1.

CubeMX initializes PB12 and PG13 is forgotten. Same with RMII_TXEN, must be PG

I must be like this:

/**ETH GPIO Configuration

PC1 ------> ETH_MDC

PA1 ------> ETH_REF_CLK

PA2 ------> ETH_MDIO

PA7 ------> ETH_CRS_DV

PC4 ------> ETH_RXD0

PC5 ------> ETH_RXD1

PB11 ------> ETH_TX_EN : wrong, must be PG11

PB12 ------> ETH_TXD0 : wrong, must be PG13

PB13 ------> ETH_TXD1

*/

GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5;

GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

GPIO_InitStruct.Alternate = GPIO_AF11_ETH;

HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_7;

GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

GPIO_InitStruct.Alternate = GPIO_AF11_ETH;

HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13;

GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

GPIO_InitStruct.Alternate = GPIO_AF11_ETH;

HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

// --- NEW! --- TXEN and TXD0

GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_13;

GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

GPIO_InitStruct.Alternate = GPIO_AF11_ETH;

HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

With this modification there is traffic on TXD0 to the LAN8742A PHY and the Own bit will be resetted after a time.

But there is still the timeout error everytime in the HAL driver. The The timeout check should be implemented in a different way.

My test application 'check the DMA transfer' works, but a real application not!

I have two apps prepared, with RTOS and without. It was a step forward but not the final solution.

:(

Joerg

Joerg Wagner
Senior III
Posted on October 14, 2017 at 21:22

I prepared an application (simple) with RTOS and static IP: 192.168.99.85/24, destination 192.168.99.99/24

ARP request is sent:

'Who has 192.168.99.99? Tell 192.168.99.85'

The oscilloscope shows the answer on PC4/PC5 (RMII_RXD0 / RMII_RXD1):

'192.168.99.99 is at ...'

But then another broadcast ARP packet is sent:

'Who has 192.168.42.0? Tell 192.168.99.85' [ETHERNET FRAME CHECK SEQUENCE INCORRECT]

This confuses me, the netmask is set to 255.255.255.0.

The request will loop forever, because ARP cannot be resolved, UDP and TCP are not useable.

LWIP_DEBUG shows:

etharp_request: sending ARP request.

etharp_raw: sending raw ARP packet.

ethernet_output: sending packet 0x30000008

etharp_timer

...

Joerg