cancel
Showing results for 
Search instead for 
Did you mean: 

How to Configure a Custom PHY Address inSTM32cube IDE 1.14.1?

priyazcs
Associate II

I'm using an STM32F427 and no RTOS, along with a custom PHY. However, I’ve encountered issues configuring a custom PHY address in STM32CubeIDE 1.14.1:

  1. Custom PHY Address Setup
    My setup requires a specific PHY address, such as 0x80, but STM32CubeIDE 1.14.1 only lists options for LAN8742 and DP83848. Selecting "Undefined PHY" triggers a warning, which limits proper configuration. In STM32CubeIDE 1.8.0, I was able to configure a custom PHY without any issues.

Could you please provide guidance on how to set up and configure a custom PHY in version 1.14.1? Any information on handling this in the latest versions to avoid warnings and allow for custom PHY addresses would be greatly appreciated.

Thank you.

4 REPLIES 4
SofLit
ST Employee

Hello,

It's basically STM32CubeMx question and not STM32CubeIDE. The thread will be moved to STM32CubeMx forum board.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
priyazcs
Associate II

Hi,

I'm using an STM32F427 and no RTOS, along with a custom PHY. However, I’ve encountered issues configuring a custom PHY address in STM32CubeIDE 1.14.1: Custom PHY Address Setup My setup requires a specific PHY address, such as 0x80, but STM32CubeIDE 1.14.1 only lists options for LAN8742 and DP83848. Selecting "Undefined PHY" triggers a warning, which limits proper configuration. In STM32CubeIDE 1.8.0, I was able to configure a custom PHY without any issues. Could you please provide guidance on how to set up and configure a custom PHY in version 1.14.1? Any information on handling this in the latest versions to avoid warnings and allow for custom PHY addresses would be greatly appreciated.

Thank you.

Hello @priyazcs 

First let me thank you for posting.

Steps to Configure a Custom PHY in STM32CubeIDE 1.14.1

Select Undefined PHY 

In the STM32CubeIDE, when configuring the Ethernet settings, select "Undefined PHY". This will allow you to bypass the default options for LAN8742 and DP83848.GhofraneGSOURI_0-1730724710228.png

 

Modify the Generated Code

  • After generating the project code, navigate to the ethernetif.c file located in your project directory .
  • You will need to manually implement the initialization and configuration for your custom PHY. This may involve:
    • Setting up the correct PHY address (e.g. 0x80).
    • Configuring any specific registers required by your custom Phy.

Create a Custom PHY Driver

  • If you haven't already, create a custom driver for your PHY based on existing drivers (like those for LAN8742 or DP83848). You can use them as templates.
  • Implement necessary functions such as:PHY_Init()
    PHY_Read()
    PHY_Write()

Handle Warnings:

  • The warning triggered by selecting "Undefined PHY" can be ignored if you ensure that your custom driver is correctly implemented and integrated into the Ethernet stack Update

Initialization Functions:

  • Ensure that any initialization functions related to Ethernet (like HAL_ETH_MspInit) are correctly implemented to call your custom PHY initialization function.

Please check this POST , it could help you .

THX

Ghofrane

Hi Ghofrane,
Thankyou for your response.After configuring a custom PHY in STM32CubeIDE 1.14.1, I successfully managed to ping the MCU. However, I am encountering issues where UDP packets are not being sent.

Steps Taken:

  1. Custom PHY Selection: I set "Undefined PHY" in the platform settings and generated the code.

  2. Code Modifications in ethernetif.c:

    • Added HAL_ETH_

 

/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * File Name          : ethernetif.c
 * Description        : This file provides code for the configuration
 *                      of the ethernetif.c MiddleWare.
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2024 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"
/* USER CODE BEGIN Include for User BSP */

/* USER CODE END Include for User BSP */
#include <string.h>

/* Within 'USER CODE' section, code will be kept by default at each generation */
/* USER CODE BEGIN 0 */
//#define PHY_SR                          ((uint16_t)0x1FU)    /*!< PHY status register Offset                      */
#define PHY_MICR                        ((uint16_t)0x11U)    /*!< MII Interrupt Control Register                  */
#define PHY_MISR                        ((uint16_t)0x12U)    /*!< MII Interrupt Status and Misc. Control Register */
#define PHY_MICR_INT_EN                 ((uint16_t)0x0002U)  /*!< PHY Enable interrupts                           */
#define PHY_MICR_INT_OE                 ((uint16_t)0x0001U)  /*!< PHY Enable output interrupt events              */
#define PHY_MISR_LINK_INT_EN            ((uint16_t)0x0020U)  /*!< Enable Interrupt on change of link status       */
#define PHY_LINK_INTERRUPT              ((uint16_t)0x2000U)  /*!< PHY link status interrupt mask                  */

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

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/* Private variables ---------------------------------------------------------*/
/*
@Note: This interface is implemented to operate in zero-copy mode only:
        - Rx Buffers will be allocated from LwIP stack Rx memory pool,
          then passed to ETH HAL driver.
        - Tx Buffers will be allocated from LwIP stack memory heap,
          then passed to ETH HAL driver.

@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_BUF_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_BUF_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;

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

int32_t regvaluephy00,regvaluephy01,regvaluephy02,regvaluephy03,regvaluephy04,regvaluephy05,regvaluephy06;
/* USER CODE END 2 */

/* Global Ethernet handle */
ETH_HandleTypeDef heth;
ETH_TxPacketConfig TxConfig;

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN Private function prototypes for User BSP */

/* USER CODE END Private function prototypes for User BSP */

/* USER CODE BEGIN 3 */

/* USER CODE END 3 */

/* Private functions ---------------------------------------------------------*/
void pbuf_free_custom(struct pbuf *p);

/* USER CODE BEGIN 4 */
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
    PC2     ------> ETH_TXD2
    PC3     ------> ETH_TX_CLK
    PA0/WKUP     ------> ETH_CRS
    PA1     ------> ETH_RX_CLK
    PA2     ------> ETH_MDIO
    PA3     ------> ETH_COL
    PA7     ------> ETH_RX_DV
    PC4     ------> ETH_RXD0
    PC5     ------> ETH_RXD1
    PB0     ------> ETH_RXD2
    PB1     ------> ETH_RXD3
    PB10     ------> ETH_RX_ER
    PB11     ------> ETH_TX_EN
    PB12     ------> ETH_TXD0
    PB13     ------> ETH_TXD1
    PB8     ------> ETH_TXD3
		 */
		GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|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_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
				|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_0|GPIO_PIN_1|GPIO_PIN_10|GPIO_PIN_11
				|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_8;
		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);
	}
}

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
    PC2     ------> ETH_TXD2
    PC3     ------> ETH_TX_CLK
    PA0/WKUP     ------> ETH_CRS
    PA1     ------> ETH_RX_CLK
    PA2     ------> ETH_MDIO
    PA3     ------> ETH_COL
    PA7     ------> ETH_RX_DV
    PC4     ------> ETH_RXD0
    PC5     ------> ETH_RXD1
    PB0     ------> ETH_RXD2
    PB1     ------> ETH_RXD3
    PB10     ------> ETH_RX_ER
    PB11     ------> ETH_TX_EN
    PB12     ------> ETH_TXD0
    PB13     ------> ETH_TXD1
    PB8     ------> ETH_TXD3
		 */
		HAL_GPIO_DeInit(GPIOC, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4
				|GPIO_PIN_5);

		HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3
				|GPIO_PIN_7);

		HAL_GPIO_DeInit(GPIOB, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_10|GPIO_PIN_11
				|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_8);

	}
}

/* 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;
	heth.Init.Speed = ETH_SPEED_100M;
	heth.Init.DuplexMode = 0x00000800U;
	heth.Init.PhyAddress = 1U;
	MACAddr[0] = 0x00;
	MACAddr[1] = 0x80;
	MACAddr[2] = 0xE1;
	MACAddr[3] = 0x00;
	MACAddr[4] = 0x00;
	MACAddr[5] = 0x00;
	heth.Init.MACAddr = &MACAddr[0];
	heth.Init.MediaInterface = HAL_ETH_MII_MODE;
	heth.Init.TxDesc = DMATxDscrTab;
	heth.Init.RxDesc = DMARxDscrTab;
	heth.Init.RxBuffLen = 1536;

	/* USER CODE BEGIN MACADDRESS */
	  uint32_t regvalue = 0;
	/* 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 low_level_init Code 1 for User BSP */
	  HAL_ETH_Start(&heth);
	  HAL_ETH_ReadPHYRegister(&heth,_PHY_ADDRESS, PHY_MICR, &regvalue);

	    regvalue |= (PHY_MICR_INT_EN | PHY_MICR_INT_OE);

	    /* Enable Interrupts */
	    HAL_ETH_WritePHYRegister(&heth,_PHY_ADDRESS, PHY_MICR, regvalue );

	    /* Read Register Configuration */
	    HAL_ETH_ReadPHYRegister(&heth,_PHY_ADDRESS, PHY_MISR, &regvalue);

	    regvalue |= PHY_MISR_LINK_INT_EN;

	    /* Enable Interrupt on change of link status */
	    HAL_ETH_WritePHYRegister(&heth,_PHY_ADDRESS, PHY_MISR, regvalue);

	/* USER CODE END low_level_init Code 1 for User BSP */

	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 */
}

/**
 * @brief 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] = {0};

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

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

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

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

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

		i++;
	}

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

	HAL_ETH_Transmit(&heth, &TxConfig, ETH_DMA_TRANSMIT_TIMEOUT);

	return errval;
}

/**
 * @brief 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;
}

/**
 * @brief 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 */

/**
 * @brief 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;
	}
}

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

/* USER CODE BEGIN PHI IO Functions for User BSP */

/* USER CODE END PHI IO Functions for User BSP */

/**
 * @brief  Check the ETH link state then update ETH driver and netif link accordingly.
 * @retval None
 */
void ethernet_link_check_state(struct netif *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_BUF_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 */

 

MspDeInit and HAL_ETH_MspInit functions.

  • Set the speed and duplex settings: heth.Init.Speed = ETH_SPEED_100M; and heth.Init.DuplexMode = 0x00000800U.

  • Configured the PHY address and enabled interrupts on link status changes:

     
    heth.Init.PhyAddress = 1U; HAL_ETH_Start(&heth); HAL_ETH_ReadPHYRegister(&heth, _PHY_ADDRESS, PHY_MICR, &regvalue); regvalue |= (PHY_MICR_INT_EN | PHY_MICR_INT_OE); HAL_ETH_WritePHYRegister(&heth, _PHY_ADDRESS, PHY_MICR, regvalue); HAL_ETH_ReadPHYRegister(&heth, _PHY_ADDRESS, PHY_MISR, &regvalue); regvalue |= PHY_MISR_LINK_INT_EN; HAL_ETH_WritePHYRegister(&heth, _PHY_ADDRESS, PHY_MISR, regvalue);
  • Results: After these modifications, I am able to ping the MCU, but UDP packets are not being transmitted.

Troubleshooting steps:

Verified:

  • The UDP socket is correctly configured.
  • HAL_ETH_Start(&heth); is placed after PHY initialization.
  • Correct IP and port are set in the UDP transmit function.

Could there be any additional configurations in ethernetif.c or in LwIP settings to ensure UDP packet transmission?