stm32f7xx_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file stm32f7xx_eth_driver.c
3  * @brief STM32F7 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.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include "stm32f7xx.h"
36 #include "stm32f7xx_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 = STM32F7XX_ETH_RAM_SECTION
51 //Receive buffer
52 #pragma data_alignment = 4
53 #pragma location = STM32F7XX_ETH_RAM_SECTION
55 //Transmit DMA descriptors
56 #pragma data_alignment = 4
57 #pragma location = STM32F7XX_ETH_RAM_SECTION
59 //Receive DMA descriptors
60 #pragma data_alignment = 4
61 #pragma location = STM32F7XX_ETH_RAM_SECTION
63 
64 //Keil MDK-ARM or GCC compiler?
65 #else
66 
67 //Transmit buffer
69  __attribute__((aligned(4), __section__(STM32F7XX_ETH_RAM_SECTION)));
70 //Receive buffer
72  __attribute__((aligned(4), __section__(STM32F7XX_ETH_RAM_SECTION)));
73 //Transmit DMA descriptors
75  __attribute__((aligned(4), __section__(STM32F7XX_ETH_RAM_SECTION)));
76 //Receive DMA descriptors
78  __attribute__((aligned(4), __section__(STM32F7XX_ETH_RAM_SECTION)));
79 
80 #endif
81 
82 //Pointer to the current TX DMA descriptor
83 static Stm32f7xxTxDmaDesc *txCurDmaDesc;
84 //Pointer to the current RX DMA descriptor
85 static Stm32f7xxRxDmaDesc *rxCurDmaDesc;
86 
87 
88 /**
89  * @brief STM32F7 Ethernet MAC driver
90  **/
91 
93 {
95  ETH_MTU,
106  TRUE,
107  TRUE,
108  TRUE,
109  FALSE
110 };
111 
112 
113 /**
114  * @brief STM32F7 Ethernet MAC initialization
115  * @param[in] interface Underlying network interface
116  * @return Error code
117  **/
118 
120 {
121  error_t error;
122 
123  //Debug message
124  TRACE_INFO("Initializing STM32F7 Ethernet MAC...\r\n");
125 
126  //Save underlying network interface
127  nicDriverInterface = interface;
128 
129  //GPIO configuration
130  stm32f7xxEthInitGpio(interface);
131 
132  //Enable Ethernet MAC clock
133  __HAL_RCC_ETHMAC_CLK_ENABLE();
134  __HAL_RCC_ETHMACTX_CLK_ENABLE();
135  __HAL_RCC_ETHMACRX_CLK_ENABLE();
136 
137  //Reset Ethernet MAC peripheral
138  __HAL_RCC_ETHMAC_FORCE_RESET();
139  __HAL_RCC_ETHMAC_RELEASE_RESET();
140 
141  //Perform a software reset
142  ETH->DMABMR |= ETH_DMABMR_SR;
143  //Wait for the reset to complete
144  while((ETH->DMABMR & ETH_DMABMR_SR) != 0)
145  {
146  }
147 
148  //Adjust MDC clock range depending on HCLK frequency
149  ETH->MACMIIAR = ETH_MACMIIAR_CR_Div102;
150 
151  //Valid Ethernet PHY or switch driver?
152  if(interface->phyDriver != NULL)
153  {
154  //Ethernet PHY initialization
155  error = interface->phyDriver->init(interface);
156  }
157  else if(interface->switchDriver != NULL)
158  {
159  //Ethernet switch initialization
160  error = interface->switchDriver->init(interface);
161  }
162  else
163  {
164  //The interface is not properly configured
165  error = ERROR_FAILURE;
166  }
167 
168  //Any error to report?
169  if(error)
170  {
171  return error;
172  }
173 
174  //Use default MAC configuration
175  ETH->MACCR = ETH_MACCR_RESERVED15 | ETH_MACCR_ROD;
176 
177  //Configure MAC address filtering
179 
180  //Disable flow control
181  ETH->MACFCR = 0;
182  //Enable store and forward mode
183  ETH->DMAOMR = ETH_DMAOMR_RSF | ETH_DMAOMR_TSF;
184 
185  //Configure DMA bus mode
186  ETH->DMABMR = ETH_DMABMR_AAB | ETH_DMABMR_USP | ETH_DMABMR_RDP_32Beat |
187  ETH_DMABMR_RTPR_1_1 | ETH_DMABMR_PBL_32Beat | ETH_DMABMR_EDE;
188 
189  //Initialize DMA descriptor lists
190  stm32f7xxEthInitDmaDesc(interface);
191 
192  //Prevent interrupts from being generated when the transmit statistic
193  //counters reach half their maximum value
194  ETH->MMCTIMR = ETH_MMCTIMR_TGFM | ETH_MMCTIMR_TGFMSCM | ETH_MMCTIMR_TGFSCM;
195 
196  //Prevent interrupts from being generated when the receive statistic
197  //counters reach half their maximum value
198  ETH->MMCRIMR = ETH_MMCRIMR_RGUFM | ETH_MMCRIMR_RFAEM | ETH_MMCRIMR_RFCEM;
199 
200  //Disable MAC interrupts
201  ETH->MACIMR = ETH_MACIMR_TSTIM | ETH_MACIMR_PMTIM;
202  //Enable the desired DMA interrupts
203  ETH->DMAIER = ETH_DMAIER_NISE | ETH_DMAIER_RIE | ETH_DMAIER_TIE;
204 
205  //Set priority grouping (4 bits for pre-emption priority, no bits for subpriority)
206  NVIC_SetPriorityGrouping(STM32F7XX_ETH_IRQ_PRIORITY_GROUPING);
207 
208  //Configure Ethernet interrupt priority
209  NVIC_SetPriority(ETH_IRQn, NVIC_EncodePriority(STM32F7XX_ETH_IRQ_PRIORITY_GROUPING,
211 
212  //Enable MAC transmission and reception
213  ETH->MACCR |= ETH_MACCR_TE | ETH_MACCR_RE;
214  //Enable DMA transmission and reception
215  ETH->DMAOMR |= ETH_DMAOMR_ST | ETH_DMAOMR_SR;
216 
217  //Accept any packets from the upper layer
218  osSetEvent(&interface->nicTxEvent);
219 
220  //Successful initialization
221  return NO_ERROR;
222 }
223 
224 
225 /**
226  * @brief GPIO configuration
227  * @param[in] interface Underlying network interface
228  **/
229 
230 __weak_func void stm32f7xxEthInitGpio(NetInterface *interface)
231 {
232 //Nucleo-F746ZG, Nucleo-F756ZG or Nucleo-F767ZI evaluation board?
233 #if defined(USE_STM32F7XX_NUCLEO_144)
234  GPIO_InitTypeDef GPIO_InitStructure;
235 
236  //Enable SYSCFG clock
237  __HAL_RCC_SYSCFG_CLK_ENABLE();
238 
239  //Enable GPIO clocks
240  __HAL_RCC_GPIOA_CLK_ENABLE();
241  __HAL_RCC_GPIOB_CLK_ENABLE();
242  __HAL_RCC_GPIOC_CLK_ENABLE();
243  __HAL_RCC_GPIOG_CLK_ENABLE();
244 
245  //Select RMII interface mode
246  SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL;
247 
248  //Configure RMII pins
249  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
250  GPIO_InitStructure.Pull = GPIO_NOPULL;
251  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
252  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
253 
254  //Configure ETH_RMII_REF_CLK (PA1), ETH_MDIO (PA2) and ETH_RMII_CRS_DV (PA7)
255  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
256  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
257 
258  //Configure ETH_RMII_TXD1 (PB13)
259  GPIO_InitStructure.Pin = GPIO_PIN_13;
260  HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
261 
262  //Configure ETH_MDC (PC1), ETH_RMII_RXD0 (PC4) and ETH_RMII_RXD1 (PC5)
263  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
264  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
265 
266  //Configure RMII_TX_EN (PG11) and ETH_RMII_TXD0 (PG13)
267  GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13;
268  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
269 
270 //STM32F746G-Discovery or STM32F7508-Discovery evaluation board?
271 #elif defined(USE_STM32746G_DISCO) || defined(USE_STM32F7508_DISCO)
272  GPIO_InitTypeDef GPIO_InitStructure;
273 
274  //Enable SYSCFG clock
275  __HAL_RCC_SYSCFG_CLK_ENABLE();
276 
277  //Enable GPIO clocks
278  __HAL_RCC_GPIOA_CLK_ENABLE();
279  __HAL_RCC_GPIOC_CLK_ENABLE();
280  __HAL_RCC_GPIOG_CLK_ENABLE();
281 
282  //Select RMII interface mode
283  SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL;
284 
285  //Configure RMII pins
286  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
287  GPIO_InitStructure.Pull = GPIO_NOPULL;
288  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
289  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
290 
291  //Configure ETH_RMII_REF_CLK (PA1), ETH_MDIO (PA2) and ETH_RMII_CRS_DV (PA7)
292  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
293  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
294 
295  //Configure ETH_MDC (PC1), ETH_RMII_RXD0 (PC4) and ETH_RMII_RXD1 (PC5)
296  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
297  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
298 
299  //Configure ETH_RMII_RX_ER (PG2), ETH_RMII_TX_EN (PG11), ETH_RMII_TXD0 (PG13)
300  //and ETH_RMII_TXD1 (PG14)
301  GPIO_InitStructure.Pin = GPIO_PIN_2 | GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14;
302  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
303 
304 //STM32F769I-Discovery evaluation board?
305 #elif defined(USE_STM32F769I_DISCO)
306  GPIO_InitTypeDef GPIO_InitStructure;
307 
308  //Enable SYSCFG clock
309  __HAL_RCC_SYSCFG_CLK_ENABLE();
310 
311  //Enable GPIO clocks
312  __HAL_RCC_GPIOA_CLK_ENABLE();
313  __HAL_RCC_GPIOC_CLK_ENABLE();
314  __HAL_RCC_GPIOD_CLK_ENABLE();
315  __HAL_RCC_GPIOG_CLK_ENABLE();
316 
317  //Select RMII interface mode
318  SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL;
319 
320  //Configure RMII pins
321  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
322  GPIO_InitStructure.Pull = GPIO_NOPULL;
323  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
324  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
325 
326  //Configure ETH_RMII_REF_CLK (PA1), ETH_MDIO (PA2) and ETH_RMII_CRS_DV (PA7)
327  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
328  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
329 
330  //Configure ETH_MDC (PC1), ETH_RMII_RXD0 (PC4) and ETH_RMII_RXD1 (PC5)
331  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
332  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
333 
334  //Configure ETH_RMII_RX_ER (PD5)
335  GPIO_InitStructure.Pin = GPIO_PIN_5;
336  HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
337 
338  //Configure ETH_RMII_TX_EN (PG11), ETH_RMII_TXD0 (PG13) and ETH_RMII_TXD1 (PG14)
339  GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14;
340  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
341 
342 //STM32756G-EVAL or STM32F769I-EVAL evaluation board?
343 #elif defined(USE_STM32756G_EVAL) || defined(USE_STM32F769I_EVAL)
344  GPIO_InitTypeDef GPIO_InitStructure;
345 
346  //Enable SYSCFG clock
347  __HAL_RCC_SYSCFG_CLK_ENABLE();
348 
349  //Enable GPIO clocks
350  __HAL_RCC_GPIOA_CLK_ENABLE();
351  __HAL_RCC_GPIOC_CLK_ENABLE();
352  __HAL_RCC_GPIOE_CLK_ENABLE();
353  __HAL_RCC_GPIOG_CLK_ENABLE();
354  __HAL_RCC_GPIOH_CLK_ENABLE();
355  __HAL_RCC_GPIOI_CLK_ENABLE();
356 
357  //Configure MCO1 (PA8) as an output
358  GPIO_InitStructure.Pin = GPIO_PIN_8;
359  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
360  GPIO_InitStructure.Pull = GPIO_NOPULL;
361  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
362  GPIO_InitStructure.Alternate = GPIO_AF0_MCO;
363  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
364 
365  //Configure MCO1 pin to output the HSE clock (25MHz)
366  HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSE, RCC_MCODIV_1);
367 
368  //Select MII interface mode
369  SYSCFG->PMC &= ~SYSCFG_PMC_MII_RMII_SEL;
370 
371  //Configure MDIO/MDC pins
372  if(interface->smiDriver == NULL)
373  {
374  //Configure ETH_MDIO (PA2)
375  GPIO_InitStructure.Pin = GPIO_PIN_2;
376  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
377  GPIO_InitStructure.Pull = GPIO_PULLUP;
378  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM;
379  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
380  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
381 
382  //Configure ETH_MDC (PC1)
383  GPIO_InitStructure.Pin = GPIO_PIN_1;
384  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
385  GPIO_InitStructure.Pull = GPIO_NOPULL;
386  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM;
387  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
388  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
389  }
390 
391  //Configure MII pins
392  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
393  GPIO_InitStructure.Pull = GPIO_NOPULL;
394  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
395  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
396 
397  //Configure ETH_MII_CRS (PA0)
398  //GPIO_InitStructure.Pin = GPIO_PIN_0;
399  //HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
400 
401  //Configure ETH_MII_RX_CLK (PA1) and ETH_MII_RX_DV (PA7)
402  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_7;
403  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
404 
405  //Configure ETH_MII_TXD2 (PC2), ETH_MII_TX_CLK (PC3), ETH_MII_RXD0 (PC4)
406  //and ETH_MII_RXD1 (PC5)
407  GPIO_InitStructure.Pin = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5;
408  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
409 
410  //Configure ETH_MII_TXD3 (PE2)
411  GPIO_InitStructure.Pin = GPIO_PIN_2;
412  HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
413 
414  //Configure ETH_MII_TX_EN (PG11), ETH_MII_TXD0 (PG13) and ETH_MII_TXD1 (PG14)
415  GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14;
416  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
417 
418  //Configure ETH_MII_COL (PH3)
419  //GPIO_InitStructure.Pin = GPIO_PIN_3;
420  //HAL_GPIO_Init(GPIOH, &GPIO_InitStructure);
421 
422  //Configure ETH_MII_RXD2 (PH6) and ETH_MII_RXD3 (PH7)
423  GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7;
424  HAL_GPIO_Init(GPIOH, &GPIO_InitStructure);
425 
426  //Configure ETH_MII_RX_ER (PI10)
427  //GPIO_InitStructure.Pin = GPIO_PIN_10;
428  //HAL_GPIO_Init(GPIOI, &GPIO_InitStructure);
429 #endif
430 }
431 
432 
433 /**
434  * @brief Initialize DMA descriptor lists
435  * @param[in] interface Underlying network interface
436  **/
437 
439 {
440  uint_t i;
441 
442  //Initialize TX DMA descriptor list
443  for(i = 0; i < STM32F7XX_ETH_TX_BUFFER_COUNT; i++)
444  {
445  //Use chain structure rather than ring structure
446  txDmaDesc[i].tdes0 = ETH_TDES0_IC | ETH_TDES0_TCH;
447  //Initialize transmit buffer size
448  txDmaDesc[i].tdes1 = 0;
449  //Transmit buffer address
450  txDmaDesc[i].tdes2 = (uint32_t) txBuffer[i];
451  //Next descriptor address
452  txDmaDesc[i].tdes3 = (uint32_t) &txDmaDesc[i + 1];
453  //Reserved fields
454  txDmaDesc[i].tdes4 = 0;
455  txDmaDesc[i].tdes5 = 0;
456  //Transmit frame time stamp
457  txDmaDesc[i].tdes6 = 0;
458  txDmaDesc[i].tdes7 = 0;
459  }
460 
461  //The last descriptor is chained to the first entry
462  txDmaDesc[i - 1].tdes3 = (uint32_t) &txDmaDesc[0];
463  //Point to the very first descriptor
464  txCurDmaDesc = &txDmaDesc[0];
465 
466  //Initialize RX DMA descriptor list
467  for(i = 0; i < STM32F7XX_ETH_RX_BUFFER_COUNT; i++)
468  {
469  //The descriptor is initially owned by the DMA
470  rxDmaDesc[i].rdes0 = ETH_RDES0_OWN;
471  //Use chain structure rather than ring structure
473  //Receive buffer address
474  rxDmaDesc[i].rdes2 = (uint32_t) rxBuffer[i];
475  //Next descriptor address
476  rxDmaDesc[i].rdes3 = (uint32_t) &rxDmaDesc[i + 1];
477  //Extended status
478  rxDmaDesc[i].rdes4 = 0;
479  //Reserved field
480  rxDmaDesc[i].rdes5 = 0;
481  //Receive frame time stamp
482  rxDmaDesc[i].rdes6 = 0;
483  rxDmaDesc[i].rdes7 = 0;
484  }
485 
486  //The last descriptor is chained to the first entry
487  rxDmaDesc[i - 1].rdes3 = (uint32_t) &rxDmaDesc[0];
488  //Point to the very first descriptor
489  rxCurDmaDesc = &rxDmaDesc[0];
490 
491  //Start location of the TX descriptor list
492  ETH->DMATDLAR = (uint32_t) txDmaDesc;
493  //Start location of the RX descriptor list
494  ETH->DMARDLAR = (uint32_t) rxDmaDesc;
495 }
496 
497 
498 /**
499  * @brief STM32F7 Ethernet MAC timer handler
500  *
501  * This routine is periodically called by the TCP/IP stack to handle periodic
502  * operations such as polling the link state
503  *
504  * @param[in] interface Underlying network interface
505  **/
506 
508 {
509  //Valid Ethernet PHY or switch driver?
510  if(interface->phyDriver != NULL)
511  {
512  //Handle periodic operations
513  interface->phyDriver->tick(interface);
514  }
515  else if(interface->switchDriver != NULL)
516  {
517  //Handle periodic operations
518  interface->switchDriver->tick(interface);
519  }
520  else
521  {
522  //Just for sanity
523  }
524 }
525 
526 
527 /**
528  * @brief Enable interrupts
529  * @param[in] interface Underlying network interface
530  **/
531 
533 {
534  //Enable Ethernet MAC interrupts
535  NVIC_EnableIRQ(ETH_IRQn);
536 
537  //Valid Ethernet PHY or switch driver?
538  if(interface->phyDriver != NULL)
539  {
540  //Enable Ethernet PHY interrupts
541  interface->phyDriver->enableIrq(interface);
542  }
543  else if(interface->switchDriver != NULL)
544  {
545  //Enable Ethernet switch interrupts
546  interface->switchDriver->enableIrq(interface);
547  }
548  else
549  {
550  //Just for sanity
551  }
552 }
553 
554 
555 /**
556  * @brief Disable interrupts
557  * @param[in] interface Underlying network interface
558  **/
559 
561 {
562  //Disable Ethernet MAC interrupts
563  NVIC_DisableIRQ(ETH_IRQn);
564 
565  //Valid Ethernet PHY or switch driver?
566  if(interface->phyDriver != NULL)
567  {
568  //Disable Ethernet PHY interrupts
569  interface->phyDriver->disableIrq(interface);
570  }
571  else if(interface->switchDriver != NULL)
572  {
573  //Disable Ethernet switch interrupts
574  interface->switchDriver->disableIrq(interface);
575  }
576  else
577  {
578  //Just for sanity
579  }
580 }
581 
582 
583 /**
584  * @brief STM32F7 Ethernet MAC interrupt service routine
585  **/
586 
587 void ETH_IRQHandler(void)
588 {
589  bool_t flag;
590  uint32_t status;
591 
592  //Interrupt service routine prologue
593  osEnterIsr();
594 
595  //This flag will be set if a higher priority task must be woken
596  flag = FALSE;
597 
598  //Read DMA status register
599  status = ETH->DMASR;
600 
601  //Packet transmitted?
602  if((status & ETH_DMASR_TS) != 0)
603  {
604  //Clear TS interrupt flag
605  ETH->DMASR = ETH_DMASR_TS;
606 
607  //Check whether the TX buffer is available for writing
608  if((txCurDmaDesc->tdes0 & ETH_TDES0_OWN) == 0)
609  {
610  //Notify the TCP/IP stack that the transmitter is ready to send
611  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
612  }
613  }
614 
615  //Packet received?
616  if((status & ETH_DMASR_RS) != 0)
617  {
618  //Clear RS interrupt flag
619  ETH->DMASR = ETH_DMASR_RS;
620 
621  //Set event flag
622  nicDriverInterface->nicEvent = TRUE;
623  //Notify the TCP/IP stack of the event
624  flag |= osSetEventFromIsr(&netEvent);
625  }
626 
627  //Clear NIS interrupt flag
628  ETH->DMASR = ETH_DMASR_NIS;
629 
630  //Interrupt service routine epilogue
631  osExitIsr(flag);
632 }
633 
634 
635 /**
636  * @brief STM32F7 Ethernet MAC event handler
637  * @param[in] interface Underlying network interface
638  **/
639 
641 {
642  error_t error;
643 
644  //Process all pending packets
645  do
646  {
647  //Read incoming packet
648  error = stm32f7xxEthReceivePacket(interface);
649 
650  //No more data in the receive buffer?
651  } while(error != ERROR_BUFFER_EMPTY);
652 }
653 
654 
655 /**
656  * @brief Send a packet
657  * @param[in] interface Underlying network interface
658  * @param[in] buffer Multi-part buffer containing the data to send
659  * @param[in] offset Offset to the first data byte
660  * @param[in] ancillary Additional options passed to the stack along with
661  * the packet
662  * @return Error code
663  **/
664 
666  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
667 {
668  size_t length;
669 
670  //Retrieve the length of the packet
671  length = netBufferGetLength(buffer) - offset;
672 
673  //Check the frame length
675  {
676  //The transmitter can accept another packet
677  osSetEvent(&interface->nicTxEvent);
678  //Report an error
679  return ERROR_INVALID_LENGTH;
680  }
681 
682  //Make sure the current buffer is available for writing
683  if((txCurDmaDesc->tdes0 & ETH_TDES0_OWN) != 0)
684  {
685  return ERROR_FAILURE;
686  }
687 
688  //Copy user data to the transmit buffer
689  netBufferRead((uint8_t *) txCurDmaDesc->tdes2, buffer, offset, length);
690 
691  //Write the number of bytes to send
692  txCurDmaDesc->tdes1 = length & ETH_TDES1_TBS1;
693  //Set LS and FS flags as the data fits in a single buffer
694  txCurDmaDesc->tdes0 |= ETH_TDES0_LS | ETH_TDES0_FS;
695  //Give the ownership of the descriptor to the DMA
696  txCurDmaDesc->tdes0 |= ETH_TDES0_OWN;
697 
698  //Data synchronization barrier
699  __DSB();
700 
701  //Clear TBUS flag to resume processing
702  ETH->DMASR = ETH_DMASR_TBUS;
703  //Instruct the DMA to poll the transmit descriptor list
704  ETH->DMATPDR = 0;
705 
706  //Point to the next descriptor in the list
707  txCurDmaDesc = (Stm32f7xxTxDmaDesc *) txCurDmaDesc->tdes3;
708 
709  //Check whether the next buffer is available for writing
710  if((txCurDmaDesc->tdes0 & ETH_TDES0_OWN) == 0)
711  {
712  //The transmitter can accept another packet
713  osSetEvent(&interface->nicTxEvent);
714  }
715 
716  //Data successfully written
717  return NO_ERROR;
718 }
719 
720 
721 /**
722  * @brief Receive a packet
723  * @param[in] interface Underlying network interface
724  * @return Error code
725  **/
726 
728 {
729  error_t error;
730  size_t n;
731  NetRxAncillary ancillary;
732 
733  //Current buffer available for reading?
734  if((rxCurDmaDesc->rdes0 & ETH_RDES0_OWN) == 0)
735  {
736  //FS and LS flags should be set
737  if((rxCurDmaDesc->rdes0 & ETH_RDES0_FS) != 0 &&
738  (rxCurDmaDesc->rdes0 & ETH_RDES0_LS) != 0)
739  {
740  //Make sure no error occurred
741  if((rxCurDmaDesc->rdes0 & ETH_RDES0_ES) == 0)
742  {
743  //Retrieve the length of the frame
744  n = (rxCurDmaDesc->rdes0 & ETH_RDES0_FL) >> 16;
745  //Limit the number of data to read
747 
748  //Additional options can be passed to the stack along with the packet
749  ancillary = NET_DEFAULT_RX_ANCILLARY;
750 
751  //Pass the packet to the upper layer
752  nicProcessPacket(interface, (uint8_t *) rxCurDmaDesc->rdes2, n,
753  &ancillary);
754 
755  //Valid packet received
756  error = NO_ERROR;
757  }
758  else
759  {
760  //The received packet contains an error
761  error = ERROR_INVALID_PACKET;
762  }
763  }
764  else
765  {
766  //The packet is not valid
767  error = ERROR_INVALID_PACKET;
768  }
769 
770  //Give the ownership of the descriptor back to the DMA
771  rxCurDmaDesc->rdes0 = ETH_RDES0_OWN;
772  //Point to the next descriptor in the list
773  rxCurDmaDesc = (Stm32f7xxRxDmaDesc *) rxCurDmaDesc->rdes3;
774  }
775  else
776  {
777  //No more data in the receive buffer
778  error = ERROR_BUFFER_EMPTY;
779  }
780 
781  //Clear RBUS flag to resume processing
782  ETH->DMASR = ETH_DMASR_RBUS;
783  //Instruct the DMA to poll the receive descriptor list
784  ETH->DMARPDR = 0;
785 
786  //Return status code
787  return error;
788 }
789 
790 
791 /**
792  * @brief Configure MAC address filtering
793  * @param[in] interface Underlying network interface
794  * @return Error code
795  **/
796 
798 {
799  uint_t i;
800  uint_t j;
801  uint_t k;
802  uint32_t crc;
803  uint32_t hashTable[2];
804  MacAddr unicastMacAddr[3];
805  MacFilterEntry *entry;
806 
807  //Debug message
808  TRACE_DEBUG("Updating MAC filter...\r\n");
809 
810  //Promiscuous mode?
811  if(interface->promiscuous)
812  {
813  //Pass all incoming frames regardless of their destination address
814  ETH->MACFFR = ETH_MACFFR_PM;
815  }
816  else
817  {
818  //Set the MAC address of the station
819  ETH->MACA0LR = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
820  ETH->MACA0HR = interface->macAddr.w[2];
821 
822  //The MAC supports 3 additional addresses for unicast perfect filtering
823  unicastMacAddr[0] = MAC_UNSPECIFIED_ADDR;
824  unicastMacAddr[1] = MAC_UNSPECIFIED_ADDR;
825  unicastMacAddr[2] = MAC_UNSPECIFIED_ADDR;
826 
827  //The hash table is used for multicast address filtering
828  hashTable[0] = 0;
829  hashTable[1] = 0;
830 
831  //The MAC address filter contains the list of MAC addresses to accept
832  //when receiving an Ethernet frame
833  for(i = 0, j = 0; i < MAC_ADDR_FILTER_SIZE; i++)
834  {
835  //Point to the current entry
836  entry = &interface->macAddrFilter[i];
837 
838  //Valid entry?
839  if(entry->refCount > 0)
840  {
841  //Multicast address?
842  if(macIsMulticastAddr(&entry->addr))
843  {
844  //Compute CRC over the current MAC address
845  crc = stm32f7xxEthCalcCrc(&entry->addr, sizeof(MacAddr));
846 
847  //The upper 6 bits in the CRC register are used to index the
848  //contents of the hash table
849  k = (crc >> 26) & 0x3F;
850 
851  //Update hash table contents
852  hashTable[k / 32] |= (1 << (k % 32));
853  }
854  else
855  {
856  //Up to 3 additional MAC addresses can be specified
857  if(j < 3)
858  {
859  //Save the unicast address
860  unicastMacAddr[j++] = entry->addr;
861  }
862  }
863  }
864  }
865 
866  //Configure the first unicast address filter
867  if(j >= 1)
868  {
869  //When the AE bit is set, the entry is used for perfect filtering
870  ETH->MACA1LR = unicastMacAddr[0].w[0] | (unicastMacAddr[0].w[1] << 16);
871  ETH->MACA1HR = unicastMacAddr[0].w[2] | ETH_MACA1HR_AE;
872  }
873  else
874  {
875  //When the AE bit is cleared, the entry is ignored
876  ETH->MACA1LR = 0;
877  ETH->MACA1HR = 0;
878  }
879 
880  //Configure the second unicast address filter
881  if(j >= 2)
882  {
883  //When the AE bit is set, the entry is used for perfect filtering
884  ETH->MACA2LR = unicastMacAddr[1].w[0] | (unicastMacAddr[1].w[1] << 16);
885  ETH->MACA2HR = unicastMacAddr[1].w[2] | ETH_MACA2HR_AE;
886  }
887  else
888  {
889  //When the AE bit is cleared, the entry is ignored
890  ETH->MACA2LR = 0;
891  ETH->MACA2HR = 0;
892  }
893 
894  //Configure the third unicast address filter
895  if(j >= 3)
896  {
897  //When the AE bit is set, the entry is used for perfect filtering
898  ETH->MACA3LR = unicastMacAddr[2].w[0] | (unicastMacAddr[2].w[1] << 16);
899  ETH->MACA3HR = unicastMacAddr[2].w[2] | ETH_MACA3HR_AE;
900  }
901  else
902  {
903  //When the AE bit is cleared, the entry is ignored
904  ETH->MACA3LR = 0;
905  ETH->MACA3HR = 0;
906  }
907 
908  //Check whether frames with a multicast destination address should be
909  //accepted
910  if(interface->acceptAllMulticast)
911  {
912  //Configure the receive filter
913  ETH->MACFFR = ETH_MACFFR_HPF | ETH_MACFFR_PAM;
914  }
915  else
916  {
917  //Configure the receive filter
918  ETH->MACFFR = ETH_MACFFR_HPF | ETH_MACFFR_HM;
919 
920  //Configure the multicast hash table
921  ETH->MACHTLR = hashTable[0];
922  ETH->MACHTHR = hashTable[1];
923 
924  //Debug message
925  TRACE_DEBUG(" MACHTLR = %08" PRIX32 "\r\n", ETH->MACHTLR);
926  TRACE_DEBUG(" MACHTHR = %08" PRIX32 "\r\n", ETH->MACHTHR);
927  }
928  }
929 
930  //Successful processing
931  return NO_ERROR;
932 }
933 
934 
935 /**
936  * @brief Adjust MAC configuration parameters for proper operation
937  * @param[in] interface Underlying network interface
938  * @return Error code
939  **/
940 
942 {
943  uint32_t config;
944 
945  //Read current MAC configuration
946  config = ETH->MACCR;
947 
948  //10BASE-T or 100BASE-TX operation mode?
949  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
950  {
951  config |= ETH_MACCR_FES;
952  }
953  else
954  {
955  config &= ~ETH_MACCR_FES;
956  }
957 
958  //Half-duplex or full-duplex mode?
959  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
960  {
961  config |= ETH_MACCR_DM;
962  }
963  else
964  {
965  config &= ~ETH_MACCR_DM;
966  }
967 
968  //Update MAC configuration register
969  ETH->MACCR = config;
970 
971  //Successful processing
972  return NO_ERROR;
973 }
974 
975 
976 /**
977  * @brief Write PHY register
978  * @param[in] opcode Access type (2 bits)
979  * @param[in] phyAddr PHY address (5 bits)
980  * @param[in] regAddr Register address (5 bits)
981  * @param[in] data Register value
982  **/
983 
984 void stm32f7xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
985  uint8_t regAddr, uint16_t data)
986 {
987  uint32_t temp;
988 
989  //Valid opcode?
990  if(opcode == SMI_OPCODE_WRITE)
991  {
992  //Take care not to alter MDC clock configuration
993  temp = ETH->MACMIIAR & ETH_MACMIIAR_CR;
994  //Set up a write operation
995  temp |= ETH_MACMIIAR_MW | ETH_MACMIIAR_MB;
996  //PHY address
997  temp |= (phyAddr << 11) & ETH_MACMIIAR_PA;
998  //Register address
999  temp |= (regAddr << 6) & ETH_MACMIIAR_MR;
1000 
1001  //Data to be written in the PHY register
1002  ETH->MACMIIDR = data & ETH_MACMIIDR_MD;
1003 
1004  //Start a write operation
1005  ETH->MACMIIAR = temp;
1006  //Wait for the write to complete
1007  while((ETH->MACMIIAR & ETH_MACMIIAR_MB) != 0)
1008  {
1009  }
1010  }
1011  else
1012  {
1013  //The MAC peripheral only supports standard Clause 22 opcodes
1014  }
1015 }
1016 
1017 
1018 /**
1019  * @brief Read PHY register
1020  * @param[in] opcode Access type (2 bits)
1021  * @param[in] phyAddr PHY address (5 bits)
1022  * @param[in] regAddr Register address (5 bits)
1023  * @return Register value
1024  **/
1025 
1026 uint16_t stm32f7xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
1027  uint8_t regAddr)
1028 {
1029  uint16_t data;
1030  uint32_t temp;
1031 
1032  //Valid opcode?
1033  if(opcode == SMI_OPCODE_READ)
1034  {
1035  //Take care not to alter MDC clock configuration
1036  temp = ETH->MACMIIAR & ETH_MACMIIAR_CR;
1037  //Set up a read operation
1038  temp |= ETH_MACMIIAR_MB;
1039  //PHY address
1040  temp |= (phyAddr << 11) & ETH_MACMIIAR_PA;
1041  //Register address
1042  temp |= (regAddr << 6) & ETH_MACMIIAR_MR;
1043 
1044  //Start a read operation
1045  ETH->MACMIIAR = temp;
1046  //Wait for the read to complete
1047  while((ETH->MACMIIAR & ETH_MACMIIAR_MB) != 0)
1048  {
1049  }
1050 
1051  //Get register value
1052  data = ETH->MACMIIDR & ETH_MACMIIDR_MD;
1053  }
1054  else
1055  {
1056  //The MAC peripheral only supports standard Clause 22 opcodes
1057  data = 0;
1058  }
1059 
1060  //Return the value of the PHY register
1061  return data;
1062 }
1063 
1064 
1065 /**
1066  * @brief CRC calculation
1067  * @param[in] data Pointer to the data over which to calculate the CRC
1068  * @param[in] length Number of bytes to process
1069  * @return Resulting CRC value
1070  **/
1071 
1072 uint32_t stm32f7xxEthCalcCrc(const void *data, size_t length)
1073 {
1074  uint_t i;
1075  uint_t j;
1076  uint32_t crc;
1077  const uint8_t *p;
1078 
1079  //Point to the data over which to calculate the CRC
1080  p = (uint8_t *) data;
1081  //CRC preset value
1082  crc = 0xFFFFFFFF;
1083 
1084  //Loop through data
1085  for(i = 0; i < length; i++)
1086  {
1087  //The message is processed bit by bit
1088  for(j = 0; j < 8; j++)
1089  {
1090  //Update CRC value
1091  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
1092  {
1093  crc = (crc << 1) ^ 0x04C11DB7;
1094  }
1095  else
1096  {
1097  crc = crc << 1;
1098  }
1099  }
1100  }
1101 
1102  //Return CRC value
1103  return ~crc;
1104 }
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
uint8_t opcode
Definition: dns_common.h:188
int bool_t
Definition: compiler_port.h:53
#define STM32F7XX_ETH_IRQ_SUB_PRIORITY
uint16_t stm32f7xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
#define netEvent
Definition: net_legacy.h:196
void stm32f7xxEthDisableIrq(NetInterface *interface)
Disable interrupts.
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
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
#define STM32F7XX_ETH_TX_BUFFER_SIZE
void stm32f7xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
uint8_t p
Definition: ndp.h:300
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
uint32_t stm32f7xxEthCalcCrc(const void *data, size_t length)
CRC calculation.
#define ETH_TDES1_TBS1
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
#define TRUE
Definition: os_port.h:50
uint8_t data[]
Definition: ethernet.h:222
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:264
#define ETH_RDES0_LS
error_t stm32f7xxEthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:392
#define macIsMulticastAddr(macAddr)
Definition: ethernet.h:133
#define osExitIsr(flag)
#define SMI_OPCODE_WRITE
Definition: nic.h:66
#define STM32F7XX_ETH_RAM_SECTION
#define STM32F7XX_ETH_RX_BUFFER_SIZE
#define FALSE
Definition: os_port.h:46
#define ETH_RDES0_FL
error_t
Error codes.
Definition: error.h:43
#define STM32F7XX_ETH_TX_BUFFER_COUNT
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:104
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
void stm32f7xxEthEnableIrq(NetInterface *interface)
Enable interrupts.
const NicDriver stm32f7xxEthDriver
STM32F7 Ethernet MAC driver.
#define txBuffer
#define ETH_RDES0_OWN
#define NetRxAncillary
Definition: net_misc.h:40
@ ERROR_INVALID_PACKET
Definition: error.h:140
#define NetInterface
Definition: net.h:36
MacAddr addr
MAC address.
Definition: ethernet.h:263
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_BUFFER_EMPTY
Definition: error.h:141
#define ETH_RDES0_FS
void stm32f7xxEthTick(NetInterface *interface)
STM32F7 Ethernet MAC timer handler.
void ETH_IRQHandler(void)
STM32F7 Ethernet MAC interrupt service routine.
#define NetTxAncillary
Definition: net_misc.h:36
#define SMI_OPCODE_READ
Definition: nic.h:67
#define TRACE_INFO(...)
Definition: debug.h:95
#define ETH_TDES0_OWN
uint8_t length
Definition: tcp.h:368
#define ETH_TDES0_TCH
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_RDES0_ES
#define rxBuffer
MacAddr
Definition: ethernet.h:195
#define STM32F7XX_ETH_IRQ_PRIORITY_GROUPING
error_t stm32f7xxEthInit(NetInterface *interface)
STM32F7 Ethernet MAC initialization.
error_t stm32f7xxEthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
#define ETH_TDES0_IC
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define STM32F7XX_ETH_IRQ_GROUP_PRIORITY
STM32F7 Ethernet MAC driver.
Enhanced TX DMA descriptor.
uint16_t regAddr
#define ETH_MTU
Definition: ethernet.h:116
uint8_t n
#define ETH_TDES0_FS
MAC filter table entry.
Definition: ethernet.h:262
#define ETH_RDES1_RCH
void stm32f7xxEthEventHandler(NetInterface *interface)
STM32F7 Ethernet MAC event handler.
#define STM32F7XX_ETH_RX_BUFFER_COUNT
#define osEnterIsr()
error_t stm32f7xxEthReceivePacket(NetInterface *interface)
Receive a packet.
#define rxDmaDesc
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define ETH_TDES0_LS
#define txDmaDesc
void stm32f7xxEthInitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
Enhanced RX DMA descriptor.
#define ETH_RDES1_RBS1
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
unsigned int uint_t
Definition: compiler_port.h:50
TCP/IP stack core.
#define ETH_MACCR_RESERVED15
NIC driver.
Definition: nic.h:286
error_t stm32f7xxEthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
__weak_func void stm32f7xxEthInitGpio(NetInterface *interface)
GPIO configuration.
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:53
@ NO_ERROR
Success.
Definition: error.h:44
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
Debugging facilities.
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83