cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F746 Ethernet DMA Transmit problem

zoltan2
Associate II
Posted on August 11, 2016 at 11:57

Hi,

I am developing Ethernet driver on STM32F7-DISCO board.

I set buffer address, buffer size in Tx descriptor.

Then I set control bits in TDES0 of Tx descriptor and write DMATPDR register to send the frame.

However the frame is not sent out. If I try to transit a new frame both the previous one and the new one are sent together after each other.

If I do some delay between setting OWN bit in TDES0 and writing DMATPDR register the frame will be sent immediately.

I found similar behavior with the STM32 FW (STM32Cube_FW_F7_V1.4.0) delivered with STM32F7-DISCO board.

I changed Ethernet HAL driver so that I exchanged code lines with setting next descriptor address and setting OWN bit, and the frame is not transmitted.

I simply did this:

original code order in stm32f7xx_hal_eth.c fn: HAL_ETH_TransmitFrame():

  /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */

    heth->TxDesc->Status |= ETH_DMATXDESC_OWN;

  /* Point to next descriptor */

    heth->TxDesc= (ETH_DMADescTypeDef *)(heth->TxDesc->Buffer2NextDescAddr);

after changing the code order:

  /* Point to next descriptor */

    heth->TxDesc= (ETH_DMADescTypeDef *)(heth->TxDesc->Buffer2NextDescAddr);

  /* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */

    heth->TxDesc->Status |= ETH_DMATXDESC_OWN;

Can anyone help me to overcome this problem?

Thanks!

Zoli

#dma #ethernet #stm32f
18 REPLIES 18
Posted on December 13, 2017 at 16:03

I just discovered this issue too. I tracked the problem down to HAL_ETH_TransmitFrame() then I checked the Community and found this thread. I am using STM32CubeMX V4.23.0 and STM32CubeF7 V1.8.0 (both the newest). It appears the problem is still not fixed. I will test this. I cannot ship code to customers that sometimes does not work...this needs to be officially fixed. I don't understand why STM is not taking this issue seriously. It is over a year old.

Posted on January 08, 2018 at 07:34

It is really useful for me , thanks.

Oussema Hajjem_O
Associate III
Posted on January 10, 2018 at 11:09

Hi All,

The issue is due to enabled cache, I explain, when the CPU updates the Descriptors fields this will be done at the D-Cache level only, and it will not be seen from the Ethernet DMA.

There are many solutions for this:

1- User can declare Ethernet descriptors and buffers in DTCM RAM (not cacheable memory) 

2- User can insure D-Cache maintenance: CPU will inform/ be informed by Ethernet DMA when updates are done (using SCB_CleanDCache() or SCB_InvalidateDCache())

3- Use of MPU (Memory Protection Unit) to protect data access, example:

   - Configure the ETH descriptors area as 'Device memory' by MPU: not cacheable, like HW registers

   - Configure the ETH Tx buffers area as 'Cacheable Write-Through': when CPU writes to Tx buffers in the D-Cache it will be copied to RAM.

   - Configure the ETH Rx Buffers area as 'Normal Not Cacheable': So the CPU will fetches the received data from the RAM and not form its D-Cache.

Please note that adding Memory Barriers Instructions is a solutions but it could decrease performance and in some cases.

Best regards,

Oussema.

Posted on January 10, 2018 at 13:24

That could be the reason for some, but in my case, I have caches disabled. I am using both the Nucleo-F767 and Nucleo-H743 boards. The CubeMX H7 Ethernet driver puts a call to SCB_CleanDCache() in the driver, but when called, it causes a hard fault. I had to comment it out. The default linker script also places all data into the DTCM section, so there is no caching. The HAL Ethernet drivers for the H7 have some serious issues. I submitted another issue that points out that DHCP cannot work, and I described a simple fix.

Posted on January 10, 2018 at 17:04

Oussema,

Caching effects also needs to be taken care of, of course, but in my case both buffers and descriptors live in uncached memory (special region setup using the MPU). Without this, more or less nothing will work in this area...

But the issue in HAL is that the store instruction the CPU performs to memory is still in the Cortex-M7 merging buffer when accessing the ETH DMA device registers to resume the transmission. The barrier is still needed to flush this buffer so that the DMA has the same view as the CPU, but a more lightweigth DMB should be enough compared to the DSB I used in the patch above.

Regards

Daniel

Posted on January 20, 2018 at 00:08

Put ETH Descriptors in domain D2, SRAM3 for instance, activate RCC for SRAM3, set MPU and D-Caching will work.

Posted on January 20, 2018 at 00:10

Point 1 except for STM32H7 series. No interconnection between DTCM and ETH DMA.

Posted on June 28, 2018 at 17:01

Daniel,

I'm using STM32F779I Eval board and I'm having same ethernet transmit issue, where it can first frame after reset but nothing after that.

I have tried with

1) I-cache and D-cache disabled

2) D-cache enabled and I-cache disabled

3) I-cache enable and D-cache disable.

Same results with all 3 above test. Sends first frame and nothing after that. I am able to verify this by wireshark.

I'm using STM32CubeMX version 1.11.

Now looking at below code from HAL_ETH_TransmitFrame which you have also shown in your comment.

if (((heth->Instance)->DMASR & ETH_DMASR_TBUS) != (uint32_t)RESET)

{

/* Clear TBUS ETHERNET DMA flag */

(heth->Instance)->DMASR = ETH_DMASR_TBUS;

  It seems here we are not clearing ETH_DMAST_TBUS flag from DMASR reg. Its settings it again. Should it be 

(heth->Instance)->DMASR &= ~ETH_DMASR_TBUS;

/* Resume DMA transmission*/

(heth->Instance)->DMATPDR = 0;

}

Posted on June 28, 2018 at 21:18

Hi,

DMASR is a 'write 1 to clear register', check reference manual

'The ETH_DMASR register bits are not cleared when read. Writing 1 to (unreserved) bits in ETH_DMASR register[16:0] clears them and writing 0 has no effect. Each field (bits [16:0]) can be masked by masking the appropriate bit in the ETH_DMAIER register.'

Regards

Daniel