gd32f2xx_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file gd32f2xx_eth_driver.c
3  * @brief GigaDevice GD32F2 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 "gd32f20x.h"
36 #include "core/net.h"
38 #include "debug.h"
39 
40 //Underlying network interface
41 static NetInterface *nicDriverInterface;
42 
43 //IAR EWARM compiler?
44 #if defined(__ICCARM__)
45 
46 //Transmit buffer
47 #pragma data_alignment = 4
49 //Receive buffer
50 #pragma data_alignment = 4
52 //Transmit DMA descriptors
53 #pragma data_alignment = 4
55 //Receive DMA descriptors
56 #pragma data_alignment = 4
58 
59 //Keil MDK-ARM or GCC compiler?
60 #else
61 
62 //Transmit buffer
64  __attribute__((aligned(4)));
65 //Receive buffer
67  __attribute__((aligned(4)));
68 //Transmit DMA descriptors
70  __attribute__((aligned(4)));
71 //Receive DMA descriptors
73  __attribute__((aligned(4)));
74 
75 #endif
76 
77 //Pointer to the current TX DMA descriptor
78 static Gd32f2xxTxDmaDesc *txCurDmaDesc;
79 //Pointer to the current RX DMA descriptor
80 static Gd32f2xxRxDmaDesc *rxCurDmaDesc;
81 
82 
83 /**
84  * @brief GD32F2XX Ethernet MAC driver
85  **/
86 
88 {
90  ETH_MTU,
101  TRUE,
102  TRUE,
103  TRUE,
104  FALSE
105 };
106 
107 
108 /**
109  * @brief GD32F2XX Ethernet MAC initialization
110  * @param[in] interface Underlying network interface
111  * @return Error code
112  **/
113 
115 {
116  error_t error;
117 
118  //Debug message
119  TRACE_INFO("Initializing GD32F2XX Ethernet MAC...\r\n");
120 
121  //Save underlying network interface
122  nicDriverInterface = interface;
123 
124  //GPIO configuration
125  gd32f2xxEthInitGpio(interface);
126 
127  //Enable Ethernet MAC clock
128  rcu_periph_clock_enable(RCU_ENET);
129  rcu_periph_clock_enable(RCU_ENETTX);
130  rcu_periph_clock_enable(RCU_ENETRX);
131 
132  //Reset Ethernet MAC peripheral
133  rcu_periph_reset_enable(RCU_ENETRST);
134  rcu_periph_reset_disable(RCU_ENETRST);
135 
136  //Perform a software reset
137  ENET_DMA_BCTL |= ENET_DMA_BCTL_SWR;
138  //Wait for the reset to complete
139  while((ENET_DMA_BCTL & ENET_DMA_BCTL_SWR) != 0)
140  {
141  }
142 
143  //Adjust MDC clock range depending on HCLK frequency
144  ENET_MAC_PHY_CTL = ENET_MDC_HCLK_DIV62;
145 
146  //Valid Ethernet PHY or switch driver?
147  if(interface->phyDriver != NULL)
148  {
149  //Ethernet PHY initialization
150  error = interface->phyDriver->init(interface);
151  }
152  else if(interface->switchDriver != NULL)
153  {
154  //Ethernet switch initialization
155  error = interface->switchDriver->init(interface);
156  }
157  else
158  {
159  //The interface is not properly configured
160  error = ERROR_FAILURE;
161  }
162 
163  //Any error to report?
164  if(error)
165  {
166  return error;
167  }
168 
169  //Use default MAC configuration
170  ENET_MAC_CFG = ENET_MAC_CFG_ROD;
171 
172  //Set the MAC address of the station
173  ENET_MAC_ADDR0L = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
174  ENET_MAC_ADDR0H = interface->macAddr.w[2] | ENET_MAC_ADDR0H_MO;
175 
176  //The MAC supports 3 additional addresses for unicast perfect filtering
177  ENET_MAC_ADDR1L = 0;
178  ENET_MAC_ADDR1H = 0;
179  ENET_MAC_ADDR2L = 0;
180  ENET_MAC_ADDT2H = 0;
181  ENET_MAC_ADDR3L = 0;
182  ENET_MAC_ADDR3H = 0;
183 
184  //Initialize hash table
185  ENET_MAC_HLL = 0;
186  ENET_MAC_HLH = 0;
187 
188  //Configure the receive filter
189  ENET_MAC_FRMF = ENET_MAC_FRMF_HPFLT | ENET_MAC_FRMF_HMF;
190  //Disable flow control
191  ENET_MAC_FCTL = 0;
192  //Enable store and forward mode
193  ENET_DMA_CTL = ENET_DMA_CTL_RSFD | ENET_DMA_CTL_TSFD;
194 
195  //Configure DMA bus mode
196  ENET_DMA_BCTL = ENET_DMA_BCTL_AA | ENET_DMA_BCTL_UIP | ENET_RXDP_32BEAT |
197  ENET_ARBITRATION_RXTX_1_1 | ENET_PGBL_32BEAT;
198 
199  //Initialize DMA descriptor lists
200  gd32f2xxEthInitDmaDesc(interface);
201 
202  //Prevent interrupts from being generated when the transmit statistic
203  //counters reach half their maximum value
204  ENET_MSC_TINTMSK = ENET_MSC_TINTMSK_TGFIM | ENET_MSC_TINTMSK_TGFMSCIM |
205  ENET_MSC_TINTMSK_TGFSCIM;
206 
207  //Prevent interrupts from being generated when the receive statistic
208  //counters reach half their maximum value
209  ENET_MSC_RINTMSK = ENET_MSC_RINTMSK_RGUFIM | ENET_MSC_RINTMSK_RFAEIM |
210  ENET_MSC_RINTMSK_RFCEIM;
211 
212  //Disable MAC interrupts
213  ENET_MAC_INTMSK = ENET_MAC_INTMSK_TMSTIM | ENET_MAC_INTMSK_WUMIM;
214  //Enable the desired DMA interrupts
215  ENET_DMA_INTEN = ENET_DMA_INTEN_NIE | ENET_DMA_INTEN_RIE | ENET_DMA_INTEN_TIE;
216 
217  //Set priority grouping (4 bits for pre-emption priority, no bits for subpriority)
218  NVIC_SetPriorityGrouping(GD32F2XX_ETH_IRQ_PRIORITY_GROUPING);
219 
220  //Configure Ethernet interrupt priority
221  NVIC_SetPriority(ENET_IRQn, NVIC_EncodePriority(GD32F2XX_ETH_IRQ_PRIORITY_GROUPING,
223 
224  //Enable MAC transmission and reception
225  ENET_MAC_CFG |= ENET_MAC_CFG_TEN | ENET_MAC_CFG_REN;
226  //Enable DMA transmission and reception
227  ENET_DMA_CTL |= ENET_DMA_CTL_STE | ENET_DMA_CTL_SRE;
228 
229  //Accept any packets from the upper layer
230  osSetEvent(&interface->nicTxEvent);
231 
232  //Successful initialization
233  return NO_ERROR;
234 }
235 
236 
237 /**
238  * @brief GPIO configuration
239  * @param[in] interface Underlying network interface
240  **/
241 
242 __weak_func void gd32f2xxEthInitGpio(NetInterface *interface)
243 {
244 //GD32207C-EVAL or GD32207I-EVAL evaluation board?
245 #if defined(USE_GD32207C_EVAL) || defined(USE_GD32207I_EVAL)
246  //Enable SYSCFG clock
247  rcu_periph_clock_enable(RCU_AF);
248 
249  //Enable GPIO clocks
250  rcu_periph_clock_enable(RCU_GPIOA);
251  rcu_periph_clock_enable(RCU_GPIOB);
252  rcu_periph_clock_enable(RCU_GPIOC);
253 
254  //Configure CKOUT0 (PA8) as an output
255  gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8);
256 
257  //Configure CKOUT0 pin to output the 50MHz reference clock
258  rcu_pll2_config(RCU_PLL2_MUL10);
259  rcu_osci_on(RCU_PLL2_CK);
260  rcu_osci_stab_wait(RCU_PLL2_CK);
261  rcu_ckout0_config(RCU_CKOUT0SRC_CKPLL2, RCU_CKOUT0_DIV1);
262 
263  //Select RMII interface mode
264  gpio_ethernet_phy_select(GPIO_ENET_PHY_RMII);
265 
266  //Configure ETH_RMII_REF_CLK (PA1)
267  gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_1);
268  //Configure ETH_MDIO (PA2)
269  gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_2);
270  //Configure ETH_RMII_CRS_DV (PA7)
271  gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
272 
273  //Configure ETH_RMII_TX_EN (PB11)
274  gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_11);
275  //Configure ETH_RMII_TXD0 (PB12)
276  gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12);
277  //Configure ETH_RMII_TXD1 (PB13)
278  gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
279 
280  //Configure ETH_MDC (PC1)
281  gpio_init(GPIOC, GPIO_MODE_AF_PP, GPIO_OSPEED_2MHZ, GPIO_PIN_1);
282  //Configure ETH_RMII_RXD0 (PC4)
283  gpio_init(GPIOC, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
284  //Configure ETH_RMII_RXD1 (PC5)
285  gpio_init(GPIOC, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_5);
286 #endif
287 }
288 
289 
290 /**
291  * @brief Initialize DMA descriptor lists
292  * @param[in] interface Underlying network interface
293  **/
294 
296 {
297  uint_t i;
298 
299  //Initialize TX DMA descriptor list
300  for(i = 0; i < GD32F2XX_ETH_TX_BUFFER_COUNT; i++)
301  {
302  //Use chain structure rather than ring structure
303  txDmaDesc[i].tdes0 = ENET_TDES0_INTC | ENET_TDES0_TCHM;
304  //Initialize transmit buffer size
305  txDmaDesc[i].tdes1 = 0;
306  //Transmit buffer address
307  txDmaDesc[i].tdes2 = (uint32_t) txBuffer[i];
308  //Next descriptor address
309  txDmaDesc[i].tdes3 = (uint32_t) &txDmaDesc[i + 1];
310  }
311 
312  //The last descriptor is chained to the first entry
313  txDmaDesc[i - 1].tdes3 = (uint32_t) &txDmaDesc[0];
314  //Point to the very first descriptor
315  txCurDmaDesc = &txDmaDesc[0];
316 
317  //Initialize RX DMA descriptor list
318  for(i = 0; i < GD32F2XX_ETH_RX_BUFFER_COUNT; i++)
319  {
320  //The descriptor is initially owned by the DMA
321  rxDmaDesc[i].rdes0 = ENET_RDES0_DAV;
322  //Use chain structure rather than ring structure
323  rxDmaDesc[i].rdes1 = ENET_RDES1_RCHM | (GD32F2XX_ETH_RX_BUFFER_SIZE & ENET_RDES1_RB1S);
324  //Receive buffer address
325  rxDmaDesc[i].rdes2 = (uint32_t) rxBuffer[i];
326  //Next descriptor address
327  rxDmaDesc[i].rdes3 = (uint32_t) &rxDmaDesc[i + 1];
328  }
329 
330  //The last descriptor is chained to the first entry
331  rxDmaDesc[i - 1].rdes3 = (uint32_t) &rxDmaDesc[0];
332  //Point to the very first descriptor
333  rxCurDmaDesc = &rxDmaDesc[0];
334 
335  //Start location of the TX descriptor list
336  ENET_DMA_TDTADDR = (uint32_t) txDmaDesc;
337  //Start location of the RX descriptor list
338  ENET_DMA_RDTADDR = (uint32_t) rxDmaDesc;
339 }
340 
341 
342 /**
343  * @brief GD32F2XX Ethernet MAC timer handler
344  *
345  * This routine is periodically called by the TCP/IP stack to handle periodic
346  * operations such as polling the link state
347  *
348  * @param[in] interface Underlying network interface
349  **/
350 
352 {
353  //Valid Ethernet PHY or switch driver?
354  if(interface->phyDriver != NULL)
355  {
356  //Handle periodic operations
357  interface->phyDriver->tick(interface);
358  }
359  else if(interface->switchDriver != NULL)
360  {
361  //Handle periodic operations
362  interface->switchDriver->tick(interface);
363  }
364  else
365  {
366  //Just for sanity
367  }
368 }
369 
370 
371 /**
372  * @brief Enable interrupts
373  * @param[in] interface Underlying network interface
374  **/
375 
377 {
378  //Enable Ethernet MAC interrupts
379  NVIC_EnableIRQ(ENET_IRQn);
380 
381  //Valid Ethernet PHY or switch driver?
382  if(interface->phyDriver != NULL)
383  {
384  //Enable Ethernet PHY interrupts
385  interface->phyDriver->enableIrq(interface);
386  }
387  else if(interface->switchDriver != NULL)
388  {
389  //Enable Ethernet switch interrupts
390  interface->switchDriver->enableIrq(interface);
391  }
392  else
393  {
394  //Just for sanity
395  }
396 }
397 
398 
399 /**
400  * @brief Disable interrupts
401  * @param[in] interface Underlying network interface
402  **/
403 
405 {
406  //Disable Ethernet MAC interrupts
407  NVIC_DisableIRQ(ENET_IRQn);
408 
409  //Valid Ethernet PHY or switch driver?
410  if(interface->phyDriver != NULL)
411  {
412  //Disable Ethernet PHY interrupts
413  interface->phyDriver->disableIrq(interface);
414  }
415  else if(interface->switchDriver != NULL)
416  {
417  //Disable Ethernet switch interrupts
418  interface->switchDriver->disableIrq(interface);
419  }
420  else
421  {
422  //Just for sanity
423  }
424 }
425 
426 
427 /**
428  * @brief GD32F2XX Ethernet MAC interrupt service routine
429  **/
430 
431 void ENET_IRQHandler(void)
432 {
433  bool_t flag;
434  uint32_t status;
435 
436  //Interrupt service routine prologue
437  osEnterIsr();
438 
439  //This flag will be set if a higher priority task must be woken
440  flag = FALSE;
441 
442  //Read DMA status register
443  status = ENET_DMA_STAT;
444 
445  //Packet transmitted?
446  if((status & ENET_DMA_STAT_TS) != 0)
447  {
448  //Clear TS interrupt flag
449  ENET_DMA_STAT = ENET_DMA_STAT_TS;
450 
451  //Check whether the TX buffer is available for writing
452  if((txCurDmaDesc->tdes0 & ENET_TDES0_DAV) == 0)
453  {
454  //Notify the TCP/IP stack that the transmitter is ready to send
455  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
456  }
457  }
458 
459  //Packet received?
460  if((status & ENET_DMA_STAT_RS) != 0)
461  {
462  //Clear RS interrupt flag
463  ENET_DMA_STAT = ENET_DMA_STAT_RS;
464 
465  //Set event flag
466  nicDriverInterface->nicEvent = TRUE;
467  //Notify the TCP/IP stack of the event
468  flag |= osSetEventFromIsr(&netEvent);
469  }
470 
471  //Clear NIS interrupt flag
472  ENET_DMA_STAT = ENET_DMA_STAT_NI;
473 
474  //Interrupt service routine epilogue
475  osExitIsr(flag);
476 }
477 
478 
479 /**
480  * @brief GD32F2XX Ethernet MAC event handler
481  * @param[in] interface Underlying network interface
482  **/
483 
485 {
486  error_t error;
487 
488  //Process all pending packets
489  do
490  {
491  //Read incoming packet
492  error = gd32f2xxEthReceivePacket(interface);
493 
494  //No more data in the receive buffer?
495  } while(error != ERROR_BUFFER_EMPTY);
496 }
497 
498 
499 /**
500  * @brief Send a packet
501  * @param[in] interface Underlying network interface
502  * @param[in] buffer Multi-part buffer containing the data to send
503  * @param[in] offset Offset to the first data byte
504  * @param[in] ancillary Additional options passed to the stack along with
505  * the packet
506  * @return Error code
507  **/
508 
510  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
511 {
512  size_t length;
513 
514  //Retrieve the length of the packet
515  length = netBufferGetLength(buffer) - offset;
516 
517  //Check the frame length
519  {
520  //The transmitter can accept another packet
521  osSetEvent(&interface->nicTxEvent);
522  //Report an error
523  return ERROR_INVALID_LENGTH;
524  }
525 
526  //Make sure the current buffer is available for writing
527  if((txCurDmaDesc->tdes0 & ENET_TDES0_DAV) != 0)
528  {
529  return ERROR_FAILURE;
530  }
531 
532  //Copy user data to the transmit buffer
533  netBufferRead((uint8_t *) txCurDmaDesc->tdes2, buffer, offset, length);
534 
535  //Write the number of bytes to send
536  txCurDmaDesc->tdes1 = length & ENET_TDES1_TB1S;
537  //Set LS and FS flags as the data fits in a single buffer
538  txCurDmaDesc->tdes0 |= ENET_TDES0_LSG | ENET_TDES0_FSG;
539  //Give the ownership of the descriptor to the DMA
540  txCurDmaDesc->tdes0 |= ENET_TDES0_DAV;
541 
542  //Clear TBU flag to resume processing
543  ENET_DMA_STAT = ENET_DMA_STAT_TBU;
544  //Instruct the DMA to poll the transmit descriptor list
545  ENET_DMA_TPEN = 0;
546 
547  //Point to the next descriptor in the list
548  txCurDmaDesc = (Gd32f2xxTxDmaDesc *) txCurDmaDesc->tdes3;
549 
550  //Check whether the next buffer is available for writing
551  if((txCurDmaDesc->tdes0 & ENET_TDES0_DAV) == 0)
552  {
553  //The transmitter can accept another packet
554  osSetEvent(&interface->nicTxEvent);
555  }
556 
557  //Data successfully written
558  return NO_ERROR;
559 }
560 
561 
562 /**
563  * @brief Receive a packet
564  * @param[in] interface Underlying network interface
565  * @return Error code
566  **/
567 
569 {
570  error_t error;
571  size_t n;
572  NetRxAncillary ancillary;
573 
574  //Current buffer available for reading?
575  if((rxCurDmaDesc->rdes0 & ENET_RDES0_DAV) == 0)
576  {
577  //FS and LS flags should be set
578  if((rxCurDmaDesc->rdes0 & ENET_RDES0_FDES) != 0 &&
579  (rxCurDmaDesc->rdes0 & ENET_RDES0_LDES) != 0)
580  {
581  //Make sure no error occurred
582  if((rxCurDmaDesc->rdes0 & ENET_RDES0_ERRS) == 0)
583  {
584  //Retrieve the length of the frame
585  n = (rxCurDmaDesc->rdes0 & ENET_RDES0_FRML) >> 16;
586  //Limit the number of data to read
588 
589  //Additional options can be passed to the stack along with the packet
590  ancillary = NET_DEFAULT_RX_ANCILLARY;
591 
592  //Pass the packet to the upper layer
593  nicProcessPacket(interface, (uint8_t *) rxCurDmaDesc->rdes2, n,
594  &ancillary);
595 
596  //Valid packet received
597  error = NO_ERROR;
598  }
599  else
600  {
601  //The received packet contains an error
602  error = ERROR_INVALID_PACKET;
603  }
604  }
605  else
606  {
607  //The packet is not valid
608  error = ERROR_INVALID_PACKET;
609  }
610 
611  //Give the ownership of the descriptor back to the DMA
612  rxCurDmaDesc->rdes0 = ENET_RDES0_DAV;
613  //Point to the next descriptor in the list
614  rxCurDmaDesc = (Gd32f2xxRxDmaDesc *) rxCurDmaDesc->rdes3;
615  }
616  else
617  {
618  //No more data in the receive buffer
619  error = ERROR_BUFFER_EMPTY;
620  }
621 
622  //Clear RBU flag to resume processing
623  ENET_DMA_STAT = ENET_DMA_STAT_RBU;
624  //Instruct the DMA to poll the receive descriptor list
625  ENET_DMA_RPEN = 0;
626 
627  //Return status code
628  return error;
629 }
630 
631 
632 /**
633  * @brief Configure MAC address filtering
634  * @param[in] interface Underlying network interface
635  * @return Error code
636  **/
637 
639 {
640  uint_t i;
641  uint_t j;
642  uint_t k;
643  uint32_t crc;
644  uint32_t hashTable[2];
645  MacAddr unicastMacAddr[3];
646  MacFilterEntry *entry;
647 
648  //Debug message
649  TRACE_DEBUG("Updating MAC filter...\r\n");
650 
651  //Set the MAC address of the station
652  ENET_MAC_ADDR0L = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
653  ENET_MAC_ADDR0H = interface->macAddr.w[2] | ENET_MAC_ADDR0H_MO;
654 
655  //The MAC supports 3 additional addresses for unicast perfect filtering
656  unicastMacAddr[0] = MAC_UNSPECIFIED_ADDR;
657  unicastMacAddr[1] = MAC_UNSPECIFIED_ADDR;
658  unicastMacAddr[2] = MAC_UNSPECIFIED_ADDR;
659 
660  //The hash table is used for multicast address filtering
661  hashTable[0] = 0;
662  hashTable[1] = 0;
663 
664  //The MAC address filter contains the list of MAC addresses to accept
665  //when receiving an Ethernet frame
666  for(i = 0, j = 0; i < MAC_ADDR_FILTER_SIZE; i++)
667  {
668  //Point to the current entry
669  entry = &interface->macAddrFilter[i];
670 
671  //Valid entry?
672  if(entry->refCount > 0)
673  {
674  //Multicast address?
675  if(macIsMulticastAddr(&entry->addr))
676  {
677  //Compute CRC over the current MAC address
678  crc = gd32f2xxEthCalcCrc(&entry->addr, sizeof(MacAddr));
679 
680  //The upper 6 bits in the CRC register are used to index the
681  //contents of the hash table
682  k = (crc >> 26) & 0x3F;
683 
684  //Update hash table contents
685  hashTable[k / 32] |= (1 << (k % 32));
686  }
687  else
688  {
689  //Up to 3 additional MAC addresses can be specified
690  if(j < 3)
691  {
692  //Save the unicast address
693  unicastMacAddr[j++] = entry->addr;
694  }
695  }
696  }
697  }
698 
699  //Configure the first unicast address filter
700  if(j >= 1)
701  {
702  //When the AE bit is set, the entry is used for perfect filtering
703  ENET_MAC_ADDR1L = unicastMacAddr[0].w[0] | (unicastMacAddr[0].w[1] << 16);
704  ENET_MAC_ADDR1H = unicastMacAddr[0].w[2] | ENET_MAC_ADDR1H_AFE;
705  }
706  else
707  {
708  //When the AE bit is cleared, the entry is ignored
709  ENET_MAC_ADDR1L = 0;
710  ENET_MAC_ADDR1H = 0;
711  }
712 
713  //Configure the second unicast address filter
714  if(j >= 2)
715  {
716  //When the AE bit is set, the entry is used for perfect filtering
717  ENET_MAC_ADDR2L = unicastMacAddr[1].w[0] | (unicastMacAddr[1].w[1] << 16);
718  ENET_MAC_ADDT2H = unicastMacAddr[1].w[2] | ENET_MAC_ADDR2H_AFE;
719  }
720  else
721  {
722  //When the AE bit is cleared, the entry is ignored
723  ENET_MAC_ADDR2L = 0;
724  ENET_MAC_ADDT2H = 0;
725  }
726 
727  //Configure the third unicast address filter
728  if(j >= 3)
729  {
730  //When the AE bit is set, the entry is used for perfect filtering
731  ENET_MAC_ADDR3L = unicastMacAddr[2].w[0] | (unicastMacAddr[2].w[1] << 16);
732  ENET_MAC_ADDR3H = unicastMacAddr[2].w[2] | ENET_MAC_ADDR3H_AFE;
733  }
734  else
735  {
736  //When the AE bit is cleared, the entry is ignored
737  ENET_MAC_ADDR3L = 0;
738  ENET_MAC_ADDR3H = 0;
739  }
740 
741  //Configure the multicast hash table
742  ENET_MAC_HLL = hashTable[0];
743  ENET_MAC_HLH = hashTable[1];
744 
745  //Debug message
746  TRACE_DEBUG(" ENET_MAC_HLL = %08" PRIX32 "\r\n", ENET_MAC_HLL);
747  TRACE_DEBUG(" ENET_MAC_HLH = %08" PRIX32 "\r\n", ENET_MAC_HLH);
748 
749  //Successful processing
750  return NO_ERROR;
751 }
752 
753 
754 /**
755  * @brief Adjust MAC configuration parameters for proper operation
756  * @param[in] interface Underlying network interface
757  * @return Error code
758  **/
759 
761 {
762  uint32_t config;
763 
764  //Read current MAC configuration
765  config = ENET_MAC_CFG;
766 
767  //10BASE-T or 100BASE-TX operation mode?
768  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
769  {
770  config |= ENET_MAC_CFG_SPD;
771  }
772  else
773  {
774  config &= ~ENET_MAC_CFG_SPD;
775  }
776 
777  //Half-duplex or full-duplex mode?
778  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
779  {
780  config |= ENET_MAC_CFG_DPM;
781  }
782  else
783  {
784  config &= ~ENET_MAC_CFG_DPM;
785  }
786 
787  //Update MAC configuration register
788  ENET_MAC_CFG = config;
789 
790  //Successful processing
791  return NO_ERROR;
792 }
793 
794 
795 /**
796  * @brief Write PHY register
797  * @param[in] opcode Access type (2 bits)
798  * @param[in] phyAddr PHY address (5 bits)
799  * @param[in] regAddr Register address (5 bits)
800  * @param[in] data Register value
801  **/
802 
803 void gd32f2xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
804  uint8_t regAddr, uint16_t data)
805 {
806  uint32_t temp;
807 
808  //Valid opcode?
809  if(opcode == SMI_OPCODE_WRITE)
810  {
811  //Take care not to alter MDC clock configuration
812  temp = ENET_MAC_PHY_CTL & ENET_MAC_PHY_CTL_CLR;
813  //Set up a write operation
814  temp |= ENET_MAC_PHY_CTL_PW | ENET_MAC_PHY_CTL_PB;
815  //PHY address
816  temp |= MAC_PHY_CTL_PA(phyAddr);
817  //Register address
818  temp |= MAC_PHY_CTL_PR(regAddr);
819 
820  //Data to be written in the PHY register
821  ENET_MAC_PHY_DATA = data & ENET_MAC_PHY_DATA_PD;
822 
823  //Start a write operation
824  ENET_MAC_PHY_CTL = temp;
825  //Wait for the write to complete
826  while((ENET_MAC_PHY_CTL & ENET_MAC_PHY_CTL_PB) != 0)
827  {
828  }
829  }
830  else
831  {
832  //The MAC peripheral only supports standard Clause 22 opcodes
833  }
834 }
835 
836 
837 /**
838  * @brief Read PHY register
839  * @param[in] opcode Access type (2 bits)
840  * @param[in] phyAddr PHY address (5 bits)
841  * @param[in] regAddr Register address (5 bits)
842  * @return Register value
843  **/
844 
845 uint16_t gd32f2xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
846  uint8_t regAddr)
847 {
848  uint16_t data;
849  uint32_t temp;
850 
851  //Valid opcode?
852  if(opcode == SMI_OPCODE_READ)
853  {
854  //Take care not to alter MDC clock configuration
855  temp = ENET_MAC_PHY_CTL & ENET_MAC_PHY_CTL_CLR;
856  //Set up a read operation
857  temp |= ENET_MAC_PHY_CTL_PB;
858  //PHY address
859  temp |= MAC_PHY_CTL_PA(phyAddr);
860  //Register address
861  temp |= MAC_PHY_CTL_PR(regAddr);
862 
863  //Start a read operation
864  ENET_MAC_PHY_CTL = temp;
865  //Wait for the read to complete
866  while((ENET_MAC_PHY_CTL & ENET_MAC_PHY_CTL_PB) != 0)
867  {
868  }
869 
870  //Get register value
871  data = ENET_MAC_PHY_DATA & ENET_MAC_PHY_DATA_PD;
872  }
873  else
874  {
875  //The MAC peripheral only supports standard Clause 22 opcodes
876  data = 0;
877  }
878 
879  //Return the value of the PHY register
880  return data;
881 }
882 
883 
884 /**
885  * @brief CRC calculation
886  * @param[in] data Pointer to the data over which to calculate the CRC
887  * @param[in] length Number of bytes to process
888  * @return Resulting CRC value
889  **/
890 
891 uint32_t gd32f2xxEthCalcCrc(const void *data, size_t length)
892 {
893  uint_t i;
894  uint_t j;
895  uint32_t crc;
896  const uint8_t *p;
897 
898  //Point to the data over which to calculate the CRC
899  p = (uint8_t *) data;
900  //CRC preset value
901  crc = 0xFFFFFFFF;
902 
903  //Loop through data
904  for(i = 0; i < length; i++)
905  {
906  //The message is processed bit by bit
907  for(j = 0; j < 8; j++)
908  {
909  //Update CRC value
910  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
911  {
912  crc = (crc << 1) ^ 0x04C11DB7;
913  }
914  else
915  {
916  crc = crc << 1;
917  }
918  }
919  }
920 
921  //Return CRC value
922  return ~crc;
923 }
#define txDmaDesc
#define rxBuffer
#define txBuffer
#define rxDmaDesc
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
unsigned int uint_t
Definition: compiler_port.h:50
int bool_t
Definition: compiler_port.h:53
Debugging facilities.
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t n
uint8_t opcode
Definition: dns_common.h:188
error_t
Error codes.
Definition: error.h:43
@ ERROR_BUFFER_EMPTY
Definition: error.h:141
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_PACKET
Definition: error.h:140
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:53
#define macIsMulticastAddr(macAddr)
Definition: ethernet.h:133
#define ETH_MTU
Definition: ethernet.h:116
uint8_t data[]
Definition: ethernet.h:222
MacAddr
Definition: ethernet.h:195
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
uint16_t gd32f2xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
error_t gd32f2xxEthReceivePacket(NetInterface *interface)
Receive a packet.
void gd32f2xxEthEnableIrq(NetInterface *interface)
Enable interrupts.
const NicDriver gd32f2xxEthDriver
GD32F2XX Ethernet MAC driver.
error_t gd32f2xxEthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
error_t gd32f2xxEthInit(NetInterface *interface)
GD32F2XX Ethernet MAC initialization.
void gd32f2xxEthEventHandler(NetInterface *interface)
GD32F2XX Ethernet MAC event handler.
void gd32f2xxEthTick(NetInterface *interface)
GD32F2XX Ethernet MAC timer handler.
void ENET_IRQHandler(void)
GD32F2XX Ethernet MAC interrupt service routine.
void gd32f2xxEthDisableIrq(NetInterface *interface)
Disable interrupts.
void gd32f2xxEthInitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
uint32_t gd32f2xxEthCalcCrc(const void *data, size_t length)
CRC calculation.
error_t gd32f2xxEthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
void gd32f2xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
__weak_func void gd32f2xxEthInitGpio(NetInterface *interface)
GPIO configuration.
error_t gd32f2xxEthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
GigaDevice GD32F2 Ethernet MAC driver.
#define GD32F2XX_ETH_IRQ_SUB_PRIORITY
#define GD32F2XX_ETH_TX_BUFFER_COUNT
#define GD32F2XX_ETH_IRQ_GROUP_PRIORITY
#define GD32F2XX_ETH_IRQ_PRIORITY_GROUPING
#define GD32F2XX_ETH_RX_BUFFER_COUNT
#define GD32F2XX_ETH_RX_BUFFER_SIZE
#define GD32F2XX_ETH_TX_BUFFER_SIZE
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)
Enhanced RX DMA descriptor.
Enhanced TX DMA descriptor.
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
uint8_t length
Definition: tcp.h:368