STM32H7 Ethernet ve LwIP Problemi

Başlatan kimlenbu, 30 Aralık 2022, 11:01:13

kimlenbu

Düzeltme : Code bloğu içinde bold kullanımına izin vermemiş, bilginize.

Selamlar,

Problemimi çözüm, benden sonra H7 ve F7'nin yeni serilerini kullanacak olanlara ufak bir uyarı olması için yazıyorum. Yazdıklarım STM32H723VET için geçerli olsa da neredeyse H7 serisinin tamamını ve F7'nin yeni nesillerini kapsıyor.

H7 ve F7 de bulunan MPU unitesi yüzünden Ethernet her RAM bölgesine "default" olarak erişemiyor, ayrıca CubeMX Ethernet ve LwIP kodlarını hatalı oluşturuyor. Örneğin benim durumumda Tx ve Rx descriptor adreslerini default olarak DTCMRAM'e atıyordu.

Çözüm için hem CubeMX'de MPU ayarlarını yapmak gerekiyor (ben 0x30000000 yani D2 Rami kullandım). Bunun için çok fazla kaynak var ben sadece ekran görüntüsü ekliyorum :




0x30004800 10kb'lık Heap Memory Bitişi
1024*10 = 10240byte = 0x2800 Heap Memory
0x30002000 Rx Buffer Bitisini Hesap Kolay Olsun Diye Yuvarliyoruz.
0x300018D0 Rx Buffer End
6096 Byte (Rx Buffers Length * Rx Desctiptor Length = 1524 * 4 = 6096)
0x30000100 RxArraySection
128 Byte ( Tx Desctiptor Length 4 * 32Byte)
0x30000080 TxDecripSection
128 Byte ( Rx Desctiptor Length 4 * 32Byte)
0x30000000 RxDecripSection

Ondan sonra STM32H723VETX_FLASH.ld içine aşağıdaki bölümü eklememiz lazım :

    /* Modification start */
  .lwip_sec (NOLOAD) : {
    . = ABSOLUTE(0x30000000);
    *(.RxDecripSection) 
    
    . = ABSOLUTE(0x30000080);
    *(.TxDecripSection)
    
    . = ABSOLUTE(0x30002000);
    *(.RxArraySection) 
  } >RAM_D2
  /* Modification end */

main.c'de ram'in clock'unu aktif etmemiz lazım :

  /* USER CODE BEGIN SysInit */
__HAL_RCC_D2SRAM1_CLK_ENABLE();
  /* USER CODE END SysInit */

Eğer benim gibi harici voltage supervisor chipi kullanıyorsanız lan8742.c dosyası içinde de supervisor chipine reset sinyali yollamanız veya supervisor kontrol süresini uzatmanız lazım.

Ayrıca benim gibi LAN8742 yerine donanımınızı işlemciyi tam incelemeden DP83848 kullanarak tasarladıysanız vay halinize. Yapılması gereken değişiklikleri koyu renk yaptım. Özetle DP83848'in varsayılan ID'si 1, LAN8742 ise 0. Ayrıca registerları da biraz farklı, DP83848'de 19 offsetle ulaşılması gereken bir register var.

/**
  * @brief  Initialize the lan8742 and configure the needed hardware resources
  * @param  pObj: device object LAN8742_Object_t. 
  * @retval LAN8742_STATUS_OK  if OK
  *         LAN8742_STATUS_ADDRESS_ERROR if cannot find device address
  *         LAN8742_STATUS_READ_ERROR if connot read register
  *         LAN8742_STATUS_WRITE_ERROR if connot write to register
  *         LAN8742_STATUS_RESET_TIMEOUT if cannot perform a software reset
  */
 int32_t LAN8742_Init(lan8742_Object_t *pObj)
 {
   uint32_t tickstart = 0, regvalue = 0, addr = 0;
   int32_t status = LAN8742_STATUS_OK;
   
   if(pObj->Is_Initialized == 0)
   {
     if(pObj->IO.Init != 0)
     {
       /* GPIO and Clocks initialization */
       pObj->IO.Init();
     }
   
     /* for later check */
     //pObj->DevAddr = LAN8742_MAX_DEV_ADDR + 1;
     [b]pObj->DevAddr = 0x01;[/b]
   
     /* Get the device address from special mode register */
     for(addr = 0; addr <= LAN8742_MAX_DEV_ADDR; addr ++)
     {
       if(pObj->IO.ReadReg(addr, [b]0x19[/b], &regvalue) < 0)
       {
         status = LAN8742_STATUS_READ_ERROR;
         /* Can't read from this device address
            continue with next address */
         continue;
       }
     
       if((regvalue & LAN8742_SMR_PHY_ADDR) == addr)
       {
         pObj->DevAddr = addr;
         status = LAN8742_STATUS_OK;
         break;
       }
     }
   
     if(pObj->DevAddr > LAN8742_MAX_DEV_ADDR)
     {
       status = LAN8742_STATUS_ADDRESS_ERROR;
     }
     
     /* if device address is matched */
     if(status == LAN8742_STATUS_OK)
     {
       /* set a software reset  */
       if(pObj->IO.WriteReg(pObj->DevAddr, LAN8742_BCR, LAN8742_BCR_SOFT_RESET) >= 0)
       { 
         /* get software reset status */
         if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &regvalue) >= 0)
         { 
           tickstart = pObj->IO.GetTick();
           
           /* wait until software reset is done or timeout occured  */
           while(regvalue & LAN8742_BCR_SOFT_RESET)
           {
             if((pObj->IO.GetTick() - tickstart) <= LAN8742_SW_RESET_TO)
             {
               if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &regvalue) < 0)
               { 
                 status = LAN8742_STATUS_READ_ERROR;
                 break;
               }
             }
             else
             {
               status = LAN8742_STATUS_RESET_TIMEOUT;
               break;
             }
           } 
         }
         else
         {
           status = LAN8742_STATUS_READ_ERROR;
         }
       }
       else
       {
         status = LAN8742_STATUS_WRITE_ERROR;
       }
     }
   }
      
   if(status == LAN8742_STATUS_OK)
   {
     tickstart =  pObj->IO.GetTick();
     
     /* Wait for 2s to perform initialization */
     while((pObj->IO.GetTick() - tickstart) <= LAN8742_INIT_TO)
     {
    	 [b]HAL_GPIO_TogglePin(WATCHDOG_INPUT_GPIO_Port, WATCHDOG_INPUT_Pin);[/b]
     }
     pObj->Is_Initialized = 1;
   }
   
   return status;
 }


lan8742.h dosyası içinde farklı register adresleri düzeltilmeli :

/** @defgroup LAN8742_PHYSCSR_Bit_Definition LAN8742 PHYSCSR Bit Definition
  * @{
  */
#define LAN8742_PHYSCSR_AUTONEGO_DONE   ((uint16_t)0x0010U)
#define LAN8742_PHYSCSR_HCDSPEEDMASK    ((uint16_t)0x0006U)
#define LAN8742_PHYSCSR_10BT_HD         ((uint16_t)0x0002U)
#define LAN8742_PHYSCSR_10BT_FD         ((uint16_t)0x0006U)
#define LAN8742_PHYSCSR_100BTX_HD       ((uint16_t)0x0000U)
#define LAN8742_PHYSCSR_100BTX_FD       ((uint16_t)0x0004U)

/** @defgroup LAN8742_Registers_Mapping LAN8742 Registers Mapping
  * @{
  */ 
#define LAN8742_BCR      ((uint16_t)0x0000U)
#define LAN8742_BSR      ((uint16_t)0x0001U)
#define LAN8742_PHYI1R   ((uint16_t)0x0002U)
#define LAN8742_PHYI2R   ((uint16_t)0x0003U)
#define LAN8742_ANAR     ((uint16_t)0x0004U)
#define LAN8742_ANLPAR   ((uint16_t)0x0005U)
#define LAN8742_ANER     ((uint16_t)0x0006U)
#define LAN8742_ANNPTR   ((uint16_t)0x0007U)
#define LAN8742_ANNPRR   ((uint16_t)0x0008U)
#define LAN8742_MMDACR   ((uint16_t)0x000DU)
#define LAN8742_MMDAADR  ((uint16_t)0x000EU)
#define LAN8742_ENCTR    ((uint16_t)0x0010U)
#define LAN8742_MCSR     ((uint16_t)0x0011U)
#define LAN8742_SMR      ((uint16_t)0x0012U)
#define LAN8742_TPDCR    ((uint16_t)0x0018U)
#define LAN8742_TCSR     ((uint16_t)0x0019U)
#define LAN8742_SECR     ((uint16_t)0x001AU)
#define LAN8742_SCSIR    ((uint16_t)0x001BU)
#define LAN8742_CLR      ((uint16_t)0x001CU)
#define LAN8742_ISFR     ((uint16_t)0x001DU)
#define LAN8742_IMR      ((uint16_t)0x001EU)
[b]#define LAN8742_PHYSCSR  ((uint16_t)0x0010FU)[/b]

son olarak da CubeMX'de I ve D cache aktif etmeden ETH donanımını kullanmaya izin vermediği için sıkıntılara sebep olmaması için cache'in invalidate edilmesi gerekiyor. ethernetif.c dosyası içinde şu değişiklikler yapılacak :

static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
  uint32_t i = 0U;
  struct pbuf *q = NULL;
  err_t errval = ERR_OK;
  ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT] = {0};

  memset(Txbuffer, 0 , ETH_TX_DESC_CNT*sizeof(ETH_BufferTypeDef));

  for(q = p; q != NULL; q = q->next)
  {
    if(i >= ETH_TX_DESC_CNT)
      return ERR_IF;

    Txbuffer[i].buffer = q->payload;
    Txbuffer[i].len = q->len;

    if(i>0)
    {
      Txbuffer[i-1].next = &Txbuffer[i];
    }

    if(q->next == NULL)
    {
      Txbuffer[i].next = NULL;
    }

    i++;
  }

  TxConfig.Length = p->tot_len;
  TxConfig.TxBuffer = Txbuffer;
  TxConfig.pData = p;

 [b] SCB_CleanInvalidateDCache();[/b]

  HAL_ETH_Transmit(&heth, &TxConfig, ETH_DMA_TRANSMIT_TIMEOUT);

  return errval;
}


static struct pbuf * low_level_input(struct netif *netif)
{
  struct pbuf *p = NULL;

  [b]SCB_CleanInvalidateDCache();[/b]

  if(RxAllocStatus == RX_ALLOC_OK)
  {
    HAL_ETH_ReadData(&heth, (void **)&p);
  }

  return p;
}

Eğer artık udp, tcp, webserver vs ne kullanacaksanız onun kodunu doğru yazdıysanız sistemin çalışması lazım. Benim neredeyse toplamda 2 haftamı belki daha fazlasını yedi, sizin yemesin.





 


dumansiz

Merhaba,
Bilgi için teşekkürler. CubeIDE ve CubeMX'in sürümlerini de yazar mısınız?
Ayrıca; bu yoklukta STM32F7 veya STM32H7 işlemcilerini nasıl temin ettiniz?

kimlenbu

#2
CubeMX 6.7.0
CubeIDE Version: 1.10.1 Build: 12716_20220707_0928 (UTC)
Firmware : STM32Cube FW_H7 V 1.11.0

Demsay veya uzakdoğulu tedarikçileri kullanıyorum (alibaba üzerinden deneme yanılma ile bulup güvenilir olanları ile direkt olarak iletişimdeyim), Demsay bazen uçuk fiyatlar veriyor. Benim 18$'a bulduğum işlemciye 120 dolar fiyat gelebiliyor ama genellikle kabul edilebilir fiyatları var ve çok ilgililer. Çalıştığım firmayı her yıl en az 2 kez ziyarete geliyorlar.

MCU ları ve IC'leri ne yazık ki eskisi gibi mouser, digikey vs gibi yerlerden bulmak imkanız, hepsi karaborsada.



flowchartx

Hocam sizden farklı olarak Shareability Permissionu enable yapıp sorunsuz bir şekilde Rx Tx buffer adreslerini kullanabiliyorum ve D2 rami kullanmaya gerek kalmıyor. Bana kalırsa burda siz doğru config yapamamışsınız.

kimlenbu

#4
Alıntı yapılan: flowchartx - 30 Aralık 2022, 12:17:48Hocam sizden farklı olarak Shareability Permissionu enable yapıp sorunsuz bir şekilde Rx Tx buffer adreslerini kullanabiliyorum ve D2 rami kullanmaya gerek kalmıyor. Bana kalırsa burda siz doğru config yapamamışsınız.

İşlemcinin tam kodu nedir ? H723VET'nin kendi dosyasında bile şu yazıyor :

"@Note  The internal DMA of the Ethernet peripheral can't access the DTCM memory (@0x20000000)
       of the STM32H7, All data accessible by the Ethernet DMA must be located in the D1 or D2 SRAM.
       For more details please refer to "ethernetif.c" file."

flowchartx

Benim işlemcim F746VGT6. Sizin yazdığın adres SRAM'in dışında kalıyo olabilir ona dikkat ederek denediniz mi?

kimlenbu

Alıntı yapılan: flowchartx - 30 Aralık 2022, 13:15:06Benim işlemcim F746VGT6. Sizin yazdığın adres SRAM'in dışında kalıyo olabilir ona dikkat ederek denediniz mi?

F767 ve F746'da sıkıntı yok zaten (ikisini de kullandım). Özellikle H serisinde sıkıntı var.

flowchartx

H7'de kulladım aynı configle. Fırsat bulursam H7'de deneyip sizinle paylaşayım hocam

kimlenbu

Alıntı yapılan: flowchartx - 30 Aralık 2022, 14:36:55H7'de kulladım aynı configle. Fırsat bulursam H7'de deneyip sizinle paylaşayım hocam

CubeMX'de System Core/Cortex M7 ve LWIP/Key Options/Infrastructure - Heap and Memory Pools Options kısmının ekran görüntüsünü atarsan süper olur.