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