stm32h5xx_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file stm32h5xx_eth_driver.c
3  * @brief STM32H5 Ethernet MAC driver
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include "stm32h5xx.h"
36 #include "stm32h5xx_hal.h"
37 #include "core/net.h"
39 #include "debug.h"
40 
41 //Underlying network interface
42 static NetInterface *nicDriverInterface;
43 
44 //IAR EWARM compiler?
45 #if defined(__ICCARM__)
46 
47 //Transmit buffer
48 #pragma data_alignment = 4
50 //Receive buffer
51 #pragma data_alignment = 4
53 //Transmit DMA descriptors
54 #pragma data_alignment = 4
56 //Receive DMA descriptors
57 #pragma data_alignment = 4
59 
60 //Keil MDK-ARM or GCC compiler?
61 #else
62 
63 //Transmit buffer
65  __attribute__((aligned(4)));
66 //Receive buffer
68  __attribute__((aligned(4)));
69 //Transmit DMA descriptors
71  __attribute__((aligned(4)));
72 //Receive DMA descriptors
74  __attribute__((aligned(4)));
75 
76 #endif
77 
78 //Current transmit descriptor
79 static uint_t txIndex;
80 //Current receive descriptor
81 static uint_t rxIndex;
82 
83 
84 /**
85  * @brief STM32H5 Ethernet MAC driver
86  **/
87 
89 {
91  ETH_MTU,
102  TRUE,
103  TRUE,
104  TRUE,
105  FALSE
106 };
107 
108 
109 /**
110  * @brief STM32H5 Ethernet MAC initialization
111  * @param[in] interface Underlying network interface
112  * @return Error code
113  **/
114 
116 {
117  error_t error;
118  uint32_t temp;
119 
120  //Debug message
121  TRACE_INFO("Initializing STM32H5 Ethernet MAC...\r\n");
122 
123  //Save underlying network interface
124  nicDriverInterface = interface;
125 
126  //GPIO configuration
127  stm32h5xxEthInitGpio(interface);
128 
129  //Enable Ethernet MAC clock
130  __HAL_RCC_ETH_CLK_ENABLE();
131  __HAL_RCC_ETHTX_CLK_ENABLE();
132  __HAL_RCC_ETHRX_CLK_ENABLE();
133 
134  //Reset Ethernet MAC peripheral
135  __HAL_RCC_ETH_FORCE_RESET();
136  __HAL_RCC_ETH_RELEASE_RESET();
137 
138  //Perform a software reset
139  ETH->DMAMR |= ETH_DMAMR_SWR;
140  //Wait for the reset to complete
141  while((ETH->DMAMR & ETH_DMAMR_SWR) != 0)
142  {
143  }
144 
145  //Adjust MDC clock range depending on HCLK frequency
146  ETH->MACMDIOAR = ETH_MACMDIOAR_CR_DIV124;
147 
148  //Valid Ethernet PHY or switch driver?
149  if(interface->phyDriver != NULL)
150  {
151  //Ethernet PHY initialization
152  error = interface->phyDriver->init(interface);
153  }
154  else if(interface->switchDriver != NULL)
155  {
156  //Ethernet switch initialization
157  error = interface->switchDriver->init(interface);
158  }
159  else
160  {
161  //The interface is not properly configured
162  error = ERROR_FAILURE;
163  }
164 
165  //Any error to report?
166  if(error)
167  {
168  return error;
169  }
170 
171  //Use default MAC configuration
172  ETH->MACCR = ETH_MACCR_GPSLCE | ETH_MACCR_RESERVED15 | ETH_MACCR_DO;
173 
174  //Set the maximum packet size that can be accepted
175  temp = ETH->MACECR & ~ETH_MACECR_GPSL;
176  ETH->MACECR = temp | STM32H5XX_ETH_RX_BUFFER_SIZE;
177 
178  //Configure MAC address filtering
180 
181  //Disable flow control
182  ETH->MACTFCR = 0;
183  ETH->MACRFCR = 0;
184 
185  //Configure DMA operating mode
186  ETH->DMAMR = ETH_DMAMR_INTM_0 | ETH_DMAMR_PR_1_1;
187  //Configure system bus mode
188  ETH->DMASBMR |= ETH_DMASBMR_AAL;
189  //The DMA takes the descriptor table as contiguous
190  ETH->DMACCR = ETH_DMACCR_DSL_0BIT;
191 
192  //Configure TX features
193  ETH->DMACTCR = ETH_DMACTCR_TPBL_32PBL;
194 
195  //Configure RX features
196  ETH->DMACRCR = ETH_DMACRCR_RPBL_32PBL;
197  ETH->DMACRCR |= (STM32H5XX_ETH_RX_BUFFER_SIZE << 1) & ETH_DMACRCR_RBSZ;
198 
199  //Enable store and forward mode
200  ETH->MTLTQOMR |= ETH_MTLTQOMR_TSF;
201  ETH->MTLRQOMR |= ETH_MTLRQOMR_RSF;
202 
203  //Initialize DMA descriptor lists
204  stm32h5xxEthInitDmaDesc(interface);
205 
206  //Prevent interrupts from being generated when the transmit statistic
207  //counters reach half their maximum value
208  ETH->MMCTIMR = ETH_MMCTIMR_TXLPITRCIM | ETH_MMCTIMR_TXLPIUSCIM |
209  ETH_MMCTIMR_TXGPKTIM | ETH_MMCTIMR_TXMCOLGPIM | ETH_MMCTIMR_TXSCOLGPIM;
210 
211  //Prevent interrupts from being generated when the receive statistic
212  //counters reach half their maximum value
213  ETH->MMCRIMR = ETH_MMCRIMR_RXLPITRCIM | ETH_MMCRIMR_RXLPIUSCIM |
214  ETH_MMCRIMR_RXUCGPIM | ETH_MMCRIMR_RXALGNERPIM | ETH_MMCRIMR_RXCRCERPIM;
215 
216  //Disable MAC interrupts
217  ETH->MACIER = 0;
218  //Enable the desired DMA interrupts
219  ETH->DMACIER = ETH_DMACIER_NIE | ETH_DMACIER_RIE | ETH_DMACIER_TIE;
220 
221  //Set priority grouping (4 bits for pre-emption priority, no bits for subpriority)
222  NVIC_SetPriorityGrouping(STM32H5XX_ETH_IRQ_PRIORITY_GROUPING);
223 
224  //Configure Ethernet interrupt priority
225  NVIC_SetPriority(ETH_IRQn, NVIC_EncodePriority(STM32H5XX_ETH_IRQ_PRIORITY_GROUPING,
227 
228  //Enable MAC transmission and reception
229  ETH->MACCR |= ETH_MACCR_TE | ETH_MACCR_RE;
230 
231  //Enable DMA transmission and reception
232  ETH->DMACTCR |= ETH_DMACTCR_ST;
233  ETH->DMACRCR |= ETH_DMACRCR_SR;
234 
235  //Accept any packets from the upper layer
236  osSetEvent(&interface->nicTxEvent);
237 
238  //Successful initialization
239  return NO_ERROR;
240 }
241 
242 
243 /**
244  * @brief GPIO configuration
245  * @param[in] interface Underlying network interface
246  **/
247 
248 __weak_func void stm32h5xxEthInitGpio(NetInterface *interface)
249 {
250 //Nucleo-H563ZI evaluation board?
251 #if defined(USE_NUCLEO_H563ZI)
252  GPIO_InitTypeDef GPIO_InitStructure;
253 
254  //Enable SBS clock
255  __HAL_RCC_SBS_CLK_ENABLE();
256 
257  //Enable GPIO clocks
258  __HAL_RCC_GPIOA_CLK_ENABLE();
259  __HAL_RCC_GPIOB_CLK_ENABLE();
260  __HAL_RCC_GPIOC_CLK_ENABLE();
261  __HAL_RCC_GPIOG_CLK_ENABLE();
262 
263  //Select RMII interface mode
264  HAL_SBS_ETHInterfaceSelect(SBS_ETH_RMII);
265 
266  //Configure RMII pins
267  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
268  GPIO_InitStructure.Pull = GPIO_NOPULL;
269  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
270  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
271 
272  //Configure ETH_RMII_REF_CLK (PA1), ETH_MDIO (PA2) and ETH_RMII_CRS_DV (PA7)
273  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
274  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
275 
276  //Configure ETH_RMII_TXD1 (PB15)
277  GPIO_InitStructure.Pin = GPIO_PIN_15;
278  HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
279 
280  //Configure ETH_MDC (PC1), ETH_RMII_RXD0 (PC4) and ETH_RMII_RXD1 (PC5)
281  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
282  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
283 
284  //Configure RMII_TX_EN (PG11) and ETH_RMII_TXD0 (PG13)
285  GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13;
286  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
287 
288 //Nucleo-H5E5ZJ evaluation board?
289 #elif defined(USE_NUCLEO_H5E5ZJ)
290  GPIO_InitTypeDef GPIO_InitStructure;
291 
292  //Enable SBS clock
293  __HAL_RCC_SBS_CLK_ENABLE();
294 
295  //Enable GPIO clocks
296  __HAL_RCC_GPIOA_CLK_ENABLE();
297  __HAL_RCC_GPIOB_CLK_ENABLE();
298  __HAL_RCC_GPIOC_CLK_ENABLE();
299  __HAL_RCC_GPIOD_CLK_ENABLE();
300  __HAL_RCC_GPIOG_CLK_ENABLE();
301 
302  //Select RMII interface mode
303  HAL_SBS_ETHInterfaceSelect(SBS_ETH_RMII);
304 
305  //Configure RMII pins
306  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
307  GPIO_InitStructure.Pull = GPIO_NOPULL;
308  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
309  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
310 
311  //Configure ETH_RMII_REF_CLK (PA1), ETH_MDIO (PA2) and RMII_TX_EN (PA5)
312  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_5;
313  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
314 
315  //Configure ETH_RMII_TXD0 (PB12)
316  GPIO_InitStructure.Pin = GPIO_PIN_12;
317  HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
318 
319  //Configure ETH_MDC (PC1), ETH_RMII_RXD0 (PC4) and ETH_RMII_RXD1 (PC5)
320  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
321  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
322 
323  //Configure ETH_RMII_CRS_DV (PD1)
324  GPIO_InitStructure.Pin = GPIO_PIN_1;
325  HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
326 
327  //Configure ETH_RMII_TXD1 (PG12)
328  GPIO_InitStructure.Pin = GPIO_PIN_12;
329  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
330 
331 //STM32H573I-DK evaluation board?
332 #elif defined(USE_STM32H573I_DK)
333  GPIO_InitTypeDef GPIO_InitStructure;
334 
335  //Enable SBS clock
336  __HAL_RCC_SBS_CLK_ENABLE();
337 
338  //Enable GPIO clocks
339  __HAL_RCC_GPIOA_CLK_ENABLE();
340  __HAL_RCC_GPIOC_CLK_ENABLE();
341  __HAL_RCC_GPIOG_CLK_ENABLE();
342 
343  //Select RMII interface mode
344  HAL_SBS_ETHInterfaceSelect(SBS_ETH_RMII);
345 
346  //Configure RMII pins
347  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
348  GPIO_InitStructure.Pull = GPIO_NOPULL;
349  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
350  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
351 
352  //Configure ETH_RMII_REF_CLK (PA1), ETH_MDIO (PA2) and ETH_RMII_CRS_DV (PA7)
353  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
354  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
355 
356  //Configure ETH_MDC (PC1), ETH_RMII_RXD0 (PC4) and ETH_RMII_RXD1 (PC5)
357  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
358  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
359 
360  //Configure RMII_TX_EN (PG11), ETH_RMII_TXD1 (PG12) and ETH_RMII_TXD0 (PG13)
361  GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13;
362  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
363 
364 //STM32H5F5J-DK evaluation board?
365 #elif defined(USE_STM32H5F5J_DK)
366  GPIO_InitTypeDef GPIO_InitStructure;
367 
368  //Enable SBS clock
369  __HAL_RCC_SBS_CLK_ENABLE();
370 
371  //Enable GPIO clocks
372  __HAL_RCC_GPIOA_CLK_ENABLE();
373  __HAL_RCC_GPIOB_CLK_ENABLE();
374  __HAL_RCC_GPIOC_CLK_ENABLE();
375  __HAL_RCC_GPIOD_CLK_ENABLE();
376  __HAL_RCC_GPIOE_CLK_ENABLE();
377  __HAL_RCC_GPIOG_CLK_ENABLE();
378  __HAL_RCC_GPIOJ_CLK_ENABLE();
379 
380  //Select RMII interface mode
381  HAL_SBS_ETHInterfaceSelect(SBS_ETH_RMII);
382 
383  //Configure RMII pins
384  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
385  GPIO_InitStructure.Pull = GPIO_NOPULL;
386  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
387 
388  //Configure ETH_RMII_REF_CLK (PA1)
389  GPIO_InitStructure.Pin = GPIO_PIN_1;
390  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
391  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
392 
393  //Configure RMII_TX_EN (PB11) and ETH_RMII_TXD0 (PB12)
394  GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_12;
395  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
396  HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
397 
398  //Configure ETH_RMII_RXD0 (PC4)
399  GPIO_InitStructure.Pin = GPIO_PIN_4;
400  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
401  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
402 
403  //Configure ETH_RMII_CRS_DV (PD1)
404  GPIO_InitStructure.Pin = GPIO_PIN_1;
405  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
406  HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
407 
408  //Configure ETH_RMII_RXD1 (PE5)
409  GPIO_InitStructure.Pin = GPIO_PIN_5;
410  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
411  HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
412 
413  //Configure ETH_RMII_TXD1 (PG12)
414  GPIO_InitStructure.Pin = GPIO_PIN_12;
415  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
416  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
417 
418  //Configure ETH_MDIO (PJ6) and ETH_MDC (PJ7)
419  GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7;
420  GPIO_InitStructure.Alternate = GPIO_AF12_ETH;
421  HAL_GPIO_Init(GPIOJ, &GPIO_InitStructure);
422 #endif
423 }
424 
425 
426 /**
427  * @brief Initialize DMA descriptor lists
428  * @param[in] interface Underlying network interface
429  **/
430 
432 {
433  uint_t i;
434 
435  //Initialize TX DMA descriptor list
436  for(i = 0; i < STM32H5XX_ETH_TX_BUFFER_COUNT; i++)
437  {
438  //The descriptor is initially owned by the application
439  txDmaDesc[i].tdes0 = 0;
440  txDmaDesc[i].tdes1 = 0;
441  txDmaDesc[i].tdes2 = 0;
442  txDmaDesc[i].tdes3 = 0;
443  }
444 
445  //Initialize TX descriptor index
446  txIndex = 0;
447 
448  //Initialize RX DMA descriptor list
449  for(i = 0; i < STM32H5XX_ETH_RX_BUFFER_COUNT; i++)
450  {
451  //The descriptor is initially owned by the DMA
452  rxDmaDesc[i].rdes0 = (uint32_t) rxBuffer[i];
453  rxDmaDesc[i].rdes1 = 0;
454  rxDmaDesc[i].rdes2 = 0;
456  }
457 
458  //Initialize RX descriptor index
459  rxIndex = 0;
460 
461  //Start location of the TX descriptor list
462  ETH->DMACTDLAR = (uint32_t) &txDmaDesc[0];
463  //Length of the transmit descriptor ring
464  ETH->DMACTDRLR = STM32H5XX_ETH_TX_BUFFER_COUNT - 1;
465 
466  //Start location of the RX descriptor list
467  ETH->DMACRDLAR = (uint32_t) &rxDmaDesc[0];
468  //Length of the receive descriptor ring
469  ETH->DMACRDRLR = STM32H5XX_ETH_RX_BUFFER_COUNT - 1;
470 }
471 
472 
473 /**
474  * @brief STM32H5 Ethernet MAC timer handler
475  *
476  * This routine is periodically called by the TCP/IP stack to handle periodic
477  * operations such as polling the link state
478  *
479  * @param[in] interface Underlying network interface
480  **/
481 
483 {
484  //Valid Ethernet PHY or switch driver?
485  if(interface->phyDriver != NULL)
486  {
487  //Handle periodic operations
488  interface->phyDriver->tick(interface);
489  }
490  else if(interface->switchDriver != NULL)
491  {
492  //Handle periodic operations
493  interface->switchDriver->tick(interface);
494  }
495  else
496  {
497  //Just for sanity
498  }
499 }
500 
501 
502 /**
503  * @brief Enable interrupts
504  * @param[in] interface Underlying network interface
505  **/
506 
508 {
509  //Enable Ethernet MAC interrupts
510  NVIC_EnableIRQ(ETH_IRQn);
511 
512  //Valid Ethernet PHY or switch driver?
513  if(interface->phyDriver != NULL)
514  {
515  //Enable Ethernet PHY interrupts
516  interface->phyDriver->enableIrq(interface);
517  }
518  else if(interface->switchDriver != NULL)
519  {
520  //Enable Ethernet switch interrupts
521  interface->switchDriver->enableIrq(interface);
522  }
523  else
524  {
525  //Just for sanity
526  }
527 }
528 
529 
530 /**
531  * @brief Disable interrupts
532  * @param[in] interface Underlying network interface
533  **/
534 
536 {
537  //Disable Ethernet MAC interrupts
538  NVIC_DisableIRQ(ETH_IRQn);
539 
540  //Valid Ethernet PHY or switch driver?
541  if(interface->phyDriver != NULL)
542  {
543  //Disable Ethernet PHY interrupts
544  interface->phyDriver->disableIrq(interface);
545  }
546  else if(interface->switchDriver != NULL)
547  {
548  //Disable Ethernet switch interrupts
549  interface->switchDriver->disableIrq(interface);
550  }
551  else
552  {
553  //Just for sanity
554  }
555 }
556 
557 
558 /**
559  * @brief STM32H5 Ethernet MAC interrupt service routine
560  **/
561 
562 void ETH_IRQHandler(void)
563 {
564  bool_t flag;
565  uint32_t status;
566 
567  //Interrupt service routine prologue
568  osEnterIsr();
569 
570  //This flag will be set if a higher priority task must be woken
571  flag = FALSE;
572 
573  //Read DMA status register
574  status = ETH->DMACSR;
575 
576  //Packet transmitted?
577  if((status & ETH_DMACSR_TI) != 0)
578  {
579  //Clear TI interrupt flag
580  ETH->DMACSR = ETH_DMACSR_TI;
581 
582  //Check whether the TX buffer is available for writing
583  if((txDmaDesc[txIndex].tdes3 & ETH_TDES3_OWN) == 0)
584  {
585  //Notify the TCP/IP stack that the transmitter is ready to send
586  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
587  }
588  }
589 
590  //Packet received?
591  if((status & ETH_DMACSR_RI) != 0)
592  {
593  //Clear RI interrupt flag
594  ETH->DMACSR = ETH_DMACSR_RI;
595 
596  //Set event flag
597  nicDriverInterface->nicEvent = TRUE;
598  //Notify the TCP/IP stack of the event
599  flag |= osSetEventFromIsr(&nicDriverInterface->netContext->event);
600  }
601 
602  //Clear NIS interrupt flag
603  ETH->DMACSR = ETH_DMACSR_NIS;
604 
605  //Interrupt service routine epilogue
606  osExitIsr(flag);
607 }
608 
609 
610 /**
611  * @brief STM32H5 Ethernet MAC event handler
612  * @param[in] interface Underlying network interface
613  **/
614 
616 {
617  error_t error;
618 
619  //Process all pending packets
620  do
621  {
622  //Read incoming packet
623  error = stm32h5xxEthReceivePacket(interface);
624 
625  //No more data in the receive buffer?
626  } while(error != ERROR_BUFFER_EMPTY);
627 }
628 
629 
630 /**
631  * @brief Send a packet
632  * @param[in] interface Underlying network interface
633  * @param[in] buffer Multi-part buffer containing the data to send
634  * @param[in] offset Offset to the first data byte
635  * @param[in] ancillary Additional options passed to the stack along with
636  * the packet
637  * @return Error code
638  **/
639 
641  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
642 {
643  size_t length;
644 
645  //Retrieve the length of the packet
646  length = netBufferGetLength(buffer) - offset;
647 
648  //Check the frame length
650  {
651  //The transmitter can accept another packet
652  osSetEvent(&interface->nicTxEvent);
653  //Report an error
654  return ERROR_INVALID_LENGTH;
655  }
656 
657  //Make sure the current buffer is available for writing
658  if((txDmaDesc[txIndex].tdes3 & ETH_TDES3_OWN) != 0)
659  {
660  return ERROR_FAILURE;
661  }
662 
663  //Copy user data to the transmit buffer
664  netBufferRead(txBuffer[txIndex], buffer, offset, length);
665 
666  //Set the start address of the buffer
667  txDmaDesc[txIndex].tdes0 = (uint32_t) txBuffer[txIndex];
668  //Write the number of bytes to send
669  txDmaDesc[txIndex].tdes2 = ETH_TDES2_IOC | (length & ETH_TDES2_B1L);
670  //Give the ownership of the descriptor to the DMA
671  txDmaDesc[txIndex].tdes3 = ETH_TDES3_OWN | ETH_TDES3_FD | ETH_TDES3_LD;
672 
673  //Data synchronization barrier
674  __DSB();
675 
676  //Clear TBU flag to resume processing
677  ETH->DMACSR = ETH_DMACSR_TBU;
678  //Instruct the DMA to poll the transmit descriptor list
679  ETH->DMACTDTPR = 0;
680 
681  //Increment index and wrap around if necessary
682  if(++txIndex >= STM32H5XX_ETH_TX_BUFFER_COUNT)
683  {
684  txIndex = 0;
685  }
686 
687  //Check whether the next buffer is available for writing
688  if((txDmaDesc[txIndex].tdes3 & ETH_TDES3_OWN) == 0)
689  {
690  //The transmitter can accept another packet
691  osSetEvent(&interface->nicTxEvent);
692  }
693 
694  //Data successfully written
695  return NO_ERROR;
696 }
697 
698 
699 /**
700  * @brief Receive a packet
701  * @param[in] interface Underlying network interface
702  * @return Error code
703  **/
704 
706 {
707  error_t error;
708  size_t n;
709  uint32_t status;
710  NetRxAncillary ancillary;
711 
712  //Current buffer available for reading?
713  if((rxDmaDesc[rxIndex].rdes3 & ETH_RDES3_OWN) == 0)
714  {
715  //FD and LD flags should be set
716  if((rxDmaDesc[rxIndex].rdes3 & ETH_RDES3_FD) != 0 &&
717  (rxDmaDesc[rxIndex].rdes3 & ETH_RDES3_LD) != 0)
718  {
719  //Check error bits
720  status = rxDmaDesc[rxIndex].rdes3 & (ETH_RDES3_CE | ETH_RDES3_GP |
722 
723  //The dribble bit error is valid only in the MII mode
724  if((SBS->PMCR & SBS_PMCR_ETH_SEL_PHY) != SBS_ETH_MII)
725  {
726  status &= ~ETH_RDES3_DE;
727  }
728 
729  //Make sure no error occurred
730  if(status == 0)
731  {
732  //Retrieve the length of the frame
733  n = rxDmaDesc[rxIndex].rdes3 & ETH_RDES3_PL;
734  //Limit the number of data to read
736 
737  //Additional options can be passed to the stack along with the packet
738  ancillary = NET_DEFAULT_RX_ANCILLARY;
739 
740  //Pass the packet to the upper layer
741  nicProcessPacket(interface, rxBuffer[rxIndex], n, &ancillary);
742 
743  //Valid packet received
744  error = NO_ERROR;
745  }
746  else
747  {
748  //The received packet contains an error
749  error = ERROR_INVALID_PACKET;
750  }
751  }
752  else
753  {
754  //The packet is not valid
755  error = ERROR_INVALID_PACKET;
756  }
757 
758  //Set the start address of the buffer
759  rxDmaDesc[rxIndex].rdes0 = (uint32_t) rxBuffer[rxIndex];
760  //Give the ownership of the descriptor back to the DMA
762 
763  //Increment index and wrap around if necessary
764  if(++rxIndex >= STM32H5XX_ETH_RX_BUFFER_COUNT)
765  {
766  rxIndex = 0;
767  }
768  }
769  else
770  {
771  //No more data in the receive buffer
772  error = ERROR_BUFFER_EMPTY;
773  }
774 
775  //Clear RBU flag to resume processing
776  ETH->DMACSR = ETH_DMACSR_RBU;
777  //Instruct the DMA to poll the receive descriptor list
778  ETH->DMACRDTPR = 0;
779 
780  //Return status code
781  return error;
782 }
783 
784 
785 /**
786  * @brief Configure MAC address filtering
787  * @param[in] interface Underlying network interface
788  * @return Error code
789  **/
790 
792 {
793  uint_t i;
794  uint_t j;
795  uint_t k;
796  uint32_t crc;
797  uint32_t hashTable[2];
798  MacAddr unicastMacAddr[3];
799  MacFilterEntry *entry;
800 
801  //Debug message
802  TRACE_DEBUG("Updating MAC filter...\r\n");
803 
804  //Promiscuous mode?
805  if(interface->promiscuous)
806  {
807  //Pass all incoming frames regardless of their destination address
808  ETH->MACPFR = ETH_MACPFR_PR;
809  }
810  else
811  {
812  //Set the MAC address of the station
813  ETH->MACA0LR = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
814  ETH->MACA0HR = interface->macAddr.w[2];
815 
816  //The MAC supports 3 additional addresses for unicast perfect filtering
817  unicastMacAddr[0] = MAC_UNSPECIFIED_ADDR;
818  unicastMacAddr[1] = MAC_UNSPECIFIED_ADDR;
819  unicastMacAddr[2] = MAC_UNSPECIFIED_ADDR;
820 
821  //The hash table is used for multicast address filtering
822  hashTable[0] = 0;
823  hashTable[1] = 0;
824 
825  //The MAC address filter contains the list of MAC addresses to accept
826  //when receiving an Ethernet frame
827  for(i = 0, j = 0; i < MAC_ADDR_FILTER_SIZE; i++)
828  {
829  //Point to the current entry
830  entry = &interface->macAddrFilter[i];
831 
832  //Valid entry?
833  if(entry->refCount > 0)
834  {
835  //Multicast address?
836  if(macIsMulticastAddr(&entry->addr))
837  {
838  //Compute CRC over the current MAC address
839  crc = stm32h5xxEthCalcCrc(&entry->addr, sizeof(MacAddr));
840 
841  //The upper 6 bits in the CRC register are used to index the
842  //contents of the hash table
843  k = (crc >> 26) & 0x3F;
844 
845  //Update hash table contents
846  hashTable[k / 32] |= (1 << (k % 32));
847  }
848  else
849  {
850  //Up to 3 additional MAC addresses can be specified
851  if(j < 3)
852  {
853  //Save the unicast address
854  unicastMacAddr[j++] = entry->addr;
855  }
856  }
857  }
858  }
859 
860  //Configure the first unicast address filter
861  if(j >= 1)
862  {
863  //When the AE bit is set, the entry is used for perfect filtering
864  ETH->MACA1LR = unicastMacAddr[0].w[0] | (unicastMacAddr[0].w[1] << 16);
865  ETH->MACA1HR = unicastMacAddr[0].w[2] | ETH_MACAHR_AE;
866  }
867  else
868  {
869  //When the AE bit is cleared, the entry is ignored
870  ETH->MACA1LR = 0;
871  ETH->MACA1HR = 0;
872  }
873 
874  //Configure the second unicast address filter
875  if(j >= 2)
876  {
877  //When the AE bit is set, the entry is used for perfect filtering
878  ETH->MACA2LR = unicastMacAddr[1].w[0] | (unicastMacAddr[1].w[1] << 16);
879  ETH->MACA2HR = unicastMacAddr[1].w[2] | ETH_MACAHR_AE;
880  }
881  else
882  {
883  //When the AE bit is cleared, the entry is ignored
884  ETH->MACA2LR = 0;
885  ETH->MACA2HR = 0;
886  }
887 
888  //Configure the third unicast address filter
889  if(j >= 3)
890  {
891  //When the AE bit is set, the entry is used for perfect filtering
892  ETH->MACA3LR = unicastMacAddr[2].w[0] | (unicastMacAddr[2].w[1] << 16);
893  ETH->MACA3HR = unicastMacAddr[2].w[2] | ETH_MACAHR_AE;
894  }
895  else
896  {
897  //When the AE bit is cleared, the entry is ignored
898  ETH->MACA3LR = 0;
899  ETH->MACA3HR = 0;
900  }
901 
902  //Check whether frames with a multicast destination address should be
903  //accepted
904  if(interface->acceptAllMulticast)
905  {
906  //Configure the receive filter
907  ETH->MACPFR = ETH_MACPFR_HPF | ETH_MACPFR_PM;
908  }
909  else
910  {
911  //Configure the receive filter
912  ETH->MACPFR = ETH_MACPFR_HPF | ETH_MACPFR_HMC;
913 
914  //Configure the multicast hash table
915  ETH->MACHT0R = hashTable[0];
916  ETH->MACHT1R = hashTable[1];
917 
918  //Debug message
919  TRACE_DEBUG(" MACHT0R = 0x%08" PRIX32 "\r\n", ETH->MACHT0R);
920  TRACE_DEBUG(" MACHT1R = 0x%08" PRIX32 "\r\n", ETH->MACHT1R);
921  }
922  }
923 
924  //Successful processing
925  return NO_ERROR;
926 }
927 
928 
929 /**
930  * @brief Adjust MAC configuration parameters for proper operation
931  * @param[in] interface Underlying network interface
932  * @return Error code
933  **/
934 
936 {
937  uint32_t config;
938 
939  //Read current MAC configuration
940  config = ETH->MACCR;
941 
942  //10BASE-T or 100BASE-TX operation mode?
943  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
944  {
945  config |= ETH_MACCR_FES;
946  }
947  else
948  {
949  config &= ~ETH_MACCR_FES;
950  }
951 
952  //Half-duplex or full-duplex mode?
953  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
954  {
955  config |= ETH_MACCR_DM;
956  }
957  else
958  {
959  config &= ~ETH_MACCR_DM;
960  }
961 
962  //Update MAC configuration register
963  ETH->MACCR = config;
964 
965  //Successful processing
966  return NO_ERROR;
967 }
968 
969 
970 /**
971  * @brief Write PHY register
972  * @param[in] opcode Access type (2 bits)
973  * @param[in] phyAddr PHY address (5 bits)
974  * @param[in] regAddr Register address (5 bits)
975  * @param[in] data Register value
976  **/
977 
978 void stm32h5xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
979  uint8_t regAddr, uint16_t data)
980 {
981  uint32_t temp;
982 
983  //Valid opcode?
984  if(opcode == SMI_OPCODE_WRITE)
985  {
986  //Take care not to alter MDC clock configuration
987  temp = ETH->MACMDIOAR & ETH_MACMDIOAR_CR;
988  //Set up a write operation
989  temp |= ETH_MACMDIOAR_MOC_WR | ETH_MACMDIOAR_MB;
990  //PHY address
991  temp |= (phyAddr << 21) & ETH_MACMDIOAR_PA;
992  //Register address
993  temp |= (regAddr << 16) & ETH_MACMDIOAR_RDA;
994 
995  //Data to be written in the PHY register
996  ETH->MACMDIODR = data & ETH_MACMDIODR_MD;
997 
998  //Start a write operation
999  ETH->MACMDIOAR = temp;
1000  //Wait for the write to complete
1001  while((ETH->MACMDIOAR & ETH_MACMDIOAR_MB) != 0)
1002  {
1003  }
1004  }
1005  else
1006  {
1007  //The MAC peripheral only supports standard Clause 22 opcodes
1008  }
1009 }
1010 
1011 
1012 /**
1013  * @brief Read PHY register
1014  * @param[in] opcode Access type (2 bits)
1015  * @param[in] phyAddr PHY address (5 bits)
1016  * @param[in] regAddr Register address (5 bits)
1017  * @return Register value
1018  **/
1019 
1020 uint16_t stm32h5xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
1021  uint8_t regAddr)
1022 {
1023  uint16_t data;
1024  uint32_t temp;
1025 
1026  //Valid opcode?
1027  if(opcode == SMI_OPCODE_READ)
1028  {
1029  //Take care not to alter MDC clock configuration
1030  temp = ETH->MACMDIOAR & ETH_MACMDIOAR_CR;
1031  //Set up a read operation
1032  temp |= ETH_MACMDIOAR_MOC_RD | ETH_MACMDIOAR_MB;
1033  //PHY address
1034  temp |= (phyAddr << 21) & ETH_MACMDIOAR_PA;
1035  //Register address
1036  temp |= (regAddr << 16) & ETH_MACMDIOAR_RDA;
1037 
1038  //Start a read operation
1039  ETH->MACMDIOAR = temp;
1040  //Wait for the read to complete
1041  while((ETH->MACMDIOAR & ETH_MACMDIOAR_MB) != 0)
1042  {
1043  }
1044 
1045  //Get register value
1046  data = ETH->MACMDIODR & ETH_MACMDIODR_MD;
1047  }
1048  else
1049  {
1050  //The MAC peripheral only supports standard Clause 22 opcodes
1051  data = 0;
1052  }
1053 
1054  //Return the value of the PHY register
1055  return data;
1056 }
1057 
1058 
1059 /**
1060  * @brief CRC calculation
1061  * @param[in] data Pointer to the data over which to calculate the CRC
1062  * @param[in] length Number of bytes to process
1063  * @return Resulting CRC value
1064  **/
1065 
1066 uint32_t stm32h5xxEthCalcCrc(const void *data, size_t length)
1067 {
1068  uint_t i;
1069  uint_t j;
1070  uint32_t crc;
1071  const uint8_t *p;
1072 
1073  //Point to the data over which to calculate the CRC
1074  p = (uint8_t *) data;
1075  //CRC preset value
1076  crc = 0xFFFFFFFF;
1077 
1078  //Loop through data
1079  for(i = 0; i < length; i++)
1080  {
1081  //The message is processed bit by bit
1082  for(j = 0; j < 8; j++)
1083  {
1084  //Update CRC value
1085  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
1086  {
1087  crc = (crc << 1) ^ 0x04C11DB7;
1088  }
1089  else
1090  {
1091  crc = crc << 1;
1092  }
1093  }
1094  }
1095 
1096  //Return CRC value
1097  return ~crc;
1098 }
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
STM32H5 Ethernet MAC driver.
uint8_t opcode
Definition: dns_common.h:191
int bool_t
Definition: compiler_port.h:63
#define ETH_RDES3_DE
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
#define STM32H5XX_ETH_IRQ_SUB_PRIORITY
size_t netBufferRead(void *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Read data from a multi-part buffer.
Definition: net_mem.c:690
uint16_t stm32h5xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
#define ETH_RDES3_LD
#define STM32H5XX_ETH_TX_BUFFER_COUNT
uint8_t p
Definition: ndp.h:300
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
#define TRUE
Definition: os_port.h:50
void stm32h5xxEthEnableIrq(NetInterface *interface)
Enable interrupts.
uint8_t data[]
Definition: ethernet.h:224
#define ETH_TDES3_LD
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:266
#define STM32H5XX_ETH_TX_BUFFER_SIZE
#define ETH_RDES3_GP
#define ETH_RDES3_CE
error_t stm32h5xxEthReceivePacket(NetInterface *interface)
Receive a packet.
#define ETH_MACCR_RESERVED15
void ETH_IRQHandler(void)
STM32H5 Ethernet MAC interrupt service routine.
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:418
#define macIsMulticastAddr(macAddr)
Definition: ethernet.h:133
#define osExitIsr(flag)
#define STM32H5XX_ETH_RX_BUFFER_SIZE
#define SMI_OPCODE_WRITE
Definition: nic.h:66
error_t stm32h5xxEthInit(NetInterface *interface)
STM32H5 Ethernet MAC initialization.
#define ETH_RDES3_RE
error_t stm32h5xxEthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
#define FALSE
Definition: os_port.h:46
#define ETH_RDES3_RWT
error_t
Error codes.
Definition: error.h:43
#define ETH_TDES2_B1L
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:103
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
const NicDriver stm32h5xxEthDriver
STM32H5 Ethernet MAC driver.
void stm32h5xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
#define txBuffer
#define NetRxAncillary
Definition: net_misc.h:40
@ ERROR_INVALID_PACKET
Definition: error.h:141
#define NetInterface
Definition: net.h:40
void stm32h5xxEthInitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
MacAddr addr
MAC address.
Definition: ethernet.h:265
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_BUFFER_EMPTY
Definition: error.h:142
#define STM32H5XX_ETH_IRQ_GROUP_PRIORITY
#define NetTxAncillary
Definition: net_misc.h:36
#define ETH_RDES3_BUF1V
#define SMI_OPCODE_READ
Definition: nic.h:67
#define ETH_TDES2_IOC
#define TRACE_INFO(...)
Definition: debug.h:105
uint8_t length
Definition: tcp.h:375
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
#define MIN(a, b)
Definition: os_port.h:63
#define ETH_RDES3_OWN
#define ETH_TDES3_OWN
#define rxBuffer
MacAddr
Definition: ethernet.h:197
#define TRACE_DEBUG(...)
Definition: debug.h:119
__weak_func void stm32h5xxEthInitGpio(NetInterface *interface)
GPIO configuration.
void stm32h5xxEthEventHandler(NetInterface *interface)
STM32H5 Ethernet MAC event handler.
uint16_t regAddr
#define ETH_MTU
Definition: ethernet.h:116
error_t stm32h5xxEthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
uint8_t n
MAC filter table entry.
Definition: ethernet.h:264
void stm32h5xxEthTick(NetInterface *interface)
STM32H5 Ethernet MAC timer handler.
#define STM32H5XX_ETH_RX_BUFFER_COUNT
#define ETH_RDES3_FD
#define STM32H5XX_ETH_IRQ_PRIORITY_GROUPING
Transmit descriptor.
#define osEnterIsr()
#define rxDmaDesc
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define ETH_TDES3_FD
void stm32h5xxEthDisableIrq(NetInterface *interface)
Disable interrupts.
#define ETH_RDES3_OE
#define txDmaDesc
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
error_t stm32h5xxEthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
unsigned int uint_t
Definition: compiler_port.h:57
TCP/IP stack core.
NIC driver.
Definition: nic.h:286
Receive descriptor.
#define ETH_RDES3_IOC
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:51
uint32_t stm32h5xxEthCalcCrc(const void *data, size_t length)
CRC calculation.
@ NO_ERROR
Success.
Definition: error.h:44
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
Debugging facilities.
#define ETH_RDES3_PL
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83