stm32h7xx_hal_driver icon indicating copy to clipboard operation
stm32h7xx_hal_driver copied to clipboard

ETH Rx Tailpointer calculation wrong

Open Florian-Fischer-InMach opened this issue 1 year ago • 2 comments

Caution The Issues are strictly limited for the reporting of problem encountered with the software provided in this project. For any other problem related to the STM32 product, the performance, the hardware characteristics and boards, the tools the environment in general, please post a topic in the ST Community/STM32 MCUs forum

Describe the set-up Custom Board with STM32H743XIHX

Describe the bug In v1.11.3 in the function ETH_UpdateDescriptor the calculation of the tailidx/DMACRDTPR is wrong. Becaus of this the HAL_ETH_ErrorCallback is reached in my application

The tail pointer should point to the last built/updated descriptor.

v1.11.0 points to NULL -- completly wrong v1.11.3 tried to fix it but points to 2 after the last updated descriptor

Florian-Fischer-InMach avatar Jun 17 '24 09:06 Florian-Fischer-InMach

Hello @Florian-Fischer-InMach,

To assist you more effectively with the DMA pointer issue you're experiencing, could you please provide us with the following configuration details of your custom board?

  • The exact configuration of the MPU settings for the DMA descriptors.
  • Any custom settings or modifications you have made to the DMA controller.

With Regards,

ASEHSTM avatar Jun 21 '24 14:06 ASEHSTM

Hello I use this code to configure the MPU. I use some linker script magic to place dma stuff at begin of each ram section(d1/d2/d3/external) and extended to statisfy the power of 2 requierment of mpu region size The DMA descriptors end up in uncachable dma region at begin of d2 ram.

What do you mean by custom setting to DMA controller? For ETH stuff i use the HAL functions. No custom settings.

For adc, spi and uart DMA1 is used

/**
 * Set the whole memory to cacheable and set  overlay region for dma to uncacheable
 */
static void set_region ( const uint8_t region_number, const uint32_t base_adress, const uint32_t memeory_size, const uint32_t dma_size )
{
  MPU_Region_InitTypeDef MPU_InitStruct = {0};
  /*
   * Initializes Ram as Write-back, write and read allocate   -> tex 1  + c + b + no s
   */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = region_number;
  MPU_InitStruct.BaseAddress = base_adress;
  MPU_InitStruct.Size = calc_mpu_region_size ( memeory_size );
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
  MPU_InitStruct.IsShareable  = MPU_ACCESS_NOT_SHAREABLE;
  MPU_InitStruct.IsCacheable  = MPU_ACCESS_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;

  HAL_MPU_ConfigRegion(&MPU_InitStruct);
`
  /*
   * Initializes overlay of dma part as shareable and not cachable -> tex 1  + no c + no b + s
   */
  volatile uint32_t volatile_dma_size = dma_size;//workaround compiler bug. It assumes a adress is never 0 and optimises the if away
  if ( volatile_dma_size > 0 )
  {
    MPU_InitStruct.Number = region_number + 1;
    MPU_InitStruct.BaseAddress = base_adress;
    MPU_InitStruct.Size = calc_mpu_region_size ( dma_size );
    MPU_InitStruct.IsShareable  = MPU_ACCESS_SHAREABLE;
    MPU_InitStruct.IsCacheable  = MPU_ACCESS_NOT_CACHEABLE;
    MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;

    HAL_MPU_ConfigRegion(&MPU_InitStruct);
  }
}

Florian-Fischer-InMach avatar Jun 25 '24 08:06 Florian-Fischer-InMach

My solution to fix the tail pointer: replace

tailidx = (descidx + 1U) % ETH_RX_DESC_CNT;

with

tailidx = (ETH_RX_DESC_CNT + descidx - 1U) % ETH_RX_DESC_CNT;

Florian-Fischer-InMach avatar Jul 17 '24 11:07 Florian-Fischer-InMach

Indeed, that fixes it for me too. Can you explain the reasoning behind adding ETH_RX_DESC_CNT the sum to be modulod? It should be the mathematically the same without, no? I think I understand the - 1... you want the match to happen, and the index was incremented before this, so you're just "undoing" that increment so it matches to the actual last descriptor to be processed. Is that correct?

chris1seto avatar Jul 17 '24 17:07 chris1seto

For some reason i assumed modulo does not work for -1 in a unsigned variable. Do not remember if proofed this assumption.

Yes the idea is to get the idx of the last touched descriptor

Florian-Fischer-InMach avatar Jul 22 '24 14:07 Florian-Fischer-InMach

Did the proof now. Simplified to uint8_t -1 results 255 in the unsigned variable.

Assume amount of descriptors to be 7. 255 % 7 = 3 Expected is 6 --> addition is needed.

Florian-Fischer-InMach avatar Jul 22 '24 14:07 Florian-Fischer-InMach

Yes I also just did that. Good thinking, you are right that it's needed.

chris1seto avatar Jul 22 '24 14:07 chris1seto

Hello @Florian-Fischer-InMach and @chris1seto,

During initialization in the ETH_DMARxDescListInit() function, the tail pointer is set to the address of the last descriptor, which is at index 3 when ETH_RX_DESC_CNT=4. In the ETH_UpdateDescriptor() function, the tail pointer is updated to point to the next descriptor (descidx + 1). It starts at 1, since the initial descriptor is at index 0, and then increments by 1 until it reaches the last descriptor at index 3.

Could you please explain why you want to change the pointer so that it points to the previous descriptor instead of the next descriptor?

With Regards,

ASEHSTM avatar Jul 23 '24 11:07 ASEHSTM

Please think about what the idea of interrupts and dma is. Then think about what your code is doing.

If you want to shourcut the thinking read the answer i wrote also in my online support ticket #00208305

To avoid packet loss you always want maximum amount of descriptors assigned to the dma. If i understand this corret ETH_UpdateDescriptor is intended to doing exactly that.

Description of what happens during first call of ETH_UpdateDescriptor. descidx is initialised with heth->RxDescList.RxBuildDescIdx because of first call this is 0.

in the while loop all descriptors are assigned to the dma and descidx is increased

After the loop descidx got incremented ETH_RX_DESC_CNT times in the first call. Due to wrap around this results in 0 Then you set the tail pointer to descidx + 1 Thus the dma is allowed to use 1 descriptor but all descriptors are ready to be used by dma

Florian-Fischer-InMach avatar Jul 23 '24 12:07 Florian-Fischer-InMach

Thank you for your contribution and for bringing this to our attention. You are right, this issue will be fixed soon.

ST Internal Reference: 187268

With Regards,

ASEHSTM avatar Jul 23 '24 15:07 ASEHSTM

@Florian-Fischer-InMach Great description, you hit it on the head

chris1seto avatar Jul 23 '24 15:07 chris1seto

Fixed in : ceda3ceeca2ee77a76d2de2ee6b560ad87c90a48

RJMSTM avatar Aug 13 '24 12:08 RJMSTM

The stm32h5xx_hal_driver has the same issue with tailpointer (tested on STM32H563VI). Please include the fix in the next release as well. Current (v1.3.0) implementation: https://github.com/STMicroelectronics/stm32h5xx_hal_driver/blob/0de1dbf8ad03e6e466ed55d1c174656561e3240d/Src/stm32h5xx_hal_eth.c#L1212

gresolio avatar Aug 13 '24 13:08 gresolio