cancel
Showing results for 
Search instead for 
Did you mean: 

DMA fails to transmit Ethernet frame with STM32F765 board.

BitBanger46
Associate III

I am trying to implement Ethernet capability using the LwIP middleware on a STM32F765 board with a LAN8742A PHY.

I have observed that the firmware/hardware functions properly when receiving an ARP request.

However, when the low_level_output routine (in ethernetif.c) calls the HAL_ETH_TransmitFrame routine (in stm32f7xx_hal_eth.c) to transmit the ARP response frame, the ARP response frame is never sent. (I am using a packet sniffer to monitor the traffic on the LAN.)

After almost 50 hours of debugging, I have determined that, for some reason, the transmission to the MAC is not being completed as evidenced by the beginning and ending status.

The following is the source code for the HAL_ETH_TransmitFrame routine. I added two blocks of code which are bracketed by //$$$$ ... $$$ lines. The first block reads the initial status (from the DMASR), resets the status bits and then reads the status bits after reset. The contents of the status register bits in the first block are shown in the listing below. The second block is a wait loop at the end of the routine which polls the status register until the Transmission Complete (TS) bit is set. The contents of the status register bits in the second block are shown in the listing below.

When debugging, I observed that the TS bit is never set causing execution to not progress beyond the wait loop in the second block of code (which was intentional). The only change in the status between the first and second block is that the ETS bit (10) in the DMA status register is set in the second block. This indicates that the Ethernet frame data was transferred to the FIFO in the MAC.

I have seen a number of posts that mention problems like this but I have not found any clear suggestions as to how to resolve this issue!!

I am using the latest versions of the STM32CubeMX IDE and the LwIP middleware. All of the clocks, including the Ethernet PTP, are running at 100 MHz except for the APB1 Peripheral Clock which is running at 50 MHz.

Any help would be greatly appreciated!!

/**

 * @brief Sends an Ethernet frame. 

 * @param heth pointer to a ETH_HandleTypeDef structure that contains

 *     the configuration information for ETHERNET module

 * @param FrameLength Amount of data to be sent

 * @retval HAL status

 */

HAL_StatusTypeDef HAL_ETH_TransmitFrame(ETH_HandleTypeDef *heth, uint32_t FrameLength)

{

 uint32_t bufcount = 0, size = 0, i = 0;

  

 /* Process Locked */

 __HAL_LOCK(heth);

  

 /* Set the ETH peripheral state to BUSY */

 heth->State = HAL_ETH_STATE_BUSY;

  

 if (FrameLength == 0) 

 {

  /* Set ETH HAL state to READY */

  heth->State = HAL_ETH_STATE_READY;

   

  /* Process Unlocked */

  __HAL_UNLOCK(heth);

   

  return HAL_ERROR;                   

 }  

  

 /* Check if the descriptor is owned by the ETHERNET DMA (when set) or CPU (when reset) */

 if(((heth->TxDesc)->Status & ETH_DMATXDESC_OWN) != (uint32_t)RESET)

 {  

  /* OWN bit set */

  heth->State = HAL_ETH_STATE_BUSY_TX;

   

  /* Process Unlocked */

  __HAL_UNLOCK(heth);

   

  return HAL_ERROR;

 }

  

 /* Get the number of needed Tx buffers for the current frame */

 if (FrameLength > ETH_TX_BUF_SIZE)

 {

  bufcount = FrameLength/ETH_TX_BUF_SIZE;

  if (FrameLength % ETH_TX_BUF_SIZE) 

  {

   bufcount++;

  }

 }

 else 

 {  

  bufcount = 1;

 }

  //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

  // Clear the status:

  uint32_t dma_status=

   (heth->Instance)->DMASR;  // get the initial DMA status

  (dma_status before reset is: 0x660044 )          

  (heth->Instance)->DMASR=       // reset all of the status bits

      (0xffff ^ ETH_DMASR_TBUS);  // except TBUF

  dma_status=(heth->Instance)->DMASR; // check the status after reset

  (dma_status after reset is: 0x6800C4 ) 

  //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

 if (bufcount == 1)

 {

  /* Set LAST and FIRST segment */

  heth->TxDesc->Status |=ETH_DMATXDESC_FS|ETH_DMATXDESC_LS;

  /* Set frame size */

  heth->TxDesc->ControlBufferSize = (FrameLength & ETH_DMATXDESC_TBS1);

  /* 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);

 }

 else

 {

  for (i=0; i< bufcount; i++)

  {

   /* Clear FIRST and LAST segment bits */

   heth->TxDesc->Status &= ~(ETH_DMATXDESC_FS | ETH_DMATXDESC_LS);

    

   if (i == 0) 

   {

    /* Setting the first segment bit */

    heth->TxDesc->Status |= ETH_DMATXDESC_FS;  

   }

    

   /* Program size */

   heth->TxDesc->ControlBufferSize = (ETH_TX_BUF_SIZE & ETH_DMATXDESC_TBS1);

    

   if (i == (bufcount-1))

   {

    /* Setting the last segment bit */

    heth->TxDesc->Status |= ETH_DMATXDESC_LS;

    size = FrameLength - (bufcount-1)*ETH_TX_BUF_SIZE;

    heth->TxDesc->ControlBufferSize = (size & ETH_DMATXDESC_TBS1);

   }

    

   /* 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);

  }

 }

  

 /* When Tx Buffer unavailable flag is set: clear it and resume transmission */

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

 {

  /* Clear TBUS ETHERNET DMA flag */

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

  /* Resume DMA transmission*/

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

 }

  

 /* Set ETH HAL State to Ready */

 heth->State = HAL_ETH_STATE_READY;

  

 /* Process Unlocked */

 __HAL_UNLOCK(heth);

  

  //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

  // Wait for transmission to complete:

  while (1)              // wait for the TS bit to be set

  {                  // indicating transmission done

   dma_status=

       (heth->Instance)->DMASR;

   (dma_status here is: 0x6804C4 )

   if (dma_status &

         ETH_DMASR_TS) break;

  }

  //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

  /* Return function status */

  return HAL_OK;

}

3 REPLIES 3

Check the memory being used for the buffer. Check against support matrix for DMA. Check memory alignment.

Use fencing instructions and Clean DCache to ensure that the write buffers and cache have coherency with the data in physical memory

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
BitBanger46
Associate III

The buffer for the ARP response is near the start of the SRAM1 internal RAM memory (starting at 0x2000 484C). I verified that the Ethernet MAC intersects the SRAM1 memory in the DMA support matrix. The buffer is aligned on a 4-byte basis. It seems like the most likely issue is that the buffer data is cached and possibly out of sync with the physical (SRAM) memory. I reviewed App Note 4839 which explains the caching scheme in the Cortex processor and the note refers to several routines (including SCB_CleanDCache) which may be used to operate on the cached memory. Unfortunately, I have not been able to locate the source code for any of the routines.

I should note that I just examined the Cortex Interface Settings in the Configuration Tool and I found that the ART accelerator, instruction prefetch , CPU ICache and CPU DCache ARE ALL DISABLED!! I remembered disabling these options at the start of my project because, at that time, I did not feel comfortable using them because I had didn't know enough about these features. This being the case, I don't see how caching could be an issue.

Piranha
Chief II

> I have seen a number of posts that mention problems like this but I have not found any clear suggestions as to how to resolve this issue!!

ST's brainless code monkeys and HAL users have decided that they will just ignore it...

https://community.st.com/s/question/0D50X0000C4Nk4GSQS/bug-missing-compiler-and-cpu-memory-barriers

> several routines (including SCB_CleanDCache) which may be used to operate on the cached memory

Read my posts here:

https://community.st.com/s/question/0D50X0000AnsIJeSQM/how-to-get-ethernet-working-again-after-upgrading-to-firmware-fwh7v140-

> Unfortunately, I have not been able to locate the source code for any of the routines.

Those are in core_cm7.h or in the newest CMSIS version in cachel1_armv7.h file.

> ART accelerator, instruction prefetch , CPU ICache and CPU DCache ARE ALL DISABLED!!

All, except D-cache, can be enabled safely and doesn't require special care. By the way, if code is accessed through 0x08000000 based addresses, then ART is left unused anyway.

All of that is collected there:

https://community.st.com/s/question/0D50X0000BOtfhnSQB/how-to-make-ethernet-and-lwip-working-on-stm32