[PATCH rtems-lwip v2 3/7] Add STM32 Ethernet source

Kinsey Moore kinsey.moore at oarcorp.com
Tue Sep 6 18:55:15 UTC 2022


This should also add a ORIGIN.stm32 and a COPYING.stm32 to describe the 
imported sources. The information in the commit message you have here 
should suffice as the majority of the content of ORIGIN.stm32.


Kinsey

On 9/6/2022 11:20, Duc Doan wrote:
> This patch adds ST's Ethernet and lwIP port and DP83848 driver. The
> files are generated using STM32CubeIDE with STM32F4 Cube FW v1.27.1,
> under no RTOS mode.
> ---
>   stm32/driver/dp83848.c | 664 +++++++++++++++++++++++++++++++++++++
>   stm32/driver/dp83848.h | 436 ++++++++++++++++++++++++
>   stm32/ethernetif.c     | 737 +++++++++++++++++++++++++++++++++++++++++
>   stm32/ethernetif.h     |  45 +++
>   stm32/lwip.c           | 260 +++++++++++++++
>   stm32/lwip.h           |  76 +++++
>   6 files changed, 2218 insertions(+)
>   create mode 100644 stm32/driver/dp83848.c
>   create mode 100644 stm32/driver/dp83848.h
>   create mode 100644 stm32/ethernetif.c
>   create mode 100644 stm32/ethernetif.h
>   create mode 100644 stm32/lwip.c
>   create mode 100644 stm32/lwip.h
>
> diff --git a/stm32/driver/dp83848.c b/stm32/driver/dp83848.c
> new file mode 100644
> index 0000000..2c5d59b
> --- /dev/null
> +++ b/stm32/driver/dp83848.c
> @@ -0,0 +1,664 @@
> +/**
> +  ******************************************************************************
> +  * @file    dp83848.c
> +  * @author  MCD Application Team
> +  * @brief   This file provides a set of functions needed to manage the DP83848
> +  *          PHY devices.
> +  ******************************************************************************
> +  * @attention
> +  *
> +  * <h2><center>© Copyright (c) 2021 STMicroelectronics.
> +  * All rights reserved.</center></h2>
> +  *
> +  * This software component is licensed by ST under BSD 3-Clause license,
> +  * the "License"; You may not use this file except in compliance with the
> +  * License. You may obtain a copy of the License at:
> +  *                        opensource.org/licenses/BSD-3-Clause
> +  *
> +  ******************************************************************************
> +  */
> +
> +/* Includes ------------------------------------------------------------------*/
> +#include "dp83848.h"
> +
> +/** @addtogroup BSP
> +  * @{
> +  */
> +
> +/** @addtogroup Component
> +  * @{
> +  */
> +
> +/** @defgroup DP83848 DP83848
> +  * @{
> +  */
> +
> +/* Private typedef -----------------------------------------------------------*/
> +/* Private define ------------------------------------------------------------*/
> +/** @defgroup DP83848_Private_Defines DP83848 Private Defines
> +  * @{
> +  */
> +#define DP83848_SW_RESET_TO    ((uint32_t)500U)
> +#define DP83848_INIT_TO        ((uint32_t)2000U)
> +#define DP83848_MAX_DEV_ADDR   ((uint32_t)31U)
> +/**
> +  * @}
> +  */
> +
> +/* Private macro -------------------------------------------------------------*/
> +/* Private variables ---------------------------------------------------------*/
> +/* Private function prototypes -----------------------------------------------*/
> +/* Private functions ---------------------------------------------------------*/
> +/** @defgroup DP83848_Private_Functions DP83848 Private Functions
> +  * @{
> +  */
> +
> +/**
> +  * @brief  Register IO functions to component object
> +  * @param  pObj: device object  of DP83848_Object_t.
> +  * @param  ioctx: holds device IO functions.
> +  * @retval DP83848_STATUS_OK  if OK
> +  *         DP83848_STATUS_ERROR if missing mandatory function
> +  */
> +int32_t  DP83848_RegisterBusIO(dp83848_Object_t *pObj, dp83848_IOCtx_t *ioctx)
> +{
> +  if(!pObj || !ioctx->ReadReg || !ioctx->WriteReg || !ioctx->GetTick)
> +  {
> +    return DP83848_STATUS_ERROR;
> +  }
> +
> +  pObj->IO.Init = ioctx->Init;
> +  pObj->IO.DeInit = ioctx->DeInit;
> +  pObj->IO.ReadReg = ioctx->ReadReg;
> +  pObj->IO.WriteReg = ioctx->WriteReg;
> +  pObj->IO.GetTick = ioctx->GetTick;
> +
> +  return DP83848_STATUS_OK;
> +}
> +
> +/**
> +  * @brief  Initialize the DP83848 and configure the needed hardware resources
> +  * @param  pObj: device object DP83848_Object_t.
> +  * @retval DP83848_STATUS_OK  if OK
> +  *         DP83848_STATUS_ADDRESS_ERROR if cannot find device address
> +  *         DP83848_STATUS_READ_ERROR if connot read register
> +  *         DP83848_STATUS_WRITE_ERROR if connot write to register
> +  *         DP83848_STATUS_RESET_TIMEOUT if cannot perform a software reset
> +  */
> + int32_t DP83848_Init(dp83848_Object_t *pObj)
> + {
> +   uint32_t tickstart = 0, regvalue = 0, addr = 0;
> +   int32_t status = DP83848_STATUS_OK;
> +
> +   if(pObj->Is_Initialized == 0)
> +   {
> +     if(pObj->IO.Init != 0)
> +     {
> +       /* GPIO and Clocks initialization */
> +       pObj->IO.Init();
> +     }
> +
> +     /* for later check */
> +     pObj->DevAddr = DP83848_MAX_DEV_ADDR + 1;
> +
> +     /* Get the device address from special mode register */
> +     for(addr = 0; addr <= DP83848_MAX_DEV_ADDR; addr ++)
> +     {
> +       if(pObj->IO.ReadReg(addr, DP83848_SMR, &regvalue) < 0)
> +       {
> +         status = DP83848_STATUS_READ_ERROR;
> +         /* Can't read from this device address
> +            continue with next address */
> +         continue;
> +       }
> +
> +       if((regvalue & DP83848_SMR_PHY_ADDR) == addr)
> +       {
> +         pObj->DevAddr = addr;
> +         status = DP83848_STATUS_OK;
> +         break;
> +       }
> +     }
> +
> +     if(pObj->DevAddr > DP83848_MAX_DEV_ADDR)
> +     {
> +       status = DP83848_STATUS_ADDRESS_ERROR;
> +     }
> +
> +     /* if device address is matched */
> +     if(status == DP83848_STATUS_OK)
> +     {
> +       /* set a software reset  */
> +       if(pObj->IO.WriteReg(pObj->DevAddr, DP83848_BCR, DP83848_BCR_SOFT_RESET) >= 0)
> +       {
> +         /* get software reset status */
> +         if(pObj->IO.ReadReg(pObj->DevAddr, DP83848_BCR, &regvalue) >= 0)
> +         {
> +           tickstart = pObj->IO.GetTick();
> +
> +           /* wait until software reset is done or timeout occured  */
> +           while(regvalue & DP83848_BCR_SOFT_RESET)
> +           {
> +             if((pObj->IO.GetTick() - tickstart) <= DP83848_SW_RESET_TO)
> +             {
> +               if(pObj->IO.ReadReg(pObj->DevAddr, DP83848_BCR, &regvalue) < 0)
> +               {
> +                 status = DP83848_STATUS_READ_ERROR;
> +                 break;
> +               }
> +             }
> +             else
> +             {
> +               status = DP83848_STATUS_RESET_TIMEOUT;
> +               break;
> +             }
> +           }
> +         }
> +         else
> +         {
> +           status = DP83848_STATUS_READ_ERROR;
> +         }
> +       }
> +       else
> +       {
> +         status = DP83848_STATUS_WRITE_ERROR;
> +       }
> +     }
> +   }
> +
> +   if(status == DP83848_STATUS_OK)
> +   {
> +     tickstart =  pObj->IO.GetTick();
> +
> +     /* Wait for 2s to perform initialization */
> +     while((pObj->IO.GetTick() - tickstart) <= DP83848_INIT_TO)
> +     {
> +     }
> +     pObj->Is_Initialized = 1;
> +   }
> +
> +   return status;
> + }
> +
> +/**
> +  * @brief  De-Initialize the dp83848 and it's hardware resources
> +  * @param  pObj: device object DP83848_Object_t.
> +  * @retval None
> +  */
> +int32_t DP83848_DeInit(dp83848_Object_t *pObj)
> +{
> +  if(pObj->Is_Initialized)
> +  {
> +    if(pObj->IO.DeInit != 0)
> +    {
> +      if(pObj->IO.DeInit() < 0)
> +      {
> +        return DP83848_STATUS_ERROR;
> +      }
> +    }
> +
> +    pObj->Is_Initialized = 0;
> +  }
> +
> +  return DP83848_STATUS_OK;
> +}
> +
> +/**
> +  * @brief  Disable the DP83848 power down mode.
> +  * @param  pObj: device object DP83848_Object_t.
> +  * @retval DP83848_STATUS_OK  if OK
> +  *         DP83848_STATUS_READ_ERROR if connot read register
> +  *         DP83848_STATUS_WRITE_ERROR if connot write to register
> +  */
> +int32_t DP83848_DisablePowerDownMode(dp83848_Object_t *pObj)
> +{
> +  uint32_t readval = 0;
> +  int32_t status = DP83848_STATUS_OK;
> +
> +  if(pObj->IO.ReadReg(pObj->DevAddr, DP83848_BCR, &readval) >= 0)
> +  {
> +    readval &= ~DP83848_BCR_POWER_DOWN;
> +
> +    /* Apply configuration */
> +    if(pObj->IO.WriteReg(pObj->DevAddr, DP83848_BCR, readval) < 0)
> +    {
> +      status =  DP83848_STATUS_WRITE_ERROR;
> +    }
> +  }
> +  else
> +  {
> +    status = DP83848_STATUS_READ_ERROR;
> +  }
> +
> +  return status;
> +}
> +
> +/**
> +  * @brief  Enable the DP83848 power down mode.
> +  * @param  pObj: device object DP83848_Object_t.
> +  * @retval DP83848_STATUS_OK  if OK
> +  *         DP83848_STATUS_READ_ERROR if connot read register
> +  *         DP83848_STATUS_WRITE_ERROR if connot write to register
> +  */
> +int32_t DP83848_EnablePowerDownMode(dp83848_Object_t *pObj)
> +{
> +  uint32_t readval = 0;
> +  int32_t status = DP83848_STATUS_OK;
> +
> +  if(pObj->IO.ReadReg(pObj->DevAddr, DP83848_BCR, &readval) >= 0)
> +  {
> +    readval |= DP83848_BCR_POWER_DOWN;
> +
> +    /* Apply configuration */
> +    if(pObj->IO.WriteReg(pObj->DevAddr, DP83848_BCR, readval) < 0)
> +    {
> +      status =  DP83848_STATUS_WRITE_ERROR;
> +    }
> +  }
> +  else
> +  {
> +    status = DP83848_STATUS_READ_ERROR;
> +  }
> +
> +  return status;
> +}
> +
> +/**
> +  * @brief  Start the auto negotiation process.
> +  * @param  pObj: device object DP83848_Object_t.
> +  * @retval DP83848_STATUS_OK  if OK
> +  *         DP83848_STATUS_READ_ERROR if connot read register
> +  *         DP83848_STATUS_WRITE_ERROR if connot write to register
> +  */
> +int32_t DP83848_StartAutoNego(dp83848_Object_t *pObj)
> +{
> +  uint32_t readval = 0;
> +  int32_t status = DP83848_STATUS_OK;
> +
> +  if(pObj->IO.ReadReg(pObj->DevAddr, DP83848_BCR, &readval) >= 0)
> +  {
> +    readval |= DP83848_BCR_AUTONEGO_EN;
> +
> +    /* Apply configuration */
> +    if(pObj->IO.WriteReg(pObj->DevAddr, DP83848_BCR, readval) < 0)
> +    {
> +      status =  DP83848_STATUS_WRITE_ERROR;
> +    }
> +  }
> +  else
> +  {
> +    status = DP83848_STATUS_READ_ERROR;
> +  }
> +
> +  return status;
> +}
> +
> +/**
> +  * @brief  Get the link state of DP83848 device.
> +  * @param  pObj: Pointer to device object.
> +  * @param  pLinkState: Pointer to link state
> +  * @retval DP83848_STATUS_LINK_DOWN  if link is down
> +  *         DP83848_STATUS_AUTONEGO_NOTDONE if Auto nego not completed
> +  *         DP83848_STATUS_100MBITS_FULLDUPLEX if 100Mb/s FD
> +  *         DP83848_STATUS_100MBITS_HALFDUPLEX if 100Mb/s HD
> +  *         DP83848_STATUS_10MBITS_FULLDUPLEX  if 10Mb/s FD
> +  *         DP83848_STATUS_10MBITS_HALFDUPLEX  if 10Mb/s HD
> +  *         DP83848_STATUS_READ_ERROR if connot read register
> +  *         DP83848_STATUS_WRITE_ERROR if connot write to register
> +  */
> +int32_t DP83848_GetLinkState(dp83848_Object_t *pObj)
> +{
> +  uint32_t readval = 0;
> +
> +  /* Read Status register  */
> +  if(pObj->IO.ReadReg(pObj->DevAddr, DP83848_BSR, &readval) < 0)
> +  {
> +    return DP83848_STATUS_READ_ERROR;
> +  }
> +
> +  /* Read Status register again */
> +  if(pObj->IO.ReadReg(pObj->DevAddr, DP83848_BSR, &readval) < 0)
> +  {
> +    return DP83848_STATUS_READ_ERROR;
> +  }
> +
> +  if((readval & DP83848_BSR_LINK_STATUS) == 0)
> +  {
> +    /* Return Link Down status */
> +    return DP83848_STATUS_LINK_DOWN;
> +  }
> +
> +  /* Check Auto negotiaition */
> +  if(pObj->IO.ReadReg(pObj->DevAddr, DP83848_BCR, &readval) < 0)
> +  {
> +    return DP83848_STATUS_READ_ERROR;
> +  }
> +
> +  if((readval & DP83848_BCR_AUTONEGO_EN) != DP83848_BCR_AUTONEGO_EN)
> +  {
> +    if(((readval & DP83848_BCR_SPEED_SELECT) == DP83848_BCR_SPEED_SELECT) && ((readval & DP83848_BCR_DUPLEX_MODE) == DP83848_BCR_DUPLEX_MODE))
> +    {
> +      return DP83848_STATUS_100MBITS_FULLDUPLEX;
> +    }
> +    else if ((readval & DP83848_BCR_SPEED_SELECT) == DP83848_BCR_SPEED_SELECT)
> +    {
> +      return DP83848_STATUS_100MBITS_HALFDUPLEX;
> +    }
> +    else if ((readval & DP83848_BCR_DUPLEX_MODE) == DP83848_BCR_DUPLEX_MODE)
> +    {
> +      return DP83848_STATUS_10MBITS_FULLDUPLEX;
> +    }
> +    else
> +    {
> +      return DP83848_STATUS_10MBITS_HALFDUPLEX;
> +    }
> +  }
> +  else /* Auto Nego enabled */
> +  {
> +    if(pObj->IO.ReadReg(pObj->DevAddr, DP83848_PHYSCSR, &readval) < 0)
> +    {
> +      return DP83848_STATUS_READ_ERROR;
> +    }
> +
> +    /* Check if auto nego not done */
> +    if((readval & DP83848_PHYSCSR_AUTONEGO_DONE) == 0)
> +    {
> +      return DP83848_STATUS_AUTONEGO_NOTDONE;
> +    }
> +
> +    if((readval & DP83848_PHYSCSR_HCDSPEEDMASK) == DP83848_PHYSCSR_100BTX_FD)
> +    {
> +      return DP83848_STATUS_100MBITS_FULLDUPLEX;
> +    }
> +    else if ((readval & DP83848_PHYSCSR_HCDSPEEDMASK) == DP83848_PHYSCSR_100BTX_HD)
> +    {
> +      return DP83848_STATUS_100MBITS_HALFDUPLEX;
> +    }
> +    else if ((readval & DP83848_PHYSCSR_HCDSPEEDMASK) == DP83848_PHYSCSR_10BT_FD)
> +    {
> +      return DP83848_STATUS_10MBITS_FULLDUPLEX;
> +    }
> +    else
> +    {
> +      return DP83848_STATUS_10MBITS_HALFDUPLEX;
> +    }
> +  }
> +}
> +
> +/**
> +  * @brief  Set the link state of DP83848 device.
> +  * @param  pObj: Pointer to device object.
> +  * @param  pLinkState: link state can be one of the following
> +  *         DP83848_STATUS_100MBITS_FULLDUPLEX if 100Mb/s FD
> +  *         DP83848_STATUS_100MBITS_HALFDUPLEX if 100Mb/s HD
> +  *         DP83848_STATUS_10MBITS_FULLDUPLEX  if 10Mb/s FD
> +  *         DP83848_STATUS_10MBITS_HALFDUPLEX  if 10Mb/s HD
> +  * @retval DP83848_STATUS_OK  if OK
> +  *         DP83848_STATUS_ERROR  if parameter error
> +  *         DP83848_STATUS_READ_ERROR if connot read register
> +  *         DP83848_STATUS_WRITE_ERROR if connot write to register
> +  */
> +int32_t DP83848_SetLinkState(dp83848_Object_t *pObj, uint32_t LinkState)
> +{
> +  uint32_t bcrvalue = 0;
> +  int32_t status = DP83848_STATUS_OK;
> +
> +  if(pObj->IO.ReadReg(pObj->DevAddr, DP83848_BCR, &bcrvalue) >= 0)
> +  {
> +    /* Disable link config (Auto nego, speed and duplex) */
> +    bcrvalue &= ~(DP83848_BCR_AUTONEGO_EN | DP83848_BCR_SPEED_SELECT | DP83848_BCR_DUPLEX_MODE);
> +
> +    if(LinkState == DP83848_STATUS_100MBITS_FULLDUPLEX)
> +    {
> +      bcrvalue |= (DP83848_BCR_SPEED_SELECT | DP83848_BCR_DUPLEX_MODE);
> +    }
> +    else if (LinkState == DP83848_STATUS_100MBITS_HALFDUPLEX)
> +    {
> +      bcrvalue |= DP83848_BCR_SPEED_SELECT;
> +    }
> +    else if (LinkState == DP83848_STATUS_10MBITS_FULLDUPLEX)
> +    {
> +      bcrvalue |= DP83848_BCR_DUPLEX_MODE;
> +    }
> +    else
> +    {
> +      /* Wrong link status parameter */
> +      status = DP83848_STATUS_ERROR;
> +    }
> +  }
> +  else
> +  {
> +    status = DP83848_STATUS_READ_ERROR;
> +  }
> +
> +  if(status == DP83848_STATUS_OK)
> +  {
> +    /* Apply configuration */
> +    if(pObj->IO.WriteReg(pObj->DevAddr, DP83848_BCR, bcrvalue) < 0)
> +    {
> +      status = DP83848_STATUS_WRITE_ERROR;
> +    }
> +  }
> +
> +  return status;
> +}
> +
> +/**
> +  * @brief  Enable loopback mode.
> +  * @param  pObj: Pointer to device object.
> +  * @retval DP83848_STATUS_OK  if OK
> +  *         DP83848_STATUS_READ_ERROR if connot read register
> +  *         DP83848_STATUS_WRITE_ERROR if connot write to register
> +  */
> +int32_t DP83848_EnableLoopbackMode(dp83848_Object_t *pObj)
> +{
> +  uint32_t readval = 0;
> +  int32_t status = DP83848_STATUS_OK;
> +
> +  if(pObj->IO.ReadReg(pObj->DevAddr, DP83848_BCR, &readval) >= 0)
> +  {
> +    readval |= DP83848_BCR_LOOPBACK;
> +
> +    /* Apply configuration */
> +    if(pObj->IO.WriteReg(pObj->DevAddr, DP83848_BCR, readval) < 0)
> +    {
> +      status = DP83848_STATUS_WRITE_ERROR;
> +    }
> +  }
> +  else
> +  {
> +    status = DP83848_STATUS_READ_ERROR;
> +  }
> +
> +  return status;
> +}
> +
> +/**
> +  * @brief  Disable loopback mode.
> +  * @param  pObj: Pointer to device object.
> +  * @retval DP83848_STATUS_OK  if OK
> +  *         DP83848_STATUS_READ_ERROR if connot read register
> +  *         DP83848_STATUS_WRITE_ERROR if connot write to register
> +  */
> +int32_t DP83848_DisableLoopbackMode(dp83848_Object_t *pObj)
> +{
> +  uint32_t readval = 0;
> +  int32_t status = DP83848_STATUS_OK;
> +
> +  if(pObj->IO.ReadReg(pObj->DevAddr, DP83848_BCR, &readval) >= 0)
> +  {
> +    readval &= ~DP83848_BCR_LOOPBACK;
> +
> +    /* Apply configuration */
> +    if(pObj->IO.WriteReg(pObj->DevAddr, DP83848_BCR, readval) < 0)
> +    {
> +      status =  DP83848_STATUS_WRITE_ERROR;
> +    }
> +  }
> +  else
> +  {
> +    status = DP83848_STATUS_READ_ERROR;
> +  }
> +
> +  return status;
> +}
> +
> +/**
> +  * @brief  Enable IT source.
> +  * @param  pObj: Pointer to device object.
> +  * @param  Interrupt: IT source to be enabled
> +  *         should be a value or a combination of the following:
> +  *         DP83848_WOL_IT
> +  *         DP83848_ENERGYON_IT
> +  *         DP83848_AUTONEGO_COMPLETE_IT
> +  *         DP83848_REMOTE_FAULT_IT
> +  *         DP83848_LINK_DOWN_IT
> +  *         DP83848_AUTONEGO_LP_ACK_IT
> +  *         DP83848_PARALLEL_DETECTION_FAULT_IT
> +  *         DP83848_AUTONEGO_PAGE_RECEIVED_IT
> +  * @retval DP83848_STATUS_OK  if OK
> +  *         DP83848_STATUS_READ_ERROR if connot read register
> +  *         DP83848_STATUS_WRITE_ERROR if connot write to register
> +  */
> +int32_t DP83848_EnableIT(dp83848_Object_t *pObj, uint32_t Interrupt)
> +{
> +  uint32_t readval = 0;
> +  int32_t status = DP83848_STATUS_OK;
> +
> +  if(pObj->IO.ReadReg(pObj->DevAddr, DP83848_IMR, &readval) >= 0)
> +  {
> +    readval |= Interrupt;
> +
> +    /* Apply configuration */
> +    if(pObj->IO.WriteReg(pObj->DevAddr, DP83848_IMR, readval) < 0)
> +    {
> +      status =  DP83848_STATUS_WRITE_ERROR;
> +    }
> +  }
> +  else
> +  {
> +    status = DP83848_STATUS_READ_ERROR;
> +  }
> +
> +  return status;
> +}
> +
> +/**
> +  * @brief  Disable IT source.
> +  * @param  pObj: Pointer to device object.
> +  * @param  Interrupt: IT source to be disabled
> +  *         should be a value or a combination of the following:
> +  *         DP83848_WOL_IT
> +  *         DP83848_ENERGYON_IT
> +  *         DP83848_AUTONEGO_COMPLETE_IT
> +  *         DP83848_REMOTE_FAULT_IT
> +  *         DP83848_LINK_DOWN_IT
> +  *         DP83848_AUTONEGO_LP_ACK_IT
> +  *         DP83848_PARALLEL_DETECTION_FAULT_IT
> +  *         DP83848_AUTONEGO_PAGE_RECEIVED_IT
> +  * @retval DP83848_STATUS_OK  if OK
> +  *         DP83848_STATUS_READ_ERROR if connot read register
> +  *         DP83848_STATUS_WRITE_ERROR if connot write to register
> +  */
> +int32_t DP83848_DisableIT(dp83848_Object_t *pObj, uint32_t Interrupt)
> +{
> +  uint32_t readval = 0;
> +  int32_t status = DP83848_STATUS_OK;
> +
> +  if(pObj->IO.ReadReg(pObj->DevAddr, DP83848_IMR, &readval) >= 0)
> +  {
> +    readval &= ~Interrupt;
> +
> +    /* Apply configuration */
> +    if(pObj->IO.WriteReg(pObj->DevAddr, DP83848_IMR, readval) < 0)
> +    {
> +      status = DP83848_STATUS_WRITE_ERROR;
> +    }
> +  }
> +  else
> +  {
> +    status = DP83848_STATUS_READ_ERROR;
> +  }
> +
> +  return status;
> +}
> +
> +/**
> +  * @brief  Clear IT flag.
> +  * @param  pObj: Pointer to device object.
> +  * @param  Interrupt: IT flag to be cleared
> +  *         should be a value or a combination of the following:
> +  *         DP83848_WOL_IT
> +  *         DP83848_ENERGYON_IT
> +  *         DP83848_AUTONEGO_COMPLETE_IT
> +  *         DP83848_REMOTE_FAULT_IT
> +  *         DP83848_LINK_DOWN_IT
> +  *         DP83848_AUTONEGO_LP_ACK_IT
> +  *         DP83848_PARALLEL_DETECTION_FAULT_IT
> +  *         DP83848_AUTONEGO_PAGE_RECEIVED_IT
> +  * @retval DP83848_STATUS_OK  if OK
> +  *         DP83848_STATUS_READ_ERROR if connot read register
> +  */
> +int32_t  DP83848_ClearIT(dp83848_Object_t *pObj, uint32_t Interrupt)
> +{
> +  uint32_t readval = 0;
> +  int32_t status = DP83848_STATUS_OK;
> +
> +  if(pObj->IO.ReadReg(pObj->DevAddr, DP83848_ISFR, &readval) < 0)
> +  {
> +    status =  DP83848_STATUS_READ_ERROR;
> +  }
> +
> +  return status;
> +}
> +
> +/**
> +  * @brief  Get IT Flag status.
> +  * @param  pObj: Pointer to device object.
> +  * @param  Interrupt: IT Flag to be checked,
> +  *         should be a value or a combination of the following:
> +  *         DP83848_WOL_IT
> +  *         DP83848_ENERGYON_IT
> +  *         DP83848_AUTONEGO_COMPLETE_IT
> +  *         DP83848_REMOTE_FAULT_IT
> +  *         DP83848_LINK_DOWN_IT
> +  *         DP83848_AUTONEGO_LP_ACK_IT
> +  *         DP83848_PARALLEL_DETECTION_FAULT_IT
> +  *         DP83848_AUTONEGO_PAGE_RECEIVED_IT
> +  * @retval 1 IT flag is SET
> +  *         0 IT flag is RESET
> +  *         DP83848_STATUS_READ_ERROR if connot read register
> +  */
> +int32_t DP83848_GetITStatus(dp83848_Object_t *pObj, uint32_t Interrupt)
> +{
> +  uint32_t readval = 0;
> +  int32_t status = 0;
> +
> +  if(pObj->IO.ReadReg(pObj->DevAddr, DP83848_ISFR, &readval) >= 0)
> +  {
> +    status = ((readval & Interrupt) == Interrupt);
> +  }
> +  else
> +  {
> +    status = DP83848_STATUS_READ_ERROR;
> +  }
> +
> +  return status;
> +}
> +
> +/**
> +  * @}
> +  */
> +
> +/**
> +  * @}
> +  */
> +
> +/**
> +  * @}
> +  */
> +
> +/**
> +  * @}
> +  */
> +
> diff --git a/stm32/driver/dp83848.h b/stm32/driver/dp83848.h
> new file mode 100644
> index 0000000..d49496d
> --- /dev/null
> +++ b/stm32/driver/dp83848.h
> @@ -0,0 +1,436 @@
> +/**
> +  ******************************************************************************
> +  * @file    dp83848.h
> +  * @author  MCD Application Team
> +  * @brief   This file contains all the functions prototypes for the
> +  *          dp83848.c PHY driver.
> +  ******************************************************************************
> +  * @attention
> +  *
> +  * <h2><center>© Copyright (c) 2021 STMicroelectronics.
> +  * All rights reserved.</center></h2>
> +  *
> +  * This software component is licensed by ST under BSD 3-Clause license,
> +  * the "License"; You may not use this file except in compliance with the
> +  * License. You may obtain a copy of the License at:
> +  *                        opensource.org/licenses/BSD-3-Clause
> +  *
> +  ******************************************************************************
> +  */
> +
> +/* Define to prevent recursive inclusion -------------------------------------*/
> +#ifndef DP83848_H
> +#define DP83848_H
> +
> +#ifdef __cplusplus
> + extern "C" {
> +#endif
> +
> +/* Includes ------------------------------------------------------------------*/
> +#include <stdint.h>
> +
> +/** @addtogroup BSP
> +  * @{
> +  */
> +
> +/** @addtogroup Component
> +  * @{
> +  */
> +
> +/** @defgroup DP83848
> +  * @{
> +  */
> +/* Exported constants --------------------------------------------------------*/
> +/** @defgroup DP83848_Exported_Constants DP83848 Exported Constants
> +  * @{
> +  */
> +
> +/** @defgroup DP83848_Registers_Mapping DP83848 Registers Mapping
> +  * @{
> +  */
> +#define DP83848_BCR      ((uint16_t)0x0000U)
> +#define DP83848_BSR      ((uint16_t)0x0001U)
> +#define DP83848_PHYI1R   ((uint16_t)0x0002U)
> +#define DP83848_PHYI2R   ((uint16_t)0x0003U)
> +#define DP83848_ANAR     ((uint16_t)0x0004U)
> +#define DP83848_ANLPAR   ((uint16_t)0x0005U)
> +#define DP83848_ANER     ((uint16_t)0x0006U)
> +#define DP83848_ANNPTR   ((uint16_t)0x0007U)
> +#define DP83848_SMR      ((uint16_t)0x0019U)
> +#define DP83848_ISFR     ((uint16_t)0x0012U)
> +#define DP83848_IMR      ((uint16_t)0x0011U)
> +#define DP83848_PHYSCSR  ((uint16_t)0x0010U)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_BCR_Bit_Definition DP83848 BCR Bit Definition
> +  * @{
> +  */
> +#define DP83848_BCR_SOFT_RESET         ((uint16_t)0x8000U)
> +#define DP83848_BCR_LOOPBACK           ((uint16_t)0x4000U)
> +#define DP83848_BCR_SPEED_SELECT       ((uint16_t)0x2000U)
> +#define DP83848_BCR_AUTONEGO_EN        ((uint16_t)0x1000U)
> +#define DP83848_BCR_POWER_DOWN         ((uint16_t)0x0800U)
> +#define DP83848_BCR_ISOLATE            ((uint16_t)0x0400U)
> +#define DP83848_BCR_RESTART_AUTONEGO   ((uint16_t)0x0200U)
> +#define DP83848_BCR_DUPLEX_MODE        ((uint16_t)0x0100U)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_BSR_Bit_Definition DP83848 BSR Bit Definition
> +  * @{
> +  */
> +#define DP83848_BSR_100BASE_T4       ((uint16_t)0x8000U)
> +#define DP83848_BSR_100BASE_TX_FD    ((uint16_t)0x4000U)
> +#define DP83848_BSR_100BASE_TX_HD    ((uint16_t)0x2000U)
> +#define DP83848_BSR_10BASE_T_FD      ((uint16_t)0x1000U)
> +#define DP83848_BSR_10BASE_T_HD      ((uint16_t)0x0800U)
> +#define DP83848_BSR_MF_PREAMBLE      ((uint16_t)0x0040U)
> +#define DP83848_BSR_AUTONEGO_CPLT    ((uint16_t)0x0020U)
> +#define DP83848_BSR_REMOTE_FAULT     ((uint16_t)0x0010U)
> +#define DP83848_BSR_AUTONEGO_ABILITY ((uint16_t)0x0008U)
> +#define DP83848_BSR_LINK_STATUS      ((uint16_t)0x0004U)
> +#define DP83848_BSR_JABBER_DETECT    ((uint16_t)0x0002U)
> +#define DP83848_BSR_EXTENDED_CAP     ((uint16_t)0x0001U)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_PHYI1R_Bit_Definition DP83848 PHYI1R Bit Definition
> +  * @{
> +  */
> +#define DP83848_PHYI1R_OUI_3_18           ((uint16_t)0xFFFFU)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_PHYI2R_Bit_Definition DP83848 PHYI2R Bit Definition
> +  * @{
> +  */
> +#define DP83848_PHYI2R_OUI_19_24          ((uint16_t)0xFC00U)
> +#define DP83848_PHYI2R_MODEL_NBR          ((uint16_t)0x03F0U)
> +#define DP83848_PHYI2R_REVISION_NBR       ((uint16_t)0x000FU)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_ANAR_Bit_Definition DP83848 ANAR Bit Definition
> +  * @{
> +  */
> +#define DP83848_ANAR_NEXT_PAGE               ((uint16_t)0x8000U)
> +#define DP83848_ANAR_REMOTE_FAULT            ((uint16_t)0x2000U)
> +#define DP83848_ANAR_PAUSE_OPERATION         ((uint16_t)0x0C00U)
> +#define DP83848_ANAR_PO_NOPAUSE              ((uint16_t)0x0000U)
> +#define DP83848_ANAR_PO_SYMMETRIC_PAUSE      ((uint16_t)0x0400U)
> +#define DP83848_ANAR_PO_ASYMMETRIC_PAUSE     ((uint16_t)0x0800U)
> +#define DP83848_ANAR_PO_ADVERTISE_SUPPORT    ((uint16_t)0x0C00U)
> +#define DP83848_ANAR_100BASE_TX_FD           ((uint16_t)0x0100U)
> +#define DP83848_ANAR_100BASE_TX              ((uint16_t)0x0080U)
> +#define DP83848_ANAR_10BASE_T_FD             ((uint16_t)0x0040U)
> +#define DP83848_ANAR_10BASE_T                ((uint16_t)0x0020U)
> +#define DP83848_ANAR_SELECTOR_FIELD          ((uint16_t)0x000FU)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_ANLPAR_Bit_Definition DP83848 ANLPAR Bit Definition
> +  * @{
> +  */
> +#define DP83848_ANLPAR_NEXT_PAGE            ((uint16_t)0x8000U)
> +#define DP83848_ANLPAR_REMOTE_FAULT         ((uint16_t)0x2000U)
> +#define DP83848_ANLPAR_PAUSE_OPERATION      ((uint16_t)0x0C00U)
> +#define DP83848_ANLPAR_PO_NOPAUSE           ((uint16_t)0x0000U)
> +#define DP83848_ANLPAR_PO_SYMMETRIC_PAUSE   ((uint16_t)0x0400U)
> +#define DP83848_ANLPAR_PO_ASYMMETRIC_PAUSE  ((uint16_t)0x0800U)
> +#define DP83848_ANLPAR_PO_ADVERTISE_SUPPORT ((uint16_t)0x0C00U)
> +#define DP83848_ANLPAR_100BASE_TX_FD        ((uint16_t)0x0100U)
> +#define DP83848_ANLPAR_100BASE_TX           ((uint16_t)0x0080U)
> +#define DP83848_ANLPAR_10BASE_T_FD          ((uint16_t)0x0040U)
> +#define DP83848_ANLPAR_10BASE_T             ((uint16_t)0x0020U)
> +#define DP83848_ANLPAR_SELECTOR_FIELD       ((uint16_t)0x000FU)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_ANER_Bit_Definition DP83848 ANER Bit Definition
> +  * @{
> +  */
> +#define DP83848_ANER_RX_NP_LOCATION_ABLE    ((uint16_t)0x0040U)
> +#define DP83848_ANER_RX_NP_STORAGE_LOCATION ((uint16_t)0x0020U)
> +#define DP83848_ANER_PARALLEL_DETECT_FAULT  ((uint16_t)0x0010U)
> +#define DP83848_ANER_LP_NP_ABLE             ((uint16_t)0x0008U)
> +#define DP83848_ANER_NP_ABLE                ((uint16_t)0x0004U)
> +#define DP83848_ANER_PAGE_RECEIVED          ((uint16_t)0x0002U)
> +#define DP83848_ANER_LP_AUTONEG_ABLE        ((uint16_t)0x0001U)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_ANNPTR_Bit_Definition DP83848 ANNPTR Bit Definition
> +  * @{
> +  */
> +#define DP83848_ANNPTR_NEXT_PAGE         ((uint16_t)0x8000U)
> +#define DP83848_ANNPTR_MESSAGE_PAGE      ((uint16_t)0x2000U)
> +#define DP83848_ANNPTR_ACK2              ((uint16_t)0x1000U)
> +#define DP83848_ANNPTR_TOGGLE            ((uint16_t)0x0800U)
> +#define DP83848_ANNPTR_MESSAGE_CODE      ((uint16_t)0x07FFU)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_ANNPRR_Bit_Definition DP83848 ANNPRR Bit Definition
> +  * @{
> +  */
> +#define DP83848_ANNPRR_NEXT_PAGE         ((uint16_t)0x8000U)
> +#define DP83848_ANNPRR_ACK               ((uint16_t)0x4000U)
> +#define DP83848_ANNPRR_MESSAGE_PAGE      ((uint16_t)0x2000U)
> +#define DP83848_ANNPRR_ACK2              ((uint16_t)0x1000U)
> +#define DP83848_ANNPRR_TOGGLE            ((uint16_t)0x0800U)
> +#define DP83848_ANNPRR_MESSAGE_CODE      ((uint16_t)0x07FFU)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_MMDACR_Bit_Definition DP83848 MMDACR Bit Definition
> +  * @{
> +  */
> +#define DP83848_MMDACR_MMD_FUNCTION       ((uint16_t)0xC000U)
> +#define DP83848_MMDACR_MMD_FUNCTION_ADDR  ((uint16_t)0x0000U)
> +#define DP83848_MMDACR_MMD_FUNCTION_DATA  ((uint16_t)0x4000U)
> +#define DP83848_MMDACR_MMD_DEV_ADDR       ((uint16_t)0x001FU)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_ENCTR_Bit_Definition DP83848 ENCTR Bit Definition
> +  * @{
> +  */
> +#define DP83848_ENCTR_TX_ENABLE             ((uint16_t)0x8000U)
> +#define DP83848_ENCTR_TX_TIMER              ((uint16_t)0x6000U)
> +#define DP83848_ENCTR_TX_TIMER_1S           ((uint16_t)0x0000U)
> +#define DP83848_ENCTR_TX_TIMER_768MS        ((uint16_t)0x2000U)
> +#define DP83848_ENCTR_TX_TIMER_512MS        ((uint16_t)0x4000U)
> +#define DP83848_ENCTR_TX_TIMER_265MS        ((uint16_t)0x6000U)
> +#define DP83848_ENCTR_RX_ENABLE             ((uint16_t)0x1000U)
> +#define DP83848_ENCTR_RX_MAX_INTERVAL       ((uint16_t)0x0C00U)
> +#define DP83848_ENCTR_RX_MAX_INTERVAL_64MS  ((uint16_t)0x0000U)
> +#define DP83848_ENCTR_RX_MAX_INTERVAL_256MS ((uint16_t)0x0400U)
> +#define DP83848_ENCTR_RX_MAX_INTERVAL_512MS ((uint16_t)0x0800U)
> +#define DP83848_ENCTR_RX_MAX_INTERVAL_1S    ((uint16_t)0x0C00U)
> +#define DP83848_ENCTR_EX_CROSS_OVER         ((uint16_t)0x0002U)
> +#define DP83848_ENCTR_EX_MANUAL_CROSS_OVER  ((uint16_t)0x0001U)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_MCSR_Bit_Definition DP83848 MCSR Bit Definition
> +  * @{
> +  */
> +#define DP83848_MCSR_EDPWRDOWN        ((uint16_t)0x2000U)
> +#define DP83848_MCSR_FARLOOPBACK      ((uint16_t)0x0200U)
> +#define DP83848_MCSR_ALTINT           ((uint16_t)0x0040U)
> +#define DP83848_MCSR_ENERGYON         ((uint16_t)0x0002U)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_SMR_Bit_Definition DP83848 SMR Bit Definition
> +  * @{
> +  */
> +#define DP83848_SMR_MODE       ((uint16_t)0x00E0U)
> +#define DP83848_SMR_PHY_ADDR   ((uint16_t)0x001FU)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_TPDCR_Bit_Definition DP83848 TPDCR Bit Definition
> +  * @{
> +  */
> +#define DP83848_TPDCR_DELAY_IN                 ((uint16_t)0x8000U)
> +#define DP83848_TPDCR_LINE_BREAK_COUNTER       ((uint16_t)0x7000U)
> +#define DP83848_TPDCR_PATTERN_HIGH             ((uint16_t)0x0FC0U)
> +#define DP83848_TPDCR_PATTERN_LOW              ((uint16_t)0x003FU)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_TCSR_Bit_Definition DP83848 TCSR Bit Definition
> +  * @{
> +  */
> +#define DP83848_TCSR_TDR_ENABLE           ((uint16_t)0x8000U)
> +#define DP83848_TCSR_TDR_AD_FILTER_ENABLE ((uint16_t)0x4000U)
> +#define DP83848_TCSR_TDR_CH_CABLE_TYPE    ((uint16_t)0x0600U)
> +#define DP83848_TCSR_TDR_CH_CABLE_DEFAULT ((uint16_t)0x0000U)
> +#define DP83848_TCSR_TDR_CH_CABLE_SHORTED ((uint16_t)0x0200U)
> +#define DP83848_TCSR_TDR_CH_CABLE_OPEN    ((uint16_t)0x0400U)
> +#define DP83848_TCSR_TDR_CH_CABLE_MATCH   ((uint16_t)0x0600U)
> +#define DP83848_TCSR_TDR_CH_STATUS        ((uint16_t)0x0100U)
> +#define DP83848_TCSR_TDR_CH_LENGTH        ((uint16_t)0x00FFU)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_SCSIR_Bit_Definition DP83848 SCSIR Bit Definition
> +  * @{
> +  */
> +#define DP83848_SCSIR_AUTO_MDIX_ENABLE    ((uint16_t)0x8000U)
> +#define DP83848_SCSIR_CHANNEL_SELECT      ((uint16_t)0x2000U)
> +#define DP83848_SCSIR_SQE_DISABLE         ((uint16_t)0x0800U)
> +#define DP83848_SCSIR_XPOLALITY           ((uint16_t)0x0010U)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_CLR_Bit_Definition DP83848 CLR Bit Definition
> +  * @{
> +  */
> +#define DP83848_CLR_CABLE_LENGTH       ((uint16_t)0xF000U)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_IMR_ISFR_Bit_Definition DP83848 IMR ISFR Bit Definition
> +  * @{
> +  */
> +#define DP83848_INT_8       ((uint16_t)0x0100U)
> +#define DP83848_INT_7       ((uint16_t)0x0080U)
> +#define DP83848_INT_6       ((uint16_t)0x0040U)
> +#define DP83848_INT_5       ((uint16_t)0x0020U)
> +#define DP83848_INT_4       ((uint16_t)0x0010U)
> +#define DP83848_INT_3       ((uint16_t)0x0008U)
> +#define DP83848_INT_2       ((uint16_t)0x0004U)
> +#define DP83848_INT_1       ((uint16_t)0x0002U)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_PHYSCSR_Bit_Definition DP83848 PHYSCSR Bit Definition
> +  * @{
> +  */
> +#define DP83848_PHYSCSR_AUTONEGO_DONE   ((uint16_t)0x100U)
> +#define DP83848_PHYSCSR_HCDSPEEDMASK    ((uint16_t)0x006U)
> +#define DP83848_PHYSCSR_10BT_HD         ((uint16_t)0x002U)
> +#define DP83848_PHYSCSR_10BT_FD         ((uint16_t)0x006U)
> +#define DP83848_PHYSCSR_100BTX_HD       ((uint16_t)0x000U)
> +#define DP83848_PHYSCSR_100BTX_FD       ((uint16_t)0x004U)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_Status DP83848 Status
> +  * @{
> +  */
> +
> +#define  DP83848_STATUS_READ_ERROR            ((int32_t)-5)
> +#define  DP83848_STATUS_WRITE_ERROR           ((int32_t)-4)
> +#define  DP83848_STATUS_ADDRESS_ERROR         ((int32_t)-3)
> +#define  DP83848_STATUS_RESET_TIMEOUT         ((int32_t)-2)
> +#define  DP83848_STATUS_ERROR                 ((int32_t)-1)
> +#define  DP83848_STATUS_OK                    ((int32_t) 0)
> +#define  DP83848_STATUS_LINK_DOWN             ((int32_t) 1)
> +#define  DP83848_STATUS_100MBITS_FULLDUPLEX   ((int32_t) 2)
> +#define  DP83848_STATUS_100MBITS_HALFDUPLEX   ((int32_t) 3)
> +#define  DP83848_STATUS_10MBITS_FULLDUPLEX    ((int32_t) 4)
> +#define  DP83848_STATUS_10MBITS_HALFDUPLEX    ((int32_t) 5)
> +#define  DP83848_STATUS_AUTONEGO_NOTDONE      ((int32_t) 6)
> +/**
> +  * @}
> +  */
> +
> +/** @defgroup DP83848_IT_Flags DP83848 IT Flags
> +  * @{
> +  */
> +#define  DP83848_WOL_IT                        DP83848_INT_8
> +#define  DP83848_ENERGYON_IT                   DP83848_INT_7
> +#define  DP83848_AUTONEGO_COMPLETE_IT          DP83848_INT_6
> +#define  DP83848_REMOTE_FAULT_IT               DP83848_INT_5
> +#define  DP83848_LINK_DOWN_IT                  DP83848_INT_4
> +#define  DP83848_AUTONEGO_LP_ACK_IT            DP83848_INT_3
> +#define  DP83848_PARALLEL_DETECTION_FAULT_IT   DP83848_INT_2
> +#define  DP83848_AUTONEGO_PAGE_RECEIVED_IT     DP83848_INT_1
> +/**
> +  * @}
> +  */
> +
> +/**
> +  * @}
> +  */
> +
> +/* Exported types ------------------------------------------------------------*/
> +/** @defgroup DP83848_Exported_Types DP83848 Exported Types
> +  * @{
> +  */
> +typedef int32_t  (*dp83848_Init_Func) (void);
> +typedef int32_t  (*dp83848_DeInit_Func) (void);
> +typedef int32_t  (*dp83848_ReadReg_Func)   (uint32_t, uint32_t, uint32_t *);
> +typedef int32_t  (*dp83848_WriteReg_Func)  (uint32_t, uint32_t, uint32_t);
> +typedef int32_t  (*dp83848_GetTick_Func)  (void);
> +
> +typedef struct
> +{
> +  dp83848_Init_Func      Init;
> +  dp83848_DeInit_Func    DeInit;
> +  dp83848_WriteReg_Func  WriteReg;
> +  dp83848_ReadReg_Func   ReadReg;
> +  dp83848_GetTick_Func   GetTick;
> +} dp83848_IOCtx_t;
> +
> +
> +typedef struct
> +{
> +  uint32_t            DevAddr;
> +  uint32_t            Is_Initialized;
> +  dp83848_IOCtx_t     IO;
> +  void               *pData;
> +}dp83848_Object_t;
> +/**
> +  * @}
> +  */
> +
> +/* Exported macro ------------------------------------------------------------*/
> +/* Exported functions --------------------------------------------------------*/
> +/** @defgroup DP83848_Exported_Functions DP83848 Exported Functions
> +  * @{
> +  */
> +int32_t DP83848_RegisterBusIO(dp83848_Object_t *pObj, dp83848_IOCtx_t *ioctx);
> +int32_t DP83848_Init(dp83848_Object_t *pObj);
> +int32_t DP83848_DeInit(dp83848_Object_t *pObj);
> +int32_t DP83848_DisablePowerDownMode(dp83848_Object_t *pObj);
> +int32_t DP83848_EnablePowerDownMode(dp83848_Object_t *pObj);
> +int32_t DP83848_StartAutoNego(dp83848_Object_t *pObj);
> +int32_t DP83848_GetLinkState(dp83848_Object_t *pObj);
> +int32_t DP83848_SetLinkState(dp83848_Object_t *pObj, uint32_t LinkState);
> +int32_t DP83848_EnableLoopbackMode(dp83848_Object_t *pObj);
> +int32_t DP83848_DisableLoopbackMode(dp83848_Object_t *pObj);
> +int32_t DP83848_EnableIT(dp83848_Object_t *pObj, uint32_t Interrupt);
> +int32_t DP83848_DisableIT(dp83848_Object_t *pObj, uint32_t Interrupt);
> +int32_t DP83848_ClearIT(dp83848_Object_t *pObj, uint32_t Interrupt);
> +int32_t DP83848_GetITStatus(dp83848_Object_t *pObj, uint32_t Interrupt);
> +/**
> +  * @}
> +  */
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +#endif /* DP83848_H */
> +
> +
> +/**
> +  * @}
> +  */
> +
> +/**
> +  * @}
> +  */
> +
> +/**
> +  * @}
> +  */
> +
> +/**
> +  * @}
> +  */
> +
> diff --git a/stm32/ethernetif.c b/stm32/ethernetif.c
> new file mode 100644
> index 0000000..e54c8b6
> --- /dev/null
> +++ b/stm32/ethernetif.c
> @@ -0,0 +1,737 @@
> +/* USER CODE BEGIN Header */
> +/**
> +  ******************************************************************************
> +  * File Name          : ethernetif.c
> +  * Description        : This file provides code for the configuration
> +  *                      of the ethernetif.c MiddleWare.
> +  ******************************************************************************
> +  * @attention
> +  *
> +  * Copyright (c) 2022 STMicroelectronics.
> +  * All rights reserved.
> +  *
> +  * This software is licensed under terms that can be found in the LICENSE file
> +  * in the root directory of this software component.
> +  * If no LICENSE file comes with this software, it is provided AS-IS.
> +  *
> +  ******************************************************************************
> +  */
> +/* USER CODE END Header */
> +
> +/* Includes ------------------------------------------------------------------*/
> +#include "main.h"
> +#include "lwip/opt.h"
> +#include "lwip/mem.h"
> +#include "lwip/memp.h"
> +#include "lwip/timeouts.h"
> +#include "netif/ethernet.h"
> +#include "netif/etharp.h"
> +#include "lwip/ethip6.h"
> +#include "ethernetif.h"
> +#include "dp83848.h"
> +#include <string.h>
> +
> +/* Within 'USER CODE' section, code will be kept by default at each generation */
> +/* USER CODE BEGIN 0 */
> +
> +/* USER CODE END 0 */
> +
> +/* Private define ------------------------------------------------------------*/
> +
> +/* Network interface name */
> +#define IFNAME0 's'
> +#define IFNAME1 't'
> +
> +/* ETH Setting  */
> +#define ETH_DMA_TRANSMIT_TIMEOUT               ( 20U )
> +#define ETH_TX_BUFFER_MAX             ((ETH_TX_DESC_CNT) * 2U)
> +/* ETH_RX_BUFFER_SIZE parameter is defined in lwipopts.h */
> +
> +/* USER CODE BEGIN 1 */
> +
> +/* USER CODE END 1 */
> +
> +/* Private variables ---------------------------------------------------------*/
> +/*
> + at Note: This interface is implemented to operate in zero-copy mode only:
> +        - Rx buffers are allocated statically and passed directly to the LwIP stack
> +          they will return back to ETH DMA after been processed by the stack.
> +        - Tx Buffers will be allocated from LwIP stack memory heap,
> +          then passed to ETH HAL driver.
> +
> + at Notes:
> +  1.a. ETH DMA Rx descriptors must be contiguous, the default count is 4,
> +       to customize it please redefine ETH_RX_DESC_CNT in ETH GUI (Rx Descriptor Length)
> +       so that updated value will be generated in stm32xxxx_hal_conf.h
> +  1.b. ETH DMA Tx descriptors must be contiguous, the default count is 4,
> +       to customize it please redefine ETH_TX_DESC_CNT in ETH GUI (Tx Descriptor Length)
> +       so that updated value will be generated in stm32xxxx_hal_conf.h
> +
> +  2.a. Rx Buffers number must be between ETH_RX_DESC_CNT and 2*ETH_RX_DESC_CNT
> +  2.b. Rx Buffers must have the same size: ETH_RX_BUFFER_SIZE, this value must
> +       passed to ETH DMA in the init field (heth.Init.RxBuffLen)
> +  2.c  The RX Ruffers addresses and sizes must be properly defined to be aligned
> +       to L1-CACHE line size (32 bytes).
> +*/
> +
> +/* Data Type Definitions */
> +typedef enum
> +{
> +  RX_ALLOC_OK       = 0x00,
> +  RX_ALLOC_ERROR    = 0x01
> +} RxAllocStatusTypeDef;
> +
> +typedef struct
> +{
> +  struct pbuf_custom pbuf_custom;
> +  uint8_t buff[(ETH_RX_BUFFER_SIZE + 31) & ~31] __ALIGNED(32);
> +} RxBuff_t;
> +
> +/* Memory Pool Declaration */
> +#define ETH_RX_BUFFER_CNT             12U
> +LWIP_MEMPOOL_DECLARE(RX_POOL, ETH_RX_BUFFER_CNT, sizeof(RxBuff_t), "Zero-copy RX PBUF pool");
> +
> +/* Variable Definitions */
> +static uint8_t RxAllocStatus;
> +
> +__IO uint32_t TxPkt = 0;
> +__IO uint32_t RxPkt = 0;
> +
> +ETH_DMADescTypeDef  DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */
> +ETH_DMADescTypeDef  DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */
> +
> +/* USER CODE BEGIN 2 */
> +
> +/* USER CODE END 2 */
> +
> +/* Global Ethernet handle */
> +ETH_HandleTypeDef heth;
> +ETH_TxPacketConfig TxConfig;
> +
> +/* Private function prototypes -----------------------------------------------*/
> +int32_t ETH_PHY_IO_Init(void);
> +int32_t ETH_PHY_IO_DeInit (void);
> +int32_t ETH_PHY_IO_ReadReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal);
> +int32_t ETH_PHY_IO_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal);
> +int32_t ETH_PHY_IO_GetTick(void);
> +
> +dp83848_Object_t DP83848;
> +dp83848_IOCtx_t  DP83848_IOCtx = {ETH_PHY_IO_Init,
> +                                  ETH_PHY_IO_DeInit,
> +                                  ETH_PHY_IO_WriteReg,
> +                                  ETH_PHY_IO_ReadReg,
> +                                  ETH_PHY_IO_GetTick};
> +
> +/* USER CODE BEGIN 3 */
> +
> +/* USER CODE END 3 */
> +
> +/* Private functions ---------------------------------------------------------*/
> +void pbuf_free_custom(struct pbuf *p);
> +
> +/* USER CODE BEGIN 4 */
> +
> +/* USER CODE END 4 */
> +
> +/*******************************************************************************
> +                       LL Driver Interface ( LwIP stack --> ETH)
> +*******************************************************************************/
> +/**
> + * @brief In this function, the hardware should be initialized.
> + * Called from ethernetif_init().
> + *
> + * @param netif the already initialized lwip network interface structure
> + *        for this ethernetif
> + */
> +static void low_level_init(struct netif *netif)
> +{
> +  HAL_StatusTypeDef hal_eth_init_status = HAL_OK;
> +  /* Start ETH HAL Init */
> +
> +   uint8_t MACAddr[6] ;
> +  heth.Instance = ETH;
> +  MACAddr[0] = 0x02;
> +  MACAddr[1] = 0x00;
> +  MACAddr[2] = 0x00;
> +  MACAddr[3] = 0x00;
> +  MACAddr[4] = 0x00;
> +  MACAddr[5] = 0x01;
> +  heth.Init.MACAddr = &MACAddr[0];
> +  heth.Init.MediaInterface = HAL_ETH_RMII_MODE;
> +  heth.Init.TxDesc = DMATxDscrTab;
> +  heth.Init.RxDesc = DMARxDscrTab;
> +  heth.Init.RxBuffLen = 1536;
> +
> +  /* USER CODE BEGIN MACADDRESS */
> +
> +  /* USER CODE END MACADDRESS */
> +
> +  hal_eth_init_status = HAL_ETH_Init(&heth);
> +
> +  memset(&TxConfig, 0 , sizeof(ETH_TxPacketConfig));
> +  TxConfig.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD;
> +  TxConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
> +  TxConfig.CRCPadCtrl = ETH_CRC_PAD_INSERT;
> +
> +  /* End ETH HAL Init */
> +
> +  /* Initialize the RX POOL */
> +  LWIP_MEMPOOL_INIT(RX_POOL);
> +
> +#if LWIP_ARP || LWIP_ETHERNET
> +
> +  /* set MAC hardware address length */
> +  netif->hwaddr_len = ETH_HWADDR_LEN;
> +
> +  /* set MAC hardware address */
> +  netif->hwaddr[0] =  heth.Init.MACAddr[0];
> +  netif->hwaddr[1] =  heth.Init.MACAddr[1];
> +  netif->hwaddr[2] =  heth.Init.MACAddr[2];
> +  netif->hwaddr[3] =  heth.Init.MACAddr[3];
> +  netif->hwaddr[4] =  heth.Init.MACAddr[4];
> +  netif->hwaddr[5] =  heth.Init.MACAddr[5];
> +
> +  /* maximum transfer unit */
> +  netif->mtu = ETH_MAX_PAYLOAD;
> +
> +  /* Accept broadcast address and ARP traffic */
> +  /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
> +  #if LWIP_ARP
> +    netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
> +  #else
> +    netif->flags |= NETIF_FLAG_BROADCAST;
> +  #endif /* LWIP_ARP */
> +
> +/* USER CODE BEGIN PHY_PRE_CONFIG */
> +
> +/* USER CODE END PHY_PRE_CONFIG */
> +  /* Set PHY IO functions */
> +  DP83848_RegisterBusIO(&DP83848, &DP83848_IOCtx);
> +
> +  /* Initialize the DP83848 ETH PHY */
> +  DP83848_Init(&DP83848);
> +
> +  if (hal_eth_init_status == HAL_OK)
> +  {
> +  /* Get link state */
> +  ethernet_link_check_state(netif);
> +  }
> +  else
> +  {
> +    Error_Handler();
> +  }
> +#endif /* LWIP_ARP || LWIP_ETHERNET */
> +
> +/* USER CODE BEGIN LOW_LEVEL_INIT */
> +
> +/* USER CODE END LOW_LEVEL_INIT */
> +}
> +
> +/**
> + * This function should do the actual transmission of the packet. The packet is
> + * contained in the pbuf that is passed to the function. This pbuf
> + * might be chained.
> + *
> + * @param netif the lwip network interface structure for this ethernetif
> + * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
> + * @return ERR_OK if the packet could be sent
> + *         an err_t value if the packet couldn't be sent
> + *
> + * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
> + *       strange results. You might consider waiting for space in the DMA queue
> + *       to become available since the stack doesn't retry to send a packet
> + *       dropped because of memory failure (except for the TCP timers).
> + */
> +
> +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];
> +
> +  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;
> +
> +  HAL_ETH_Transmit(&heth, &TxConfig, ETH_DMA_TRANSMIT_TIMEOUT);
> +
> +  return errval;
> +}
> +
> +/**
> + * Should allocate a pbuf and transfer the bytes of the incoming
> + * packet from the interface into the pbuf.
> + *
> + * @param netif the lwip network interface structure for this ethernetif
> + * @return a pbuf filled with the received packet (including MAC header)
> + *         NULL on memory error
> +   */
> +static struct pbuf * low_level_input(struct netif *netif)
> +{
> +  struct pbuf *p = NULL;
> +
> +  if(RxAllocStatus == RX_ALLOC_OK)
> +  {
> +    HAL_ETH_ReadData(&heth, (void **)&p);
> +  }
> +
> +  return p;
> +}
> +
> +/**
> + * This function should be called when a packet is ready to be read
> + * from the interface. It uses the function low_level_input() that
> + * should handle the actual reception of bytes from the network
> + * interface. Then the type of the received packet is determined and
> + * the appropriate input function is called.
> + *
> + * @param netif the lwip network interface structure for this ethernetif
> + */
> +void ethernetif_input(struct netif *netif)
> +{
> +  struct pbuf *p = NULL;
> +
> +  do
> +  {
> +    p = low_level_input( netif );
> +    if (p != NULL)
> +    {
> +      if (netif->input( p, netif) != ERR_OK )
> +      {
> +        pbuf_free(p);
> +      }
> +    }
> +  } while(p!=NULL);
> +}
> +
> +#if !LWIP_ARP
> +/**
> + * This function has to be completed by user in case of ARP OFF.
> + *
> + * @param netif the lwip network interface structure for this ethernetif
> + * @return ERR_OK if ...
> + */
> +static err_t low_level_output_arp_off(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
> +{
> +  err_t errval;
> +  errval = ERR_OK;
> +
> +/* USER CODE BEGIN 5 */
> +
> +/* USER CODE END 5 */
> +
> +  return errval;
> +
> +}
> +#endif /* LWIP_ARP */
> +
> +/**
> + * Should be called at the beginning of the program to set up the
> + * network interface. It calls the function low_level_init() to do the
> + * actual setup of the hardware.
> + *
> + * This function should be passed as a parameter to netif_add().
> + *
> + * @param netif the lwip network interface structure for this ethernetif
> + * @return ERR_OK if the loopif is initialized
> + *         ERR_MEM if private data couldn't be allocated
> + *         any other err_t on error
> + */
> +err_t ethernetif_init(struct netif *netif)
> +{
> +  LWIP_ASSERT("netif != NULL", (netif != NULL));
> +
> +#if LWIP_NETIF_HOSTNAME
> +  /* Initialize interface hostname */
> +  netif->hostname = "lwip";
> +#endif /* LWIP_NETIF_HOSTNAME */
> +
> +  /*
> +   * Initialize the snmp variables and counters inside the struct netif.
> +   * The last argument should be replaced with your link speed, in units
> +   * of bits per second.
> +   */
> +  // MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
> +
> +  netif->name[0] = IFNAME0;
> +  netif->name[1] = IFNAME1;
> +  /* We directly use etharp_output() here to save a function call.
> +   * You can instead declare your own function an call etharp_output()
> +   * from it if you have to do some checks before sending (e.g. if link
> +   * is available...) */
> +
> +#if LWIP_IPV4
> +#if LWIP_ARP || LWIP_ETHERNET
> +#if LWIP_ARP
> +  netif->output = etharp_output;
> +#else
> +  /* The user should write its own code in low_level_output_arp_off function */
> +  netif->output = low_level_output_arp_off;
> +#endif /* LWIP_ARP */
> +#endif /* LWIP_ARP || LWIP_ETHERNET */
> +#endif /* LWIP_IPV4 */
> +
> +#if LWIP_IPV6
> +  netif->output_ip6 = ethip6_output;
> +#endif /* LWIP_IPV6 */
> +
> +  netif->linkoutput = low_level_output;
> +
> +  /* initialize the hardware */
> +  low_level_init(netif);
> +
> +  return ERR_OK;
> +}
> +
> +/**
> +  * @brief  Custom Rx pbuf free callback
> +  * @param  pbuf: pbuf to be freed
> +  * @retval None
> +  */
> +void pbuf_free_custom(struct pbuf *p)
> +{
> +  struct pbuf_custom* custom_pbuf = (struct pbuf_custom*)p;
> +  LWIP_MEMPOOL_FREE(RX_POOL, custom_pbuf);
> +
> +  /* If the Rx Buffer Pool was exhausted, signal the ethernetif_input task to
> +   * call HAL_ETH_GetRxDataBuffer to rebuild the Rx descriptors. */
> +
> +  if (RxAllocStatus == RX_ALLOC_ERROR)
> +  {
> +    RxAllocStatus = RX_ALLOC_OK;
> +    RxPkt = 1 ;
> +  }
> +}
> +
> +/* USER CODE BEGIN 6 */
> +
> +/**
> +* @brief  Returns the current time in milliseconds
> +*         when LWIP_TIMERS == 1 and NO_SYS == 1
> +* @param  None
> +* @retval Current Time value
> +*/
> +u32_t sys_now(void)
> +{
> +  return HAL_GetTick();
> +}
> +
> +/* USER CODE END 6 */
> +
> +void HAL_ETH_MspInit(ETH_HandleTypeDef* ethHandle)
> +{
> +  GPIO_InitTypeDef GPIO_InitStruct = {0};
> +  if(ethHandle->Instance==ETH)
> +  {
> +  /* USER CODE BEGIN ETH_MspInit 0 */
> +
> +  /* USER CODE END ETH_MspInit 0 */
> +    /* Enable Peripheral clock */
> +    __HAL_RCC_ETH_CLK_ENABLE();
> +
> +    __HAL_RCC_GPIOC_CLK_ENABLE();
> +    __HAL_RCC_GPIOA_CLK_ENABLE();
> +    __HAL_RCC_GPIOB_CLK_ENABLE();
> +    /**ETH GPIO Configuration
> +    PC1     ------> ETH_MDC
> +    PA1     ------> ETH_REF_CLK
> +    PA2     ------> ETH_MDIO
> +    PA7     ------> ETH_CRS_DV
> +    PC4     ------> ETH_RXD0
> +    PC5     ------> ETH_RXD1
> +    PB11     ------> ETH_TX_EN
> +    PB12     ------> ETH_TXD0
> +    PB13     ------> ETH_TXD1
> +    */
> +    GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5;
> +    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
> +    GPIO_InitStruct.Pull = GPIO_NOPULL;
> +    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
> +    GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
> +    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
> +
> +    GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_7;
> +    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
> +    GPIO_InitStruct.Pull = GPIO_NOPULL;
> +    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
> +    GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
> +    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
> +
> +    GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13;
> +    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
> +    GPIO_InitStruct.Pull = GPIO_NOPULL;
> +    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
> +    GPIO_InitStruct.Alternate = GPIO_AF11_ETH;
> +    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
> +
> +  /* USER CODE BEGIN ETH_MspInit 1 */
> +
> +  /* USER CODE END ETH_MspInit 1 */
> +  }
> +}
> +
> +void HAL_ETH_MspDeInit(ETH_HandleTypeDef* ethHandle)
> +{
> +  if(ethHandle->Instance==ETH)
> +  {
> +  /* USER CODE BEGIN ETH_MspDeInit 0 */
> +
> +  /* USER CODE END ETH_MspDeInit 0 */
> +    /* Peripheral clock disable */
> +    __HAL_RCC_ETH_CLK_DISABLE();
> +
> +    /**ETH GPIO Configuration
> +    PC1     ------> ETH_MDC
> +    PA1     ------> ETH_REF_CLK
> +    PA2     ------> ETH_MDIO
> +    PA7     ------> ETH_CRS_DV
> +    PC4     ------> ETH_RXD0
> +    PC5     ------> ETH_RXD1
> +    PB11     ------> ETH_TX_EN
> +    PB12     ------> ETH_TXD0
> +    PB13     ------> ETH_TXD1
> +    */
> +    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5);
> +
> +    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_7);
> +
> +    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13);
> +
> +  /* USER CODE BEGIN ETH_MspDeInit 1 */
> +
> +  /* USER CODE END ETH_MspDeInit 1 */
> +  }
> +}
> +
> +/*******************************************************************************
> +                       PHI IO Functions
> +*******************************************************************************/
> +/**
> +  * @brief  Initializes the MDIO interface GPIO and clocks.
> +  * @param  None
> +  * @retval 0 if OK, -1 if ERROR
> +  */
> +int32_t ETH_PHY_IO_Init(void)
> +{
> +  /* We assume that MDIO GPIO configuration is already done
> +     in the ETH_MspInit() else it should be done here
> +  */
> +
> +  /* Configure the MDIO Clock */
> +  HAL_ETH_SetMDIOClockRange(&heth);
> +
> +  return 0;
> +}
> +
> +/**
> +  * @brief  De-Initializes the MDIO interface .
> +  * @param  None
> +  * @retval 0 if OK, -1 if ERROR
> +  */
> +int32_t ETH_PHY_IO_DeInit (void)
> +{
> +  return 0;
> +}
> +
> +/**
> +  * @brief  Read a PHY register through the MDIO interface.
> +  * @param  DevAddr: PHY port address
> +  * @param  RegAddr: PHY register address
> +  * @param  pRegVal: pointer to hold the register value
> +  * @retval 0 if OK -1 if Error
> +  */
> +int32_t ETH_PHY_IO_ReadReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t *pRegVal)
> +{
> +  if(HAL_ETH_ReadPHYRegister(&heth, DevAddr, RegAddr, pRegVal) != HAL_OK)
> +  {
> +    return -1;
> +  }
> +
> +  return 0;
> +}
> +
> +/**
> +  * @brief  Write a value to a PHY register through the MDIO interface.
> +  * @param  DevAddr: PHY port address
> +  * @param  RegAddr: PHY register address
> +  * @param  RegVal: Value to be written
> +  * @retval 0 if OK -1 if Error
> +  */
> +int32_t ETH_PHY_IO_WriteReg(uint32_t DevAddr, uint32_t RegAddr, uint32_t RegVal)
> +{
> +  if(HAL_ETH_WritePHYRegister(&heth, DevAddr, RegAddr, RegVal) != HAL_OK)
> +  {
> +    return -1;
> +  }
> +
> +  return 0;
> +}
> +
> +/**
> +  * @brief  Get the time in millisecons used for internal PHY driver process.
> +  * @retval Time value
> +  */
> +int32_t ETH_PHY_IO_GetTick(void)
> +{
> +  return HAL_GetTick();
> +}
> +
> +/**
> +  * @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 = {0};
> +  int32_t PHYLinkState = 0;
> +  uint32_t linkchanged = 0U, speed = 0U, duplex = 0U;
> +
> +  PHYLinkState = DP83848_GetLinkState(&DP83848);
> +
> +  if(netif_is_link_up(netif) && (PHYLinkState <= DP83848_STATUS_LINK_DOWN))
> +  {
> +    HAL_ETH_Stop(&heth);
> +    netif_set_down(netif);
> +    netif_set_link_down(netif);
> +  }
> +  else if(!netif_is_link_up(netif) && (PHYLinkState > DP83848_STATUS_LINK_DOWN))
> +  {
> +    switch (PHYLinkState)
> +    {
> +    case DP83848_STATUS_100MBITS_FULLDUPLEX:
> +      duplex = ETH_FULLDUPLEX_MODE;
> +      speed = ETH_SPEED_100M;
> +      linkchanged = 1;
> +      break;
> +    case DP83848_STATUS_100MBITS_HALFDUPLEX:
> +      duplex = ETH_HALFDUPLEX_MODE;
> +      speed = ETH_SPEED_100M;
> +      linkchanged = 1;
> +      break;
> +    case DP83848_STATUS_10MBITS_FULLDUPLEX:
> +      duplex = ETH_FULLDUPLEX_MODE;
> +      speed = ETH_SPEED_10M;
> +      linkchanged = 1;
> +      break;
> +    case DP83848_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);
> +    }
> +  }
> +
> +}
> +
> +void HAL_ETH_RxAllocateCallback(uint8_t **buff)
> +{
> +/* USER CODE BEGIN HAL ETH RxAllocateCallback */
> +
> +  struct pbuf_custom *p = LWIP_MEMPOOL_ALLOC(RX_POOL);
> +  if (p)
> +  {
> +    /* Get the buff from the struct pbuf address. */
> +    *buff = (uint8_t *)p + offsetof(RxBuff_t, buff);
> +    p->custom_free_function = pbuf_free_custom;
> +    /* Initialize the struct pbuf.
> +    * This must be performed whenever a buffer's allocated because it may be
> +    * changed by lwIP or the app, e.g., pbuf_free decrements ref. */
> +    pbuf_alloced_custom(PBUF_RAW, 0, PBUF_REF, p, *buff, ETH_RX_BUFFER_SIZE);
> +  }
> +  else
> +  {
> +    RxAllocStatus = RX_ALLOC_ERROR;
> +    *buff = NULL;
> +  }
> +/* USER CODE END HAL ETH RxAllocateCallback */
> +}
> +
> +void HAL_ETH_RxLinkCallback(void **pStart, void **pEnd, uint8_t *buff, uint16_t Length)
> +{
> +/* USER CODE BEGIN HAL ETH RxLinkCallback */
> +
> +  struct pbuf **ppStart = (struct pbuf **)pStart;
> +  struct pbuf **ppEnd = (struct pbuf **)pEnd;
> +  struct pbuf *p = NULL;
> +
> +  /* Get the struct pbuf from the buff address. */
> +  p = (struct pbuf *)(buff - offsetof(RxBuff_t, buff));
> +  p->next = NULL;
> +  p->tot_len = 0;
> +  p->len = Length;
> +
> +  /* Chain the buffer. */
> +  if (!*ppStart)
> +  {
> +    /* The first buffer of the packet. */
> +    *ppStart = p;
> +  }
> +  else
> +  {
> +    /* Chain the buffer to the end of the packet. */
> +    (*ppEnd)->next = p;
> +  }
> +  *ppEnd  = p;
> +
> +  /* Update the total length of all the buffers of the chain. Each pbuf in the chain should have its tot_len
> +   * set to its own length, plus the length of all the following pbufs in the chain. */
> +  for (p = *ppStart; p != NULL; p = p->next)
> +  {
> +    p->tot_len += Length;
> +  }
> +
> +/* USER CODE END HAL ETH RxLinkCallback */
> +}
> +
> +void HAL_ETH_TxFreeCallback(uint32_t * buff)
> +{
> +/* USER CODE BEGIN HAL ETH TxFreeCallback */
> +
> +  pbuf_free((struct pbuf *)buff);
> +
> +/* USER CODE END HAL ETH TxFreeCallback */
> +}
> +
> +/* USER CODE BEGIN 8 */
> +
> +/* USER CODE END 8 */
> +
> diff --git a/stm32/ethernetif.h b/stm32/ethernetif.h
> new file mode 100644
> index 0000000..76eb91b
> --- /dev/null
> +++ b/stm32/ethernetif.h
> @@ -0,0 +1,45 @@
> +/* USER CODE BEGIN Header */
> +/**
> + ******************************************************************************
> +  * File Name          : ethernetif.h
> +  * Description        : This file provides initialization code for LWIP
> +  *                      middleWare.
> +  ******************************************************************************
> +  * @attention
> +  *
> +  * Copyright (c) 2022 STMicroelectronics.
> +  * All rights reserved.
> +  *
> +  * This software is licensed under terms that can be found in the LICENSE file
> +  * in the root directory of this software component.
> +  * If no LICENSE file comes with this software, it is provided AS-IS.
> +  *
> +  ******************************************************************************
> +  */
> +/* USER CODE END Header */
> +
> +#ifndef __ETHERNETIF_H__
> +#define __ETHERNETIF_H__
> +
> +#include "lwip/err.h"
> +#include "lwip/netif.h"
> +
> +/* Within 'USER CODE' section, code will be kept by default at each generation */
> +/* USER CODE BEGIN 0 */
> +
> +/* USER CODE END 0 */
> +
> +/* Exported functions ------------------------------------------------------- */
> +err_t ethernetif_init(struct netif *netif);
> +
> +void ethernetif_input(struct netif *netif);
> +void ethernet_link_check_state(struct netif *netif);
> +
> +void Error_Handler(void);
> +u32_t sys_jiffies(void);
> +u32_t sys_now(void);
> +
> +/* USER CODE BEGIN 1 */
> +
> +/* USER CODE END 1 */
> +#endif
> diff --git a/stm32/lwip.c b/stm32/lwip.c
> new file mode 100644
> index 0000000..9b2af8a
> --- /dev/null
> +++ b/stm32/lwip.c
> @@ -0,0 +1,260 @@
> +/* USER CODE BEGIN Header */
> +/**
> + ******************************************************************************
> +  * File Name          : LWIP.c
> +  * Description        : This file provides initialization code for LWIP
> +  *                      middleWare.
> +  ******************************************************************************
> +  * @attention
> +  *
> +  * Copyright (c) 2022 STMicroelectronics.
> +  * All rights reserved.
> +  *
> +  * This software is licensed under terms that can be found in the LICENSE file
> +  * in the root directory of this software component.
> +  * If no LICENSE file comes with this software, it is provided AS-IS.
> +  *
> +  ******************************************************************************
> +  */
> +/* USER CODE END Header */
> +
> +/* Includes ------------------------------------------------------------------*/
> +#include "lwip.h"
> +#include "lwip/init.h"
> +#include "lwip/netif.h"
> +#if defined ( __CC_ARM )  /* MDK ARM Compiler */
> +#include "lwip/sio.h"
> +#endif /* MDK ARM Compiler */
> +#include "ethernetif.h"
> +
> +/* USER CODE BEGIN 0 */
> +
> +/* USER CODE END 0 */
> +/* Private function prototypes -----------------------------------------------*/
> +static void ethernet_link_status_updated(struct netif *netif);
> +static void Ethernet_Link_Periodic_Handle(struct netif *netif);
> +/* ETH Variables initialization ----------------------------------------------*/
> +void Error_Handler(void);
> +
> +/* USER CODE BEGIN 1 */
> +
> +/* USER CODE END 1 */
> +uint32_t EthernetLinkTimer;
> +
> +/* Variables Initialization */
> +struct netif gnetif;
> +ip4_addr_t ipaddr;
> +ip4_addr_t netmask;
> +ip4_addr_t gw;
> +uint8_t IP_ADDRESS[4];
> +uint8_t NETMASK_ADDRESS[4];
> +uint8_t GATEWAY_ADDRESS[4];
> +
> +/* USER CODE BEGIN 2 */
> +
> +/* USER CODE END 2 */
> +
> +/**
> +  * LwIP initialization function
> +  */
> +void MX_LWIP_Init(void)
> +{
> +  /* IP addresses initialization */
> +  IP_ADDRESS[0] = 192;
> +  IP_ADDRESS[1] = 168;
> +  IP_ADDRESS[2] = 68;
> +  IP_ADDRESS[3] = 22;
> +  NETMASK_ADDRESS[0] = 255;
> +  NETMASK_ADDRESS[1] = 255;
> +  NETMASK_ADDRESS[2] = 255;
> +  NETMASK_ADDRESS[3] = 0;
> +  GATEWAY_ADDRESS[0] = 192;
> +  GATEWAY_ADDRESS[1] = 168;
> +  GATEWAY_ADDRESS[2] = 68;
> +  GATEWAY_ADDRESS[3] = 1;
> +
> +/* USER CODE BEGIN IP_ADDRESSES */
> +/* USER CODE END IP_ADDRESSES */
> +
> +  /* Initilialize the LwIP stack without RTOS */
> +  lwip_init();
> +
> +  /* IP addresses initialization without DHCP (IPv4) */
> +  IP4_ADDR(&ipaddr, IP_ADDRESS[0], IP_ADDRESS[1], IP_ADDRESS[2], IP_ADDRESS[3]);
> +  IP4_ADDR(&netmask, NETMASK_ADDRESS[0], NETMASK_ADDRESS[1] , NETMASK_ADDRESS[2], NETMASK_ADDRESS[3]);
> +  IP4_ADDR(&gw, GATEWAY_ADDRESS[0], GATEWAY_ADDRESS[1], GATEWAY_ADDRESS[2], GATEWAY_ADDRESS[3]);
> +
> +  /* add the network interface (IPv4/IPv6) without RTOS */
> +  netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, &ethernetif_init, &ethernet_input);
> +
> +  /* Registers the default network interface */
> +  netif_set_default(&gnetif);
> +
> +  if (netif_is_link_up(&gnetif))
> +  {
> +    /* When the netif is fully configured this function must be called */
> +    netif_set_up(&gnetif);
> +  }
> +  else
> +  {
> +    /* When the netif link is down this function must be called */
> +    netif_set_down(&gnetif);
> +  }
> +
> +  /* Set the link callback function, this function is called on change of link status*/
> +  netif_set_link_callback(&gnetif, ethernet_link_status_updated);
> +
> +  /* Create the Ethernet link handler thread */
> +
> +/* USER CODE BEGIN 3 */
> +
> +/* USER CODE END 3 */
> +}
> +
> +#ifdef USE_OBSOLETE_USER_CODE_SECTION_4
> +/* Kept to help code migration. (See new 4_1, 4_2... sections) */
> +/* Avoid to use this user section which will become obsolete. */
> +/* USER CODE BEGIN 4 */
> +/* USER CODE END 4 */
> +#endif
> +
> +/**
> +  * @brief  Ethernet Link periodic check
> +  * @param  netif
> +  * @retval None
> +  */
> +static void Ethernet_Link_Periodic_Handle(struct netif *netif)
> +{
> +/* USER CODE BEGIN 4_4_1 */
> +/* USER CODE END 4_4_1 */
> +
> +  /* Ethernet Link every 100ms */
> +  if (HAL_GetTick() - EthernetLinkTimer >= 100)
> +  {
> +    EthernetLinkTimer = HAL_GetTick();
> +    ethernet_link_check_state(netif);
> +  }
> +/* USER CODE BEGIN 4_4 */
> +/* USER CODE END 4_4 */
> +}
> +
> +/**
> + * ----------------------------------------------------------------------
> + * Function given to help user to continue LwIP Initialization
> + * Up to user to complete or change this function ...
> + * Up to user to call this function in main.c in while (1) of main(void)
> + *-----------------------------------------------------------------------
> + * Read a received packet from the Ethernet buffers
> + * Send it to the lwIP stack for handling
> + * Handle timeouts if LWIP_TIMERS is set and without RTOS
> + * Handle the llink status if LWIP_NETIF_LINK_CALLBACK is set and without RTOS
> + */
> +void MX_LWIP_Process(void)
> +{
> +/* USER CODE BEGIN 4_1 */
> +/* USER CODE END 4_1 */
> +  ethernetif_input(&gnetif);
> +
> +/* USER CODE BEGIN 4_2 */
> +/* USER CODE END 4_2 */
> +  /* Handle timeouts */
> +  sys_check_timeouts();
> +
> +  Ethernet_Link_Periodic_Handle(&gnetif);
> +
> +/* USER CODE BEGIN 4_3 */
> +/* USER CODE END 4_3 */
> +}
> +
> +/**
> +  * @brief  Notify the User about the network interface config status
> +  * @param  netif: the network interface
> +  * @retval None
> +  */
> +static void ethernet_link_status_updated(struct netif *netif)
> +{
> +  if (netif_is_up(netif))
> +  {
> +/* USER CODE BEGIN 5 */
> +/* USER CODE END 5 */
> +  }
> +  else /* netif is down */
> +  {
> +/* USER CODE BEGIN 6 */
> +/* USER CODE END 6 */
> +  }
> +}
> +
> +#if defined ( __CC_ARM )  /* MDK ARM Compiler */
> +/**
> + * Opens a serial device for communication.
> + *
> + * @param devnum device number
> + * @return handle to serial device if successful, NULL otherwise
> + */
> +sio_fd_t sio_open(u8_t devnum)
> +{
> +  sio_fd_t sd;
> +
> +/* USER CODE BEGIN 7 */
> +  sd = 0; // dummy code
> +/* USER CODE END 7 */
> +
> +  return sd;
> +}
> +
> +/**
> + * Sends a single character to the serial device.
> + *
> + * @param c character to send
> + * @param fd serial device handle
> + *
> + * @note This function will block until the character can be sent.
> + */
> +void sio_send(u8_t c, sio_fd_t fd)
> +{
> +/* USER CODE BEGIN 8 */
> +/* USER CODE END 8 */
> +}
> +
> +/**
> + * Reads from the serial device.
> + *
> + * @param fd serial device handle
> + * @param data pointer to data buffer for receiving
> + * @param len maximum length (in bytes) of data to receive
> + * @return number of bytes actually received - may be 0 if aborted by sio_read_abort
> + *
> + * @note This function will block until data can be received. The blocking
> + * can be cancelled by calling sio_read_abort().
> + */
> +u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len)
> +{
> +  u32_t recved_bytes;
> +
> +/* USER CODE BEGIN 9 */
> +  recved_bytes = 0; // dummy code
> +/* USER CODE END 9 */
> +  return recved_bytes;
> +}
> +
> +/**
> + * Tries to read from the serial device. Same as sio_read but returns
> + * immediately if no data is available and never blocks.
> + *
> + * @param fd serial device handle
> + * @param data pointer to data buffer for receiving
> + * @param len maximum length (in bytes) of data to receive
> + * @return number of bytes actually received
> + */
> +u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len)
> +{
> +  u32_t recved_bytes;
> +
> +/* USER CODE BEGIN 10 */
> +  recved_bytes = 0; // dummy code
> +/* USER CODE END 10 */
> +  return recved_bytes;
> +}
> +#endif /* MDK ARM Compiler */
> +
> diff --git a/stm32/lwip.h b/stm32/lwip.h
> new file mode 100644
> index 0000000..02df90e
> --- /dev/null
> +++ b/stm32/lwip.h
> @@ -0,0 +1,76 @@
> +/* USER CODE BEGIN Header */
> +/**
> +  ******************************************************************************
> +  * File Name          : LWIP.h
> +  * Description        : This file provides code for the configuration
> +  *                      of the LWIP.
> +  ******************************************************************************
> +  * @attention
> +  *
> +  * Copyright (c) 2022 STMicroelectronics.
> +  * All rights reserved.
> +  *
> +  * This software is licensed under terms that can be found in the LICENSE file
> +  * in the root directory of this software component.
> +  * If no LICENSE file comes with this software, it is provided AS-IS.
> +  *
> +  *************************************************************************
> +
> +  */
> +/* USER CODE END Header */
> +/* Define to prevent recursive inclusion -------------------------------------*/
> +#ifndef __mx_lwip_H
> +#define __mx_lwip_H
> +#ifdef __cplusplus
> + extern "C" {
> +#endif
> +
> +/* Includes ------------------------------------------------------------------*/
> +#include "lwip/opt.h"
> +#include "lwip/mem.h"
> +#include "lwip/memp.h"
> +#include "netif/etharp.h"
> +#include "lwip/dhcp.h"
> +#include "lwip/netif.h"
> +#include "lwip/timeouts.h"
> +#include "ethernetif.h"
> +
> +/* Includes for RTOS ---------------------------------------------------------*/
> +#if WITH_RTOS
> +#include "lwip/tcpip.h"
> +#endif /* WITH_RTOS */
> +
> +/* USER CODE BEGIN 0 */
> +
> +/* USER CODE END 0 */
> +
> +/* Global Variables ----------------------------------------------------------*/
> +extern ETH_HandleTypeDef heth;
> +
> +/* LWIP init function */
> +void MX_LWIP_Init(void);
> +
> +#if !WITH_RTOS
> +/* USER CODE BEGIN 1 */
> +/* Function defined in lwip.c to:
> + *   - Read a received packet from the Ethernet buffers
> + *   - Send it to the lwIP stack for handling
> + *   - Handle timeouts if NO_SYS_NO_TIMERS not set
> + */
> +void MX_LWIP_Process(void);
> +
> +/* USER CODE END 1 */
> +#endif /* WITH_RTOS */
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +#endif /*__ mx_lwip_H */
> +
> +/**
> +  * @}
> +  */
> +
> +/**
> +  * @}
> +  */


More information about the devel mailing list