Перейти к содержанию
    

Время инициализации LwIP в STM32H7

Работаю с RAW LwIP на плате NUCLEO-H743ZI2 и случайно обратил внимание, что 99.9% времени, затрачиваемого на запуск контроллера (выход на цикл while(1)) приходится на функцию инициализации MX_LWIP_Init(). На 400 МГц тактовой частоты ядра это время составляет 2 секунды. Измерял вот так:

Спойлер

cnt_ms_load_mcu = HAL_GetTick();
 MX_LWIP_Init();
 cnt_ms_load_mcu = HAL_GetTick() - cnt_ms_load_mcu;

 Архив с проектом прилагаю: 

Спойлер

Хотел узнать, у вас так же? Кто-нибудь ускорял инициализацию этой библиотеки?

Изменено пользователем Turgenev

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

12 часов назад, Arlleex сказал:

Думается мне, что Вы измеряете скорость автосогласования Ethernet PHY...

Я ТС-у об этом писал в другой теме. Только думаю, что он всё равно ничего не понял. Так как не знает и не желает знать - что делает какая часть его же кода.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ваши сомнения в такой долгой инициализации натолкнули на поиски.

Причина оказалась проста. Код из lan8742.c:

Спойлер

/* Wait for 2s to perform initialization */
    while((pObj->IO.GetTick() - tickstart) <= LAN8742_INIT_TO)
     {
     }

Комментарий от разработчиков ST в теме (осторожно, очень жесткая критика):

Удаление этой 2 сек задержки, предварительно, на работу сети Ethernet не повлияло- пингую, отправляю, принимаю пакеты на 100 МБ/с. Из темы на форуме ST и из кода так и не понял зачем ждать 2 секунды, если PHY и MAC и без нее синхронизируются.

14 часов назад, jcxz сказал:

Я ТС-у об этом писал в другой теме. Только думаю, что он всё равно ничего не понял. Так как не знает и не желает знать - что делает какая часть его же кода.

Что делает написанный мной код я желаю знать и знаю. Что делает код сторонних библиотек мне достаточно знать в самом общем смысле, если работа библиотеки удовлетворяет моим требованиям, иначе зачем я ее использую. Безусловно полезно знать все на свете, но возможностей для этого не достаёт. Неужели это не так работает?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ды можно и не вдаваться в подробности работы сторонних исходников, но ведь Вам пришлось же вдаваться, как минимум)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну вы сказали что не должно быть так, я и полез... Мои коллеги несколько лет на это не обращали внимание

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

7 часов назад, Turgenev сказал:

Удаление этой 2 сек задержки, предварительно, на работу сети Ethernet не повлияло- пингую, отправляю, принимаю пакеты на 100 МБ/с. Из темы на форуме ST и из кода так и не понял зачем ждать 2 секунды, если PHY и MAC и без нее синхронизируются.

Вам уже и написали выше про наиболее вероятную причину - зачем нужна эта задержка:

В 20.06.2024 в 18:58, Arlleex сказал:

автосогласования Ethernet PHY

но вы ведь всё равно не поняли. Предпочитаете пинать колёса, а не вникать.  :unknw:

7 часов назад, Turgenev сказал:

Что делает написанный мной код я желаю знать и знаю. Что делает код сторонних библиотек

Как только какой-то код, не важно где откопанный, вы влепили в свой проект, он стал вашим кодом.

7 часов назад, Turgenev сказал:

Неужели это не так работает?

Когда ваше устройство вдруг перестаёт работать, вы тоже заказчику говорите: "Это проблема не у меня, а в той либе, которую я влепил в свой проект. А я не при делах." Так? 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Распишу почему мне не понятно, зачем нужна задержка.

Задержка в 2 секунды находится в функции LAN8742_Init(lan8742_Object_t *pObj), в которой не происходит автосогласования, а только конфиг PHY, поправьте если не прав. Процесс автосогласования запускается автоматически после сброса PHY:

Спойлер

/**
  * @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;
   
     /* Get the device address from special mode register */  
     for(addr = 0; addr <= LAN8742_MAX_DEV_ADDR; addr ++)
     {
       if(pObj->IO.ReadReg(addr, LAN8742_SMR, &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)
     {
     }*/

     pObj->Is_Initialized = 1;
   }
   
   return status;
 }

Т.е. ожидание 2 с оправдано тем, что происходит процесс автосогласования, который автоматически начался после сброса PHY.

Но в RAW LwIP обработка пакетов происходит вызовом функции MX_LWIP_Process() в бесконечном цикле, в которой есть функция работы с PHY - Ethernet_Link_Periodic_Handle(struct netif *netif). Эта функция проверяет состояние канала и возможность/необходимость перехода на другую скорость функцией ethernet_link_check_state(struct netif *netif):

Спойлер

/**
  * @brief  Check the ETH link state then update ETH driver and netif link accordingly.
  * @param  argument: netif
  * @retval None
  */
void ethernet_link_check_state(struct netif *netif)
{
  ETH_MACConfigTypeDef MACConf;
  int32_t PHYLinkState;
  uint32_t linkchanged = 0, speed = 0, duplex =0;

  PHYLinkState = LAN8742_GetLinkState(&LAN8742);

  if(netif_is_link_up(netif) && (PHYLinkState <= LAN8742_STATUS_LINK_DOWN))
  {
    HAL_ETH_Stop(&heth);
    netif_set_down(netif);
    netif_set_link_down(netif);
  }
  else if(!netif_is_link_up(netif) && (PHYLinkState > LAN8742_STATUS_LINK_DOWN))
  {
    switch (PHYLinkState)
    {
    case LAN8742_STATUS_100MBITS_FULLDUPLEX:
      duplex = ETH_FULLDUPLEX_MODE;
      speed = ETH_SPEED_100M;
      linkchanged = 1;
      break;
    case LAN8742_STATUS_100MBITS_HALFDUPLEX:
      duplex = ETH_HALFDUPLEX_MODE;
      speed = ETH_SPEED_100M;
      linkchanged = 1;
      break;
    case LAN8742_STATUS_10MBITS_FULLDUPLEX:
      duplex = ETH_FULLDUPLEX_MODE;
      speed = ETH_SPEED_10M;
      linkchanged = 1;
      break;
    case LAN8742_STATUS_10MBITS_HALFDUPLEX:
      duplex = ETH_HALFDUPLEX_MODE;
      speed = ETH_SPEED_10M;
      linkchanged = 1;
      break;
    default:
      break;
    }

    if(linkchanged)
    {
      /* Get MAC Config MAC */
      HAL_ETH_GetMACConfig(&heth, &MACConf);
      MACConf.DuplexMode = duplex;
      MACConf.Speed = speed;
      HAL_ETH_SetMACConfig(&heth, &MACConf);

      HAL_ETH_Start(&heth);
      netif_set_up(netif);
      netif_set_link_up(netif);
    }
  }

}

А состояние/результат работы автосогласования проверяется/устанавливается в функции LAN8742_GetLinkState(lan8742_Object_t *pObj):

Спойлер

/**
  * @brief  Get the link state of LAN8742 device.
  * @param  pObj: Pointer to device object. 
  * @param  pLinkState: Pointer to link state
  * @retval LAN8742_STATUS_LINK_DOWN  if link is down
  *         LAN8742_STATUS_AUTONEGO_NOTDONE if Auto nego not completed 
  *         LAN8742_STATUS_100MBITS_FULLDUPLEX if 100Mb/s FD
  *         LAN8742_STATUS_100MBITS_HALFDUPLEX if 100Mb/s HD
  *         LAN8742_STATUS_10MBITS_FULLDUPLEX  if 10Mb/s FD
  *         LAN8742_STATUS_10MBITS_HALFDUPLEX  if 10Mb/s HD       
  *         LAN8742_STATUS_READ_ERROR if connot read register
  *         LAN8742_STATUS_WRITE_ERROR if connot write to register
  */
int32_t LAN8742_GetLinkState(lan8742_Object_t *pObj)
{
  uint32_t readval = 0;
  
  /* Read Status register  */
  if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BSR, &readval) < 0)
  {
    return LAN8742_STATUS_READ_ERROR;
  }
  
  /* Read Status register again */
  if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BSR, &readval) < 0)
  {
    return LAN8742_STATUS_READ_ERROR;
  }
  
  if((readval & LAN8742_BSR_LINK_STATUS) == 0)
  {
    /* Return Link Down status */
    return LAN8742_STATUS_LINK_DOWN;    
  }
  
  /* Check Auto negotiaition */
  if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_BCR, &readval) < 0)
  {
    return LAN8742_STATUS_READ_ERROR;
  }
  
  if((readval & LAN8742_BCR_AUTONEGO_EN) != LAN8742_BCR_AUTONEGO_EN)
  {
    if(((readval & LAN8742_BCR_SPEED_SELECT) == LAN8742_BCR_SPEED_SELECT) && ((readval & LAN8742_BCR_DUPLEX_MODE) == LAN8742_BCR_DUPLEX_MODE)) 
    {
      return LAN8742_STATUS_100MBITS_FULLDUPLEX;
    }
    else if ((readval & LAN8742_BCR_SPEED_SELECT) == LAN8742_BCR_SPEED_SELECT)
    {
      return LAN8742_STATUS_100MBITS_HALFDUPLEX;
    }        
    else if ((readval & LAN8742_BCR_DUPLEX_MODE) == LAN8742_BCR_DUPLEX_MODE)
    {
      return LAN8742_STATUS_10MBITS_FULLDUPLEX;
    }
    else
    {
      return LAN8742_STATUS_10MBITS_HALFDUPLEX;
    }          
  }
  else /* Auto Nego enabled */
  {
    if(pObj->IO.ReadReg(pObj->DevAddr, LAN8742_PHYSCSR, &readval) < 0)
    {
      return LAN8742_STATUS_READ_ERROR;
    }
    
    /* Check if auto nego not done */
    if((readval & LAN8742_PHYSCSR_AUTONEGO_DONE) == 0)
    {
      return LAN8742_STATUS_AUTONEGO_NOTDONE;
    }
    
    if((readval & LAN8742_PHYSCSR_HCDSPEEDMASK) == LAN8742_PHYSCSR_100BTX_FD)
    {
      return LAN8742_STATUS_100MBITS_FULLDUPLEX;
    }
    else if ((readval & LAN8742_PHYSCSR_HCDSPEEDMASK) == LAN8742_PHYSCSR_100BTX_HD)
    {
      return LAN8742_STATUS_100MBITS_HALFDUPLEX;
    }
    else if ((readval & LAN8742_PHYSCSR_HCDSPEEDMASK) == LAN8742_PHYSCSR_10BT_FD)
    {
      return LAN8742_STATUS_10MBITS_FULLDUPLEX;
    }
    else
    {
      return LAN8742_STATUS_10MBITS_HALFDUPLEX;
    }                
  }
}

  Тогда зачем ждать железные 2 с при старте, ни к чему не привязанные (может времени нужно больше или меньше), когда в процессе работы согласование PHY с MAC и так постоянно проверяется? Если задержка сделана на случай, если не удалось согласование при старте, оно по-любому запустится в процессе работы.

По-моему, это уже не по теме:

Спойлер

 

В 22.06.2024 в 06:12, jcxz сказал:

но вы ведь всё равно не поняли. Предпочитаете пинать колёса, а не вникать.  :unknw:

 

Так можно отвечать на все вопросы, когда кому-то что-то не понятно. Нашел задержку и тему где она описана- пинал колеса, в этой теме не понял что-то - не хочешь вникать. Не прикрывайтесь советами других, действуйте более открыто, будет меньше текста.

В 22.06.2024 в 06:12, jcxz сказал:

Когда ваше устройство вдруг перестаёт работать, вы тоже заказчику говорите: "Это проблема не у меня, а в той либе, которую я влепил в свой проект. А я не при делах." Так? 

Не судите по себе, есть тестировщики, этапы разработки, испытания и тд. Кто заказчику не обкатанное изделие отдает.

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Получил проблему из-за удаления 2с задержки в инициализации PHY: соединение по Ethernet устанавливается только после второй перезагрузки устройства, после прошивки МК. Т.е. прошиваю МК, перезагружаю всё устройство и связи по ethernet нет, затем перезагружаю устройство второй раз и связь появляется.

Проблема описана вот тут:

Вкратце: PHY возвращает 0xFFFF при чтении любого его регистра. Малой кровью проблема решается добавлением проверки в LAN8742_Init перед первым чтением регистра PHY в этой функции:

Спойлер

     pObj->IO.ReadReg(0, LAN8742_SMR, &regvalue);
      
     if (regvalue == 0x0000FFFF)
     {
       HAL_NVIC_SystemReset();
     }

Может кому-то будет полезно...

Изменено пользователем Turgenev

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 22.06.2024 в 00:41, Turgenev сказал:

Удаление этой 2 сек задержки, предварительно, на работу сети Ethernet не повлияло- пингую, отправляю, принимаю пакеты на 100 МБ/с. Из темы на форуме ST и из кода так и не понял зачем ждать 2 секунды, если PHY и MAC и без нее синхронизируются.

Проверять надо более комплексно, например выдернуть кабель и снова подключить, сделать power/off - power onn и т.д., наблюдать не светодиод линка, а реальный обмен пакетами.  При этом время и результат (успех/неуспех) с разными компьютерами, маршрутизаторами или коммутаторами на разных скоростях и настройках может быть разным. 


Про задержку. Почему она существует и почему она потребовалась.
Существует протокол автосогласования, для того чтобы он отработал требуется время:
https://en.wikipedia.org/wiki/Autonegotiation

autoneg_time.thumb.jpg.f836f7779d2c66065229314574517909.jpg

В ST некогда переписали HAL код Ethenet и сделали множество ошибок, одной из них является само построение логики:
они сбрасывают PHY, инициализируют, и ждут окончания процесса автосогласования, для чего выдерживают заданную паузу.
В этом у них еще и баг, так как в некоторых случаях с гигабитными линками требуемое время существенно больше, до 3сек, то есть превышает заданную ими паузу.

Правильный код должен сбросить PHY, проинициализировать, и на этом инициализация должна закончиться,
перенеся время ожидания в цикл, в периодическую проверку is link up. 

Изменено пользователем std

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В 07.07.2024 в 03:36, std сказал:

В ST некогда переписали HAL код Ethenet и сделали множество ошибок, одной из них является само построение логики:
они сбрасывают PHY, инициализируют, и ждут окончания процесса автосогласования, для чего выдерживают заданную паузу.
В этом у них еще и баг, так как в некоторых случаях с гигабитными линками требуемое время существенно больше, до 3сек, то есть превышает заданную ими паузу.

Получается, что в текущей реализации библиотеки HAL (когда время автосогласования выжидается при инициализации библиотеки LwIP), если включить моё устройство без подключенного кабеля Ethernet к компу (или другому PHY), то контроллер впустую простоит 2 секунды, согласоваться то не с кем. А как мой PHY тогда согласуется с другим PHY, когда я подключаю Ethernet кабель после "пустого" согласования (согласования без подключенного кабеля)? Ведь процедура согласования происходит один раз и только при включении МК.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 7/8/2024 at 11:40 AM, Turgenev said:

Получается, что в текущей реализации библиотеки HAL (когда время автосогласования выжидается при инициализации библиотеки LwIP), если включить моё устройство без подключенного кабеля Ethernet к компу (или другому PHY), то контроллер впустую простоит 2 секунды, согласоваться то не с кем. А как мой PHY тогда согласуется с другим PHY, когда я подключаю Ethernet кабель после "пустого" согласования (согласования без подключенного кабеля)? Ведь процедура согласования происходит один раз и только при включении МК.

На удачу )))
Выжидание требуется для МАС. PHY согласуется автоматически. По результатам согласование PHY, МАС настраивает свои регистры.
Значения Half/Full duplex, 10/100 МБит.
По умолчанию МАС настроен на Full Duplex и 100 МБит. PHY скорее всего у вас не гигабитный. 
Сейчас сеть на 10 Мбит еще умудриться найти надо. Поэтому настройка по умолчанию в подавляющем большинстве случаев подходит.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

36 минут назад, dimka76 сказал:

На удачу )))

Ужас. Надо с этим что-то делать.

Я пробовал разные версии CubeMX и, следовательно, библиотек HAL и LwIP, чтобы запустить Ethernet "из коробки". Да, так не правильно делать, но справедливости ради, ни разу таким способом ничего и не заработало. Но минимальное количество правок кода потребовала версия Cube 6.3.0 и HAL1.9.0 для STM32H7. В этой версии библиотек есть ожидание 2 сек автосогласования. В последующих версиях ST обещали исправить библиотеку HAL Ethernet и исправили, но испортили что-то другое. И так мне не удалось найти версию с нормальной библиотекой Ethernet.

Может кто-нибудь использует HAL и LwIP, где эта проблема с ожиданием и многие другие проблемы решены и библиотека стабильна, посоветуете версию?

Изменено пользователем Turgenev

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 7/8/2024 at 12:41 PM, Turgenev said:

Может кто-нибудь использует HAL и LwIP, где эта проблема с ожиданием и многие другие проблемы решены и библиотека стабильна, посоветуете версию?

HAL вам предоставляет только доступ к периферии.
Связь HAL и LwIP представлена в виде примера, а не полноценного законченного продукта.
Пример вам показывает какие в каком порядке вызывать функции HAL для того, чтобы ознакомится с библиотекой.
Полноценное рабочее приложение вы должны сделать самостоятельно.
Если вам достаточно функционала примера, то можно остановиться на этом.
Если нужно что-то большее, то придется самому развивать этот пример.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 часа назад, dimka76 сказал:

Сейчас сеть на 10 Мбит еще умудриться найти надо.

Да запросто! Открываем datasheet на один из МК, популярного ныне в РФ (а куда деваться?) китайского производителя WCH (CH32F20x Datasheet For CH32F203/205/207/208xx V2.3). И видим:

Цитата

Ethernet MAC that  reaches  gigabit,  integrated  10M-PHY  module

Дешёвое устройство вполне может быть построено на таком МК со встроенным Phy-10M.

 

Да даже если железо в устройстве само по себе поддерживает бОльшие скорости, но скорость может быть зарезана преднамеренно по каким-то причинам (помехоустойчивость, etc.). В наших устройствах мы делали возможность пользователю в конфиге устройства разрешить работу только на нужных режимах из: 10-half, 10-full, 100-half, 100-full.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...