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.0
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 //STM32756G-EVAL or STM32F769I-EVAL evaluation board?
233 #if defined(USE_STM32756G_EVAL) || defined(USE_STM32F769I_EVAL)
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_GPIOC_CLK_ENABLE();
242  __HAL_RCC_GPIOE_CLK_ENABLE();
243  __HAL_RCC_GPIOG_CLK_ENABLE();
244  __HAL_RCC_GPIOH_CLK_ENABLE();
245  __HAL_RCC_GPIOI_CLK_ENABLE();
246 
247  //Configure MCO1 (PA8) as an output
248  GPIO_InitStructure.Pin = GPIO_PIN_8;
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_AF0_MCO;
253  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
254 
255  //Configure MCO1 pin to output the HSE clock (25MHz)
256  HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSE, RCC_MCODIV_1);
257 
258  //Select MII interface mode
259  SYSCFG->PMC &= ~SYSCFG_PMC_MII_RMII_SEL;
260 
261  //Configure MDIO/MDC pins
262  if(interface->smiDriver == NULL)
263  {
264  //Configure ETH_MDIO (PA2)
265  GPIO_InitStructure.Pin = GPIO_PIN_2;
266  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
267  GPIO_InitStructure.Pull = GPIO_PULLUP;
268  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM;
269  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
270  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
271 
272  //Configure ETH_MDC (PC1)
273  GPIO_InitStructure.Pin = GPIO_PIN_1;
274  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
275  GPIO_InitStructure.Pull = GPIO_NOPULL;
276  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM;
277  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
278  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
279  }
280 
281  //Configure MII pins
282  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
283  GPIO_InitStructure.Pull = GPIO_NOPULL;
284  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
285  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
286 
287  //Configure ETH_MII_CRS (PA0)
288  //GPIO_InitStructure.Pin = GPIO_PIN_0;
289  //HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
290 
291  //Configure ETH_MII_RX_CLK (PA1) and ETH_MII_RX_DV (PA7)
292  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_7;
293  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
294 
295  //Configure ETH_MII_TXD2 (PC2), ETH_MII_TX_CLK (PC3), ETH_MII_RXD0 (PC4)
296  //and ETH_MII_RXD1 (PC5)
297  GPIO_InitStructure.Pin = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5;
298  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
299 
300  //Configure ETH_MII_TXD3 (PE2)
301  GPIO_InitStructure.Pin = GPIO_PIN_2;
302  HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
303 
304  //Configure ETH_MII_TX_EN (PG11), ETH_MII_TXD0 (PG13) and ETH_MII_TXD1 (PG14)
305  GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14;
306  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
307 
308  //Configure ETH_MII_COL (PH3)
309  //GPIO_InitStructure.Pin = GPIO_PIN_3;
310  //HAL_GPIO_Init(GPIOH, &GPIO_InitStructure);
311 
312  //Configure ETH_MII_RXD2 (PH6) and ETH_MII_RXD3 (PH7)
313  GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7;
314  HAL_GPIO_Init(GPIOH, &GPIO_InitStructure);
315 
316  //Configure ETH_MII_RX_ER (PI10)
317  //GPIO_InitStructure.Pin = GPIO_PIN_10;
318  //HAL_GPIO_Init(GPIOI, &GPIO_InitStructure);
319 
320 //STM32F746G-Discovery or STM32F7508-Discovery evaluation board?
321 #elif defined(USE_STM32746G_DISCO) || defined(USE_STM32F7508_DISCO)
322  GPIO_InitTypeDef GPIO_InitStructure;
323 
324  //Enable SYSCFG clock
325  __HAL_RCC_SYSCFG_CLK_ENABLE();
326 
327  //Enable GPIO clocks
328  __HAL_RCC_GPIOA_CLK_ENABLE();
329  __HAL_RCC_GPIOC_CLK_ENABLE();
330  __HAL_RCC_GPIOG_CLK_ENABLE();
331 
332  //Select RMII interface mode
333  SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL;
334 
335  //Configure RMII pins
336  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
337  GPIO_InitStructure.Pull = GPIO_NOPULL;
338  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
339  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
340 
341  //Configure ETH_RMII_REF_CLK (PA1), ETH_MDIO (PA2) and ETH_RMII_CRS_DV (PA7)
342  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
343  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
344 
345  //Configure ETH_MDC (PC1), ETH_RMII_RXD0 (PC4) and ETH_RMII_RXD1 (PC5)
346  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
347  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
348 
349  //Configure ETH_RMII_RX_ER (PG2), ETH_RMII_TX_EN (PG11), ETH_RMII_TXD0 (PG13)
350  //and ETH_RMII_TXD1 (PG14)
351  GPIO_InitStructure.Pin = GPIO_PIN_2 | GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14;
352  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
353 
354 //STM32F769I-Discovery evaluation board?
355 #elif defined(USE_STM32F769I_DISCO)
356  GPIO_InitTypeDef GPIO_InitStructure;
357 
358  //Enable SYSCFG clock
359  __HAL_RCC_SYSCFG_CLK_ENABLE();
360 
361  //Enable GPIO clocks
362  __HAL_RCC_GPIOA_CLK_ENABLE();
363  __HAL_RCC_GPIOC_CLK_ENABLE();
364  __HAL_RCC_GPIOD_CLK_ENABLE();
365  __HAL_RCC_GPIOG_CLK_ENABLE();
366 
367  //Select RMII interface mode
368  SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL;
369 
370  //Configure RMII pins
371  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
372  GPIO_InitStructure.Pull = GPIO_NOPULL;
373  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
374  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
375 
376  //Configure ETH_RMII_REF_CLK (PA1), ETH_MDIO (PA2) and ETH_RMII_CRS_DV (PA7)
377  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
378  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
379 
380  //Configure ETH_MDC (PC1), ETH_RMII_RXD0 (PC4) and ETH_RMII_RXD1 (PC5)
381  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
382  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
383 
384  //Configure ETH_RMII_RX_ER (PD5)
385  GPIO_InitStructure.Pin = GPIO_PIN_5;
386  HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
387 
388  //Configure ETH_RMII_TX_EN (PG11), ETH_RMII_TXD0 (PG13) and ETH_RMII_TXD1 (PG14)
389  GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14;
390  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
391 
392 //Nucleo-F746ZG or Nucleo-F767ZI evaluation board?
393 #elif defined(USE_STM32F7XX_NUCLEO_144)
394  GPIO_InitTypeDef GPIO_InitStructure;
395 
396  //Enable SYSCFG clock
397  __HAL_RCC_SYSCFG_CLK_ENABLE();
398 
399  //Enable GPIO clocks
400  __HAL_RCC_GPIOA_CLK_ENABLE();
401  __HAL_RCC_GPIOB_CLK_ENABLE();
402  __HAL_RCC_GPIOC_CLK_ENABLE();
403  __HAL_RCC_GPIOG_CLK_ENABLE();
404 
405  //Select RMII interface mode
406  SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL;
407 
408  //Configure RMII pins
409  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
410  GPIO_InitStructure.Pull = GPIO_NOPULL;
411  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
412  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
413 
414  //Configure ETH_RMII_REF_CLK (PA1), ETH_MDIO (PA2) and ETH_RMII_CRS_DV (PA7)
415  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
416  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
417 
418  //Configure ETH_RMII_TXD1 (PB13)
419  GPIO_InitStructure.Pin = GPIO_PIN_13;
420  HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
421 
422  //Configure ETH_MDC (PC1), ETH_RMII_RXD0 (PC4) and ETH_RMII_RXD1 (PC5)
423  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
424  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
425 
426  //Configure RMII_TX_EN (PG11) and ETH_RMII_TXD0 (PG13)
427  GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13;
428  HAL_GPIO_Init(GPIOG, &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  static uint32_t temp[STM32F7XX_ETH_TX_BUFFER_SIZE / 4];
669  size_t length;
670 
671  //Retrieve the length of the packet
672  length = netBufferGetLength(buffer) - offset;
673 
674  //Check the frame length
676  {
677  //The transmitter can accept another packet
678  osSetEvent(&interface->nicTxEvent);
679  //Report an error
680  return ERROR_INVALID_LENGTH;
681  }
682 
683  //Make sure the current buffer is available for writing
684  if((txCurDmaDesc->tdes0 & ETH_TDES0_OWN) != 0)
685  {
686  return ERROR_FAILURE;
687  }
688 
689  //Copy user data to the transmit buffer
690  netBufferRead(temp, buffer, offset, length);
691  osMemcpy((uint8_t *) txCurDmaDesc->tdes2, temp, (length + 3) & ~3UL);
692 
693  //Write the number of bytes to send
694  txCurDmaDesc->tdes1 = length & ETH_TDES1_TBS1;
695  //Set LS and FS flags as the data fits in a single buffer
696  txCurDmaDesc->tdes0 |= ETH_TDES0_LS | ETH_TDES0_FS;
697  //Give the ownership of the descriptor to the DMA
698  txCurDmaDesc->tdes0 |= ETH_TDES0_OWN;
699 
700  //Data synchronization barrier
701  __DSB();
702 
703  //Clear TBUS flag to resume processing
704  ETH->DMASR = ETH_DMASR_TBUS;
705  //Instruct the DMA to poll the transmit descriptor list
706  ETH->DMATPDR = 0;
707 
708  //Point to the next descriptor in the list
709  txCurDmaDesc = (Stm32f7xxTxDmaDesc *) txCurDmaDesc->tdes3;
710 
711  //Check whether the next buffer is available for writing
712  if((txCurDmaDesc->tdes0 & ETH_TDES0_OWN) == 0)
713  {
714  //The transmitter can accept another packet
715  osSetEvent(&interface->nicTxEvent);
716  }
717 
718  //Data successfully written
719  return NO_ERROR;
720 }
721 
722 
723 /**
724  * @brief Receive a packet
725  * @param[in] interface Underlying network interface
726  * @return Error code
727  **/
728 
730 {
731  static uint32_t temp[STM32F7XX_ETH_RX_BUFFER_SIZE / 4];
732  error_t error;
733  size_t n;
734  NetRxAncillary ancillary;
735 
736  //Current buffer available for reading?
737  if((rxCurDmaDesc->rdes0 & ETH_RDES0_OWN) == 0)
738  {
739  //FS and LS flags should be set
740  if((rxCurDmaDesc->rdes0 & ETH_RDES0_FS) != 0 &&
741  (rxCurDmaDesc->rdes0 & ETH_RDES0_LS) != 0)
742  {
743  //Make sure no error occurred
744  if((rxCurDmaDesc->rdes0 & ETH_RDES0_ES) == 0)
745  {
746  //Retrieve the length of the frame
747  n = (rxCurDmaDesc->rdes0 & ETH_RDES0_FL) >> 16;
748  //Limit the number of data to read
750 
751  //Copy data from the receive buffer
752  osMemcpy(temp, (uint8_t *) rxCurDmaDesc->rdes2, (n + 3) & ~3UL);
753 
754  //Additional options can be passed to the stack along with the packet
755  ancillary = NET_DEFAULT_RX_ANCILLARY;
756 
757  //Pass the packet to the upper layer
758  nicProcessPacket(interface, (uint8_t *) temp, n, &ancillary);
759 
760  //Valid packet received
761  error = NO_ERROR;
762  }
763  else
764  {
765  //The received packet contains an error
766  error = ERROR_INVALID_PACKET;
767  }
768  }
769  else
770  {
771  //The packet is not valid
772  error = ERROR_INVALID_PACKET;
773  }
774 
775  //Give the ownership of the descriptor back to the DMA
776  rxCurDmaDesc->rdes0 = ETH_RDES0_OWN;
777  //Point to the next descriptor in the list
778  rxCurDmaDesc = (Stm32f7xxRxDmaDesc *) rxCurDmaDesc->rdes3;
779  }
780  else
781  {
782  //No more data in the receive buffer
783  error = ERROR_BUFFER_EMPTY;
784  }
785 
786  //Clear RBUS flag to resume processing
787  ETH->DMASR = ETH_DMASR_RBUS;
788  //Instruct the DMA to poll the receive descriptor list
789  ETH->DMARPDR = 0;
790 
791  //Return status code
792  return error;
793 }
794 
795 
796 /**
797  * @brief Configure MAC address filtering
798  * @param[in] interface Underlying network interface
799  * @return Error code
800  **/
801 
803 {
804  uint_t i;
805  uint_t j;
806  uint_t k;
807  uint32_t crc;
808  uint32_t hashTable[2];
809  MacAddr unicastMacAddr[3];
810  MacFilterEntry *entry;
811 
812  //Debug message
813  TRACE_DEBUG("Updating MAC filter...\r\n");
814 
815  //Promiscuous mode?
816  if(interface->promiscuous)
817  {
818  //Pass all incoming frames regardless of their destination address
819  ETH->MACFFR = ETH_MACFFR_PM;
820  }
821  else
822  {
823  //Set the MAC address of the station
824  ETH->MACA0LR = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
825  ETH->MACA0HR = interface->macAddr.w[2];
826 
827  //The MAC supports 3 additional addresses for unicast perfect filtering
828  unicastMacAddr[0] = MAC_UNSPECIFIED_ADDR;
829  unicastMacAddr[1] = MAC_UNSPECIFIED_ADDR;
830  unicastMacAddr[2] = MAC_UNSPECIFIED_ADDR;
831 
832  //The hash table is used for multicast address filtering
833  hashTable[0] = 0;
834  hashTable[1] = 0;
835 
836  //The MAC address filter contains the list of MAC addresses to accept
837  //when receiving an Ethernet frame
838  for(i = 0, j = 0; i < MAC_ADDR_FILTER_SIZE; i++)
839  {
840  //Point to the current entry
841  entry = &interface->macAddrFilter[i];
842 
843  //Valid entry?
844  if(entry->refCount > 0)
845  {
846  //Multicast address?
847  if(macIsMulticastAddr(&entry->addr))
848  {
849  //Compute CRC over the current MAC address
850  crc = stm32f7xxEthCalcCrc(&entry->addr, sizeof(MacAddr));
851 
852  //The upper 6 bits in the CRC register are used to index the
853  //contents of the hash table
854  k = (crc >> 26) & 0x3F;
855 
856  //Update hash table contents
857  hashTable[k / 32] |= (1 << (k % 32));
858  }
859  else
860  {
861  //Up to 3 additional MAC addresses can be specified
862  if(j < 3)
863  {
864  //Save the unicast address
865  unicastMacAddr[j++] = entry->addr;
866  }
867  }
868  }
869  }
870 
871  //Configure the first unicast address filter
872  if(j >= 1)
873  {
874  //When the AE bit is set, the entry is used for perfect filtering
875  ETH->MACA1LR = unicastMacAddr[0].w[0] | (unicastMacAddr[0].w[1] << 16);
876  ETH->MACA1HR = unicastMacAddr[0].w[2] | ETH_MACA1HR_AE;
877  }
878  else
879  {
880  //When the AE bit is cleared, the entry is ignored
881  ETH->MACA1LR = 0;
882  ETH->MACA1HR = 0;
883  }
884 
885  //Configure the second unicast address filter
886  if(j >= 2)
887  {
888  //When the AE bit is set, the entry is used for perfect filtering
889  ETH->MACA2LR = unicastMacAddr[1].w[0] | (unicastMacAddr[1].w[1] << 16);
890  ETH->MACA2HR = unicastMacAddr[1].w[2] | ETH_MACA2HR_AE;
891  }
892  else
893  {
894  //When the AE bit is cleared, the entry is ignored
895  ETH->MACA2LR = 0;
896  ETH->MACA2HR = 0;
897  }
898 
899  //Configure the third unicast address filter
900  if(j >= 3)
901  {
902  //When the AE bit is set, the entry is used for perfect filtering
903  ETH->MACA3LR = unicastMacAddr[2].w[0] | (unicastMacAddr[2].w[1] << 16);
904  ETH->MACA3HR = unicastMacAddr[2].w[2] | ETH_MACA3HR_AE;
905  }
906  else
907  {
908  //When the AE bit is cleared, the entry is ignored
909  ETH->MACA3LR = 0;
910  ETH->MACA3HR = 0;
911  }
912 
913  //Check whether frames with a multicast destination address should be
914  //accepted
915  if(interface->acceptAllMulticast)
916  {
917  //Configure the receive filter
918  ETH->MACFFR = ETH_MACFFR_HPF | ETH_MACFFR_PAM;
919  }
920  else
921  {
922  //Configure the receive filter
923  ETH->MACFFR = ETH_MACFFR_HPF | ETH_MACFFR_HM;
924 
925  //Configure the multicast hash table
926  ETH->MACHTLR = hashTable[0];
927  ETH->MACHTHR = hashTable[1];
928 
929  //Debug message
930  TRACE_DEBUG(" MACHTLR = %08" PRIX32 "\r\n", ETH->MACHTLR);
931  TRACE_DEBUG(" MACHTHR = %08" PRIX32 "\r\n", ETH->MACHTHR);
932  }
933  }
934 
935  //Successful processing
936  return NO_ERROR;
937 }
938 
939 
940 /**
941  * @brief Adjust MAC configuration parameters for proper operation
942  * @param[in] interface Underlying network interface
943  * @return Error code
944  **/
945 
947 {
948  uint32_t config;
949 
950  //Read current MAC configuration
951  config = ETH->MACCR;
952 
953  //10BASE-T or 100BASE-TX operation mode?
954  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
955  {
956  config |= ETH_MACCR_FES;
957  }
958  else
959  {
960  config &= ~ETH_MACCR_FES;
961  }
962 
963  //Half-duplex or full-duplex mode?
964  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
965  {
966  config |= ETH_MACCR_DM;
967  }
968  else
969  {
970  config &= ~ETH_MACCR_DM;
971  }
972 
973  //Update MAC configuration register
974  ETH->MACCR = config;
975 
976  //Successful processing
977  return NO_ERROR;
978 }
979 
980 
981 /**
982  * @brief Write PHY register
983  * @param[in] opcode Access type (2 bits)
984  * @param[in] phyAddr PHY address (5 bits)
985  * @param[in] regAddr Register address (5 bits)
986  * @param[in] data Register value
987  **/
988 
989 void stm32f7xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
990  uint8_t regAddr, uint16_t data)
991 {
992  uint32_t temp;
993 
994  //Valid opcode?
995  if(opcode == SMI_OPCODE_WRITE)
996  {
997  //Take care not to alter MDC clock configuration
998  temp = ETH->MACMIIAR & ETH_MACMIIAR_CR;
999  //Set up a write operation
1000  temp |= ETH_MACMIIAR_MW | ETH_MACMIIAR_MB;
1001  //PHY address
1002  temp |= (phyAddr << 11) & ETH_MACMIIAR_PA;
1003  //Register address
1004  temp |= (regAddr << 6) & ETH_MACMIIAR_MR;
1005 
1006  //Data to be written in the PHY register
1007  ETH->MACMIIDR = data & ETH_MACMIIDR_MD;
1008 
1009  //Start a write operation
1010  ETH->MACMIIAR = temp;
1011  //Wait for the write to complete
1012  while((ETH->MACMIIAR & ETH_MACMIIAR_MB) != 0)
1013  {
1014  }
1015  }
1016  else
1017  {
1018  //The MAC peripheral only supports standard Clause 22 opcodes
1019  }
1020 }
1021 
1022 
1023 /**
1024  * @brief Read PHY register
1025  * @param[in] opcode Access type (2 bits)
1026  * @param[in] phyAddr PHY address (5 bits)
1027  * @param[in] regAddr Register address (5 bits)
1028  * @return Register value
1029  **/
1030 
1031 uint16_t stm32f7xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
1032  uint8_t regAddr)
1033 {
1034  uint16_t data;
1035  uint32_t temp;
1036 
1037  //Valid opcode?
1038  if(opcode == SMI_OPCODE_READ)
1039  {
1040  //Take care not to alter MDC clock configuration
1041  temp = ETH->MACMIIAR & ETH_MACMIIAR_CR;
1042  //Set up a read operation
1043  temp |= ETH_MACMIIAR_MB;
1044  //PHY address
1045  temp |= (phyAddr << 11) & ETH_MACMIIAR_PA;
1046  //Register address
1047  temp |= (regAddr << 6) & ETH_MACMIIAR_MR;
1048 
1049  //Start a read operation
1050  ETH->MACMIIAR = temp;
1051  //Wait for the read to complete
1052  while((ETH->MACMIIAR & ETH_MACMIIAR_MB) != 0)
1053  {
1054  }
1055 
1056  //Get register value
1057  data = ETH->MACMIIDR & ETH_MACMIIDR_MD;
1058  }
1059  else
1060  {
1061  //The MAC peripheral only supports standard Clause 22 opcodes
1062  data = 0;
1063  }
1064 
1065  //Return the value of the PHY register
1066  return data;
1067 }
1068 
1069 
1070 /**
1071  * @brief CRC calculation
1072  * @param[in] data Pointer to the data over which to calculate the CRC
1073  * @param[in] length Number of bytes to process
1074  * @return Resulting CRC value
1075  **/
1076 
1077 uint32_t stm32f7xxEthCalcCrc(const void *data, size_t length)
1078 {
1079  uint_t i;
1080  uint_t j;
1081  uint32_t crc;
1082  const uint8_t *p;
1083 
1084  //Point to the data over which to calculate the CRC
1085  p = (uint8_t *) data;
1086  //CRC preset value
1087  crc = 0xFFFFFFFF;
1088 
1089  //Loop through data
1090  for(i = 0; i < length; i++)
1091  {
1092  //The message is processed bit by bit
1093  for(j = 0; j < 8; j++)
1094  {
1095  //Update CRC value
1096  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
1097  {
1098  crc = (crc << 1) ^ 0x04C11DB7;
1099  }
1100  else
1101  {
1102  crc = crc << 1;
1103  }
1104  }
1105  }
1106 
1107  //Return CRC value
1108  return ~crc;
1109 }
#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
#define ETH_TDES0_OWN
#define ETH_RDES0_FS
#define ETH_TDES0_IC
#define ETH_RDES1_RCH
#define ETH_RDES0_OWN
#define ETH_RDES0_LS
#define ETH_RDES0_FL
#define ETH_RDES0_ES
#define ETH_TDES0_LS
#define ETH_RDES1_RBS1
#define ETH_TDES0_TCH
#define ETH_TDES0_FS
#define ETH_TDES1_TBS1
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
void stm32f7xxEthTick(NetInterface *interface)
STM32F7 Ethernet MAC timer handler.
error_t stm32f7xxEthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
error_t stm32f7xxEthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
error_t stm32f7xxEthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
uint16_t stm32f7xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
uint32_t stm32f7xxEthCalcCrc(const void *data, size_t length)
CRC calculation.
error_t stm32f7xxEthReceivePacket(NetInterface *interface)
Receive a packet.
void stm32f7xxEthInitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
void stm32f7xxEthEnableIrq(NetInterface *interface)
Enable interrupts.
void stm32f7xxEthEventHandler(NetInterface *interface)
STM32F7 Ethernet MAC event handler.
const NicDriver stm32f7xxEthDriver
STM32F7 Ethernet MAC driver.
void ETH_IRQHandler(void)
STM32F7 Ethernet MAC interrupt service routine.
__weak_func void stm32f7xxEthInitGpio(NetInterface *interface)
GPIO configuration.
void stm32f7xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
error_t stm32f7xxEthInit(NetInterface *interface)
STM32F7 Ethernet MAC initialization.
void stm32f7xxEthDisableIrq(NetInterface *interface)
Disable interrupts.
STM32F7 Ethernet MAC driver.
#define STM32F7XX_ETH_RX_BUFFER_COUNT
#define STM32F7XX_ETH_IRQ_GROUP_PRIORITY
#define STM32F7XX_ETH_IRQ_SUB_PRIORITY
#define STM32F7XX_ETH_IRQ_PRIORITY_GROUPING
#define STM32F7XX_ETH_TX_BUFFER_COUNT
#define STM32F7XX_ETH_RAM_SECTION
#define STM32F7XX_ETH_TX_BUFFER_SIZE
#define STM32F7XX_ETH_RX_BUFFER_SIZE
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
Enhanced RX DMA descriptor.
Enhanced TX DMA descriptor.
uint8_t length
Definition: tcp.h:368