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