source: ctrl/firmware/Main/SES/LWIP/Target/ethernetif.c @ 76

Last change on this file since 76 was 76, checked in by Zed, 3 months ago

Fixing project before changing NSS control for SPI2 in CubeMX.

File size: 19.3 KB
Line 
1/* USER CODE BEGIN Header */
2/**
3  ******************************************************************************
4  * File Name          : ethernetif.c
5  * Description        : This file provides code for the configuration
6  *                      of the ethernetif.c MiddleWare.
7  ******************************************************************************
8  * @attention
9  *
10  * Copyright (c) 2025 STMicroelectronics.
11  * All rights reserved.
12  *
13  * This software is licensed under terms that can be found in the LICENSE file
14  * in the root directory of this software component.
15  * If no LICENSE file comes with this software, it is provided AS-IS.
16  *
17  ******************************************************************************
18  */
19/* USER CODE END Header */
20
21/* Includes ------------------------------------------------------------------*/
22#include "main.h"
23#include "lwip/opt.h"
24#include "lwip/timeouts.h"
25#include "netif/ethernet.h"
26#include "netif/etharp.h"
27#include "lwip/ethip6.h"
28#include "ethernetif.h"
29/* USER CODE BEGIN Include for User BSP */
30
31/* USER CODE END Include for User BSP */
32#include <string.h>
33#include "cmsis_os.h"
34#include "lwip/tcpip.h"
35
36/* Within 'USER CODE' section, code will be kept by default at each generation */
37/* USER CODE BEGIN 0 */
38
39#include "w5100s.h"
40
41/* USER CODE END 0 */
42
43/* Private define ------------------------------------------------------------*/
44/* The time to block waiting for input. */
45#define TIME_WAITING_FOR_INPUT ( portMAX_DELAY )
46/* Time to block waiting for transmissions to finish */
47#define ETHIF_TX_TIMEOUT (2000U)
48/* USER CODE BEGIN OS_THREAD_STACK_SIZE_WITH_RTOS */
49/* Stack size of the interface thread */
50#define INTERFACE_THREAD_STACK_SIZE ( 350 )
51/* USER CODE END OS_THREAD_STACK_SIZE_WITH_RTOS */
52/* Network interface name */
53#define IFNAME0 'w'
54#define IFNAME1 'z'
55
56/* ETH Setting  */
57#define ETH_DMA_TRANSMIT_TIMEOUT               ( 20U )
58#define ETH_TX_BUFFER_MAX             ((ETH_TX_DESC_CNT) * 2U)
59/* ETH_RX_BUFFER_SIZE parameter is defined in lwipopts.h */
60
61/* USER CODE BEGIN 1 */
62
63/* USER CODE END 1 */
64
65/* Private variables ---------------------------------------------------------*/
66/*
67@Note: This interface is implemented to operate in zero-copy mode only:
68        - Rx Buffers will be allocated from LwIP stack Rx memory pool,
69          then passed to ETH HAL driver.
70        - Tx Buffers will be allocated from LwIP stack memory heap,
71          then passed to ETH HAL driver.
72
73@Notes:
74  1.a. ETH DMA Rx descriptors must be contiguous, the default count is 4,
75       to customize it please redefine ETH_RX_DESC_CNT in ETH GUI (Rx Descriptor Length)
76       so that updated value will be generated in stm32xxxx_hal_conf.h
77  1.b. ETH DMA Tx descriptors must be contiguous, the default count is 4,
78       to customize it please redefine ETH_TX_DESC_CNT in ETH GUI (Tx Descriptor Length)
79       so that updated value will be generated in stm32xxxx_hal_conf.h
80
81  2.a. Rx Buffers number must be between ETH_RX_DESC_CNT and 2*ETH_RX_DESC_CNT
82  2.b. Rx Buffers must have the same size: ETH_RX_BUFFER_SIZE, this value must
83       passed to ETH DMA in the init field (heth.Init.RxBuffLen)
84  2.c  The RX Ruffers addresses and sizes must be properly defined to be aligned
85       to L1-CACHE line size (32 bytes).
86*/
87
88/* Data Type Definitions */
89typedef enum
90{
91  RX_ALLOC_OK       = 0x00,
92  RX_ALLOC_ERROR    = 0x01
93} RxAllocStatusTypeDef;
94
95typedef struct
96{
97  struct pbuf_custom pbuf_custom;
98  uint8_t buff[(ETH_RX_BUFFER_SIZE + 31) & ~31] __ALIGNED(32);
99} RxBuff_t;
100
101/* Memory Pool Declaration */
102#define ETH_RX_BUFFER_CNT             12U
103LWIP_MEMPOOL_DECLARE(RX_POOL, ETH_RX_BUFFER_CNT, sizeof(RxBuff_t), "Zero-copy RX PBUF pool")
104
105/* Variable Definitions */
106static uint8_t RxAllocStatus;
107
108#if defined ( __ICCARM__ ) /*!< IAR Compiler */
109
110#pragma location=0x30000000
111ETH_DMADescTypeDef  DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */
112#pragma location=0x30000080
113ETH_DMADescTypeDef  DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */
114
115#elif defined ( __CC_ARM )  /* MDK ARM Compiler */
116
117__attribute__((at(0x30000000))) ETH_DMADescTypeDef  DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */
118__attribute__((at(0x30000080))) ETH_DMADescTypeDef  DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */
119
120#elif defined ( __GNUC__ ) /* GNU Compiler */
121
122//ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT] __attribute__((section(".RxDecripSection"))); /* Ethernet Rx DMA Descriptors */
123//ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT] __attribute__((section(".TxDecripSection")));   /* Ethernet Tx DMA Descriptors */
124
125#endif
126
127#if defined ( __ICCARM__ ) /*!< IAR Compiler */
128#pragma location = 0x30000100
129extern u8_t memp_memory_RX_POOL_base[];
130
131#elif defined ( __CC_ARM ) /* MDK ARM Compiler */
132__attribute__((section(".Rx_PoolSection"))) extern u8_t memp_memory_RX_POOL_base[];
133
134#elif defined ( __GNUC__ ) /* GNU */
135__attribute__((section(".Rx_PoolSection"))) extern u8_t memp_memory_RX_POOL_base[];
136#endif
137
138/* USER CODE BEGIN 2 */
139
140static struct netif *spi_if_netif;
141
142/* USER CODE END 2 */
143
144osSemaphoreId RxPktSemaphore = NULL;   /* Semaphore to signal incoming packets */
145osSemaphoreId TxPktSemaphore = NULL;   /* Semaphore to signal transmit packet complete */
146
147/* Global Ethernet handle */
148//ETH_HandleTypeDef heth;
149//ETH_TxPacketConfig TxConfig;
150
151/* Private function prototypes -----------------------------------------------*/
152/* USER CODE BEGIN Private function prototypes for User BSP */
153
154/* USER CODE END Private function prototypes for User BSP */
155
156/* USER CODE BEGIN 3 */
157
158/* USER CODE END 3 */
159
160/* Private functions ---------------------------------------------------------*/
161void pbuf_free_custom(struct pbuf *p);
162
163/**
164  * @brief  Ethernet Rx Transfer completed callback
165  * @param  handlerEth: ETH handler
166  * @retval None
167  */
168//void HAL_ETH_RxCpltCallback(ETH_HandleTypeDef *handlerEth)
169//{
170//  osSemaphoreRelease(RxPktSemaphore);
171//}
172/**
173  * @brief  Ethernet Tx Transfer completed callback
174  * @param  handlerEth: ETH handler
175  * @retval None
176  */
177//void HAL_ETH_TxCpltCallback(ETH_HandleTypeDef *handlerEth)
178//{
179//  osSemaphoreRelease(TxPktSemaphore);
180//}
181/**
182  * @brief  Ethernet DMA transfer error callback
183  * @param  handlerEth: ETH handler
184  * @retval None
185  */
186//void HAL_ETH_ErrorCallback(ETH_HandleTypeDef *handlerEth)
187//{
188//  if((HAL_ETH_GetDMAError(handlerEth) & ETH_DMACSR_RBU) == ETH_DMACSR_RBU)
189//  {
190//     osSemaphoreRelease(RxPktSemaphore);
191//  }
192//}
193
194/* USER CODE BEGIN 4 */
195
196/* USER CODE END 4 */
197
198/*******************************************************************************
199                       LL Driver Interface ( LwIP stack --> ETH)
200*******************************************************************************/
201/**
202 * @brief In this function, the hardware should be initialized.
203 * Called from ethernetif_init().
204 *
205 * @param netif the already initialized lwip network interface structure
206 *        for this ethernetif
207 */
208static void low_level_init(struct netif *netif)
209{
210  int result;
211  HAL_StatusTypeDef hal_eth_init_status = HAL_OK;
212/* USER CODE BEGIN OS_THREAD_ATTR_CMSIS_RTOS_V2 */
213  osThreadAttr_t attributes;
214/* USER CODE END OS_THREAD_ATTR_CMSIS_RTOS_V2 */
215/* USER CODE BEGIN low_level_init Variables Initialization for User BSP */
216
217/* USER CODE END low_level_init Variables Initialization for User BSP */
218  /* Start ETH HAL Init */
219
220  /*uint8_t MACAddr[6] ;
221  heth.Instance = ETH;
222  MACAddr[0] = 0x00;
223  MACAddr[1] = 0x80;
224  MACAddr[2] = 0xE1;
225  MACAddr[3] = 0x00;
226  MACAddr[4] = 0x00;
227  MACAddr[5] = 0x00;
228  heth.Init.MACAddr = &MACAddr[0];
229  heth.Init.MediaInterface = HAL_ETH_RMII_MODE;
230  heth.Init.TxDesc = DMATxDscrTab;
231  heth.Init.RxDesc = DMARxDscrTab;
232  heth.Init.RxBuffLen = 1536;*/
233
234  /* USER CODE BEGIN MACADDRESS */
235
236  /* USER CODE END MACADDRESS */
237
238  /*hal_eth_init_status = HAL_ETH_Init(&heth);
239
240  memset(&TxConfig, 0 , sizeof(ETH_TxPacketConfig));
241  TxConfig.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD;
242  TxConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
243  TxConfig.CRCPadCtrl = ETH_CRC_PAD_INSERT;*/
244
245  /* End ETH HAL Init */
246
247  /* Initialize the RX POOL */
248  LWIP_MEMPOOL_INIT(RX_POOL);
249
250#if LWIP_ARP || LWIP_ETHERNET
251
252  /* set MAC hardware address length */
253  netif->hwaddr_len = ETH_HWADDR_LEN;
254
255  /* set MAC hardware address */
256  netif->hwaddr[0] =  0x0C;
257  netif->hwaddr[1] =  0x4B;
258  netif->hwaddr[2] =  0x0A;
259  netif->hwaddr[3] =  0x01;
260  netif->hwaddr[4] =  0x0E;
261  netif->hwaddr[5] =  0x02;
262
263  // maximum transfer unit
264  netif->mtu = 1500;            //ETH_MAX_PAYLOAD;
265
266  /* Accept broadcast address and ARP traffic */
267  /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
268  #if LWIP_ARP
269    netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET;
270  #else
271    netif->flags |= NETIF_FLAG_BROADCAST;
272  #endif /* LWIP_ARP */
273
274  spi_if_netif = netif;
275
276  // All hardware-specific settings(SPI, GPIO) were made in corresponding CubeMX-generated files
277  // We just turn on module's power line and deassert RST signal
278  HAL_GPIO_WritePin(ETH_SPI_PWR_GPIO_Port, ETH_SPI_PWR_Pin, GPIO_PIN_RESET);
279  osDelay(100);
280  HAL_GPIO_WritePin(ETH_SPI_RST_GPIO_Port, ETH_SPI_RST_Pin, GPIO_PIN_SET);
281  osDelay(50);
282
283  uint8_t reg = getVER();
284
285  /* create a binary semaphore used for informing ethernetif of frame reception */
286  RxPktSemaphore = osSemaphoreNew(1, 0, NULL);
287
288  /* create a binary semaphore used for informing ethernetif of frame transmission */
289  TxPktSemaphore = osSemaphoreNew(1, 0, NULL);
290
291  /* create the task that handles the ETH_MAC */
292/* USER CODE BEGIN OS_THREAD_NEW_CMSIS_RTOS_V2 */
293  memset(&attributes, 0x0, sizeof(osThreadAttr_t));
294  attributes.name = "EthIf";
295  attributes.stack_size = INTERFACE_THREAD_STACK_SIZE;
296  attributes.priority = osPriorityRealtime;
297  osThreadNew(ethernetif_input, netif, &attributes);
298/* USER CODE END OS_THREAD_NEW_CMSIS_RTOS_V2 */
299
300/* USER CODE BEGIN low_level_init Code 1 for User BSP */
301
302/* USER CODE END low_level_init Code 1 for User BSP */
303
304/* USER CODE BEGIN low_level_init Code 2 for User BSP */
305
306/* USER CODE END low_level_init Code 2 for User BSP */
307
308#endif /* LWIP_ARP || LWIP_ETHERNET */
309
310/* USER CODE BEGIN LOW_LEVEL_INIT */
311
312/* USER CODE END LOW_LEVEL_INIT */
313}
314
315/**
316 * @brief This function should do the actual transmission of the packet. The packet is
317 * contained in the pbuf that is passed to the function. This pbuf
318 * might be chained.
319 *
320 * @param netif the lwip network interface structure for this ethernetif
321 * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
322 * @return ERR_OK if the packet could be sent
323 *         an err_t value if the packet couldn't be sent
324 *
325 * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
326 *       strange results. You might consider waiting for space in the DMA queue
327 *       to become available since the stack doesn't retry to send a packet
328 *       dropped because of memory failure (except for the TCP timers).
329 */
330
331static err_t low_level_output(struct netif *netif, struct pbuf *p)
332{
333  uint32_t i = 0U;
334  struct pbuf *q = NULL;
335  err_t errval = ERR_OK;
336/*  ETH_BufferTypeDef Txbuffer[ETH_TX_DESC_CNT] = {0};
337
338  memset(Txbuffer, 0 , ETH_TX_DESC_CNT*sizeof(ETH_BufferTypeDef));
339
340  for(q = p; q != NULL; q = q->next)
341  {
342    if(i >= ETH_TX_DESC_CNT)
343      return ERR_IF;
344
345    Txbuffer[i].buffer = q->payload;
346    Txbuffer[i].len = q->len;
347
348    if(i>0)
349    {
350      Txbuffer[i-1].next = &Txbuffer[i];
351    }
352
353    if(q->next == NULL)
354    {
355      Txbuffer[i].next = NULL;
356    }
357
358    i++;
359  }
360
361  TxConfig.Length = p->tot_len;
362  TxConfig.TxBuffer = Txbuffer;
363  TxConfig.pData = p;
364
365  pbuf_ref(p);
366
367  do
368  {
369    if(HAL_ETH_Transmit_IT(&heth, &TxConfig) == HAL_OK)
370    {
371      errval = ERR_OK;
372    }
373    else
374    {
375
376      if(HAL_ETH_GetError(&heth) & HAL_ETH_ERROR_BUSY)
377      {
378        // Wait for descriptors to become available
379        osSemaphoreAcquire(TxPktSemaphore, ETHIF_TX_TIMEOUT);
380        HAL_ETH_ReleaseTxPacket(&heth);
381        errval = ERR_BUF;
382      }
383      else
384      {
385        // Other error
386        pbuf_free(p);
387        errval =  ERR_IF;
388      }
389    }
390  }while(errval == ERR_BUF);*/
391
392  return errval;
393}
394
395/**
396 * @brief Should allocate a pbuf and transfer the bytes of the incoming
397 * packet from the interface into the pbuf.
398 *
399 * @param netif the lwip network interface structure for this ethernetif
400 * @return a pbuf filled with the received packet (including MAC header)
401 *         NULL on memory error
402   */
403static struct pbuf * low_level_input(struct netif *netif)
404{
405  struct pbuf *p = NULL;
406
407  if(RxAllocStatus == RX_ALLOC_OK)
408  {
409    //HAL_ETH_ReadData(&heth, (void **)&p);
410  }
411
412  return p;
413}
414
415/**
416 * @brief This function should be called when a packet is ready to be read
417 * from the interface. It uses the function low_level_input() that
418 * should handle the actual reception of bytes from the network
419 * interface. Then the type of the received packet is determined and
420 * the appropriate input function is called.
421 *
422 * @param netif the lwip network interface structure for this ethernetif
423 */
424void ethernetif_input(void* argument)
425{
426  struct pbuf *p = NULL;
427  struct netif *netif = (struct netif *) argument;
428
429  for( ;; )
430  {
431    if (osSemaphoreAcquire(RxPktSemaphore, TIME_WAITING_FOR_INPUT) == osOK)
432    {
433      do
434      {
435        p = low_level_input( netif );
436        if (p != NULL)
437        {
438          if (netif->input( p, netif) != ERR_OK )
439          {
440            pbuf_free(p);
441          }
442        }
443      } while(p!=NULL);
444    }
445  }
446}
447
448#if !LWIP_ARP
449/**
450 * This function has to be completed by user in case of ARP OFF.
451 *
452 * @param netif the lwip network interface structure for this ethernetif
453 * @return ERR_OK if ...
454 */
455static err_t low_level_output_arp_off(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
456{
457  err_t errval;
458  errval = ERR_OK;
459
460/* USER CODE BEGIN 5 */
461
462/* USER CODE END 5 */
463
464  return errval;
465
466}
467#endif /* LWIP_ARP */
468
469/**
470 * @brief Should be called at the beginning of the program to set up the
471 * network interface. It calls the function low_level_init() to do the
472 * actual setup of the hardware.
473 *
474 * This function should be passed as a parameter to netif_add().
475 *
476 * @param netif the lwip network interface structure for this ethernetif
477 * @return ERR_OK if the loopif is initialized
478 *         ERR_MEM if private data couldn't be allocated
479 *         any other err_t on error
480 */
481err_t ethernetif_init(struct netif *netif)
482{
483  LWIP_ASSERT("netif != NULL", (netif != NULL));
484
485#if LWIP_NETIF_HOSTNAME
486  /* Initialize interface hostname */
487  netif->hostname = "lwip";
488#endif /* LWIP_NETIF_HOSTNAME */
489
490  /*
491   * Initialize the snmp variables and counters inside the struct netif.
492   * The last argument should be replaced with your link speed, in units
493   * of bits per second.
494   */
495//MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
496
497  netif->name[0] = IFNAME0;
498  netif->name[1] = IFNAME1;
499  /* We directly use etharp_output() here to save a function call.
500   * You can instead declare your own function an call etharp_output()
501   * from it if you have to do some checks before sending (e.g. if link
502   * is available...) */
503
504#if LWIP_IPV4
505#if LWIP_ARP || LWIP_ETHERNET
506#if LWIP_ARP
507  netif->output = etharp_output;
508#else
509  /* The user should write its own code in low_level_output_arp_off function */
510  netif->output = low_level_output_arp_off;
511#endif /* LWIP_ARP */
512#endif /* LWIP_ARP || LWIP_ETHERNET */
513#endif /* LWIP_IPV4 */
514
515#if LWIP_IPV6
516  netif->output_ip6 = ethip6_output;
517#endif /* LWIP_IPV6 */
518
519  netif->linkoutput = low_level_output;
520
521  /* initialize the hardware */
522  low_level_init(netif);
523
524  return ERR_OK;
525}
526
527/**
528  * @brief  Custom Rx pbuf free callback
529  * @param  pbuf: pbuf to be freed
530  * @retval None
531  */
532void pbuf_free_custom(struct pbuf *p)
533{
534  struct pbuf_custom* custom_pbuf = (struct pbuf_custom*)p;
535  LWIP_MEMPOOL_FREE(RX_POOL, custom_pbuf);
536
537  /* If the Rx Buffer Pool was exhausted, signal the ethernetif_input task to
538   * call HAL_ETH_GetRxDataBuffer to rebuild the Rx descriptors. */
539
540  if (RxAllocStatus == RX_ALLOC_ERROR)
541  {
542    RxAllocStatus = RX_ALLOC_OK;
543    osSemaphoreRelease(RxPktSemaphore);
544  }
545}
546
547/* USER CODE BEGIN 6 */
548
549/**
550* @brief  Returns the current time in milliseconds
551*         when LWIP_TIMERS == 1 and NO_SYS == 1
552* @param  None
553* @retval Current Time value
554*/
555u32_t sys_now(void)
556{
557  return HAL_GetTick();
558}
559
560/* USER CODE END 6 */
561
562/* USER CODE BEGIN PHI IO Functions for User BSP */
563
564/* USER CODE END PHI IO Functions for User BSP */
565
566/**
567  * @brief  Check the ETH link state then update ETH driver and netif link accordingly.
568  * @retval None
569  */
570void ethernet_link_thread(void* argument)
571{
572
573/* USER CODE BEGIN ETH link init */
574
575/* USER CODE END ETH link init */
576
577  for(;;)
578  {
579
580/* USER CODE BEGIN ETH link Thread core code for User BSP */
581
582/* USER CODE END ETH link Thread core code for User BSP */
583
584    osDelay(100);
585  }
586}
587
588void HAL_ETH_RxAllocateCallback(uint8_t **buff)
589{
590/* USER CODE BEGIN HAL ETH RxAllocateCallback */
591  struct pbuf_custom *p = LWIP_MEMPOOL_ALLOC(RX_POOL);
592  if (p)
593  {
594    /* Get the buff from the struct pbuf address. */
595    *buff = (uint8_t *)p + offsetof(RxBuff_t, buff);
596    p->custom_free_function = pbuf_free_custom;
597    /* Initialize the struct pbuf.
598    * This must be performed whenever a buffer's allocated because it may be
599    * changed by lwIP or the app, e.g., pbuf_free decrements ref. */
600    pbuf_alloced_custom(PBUF_RAW, 0, PBUF_REF, p, *buff, ETH_RX_BUFFER_SIZE);
601  }
602  else
603  {
604    RxAllocStatus = RX_ALLOC_ERROR;
605    *buff = NULL;
606  }
607/* USER CODE END HAL ETH RxAllocateCallback */
608}
609
610void HAL_ETH_RxLinkCallback(void **pStart, void **pEnd, uint8_t *buff, uint16_t Length)
611{
612/* USER CODE BEGIN HAL ETH RxLinkCallback */
613
614  struct pbuf **ppStart = (struct pbuf **)pStart;
615  struct pbuf **ppEnd = (struct pbuf **)pEnd;
616  struct pbuf *p = NULL;
617
618  /* Get the struct pbuf from the buff address. */
619  p = (struct pbuf *)(buff - offsetof(RxBuff_t, buff));
620  p->next = NULL;
621  p->tot_len = 0;
622  p->len = Length;
623
624  /* Chain the buffer. */
625  if (!*ppStart)
626  {
627    /* The first buffer of the packet. */
628    *ppStart = p;
629  }
630  else
631  {
632    /* Chain the buffer to the end of the packet. */
633    (*ppEnd)->next = p;
634  }
635  *ppEnd  = p;
636
637  /* Update the total length of all the buffers of the chain. Each pbuf in the chain should have its tot_len
638   * set to its own length, plus the length of all the following pbufs in the chain. */
639  for (p = *ppStart; p != NULL; p = p->next)
640  {
641    p->tot_len += Length;
642  }
643
644  /* Invalidate data cache because Rx DMA's writing to physical memory makes it stale. */
645  SCB_InvalidateDCache_by_Addr((uint32_t *)buff, Length);
646
647/* USER CODE END HAL ETH RxLinkCallback */
648}
649
650void HAL_ETH_TxFreeCallback(uint32_t * buff)
651{
652/* USER CODE BEGIN HAL ETH TxFreeCallback */
653
654  pbuf_free((struct pbuf *)buff);
655
656/* USER CODE END HAL ETH TxFreeCallback */
657}
658
659/* USER CODE BEGIN 8 */
660
661/* USER CODE END 8 */
662
Note: See TracBrowser for help on using the repository browser.