at32f4xx_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file at32f4xx_eth_driver.c
3  * @brief Artery AT32F4 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 //Device-specific definitions
35 #if defined(AT32F407RGT7) || defined(AT32F407VGT7) || defined(AT32F407RCT7) || \
36  defined(AT32F407VCT7) || defined(AT32F407VET7) || defined(AT32F407RET7) || \
37  defined(AT32F407AVCT7) || defined(AT32F407AVGT7)
38  #include "at32f403a_407.h"
39 #elif defined(AT32F437RCT7) || defined(AT32F437RGT7) || defined(AT32F437RMT7) || \
40  defined(AT32F437VCT7) || defined(AT32F437VGT7) || defined(AT32F437VMT7) || \
41  defined(AT32F437ZCT7) || defined(AT32F437ZGT7) || defined(AT32F437ZMT7)
42  #include "at32f435_437.h"
43 #endif
44 
45 //Dependencies
46 #include "core/net.h"
48 #include "debug.h"
49 
50 //Underlying network interface
51 static NetInterface *nicDriverInterface;
52 
53 //IAR EWARM compiler?
54 #if defined(__ICCARM__)
55 
56 //Transmit buffer
57 #pragma data_alignment = 4
59 //Receive buffer
60 #pragma data_alignment = 4
62 //Transmit DMA descriptors
63 #pragma data_alignment = 4
65 //Receive DMA descriptors
66 #pragma data_alignment = 4
68 
69 //Keil MDK-ARM or GCC compiler?
70 #else
71 
72 //Transmit buffer
74  __attribute__((aligned(4)));
75 //Receive buffer
77  __attribute__((aligned(4)));
78 //Transmit DMA descriptors
80  __attribute__((aligned(4)));
81 //Receive DMA descriptors
83  __attribute__((aligned(4)));
84 
85 #endif
86 
87 //Pointer to the current TX DMA descriptor
88 static At32f4xxTxDmaDesc *txCurDmaDesc;
89 //Pointer to the current RX DMA descriptor
90 static At32f4xxRxDmaDesc *rxCurDmaDesc;
91 
92 
93 /**
94  * @brief AT32F4 Ethernet MAC driver
95  **/
96 
98 {
100  ETH_MTU,
111  TRUE,
112  TRUE,
113  TRUE,
114  FALSE
115 };
116 
117 
118 /**
119  * @brief AT32F4 Ethernet MAC initialization
120  * @param[in] interface Underlying network interface
121  * @return Error code
122  **/
123 
125 {
126  error_t error;
127 
128  //Debug message
129  TRACE_INFO("Initializing AT32F4 Ethernet MAC...\r\n");
130 
131  //Save underlying network interface
132  nicDriverInterface = interface;
133 
134  //GPIO configuration
135  at32f4xxEthInitGpio(interface);
136 
137  //Enable Ethernet MAC clock
138  crm_periph_clock_enable(CRM_EMAC_PERIPH_CLOCK, TRUE);
139  crm_periph_clock_enable(CRM_EMACTX_PERIPH_CLOCK, TRUE);
140  crm_periph_clock_enable(CRM_EMACRX_PERIPH_CLOCK, TRUE);
141 
142  //Reset Ethernet MAC peripheral
143  crm_periph_reset(CRM_EMAC_PERIPH_RESET, TRUE);
144  crm_periph_reset(CRM_EMAC_PERIPH_RESET, FALSE);
145 
146  //Perform a software reset
147  EMAC_DMA->bm |= EMAC_DMA_BM_SWR;
148  //Wait for the reset to complete
149  while((EMAC_DMA->bm & EMAC_DMA_BM_SWR) != 0)
150  {
151  }
152 
153  //Adjust MDC clock range depending on HCLK frequency
154  EMAC->miiaddr = EMAC_MIIADDR_CR_DIV_124;
155 
156  //Valid Ethernet PHY or switch driver?
157  if(interface->phyDriver != NULL)
158  {
159  //Ethernet PHY initialization
160  error = interface->phyDriver->init(interface);
161  }
162  else if(interface->switchDriver != NULL)
163  {
164  //Ethernet switch initialization
165  error = interface->switchDriver->init(interface);
166  }
167  else
168  {
169  //The interface is not properly configured
170  error = ERROR_FAILURE;
171  }
172 
173  //Any error to report?
174  if(error)
175  {
176  return error;
177  }
178 
179  //Use default MAC configuration
180  EMAC->ctrl = EMAC_CTRL_RESERVED15 | EMAC_CTRL_DRO;
181 
182  //Set the MAC address of the station
183  EMAC->a0l = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
184  EMAC->a0h = interface->macAddr.w[2] | EMAC_A0H_AE;
185 
186  //The MAC supports 3 additional addresses for unicast perfect filtering
187  EMAC->a1l = 0;
188  EMAC->a1h = 0;
189  EMAC->a2l = 0;
190  EMAC->a2h = 0;
191  EMAC->a3l = 0;
192  EMAC->a3h = 0;
193 
194  //Initialize hash table
195  EMAC->htl = 0;
196  EMAC->hth = 0;
197 
198  //Configure the receive filter
199  EMAC->frmf = EMAC_FRMF_HPF | EMAC_FRMF_HMC;
200  //Disable flow control
201  EMAC->fctrl = 0;
202  //Enable store and forward mode
203  EMAC_DMA->opm = EMAC_DMA_OPM_RSF | EMAC_DMA_OPM_TSF;
204 
205  //Configure DMA bus mode
208 
209  //Initialize DMA descriptor lists
210  at32f4xxEthInitDmaDesc(interface);
211 
212  //Prevent interrupts from being generated when the transmit statistic
213  //counters reach half their maximum value
214  EMAC_MMC->tim = EMAC_MMC_TIM_TGFCIM | EMAC_MMC_TIM_TMCGFCIM |
216 
217  //Prevent interrupts from being generated when the receive statistic
218  //counters reach half their maximum value
219  EMAC_MMC->rim = EMAC_MMC_RIM_RUGFCIM | EMAC_MMC_RIM_RAEFACIM |
221 
222  //Disable MAC interrupts
223  EMAC->imr = EMAC_IMR_TIM | EMAC_IMR_PIM;
224  //Enable the desired DMA interrupts
226 
227  //Set priority grouping (4 bits for pre-emption priority, no bits for subpriority)
228  NVIC_SetPriorityGrouping(AT32F4XX_ETH_IRQ_PRIORITY_GROUPING);
229 
230  //Configure Ethernet interrupt priority
231  NVIC_SetPriority(EMAC_IRQn, NVIC_EncodePriority(AT32F4XX_ETH_IRQ_PRIORITY_GROUPING,
233 
234  //Enable MAC transmission and reception
235  EMAC->ctrl |= EMAC_CTRL_TE | EMAC_CTRL_RE;
236  //Enable DMA transmission and reception
237  EMAC_DMA->opm |= EMAC_DMA_OPM_SSTC | EMAC_DMA_OPM_SSR;
238 
239  //Accept any packets from the upper layer
240  osSetEvent(&interface->nicTxEvent);
241 
242  //Successful initialization
243  return NO_ERROR;
244 }
245 
246 
247 /**
248  * @brief GPIO configuration
249  * @param[in] interface Underlying network interface
250  **/
251 
252 __weak_func void at32f4xxEthInitGpio(NetInterface *interface)
253 {
254 //AT-START-F407 evaluation board?
255 #if defined(AT_START_F407_V1)
256  gpio_init_type gpio_init_struct;
257 
258  //Enable IOMUX clock
259  crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);
260 
261  //Enable GPIO clocks
262  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
263  crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
264  crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);
265  crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE);
266 
267  //Remap EMAC pins
268  gpio_pin_remap_config(EMAC_MUX, TRUE);
269 
270  //Select RMII interface mode
271  gpio_pin_remap_config(MII_RMII_SEL_GMUX, TRUE);
272 
273  //Get default parameters
274  gpio_default_para_init(&gpio_init_struct);
275 
276  //Configure CLKOUT (PA8) as an output
277  gpio_init_struct.gpio_pins = GPIO_PINS_8;
278  gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
279  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
280  gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
281  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
282  gpio_init(GPIOA, &gpio_init_struct);
283 
284  //Configure CLKOUT pin to output SCLK/8 clock (25MHz)
285  crm_clock_out_set(CRM_CLKOUT_SCLK);
286  crm_clkout_div_set(CRM_CLKOUT_DIV_8);
287 
288  //Configure RMII pins
289  gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
290  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
291  gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
292  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
293 
294  //Configure EMAC_RMII_REF_CLK (PA1) and EMAC_MDIO (PA2)
295  gpio_init_struct.gpio_pins = GPIO_PINS_1 | GPIO_PINS_2;
296  gpio_init(GPIOA, &gpio_init_struct);
297 
298  //Configure EMAC_RMII_TX_EN (PB11), EMAC_RMII_TXD0 (PB12) and
299  //EMAC_RMII_TXD1 (PB13)
300  gpio_init_struct.gpio_pins = GPIO_PINS_11 | GPIO_PINS_12 | GPIO_PINS_13;
301  gpio_init(GPIOB, &gpio_init_struct);
302 
303  //Configure EMAC_MDC (PC1)
304  gpio_init_struct.gpio_pins = GPIO_PINS_1;
305  gpio_init(GPIOC, &gpio_init_struct);
306 
307  //Configure EMAC_RMII_CRS_DV (PD8), EMAC_RMII_RXD0 (PD9) and
308  //EMAC_RMII_RXD1 (PD10)
309  gpio_init_struct.gpio_pins = GPIO_PINS_8 | GPIO_PINS_9 | GPIO_PINS_10;
310  gpio_init(GPIOD, &gpio_init_struct);
311 
312  //Configure PHY_RST (PC8)
313  gpio_init_struct.gpio_pins = GPIO_PINS_8;
314  gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
315  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
316  gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
317  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
318  gpio_init(GPIOC, &gpio_init_struct);
319 
320  //Reset PHY transceiver
321  gpio_bits_write(GPIOC, GPIO_PINS_8, FALSE);
322  sleep(10);
323  gpio_bits_write(GPIOC, GPIO_PINS_8, TRUE);
324  sleep(10);
325 
326 //AT-START-F437 evaluation board?
327 #elif defined(AT_START_F437_V1)
328  gpio_init_type gpio_init_struct;
329 
330  //Enable SCFG clock
331  crm_periph_clock_enable(CRM_SCFG_PERIPH_CLOCK, TRUE);
332 
333  //Enable GPIO clocks
334  crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
335  crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);
336  crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE);
337  crm_periph_clock_enable(CRM_GPIOE_PERIPH_CLOCK, TRUE);
338  crm_periph_clock_enable(CRM_GPIOG_PERIPH_CLOCK, TRUE);
339 
340  //Select RMII interface mode
341  scfg_emac_interface_set(SCFG_EMAC_SELECT_RMII);
342 
343  //Get default parameters
344  gpio_default_para_init(&gpio_init_struct);
345 
346  //Configure CLKOUT1 (PA8) as an output
347  gpio_init_struct.gpio_pins = GPIO_PINS_8;
348  gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
349  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
350  gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
351  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
352  gpio_init(GPIOA, &gpio_init_struct);
353 
354  //Remap CLKOUT1 pin
355  gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE8, GPIO_MUX_0);
356 
357  //Configure CLKOUT1 pin to output PLLCLK/10 clock (25MHz)
358  crm_clock_out1_set(CRM_CLKOUT1_PLL);
359  crm_clkout_div_set(CRM_CLKOUT_INDEX_1, CRM_CLKOUT_DIV1_5, CRM_CLKOUT_DIV2_2);
360 
361  //Configure RMII pins
362  gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
363  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
364  gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
365  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
366 
367  //Configure EMAC_RMII_REF_CLK (PA1) and EMAC_MDIO (PA2)
368  gpio_init_struct.gpio_pins = GPIO_PINS_1 | GPIO_PINS_2;
369  gpio_init(GPIOA, &gpio_init_struct);
370 
371  //Configure EMAC_MDC (PC1)
372  gpio_init_struct.gpio_pins = GPIO_PINS_1;
373  gpio_init(GPIOC, &gpio_init_struct);
374 
375  //Configure EMAC_RMII_CRS_DV (PD8), EMAC_RMII_RXD0 (PD9) and
376  //EMAC_RMII_RXD1 (PD10)
377  gpio_init_struct.gpio_pins = GPIO_PINS_8 | GPIO_PINS_9 | GPIO_PINS_10;
378  gpio_init(GPIOD, &gpio_init_struct);
379 
380  //Configure EMAC_RMII_TX_EN (PG11), EMAC_RMII_TXD0 (PG13) and
381  //EMAC_RMII_TXD1 (PG14)
382  gpio_init_struct.gpio_pins = GPIO_PINS_11 | GPIO_PINS_13 | GPIO_PINS_14;
383  gpio_init(GPIOG, &gpio_init_struct);
384 
385  //Remap Ethernet pins
386  gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE1, GPIO_MUX_11);
387  gpio_pin_mux_config(GPIOA, GPIO_PINS_SOURCE2, GPIO_MUX_11);
388  gpio_pin_mux_config(GPIOC, GPIO_PINS_SOURCE1, GPIO_MUX_11);
389  gpio_pin_mux_config(GPIOD, GPIO_PINS_SOURCE8, GPIO_MUX_11);
390  gpio_pin_mux_config(GPIOD, GPIO_PINS_SOURCE9, GPIO_MUX_11);
391  gpio_pin_mux_config(GPIOD, GPIO_PINS_SOURCE10, GPIO_MUX_11);
392  gpio_pin_mux_config(GPIOG, GPIO_PINS_SOURCE11, GPIO_MUX_11);
393  gpio_pin_mux_config(GPIOG, GPIO_PINS_SOURCE13, GPIO_MUX_11);
394  gpio_pin_mux_config(GPIOG, GPIO_PINS_SOURCE14, GPIO_MUX_11);
395 
396  //Configure PHY_RST (PE15)
397  gpio_init_struct.gpio_pins = GPIO_PINS_15;
398  gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
399  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
400  gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
401  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
402  gpio_init(GPIOE, &gpio_init_struct);
403 
404  //Configure PHY_PD (PG15)
405  gpio_init_struct.gpio_pins = GPIO_PINS_15;
406  gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
407  gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
408  gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
409  gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
410  gpio_init(GPIOG, &gpio_init_struct);
411 
412  //Exit power down mode
413  gpio_bits_write(GPIOG, GPIO_PINS_15, FALSE);
414 
415  //Reset PHY transceiver
416  gpio_bits_write(GPIOE, GPIO_PINS_15, FALSE);
417  sleep(10);
418  gpio_bits_write(GPIOE, GPIO_PINS_15, TRUE);
419  sleep(10);
420 #endif
421 }
422 
423 
424 /**
425  * @brief Initialize DMA descriptor lists
426  * @param[in] interface Underlying network interface
427  **/
428 
430 {
431  uint_t i;
432 
433  //Initialize TX DMA descriptor list
434  for(i = 0; i < AT32F4XX_ETH_TX_BUFFER_COUNT; i++)
435  {
436  //Use chain structure rather than ring structure
438  //Initialize transmit buffer size
439  txDmaDesc[i].tdes1 = 0;
440  //Transmit buffer address
441  txDmaDesc[i].tdes2 = (uint32_t) txBuffer[i];
442  //Next descriptor address
443  txDmaDesc[i].tdes3 = (uint32_t) &txDmaDesc[i + 1];
444  }
445 
446  //The last descriptor is chained to the first entry
447  txDmaDesc[i - 1].tdes3 = (uint32_t) &txDmaDesc[0];
448  //Point to the very first descriptor
449  txCurDmaDesc = &txDmaDesc[0];
450 
451  //Initialize RX DMA descriptor list
452  for(i = 0; i < AT32F4XX_ETH_RX_BUFFER_COUNT; i++)
453  {
454  //The descriptor is initially owned by the DMA
455  rxDmaDesc[i].rdes0 = EMAC_RDES0_OWN;
456  //Use chain structure rather than ring structure
458  //Receive buffer address
459  rxDmaDesc[i].rdes2 = (uint32_t) rxBuffer[i];
460  //Next descriptor address
461  rxDmaDesc[i].rdes3 = (uint32_t) &rxDmaDesc[i + 1];
462  }
463 
464  //The last descriptor is chained to the first entry
465  rxDmaDesc[i - 1].rdes3 = (uint32_t) &rxDmaDesc[0];
466  //Point to the very first descriptor
467  rxCurDmaDesc = &rxDmaDesc[0];
468 
469  //Start location of the TX descriptor list
470  EMAC_DMA->tdladdr = (uint32_t) txDmaDesc;
471  //Start location of the RX descriptor list
472  EMAC_DMA->rdladdr = (uint32_t) rxDmaDesc;
473 }
474 
475 
476 /**
477  * @brief AT32F4 Ethernet MAC timer handler
478  *
479  * This routine is periodically called by the TCP/IP stack to handle periodic
480  * operations such as polling the link state
481  *
482  * @param[in] interface Underlying network interface
483  **/
484 
486 {
487  //Valid Ethernet PHY or switch driver?
488  if(interface->phyDriver != NULL)
489  {
490  //Handle periodic operations
491  interface->phyDriver->tick(interface);
492  }
493  else if(interface->switchDriver != NULL)
494  {
495  //Handle periodic operations
496  interface->switchDriver->tick(interface);
497  }
498  else
499  {
500  //Just for sanity
501  }
502 }
503 
504 
505 /**
506  * @brief Enable interrupts
507  * @param[in] interface Underlying network interface
508  **/
509 
511 {
512  //Enable Ethernet MAC interrupts
513  NVIC_EnableIRQ(EMAC_IRQn);
514 
515  //Valid Ethernet PHY or switch driver?
516  if(interface->phyDriver != NULL)
517  {
518  //Enable Ethernet PHY interrupts
519  interface->phyDriver->enableIrq(interface);
520  }
521  else if(interface->switchDriver != NULL)
522  {
523  //Enable Ethernet switch interrupts
524  interface->switchDriver->enableIrq(interface);
525  }
526  else
527  {
528  //Just for sanity
529  }
530 }
531 
532 
533 /**
534  * @brief Disable interrupts
535  * @param[in] interface Underlying network interface
536  **/
537 
539 {
540  //Disable Ethernet MAC interrupts
541  NVIC_DisableIRQ(EMAC_IRQn);
542 
543  //Valid Ethernet PHY or switch driver?
544  if(interface->phyDriver != NULL)
545  {
546  //Disable Ethernet PHY interrupts
547  interface->phyDriver->disableIrq(interface);
548  }
549  else if(interface->switchDriver != NULL)
550  {
551  //Disable Ethernet switch interrupts
552  interface->switchDriver->disableIrq(interface);
553  }
554  else
555  {
556  //Just for sanity
557  }
558 }
559 
560 
561 /**
562  * @brief AT32F4 Ethernet MAC interrupt service routine
563  **/
564 
565 void EMAC_IRQHandler(void)
566 {
567  bool_t flag;
568  uint32_t status;
569 
570  //Interrupt service routine prologue
571  osEnterIsr();
572 
573  //This flag will be set if a higher priority task must be woken
574  flag = FALSE;
575 
576  //Read DMA status register
577  status = EMAC_DMA->sts;
578 
579  //Packet transmitted?
580  if((status & EMAC_DMA_STS_TI) != 0)
581  {
582  //Clear TI interrupt flag
583  EMAC_DMA->sts = EMAC_DMA_STS_TI;
584 
585  //Check whether the TX buffer is available for writing
586  if((txCurDmaDesc->tdes0 & EMAC_TDES0_OWN) == 0)
587  {
588  //Notify the TCP/IP stack that the transmitter is ready to send
589  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
590  }
591  }
592 
593  //Packet received?
594  if((status & EMAC_DMA_STS_RI) != 0)
595  {
596  //Clear RI interrupt flag
597  EMAC_DMA->sts = EMAC_DMA_STS_RI;
598 
599  //Set event flag
600  nicDriverInterface->nicEvent = TRUE;
601  //Notify the TCP/IP stack of the event
602  flag |= osSetEventFromIsr(&netEvent);
603  }
604 
605  //Clear NIS interrupt flag
606  EMAC_DMA->sts = EMAC_DMA_STS_NIS;
607 
608  //Interrupt service routine epilogue
609  osExitIsr(flag);
610 }
611 
612 
613 /**
614  * @brief AT32F4 Ethernet MAC event handler
615  * @param[in] interface Underlying network interface
616  **/
617 
619 {
620  error_t error;
621 
622  //Process all pending packets
623  do
624  {
625  //Read incoming packet
626  error = at32f4xxEthReceivePacket(interface);
627 
628  //No more data in the receive buffer?
629  } while(error != ERROR_BUFFER_EMPTY);
630 }
631 
632 
633 /**
634  * @brief Send a packet
635  * @param[in] interface Underlying network interface
636  * @param[in] buffer Multi-part buffer containing the data to send
637  * @param[in] offset Offset to the first data byte
638  * @param[in] ancillary Additional options passed to the stack along with
639  * the packet
640  * @return Error code
641  **/
642 
644  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
645 {
646  size_t length;
647 
648  //Retrieve the length of the packet
649  length = netBufferGetLength(buffer) - offset;
650 
651  //Check the frame length
653  {
654  //The transmitter can accept another packet
655  osSetEvent(&interface->nicTxEvent);
656  //Report an error
657  return ERROR_INVALID_LENGTH;
658  }
659 
660  //Make sure the current buffer is available for writing
661  if((txCurDmaDesc->tdes0 & EMAC_TDES0_OWN) != 0)
662  {
663  return ERROR_FAILURE;
664  }
665 
666  //Copy user data to the transmit buffer
667  netBufferRead((uint8_t *) txCurDmaDesc->tdes2, buffer, offset, length);
668 
669  //Write the number of bytes to send
670  txCurDmaDesc->tdes1 = length & EMAC_TDES1_TBS1;
671  //Set LS and FS flags as the data fits in a single buffer
672  txCurDmaDesc->tdes0 |= EMAC_TDES0_LS | EMAC_TDES0_FS;
673  //Give the ownership of the descriptor to the DMA
674  txCurDmaDesc->tdes0 |= EMAC_TDES0_OWN;
675 
676  //Clear TBUS flag to resume processing
677  EMAC_DMA->sts = EMAC_DMA_STS_TBU;
678  //Instruct the DMA to poll the transmit descriptor list
679  EMAC_DMA->tpd = 0;
680 
681  //Point to the next descriptor in the list
682  txCurDmaDesc = (At32f4xxTxDmaDesc *) txCurDmaDesc->tdes3;
683 
684  //Check whether the next buffer is available for writing
685  if((txCurDmaDesc->tdes0 & EMAC_TDES0_OWN) == 0)
686  {
687  //The transmitter can accept another packet
688  osSetEvent(&interface->nicTxEvent);
689  }
690 
691  //Data successfully written
692  return NO_ERROR;
693 }
694 
695 
696 /**
697  * @brief Receive a packet
698  * @param[in] interface Underlying network interface
699  * @return Error code
700  **/
701 
703 {
704  error_t error;
705  size_t n;
706  NetRxAncillary ancillary;
707 
708  //Current buffer available for reading?
709  if((rxCurDmaDesc->rdes0 & EMAC_RDES0_OWN) == 0)
710  {
711  //FS and LS flags should be set
712  if((rxCurDmaDesc->rdes0 & EMAC_RDES0_FS) != 0 &&
713  (rxCurDmaDesc->rdes0 & EMAC_RDES0_LS) != 0)
714  {
715  //Make sure no error occurred
716  if((rxCurDmaDesc->rdes0 & EMAC_RDES0_ES) == 0)
717  {
718  //Retrieve the length of the frame
719  n = (rxCurDmaDesc->rdes0 & EMAC_RDES0_FL) >> 16;
720  //Limit the number of data to read
722 
723  //Additional options can be passed to the stack along with the packet
724  ancillary = NET_DEFAULT_RX_ANCILLARY;
725 
726  //Pass the packet to the upper layer
727  nicProcessPacket(interface, (uint8_t *) rxCurDmaDesc->rdes2, n,
728  &ancillary);
729 
730  //Valid packet received
731  error = NO_ERROR;
732  }
733  else
734  {
735  //The received packet contains an error
736  error = ERROR_INVALID_PACKET;
737  }
738  }
739  else
740  {
741  //The packet is not valid
742  error = ERROR_INVALID_PACKET;
743  }
744 
745  //Give the ownership of the descriptor back to the DMA
746  rxCurDmaDesc->rdes0 = EMAC_RDES0_OWN;
747  //Point to the next descriptor in the list
748  rxCurDmaDesc = (At32f4xxRxDmaDesc *) rxCurDmaDesc->rdes3;
749  }
750  else
751  {
752  //No more data in the receive buffer
753  error = ERROR_BUFFER_EMPTY;
754  }
755 
756  //Clear RBUS flag to resume processing
757  EMAC_DMA->sts = EMAC_DMA_STS_RBU;
758  //Instruct the DMA to poll the receive descriptor list
759  EMAC_DMA->rpd = 0;
760 
761  //Return status code
762  return error;
763 }
764 
765 
766 /**
767  * @brief Configure MAC address filtering
768  * @param[in] interface Underlying network interface
769  * @return Error code
770  **/
771 
773 {
774  uint_t i;
775  uint_t j;
776  uint_t k;
777  uint32_t crc;
778  uint32_t hashTable[2];
779  MacAddr unicastMacAddr[3];
780  MacFilterEntry *entry;
781 
782  //Debug message
783  TRACE_DEBUG("Updating MAC filter...\r\n");
784 
785  //Set the MAC address of the station
786  EMAC->a0l = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
787  EMAC->a0h = interface->macAddr.w[2] | EMAC_A0H_AE;
788 
789  //The MAC supports 3 additional addresses for unicast perfect filtering
790  unicastMacAddr[0] = MAC_UNSPECIFIED_ADDR;
791  unicastMacAddr[1] = MAC_UNSPECIFIED_ADDR;
792  unicastMacAddr[2] = MAC_UNSPECIFIED_ADDR;
793 
794  //The hash table is used for multicast address filtering
795  hashTable[0] = 0;
796  hashTable[1] = 0;
797 
798  //The MAC address filter contains the list of MAC addresses to accept
799  //when receiving an Ethernet frame
800  for(i = 0, j = 0; i < MAC_ADDR_FILTER_SIZE; i++)
801  {
802  //Point to the current entry
803  entry = &interface->macAddrFilter[i];
804 
805  //Valid entry?
806  if(entry->refCount > 0)
807  {
808  //Multicast address?
809  if(macIsMulticastAddr(&entry->addr))
810  {
811  //Compute CRC over the current MAC address
812  crc = at32f4xxEthCalcCrc(&entry->addr, sizeof(MacAddr));
813 
814  //The upper 6 bits in the CRC register are used to index the
815  //contents of the hash table
816  k = (crc >> 26) & 0x3F;
817 
818  //Update hash table contents
819  hashTable[k / 32] |= (1 << (k % 32));
820  }
821  else
822  {
823  //Up to 3 additional MAC addresses can be specified
824  if(j < 3)
825  {
826  //Save the unicast address
827  unicastMacAddr[j++] = entry->addr;
828  }
829  }
830  }
831  }
832 
833  //Configure the first unicast address filter
834  if(j >= 1)
835  {
836  //When the AE bit is set, the entry is used for perfect filtering
837  EMAC->a1l = unicastMacAddr[0].w[0] | (unicastMacAddr[0].w[1] << 16);
838  EMAC->a1h = unicastMacAddr[0].w[2] | EMAC_A1H_AE;
839  }
840  else
841  {
842  //When the AE bit is cleared, the entry is ignored
843  EMAC->a1l = 0;
844  EMAC->a1h = 0;
845  }
846 
847  //Configure the second unicast address filter
848  if(j >= 2)
849  {
850  //When the AE bit is set, the entry is used for perfect filtering
851  EMAC->a2l = unicastMacAddr[1].w[0] | (unicastMacAddr[1].w[1] << 16);
852  EMAC->a2h = unicastMacAddr[1].w[2] | EMAC_A2H_AE;
853  }
854  else
855  {
856  //When the AE bit is cleared, the entry is ignored
857  EMAC->a2l = 0;
858  EMAC->a2h = 0;
859  }
860 
861  //Configure the third unicast address filter
862  if(j >= 3)
863  {
864  //When the AE bit is set, the entry is used for perfect filtering
865  EMAC->a3l = unicastMacAddr[2].w[0] | (unicastMacAddr[2].w[1] << 16);
866  EMAC->a3h = unicastMacAddr[2].w[2] | EMAC_A3H_AE;
867  }
868  else
869  {
870  //When the AE bit is cleared, the entry is ignored
871  EMAC->a3l = 0;
872  EMAC->a3h = 0;
873  }
874 
875  //Configure the multicast hash table
876  EMAC->htl = hashTable[0];
877  EMAC->hth = hashTable[1];
878 
879  //Debug message
880  TRACE_DEBUG(" EMAC->htl = %08" PRIX32 "\r\n", EMAC->htl);
881  TRACE_DEBUG(" EMAC->hth = %08" PRIX32 "\r\n", EMAC->hth);
882 
883  //Successful processing
884  return NO_ERROR;
885 }
886 
887 
888 /**
889  * @brief Adjust MAC configuration parameters for proper operation
890  * @param[in] interface Underlying network interface
891  * @return Error code
892  **/
893 
895 {
896  uint32_t config;
897 
898  //Read current MAC configuration
899  config = EMAC->ctrl;
900 
901  //10BASE-T or 100BASE-TX operation mode?
902  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
903  {
904  config |= EMAC_CTRL_FES;
905  }
906  else
907  {
908  config &= ~EMAC_CTRL_FES;
909  }
910 
911  //Half-duplex or full-duplex mode?
912  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
913  {
914  config |= EMAC_CTRL_DM;
915  }
916  else
917  {
918  config &= ~EMAC_CTRL_DM;
919  }
920 
921  //Update MAC configuration register
922  EMAC->ctrl = config;
923 
924  //Successful processing
925  return NO_ERROR;
926 }
927 
928 
929 /**
930  * @brief Write PHY register
931  * @param[in] opcode Access type (2 bits)
932  * @param[in] phyAddr PHY address (5 bits)
933  * @param[in] regAddr Register address (5 bits)
934  * @param[in] data Register value
935  **/
936 
937 void at32f4xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
938  uint8_t regAddr, uint16_t data)
939 {
940  uint32_t temp;
941 
942  //Valid opcode?
943  if(opcode == SMI_OPCODE_WRITE)
944  {
945  //Take care not to alter MDC clock configuration
946  temp = EMAC->miiaddr & EMAC_MIIADDR_CR;
947  //Set up a write operation
949  //PHY address
950  temp |= (phyAddr << 11) & EMAC_MIIADDR_PA;
951  //Register address
952  temp |= (regAddr << 6) & EMAC_MIIADDR_MII;
953 
954  //Data to be written in the PHY register
955  EMAC->miidt = data & EMAC_MIIDT_MD;
956 
957  //Start a write operation
958  EMAC->miiaddr = temp;
959  //Wait for the write to complete
960  while((EMAC->miiaddr & EMAC_MIIADDR_MB) != 0)
961  {
962  }
963  }
964  else
965  {
966  //The MAC peripheral only supports standard Clause 22 opcodes
967  }
968 }
969 
970 
971 /**
972  * @brief Read PHY register
973  * @param[in] opcode Access type (2 bits)
974  * @param[in] phyAddr PHY address (5 bits)
975  * @param[in] regAddr Register address (5 bits)
976  * @return Register value
977  **/
978 
979 uint16_t at32f4xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
980  uint8_t regAddr)
981 {
982  uint16_t data;
983  uint32_t temp;
984 
985  //Valid opcode?
986  if(opcode == SMI_OPCODE_READ)
987  {
988  //Take care not to alter MDC clock configuration
989  temp = EMAC->miiaddr & EMAC_MIIADDR_CR;
990  //Set up a read operation
991  temp |= EMAC_MIIADDR_MB;
992  //PHY address
993  temp |= (phyAddr << 11) & EMAC_MIIADDR_PA;
994  //Register address
995  temp |= (regAddr << 6) & EMAC_MIIADDR_MII;
996 
997  //Start a read operation
998  EMAC->miiaddr = temp;
999  //Wait for the read to complete
1000  while((EMAC->miiaddr & EMAC_MIIADDR_MB) != 0)
1001  {
1002  }
1003 
1004  //Get register value
1005  data = EMAC->miidt & EMAC_MIIDT_MD;
1006  }
1007  else
1008  {
1009  //The MAC peripheral only supports standard Clause 22 opcodes
1010  data = 0;
1011  }
1012 
1013  //Return the value of the PHY register
1014  return data;
1015 }
1016 
1017 
1018 /**
1019  * @brief CRC calculation
1020  * @param[in] data Pointer to the data over which to calculate the CRC
1021  * @param[in] length Number of bytes to process
1022  * @return Resulting CRC value
1023  **/
1024 
1025 uint32_t at32f4xxEthCalcCrc(const void *data, size_t length)
1026 {
1027  uint_t i;
1028  uint_t j;
1029  uint32_t crc;
1030  const uint8_t *p;
1031 
1032  //Point to the data over which to calculate the CRC
1033  p = (uint8_t *) data;
1034  //CRC preset value
1035  crc = 0xFFFFFFFF;
1036 
1037  //Loop through data
1038  for(i = 0; i < length; i++)
1039  {
1040  //The message is processed bit by bit
1041  for(j = 0; j < 8; j++)
1042  {
1043  //Update CRC value
1044  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
1045  {
1046  crc = (crc << 1) ^ 0x04C11DB7;
1047  }
1048  else
1049  {
1050  crc = crc << 1;
1051  }
1052  }
1053  }
1054 
1055  //Return CRC value
1056  return ~crc;
1057 }
#define txDmaDesc
#define rxBuffer
#define txBuffer
#define rxDmaDesc
uint16_t at32f4xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
void at32f4xxEthEventHandler(NetInterface *interface)
AT32F4 Ethernet MAC event handler.
__weak_func void at32f4xxEthInitGpio(NetInterface *interface)
GPIO configuration.
error_t at32f4xxEthReceivePacket(NetInterface *interface)
Receive a packet.
void at32f4xxEthEnableIrq(NetInterface *interface)
Enable interrupts.
void EMAC_IRQHandler(void)
AT32F4 Ethernet MAC interrupt service routine.
uint32_t at32f4xxEthCalcCrc(const void *data, size_t length)
CRC calculation.
error_t at32f4xxEthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
void at32f4xxEthDisableIrq(NetInterface *interface)
Disable interrupts.
error_t at32f4xxEthInit(NetInterface *interface)
AT32F4 Ethernet MAC initialization.
void at32f4xxEthTick(NetInterface *interface)
AT32F4 Ethernet MAC timer handler.
error_t at32f4xxEthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
void at32f4xxEthInitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
error_t at32f4xxEthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
void at32f4xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
const NicDriver at32f4xxEthDriver
AT32F4 Ethernet MAC driver.
Artery AT32F4 Ethernet MAC driver.
#define AT32F4XX_ETH_TX_BUFFER_COUNT
#define EMAC_CTRL_DM
#define EMAC_TDES0_LS
#define EMAC_A2H_AE
#define EMAC_DMA_OPM_SSR
#define EMAC_A1H_AE
#define EMAC_RDES0_FL
#define EMAC_MIIADDR_CR_DIV_124
#define EMAC_TDES0_TCH
#define EMAC_DMA_OPM_RSF
#define EMAC_DMA_STS_NIS
#define EMAC_RDES0_FS
#define EMAC_DMA_STS_TBU
#define AT32F4XX_ETH_TX_BUFFER_SIZE
#define EMAC_TDES0_OWN
#define EMAC_MIIADDR_MB
#define EMAC_RDES0_OWN
#define EMAC_RDES1_RCH
#define EMAC_TDES1_TBS1
#define EMAC_DMA_BM_USP
#define EMAC_MMC_TIM_TMCGFCIM
#define AT32F4XX_ETH_IRQ_SUB_PRIORITY
#define EMAC_A3H_AE
#define EMAC_DMA_IE_NIE
#define EMAC_TDES0_IC
#define EMAC_MIIADDR_MII
#define EMAC_TDES0_FS
#define EMAC_MMC_TIM_TGFCIM
#define EMAC_DMA_IE_RIE
#define EMAC_MIIADDR_CR
#define EMAC_IMR_PIM
#define EMAC_MIIADDR_MW
#define EMAC_DMA_BM_RDP_32
#define EMAC_RDES1_RBS1
#define EMAC_DMA_STS_RBU
#define EMAC_FRMF_HPF
#define EMAC_DMA_BM_SWR
#define EMAC_MMC_RIM_RAEFACIM
#define EMAC_DMA_BM_PBL_32
#define AT32F4XX_ETH_RX_BUFFER_SIZE
#define EMAC_DMA_STS_TI
#define EMAC_DMA_BM_PR_1_1
#define AT32F4XX_ETH_IRQ_PRIORITY_GROUPING
#define EMAC_CTRL_TE
#define EMAC_IMR_TIM
#define EMAC_FRMF_HMC
#define AT32F4XX_ETH_RX_BUFFER_COUNT
#define EMAC_CTRL_RESERVED15
#define EMAC_DMA_IE_TIE
#define EMAC_DMA_STS_RI
#define EMAC_DMA_OPM_TSF
#define EMAC_A0H_AE
#define EMAC_CTRL_DRO
#define EMAC_MMC_TIM_TSCGFCIM
#define EMAC_DMA_BM_AAB
#define EMAC_MIIDT_MD
#define EMAC_RDES0_ES
#define EMAC_RDES0_LS
#define EMAC_MMC_RIM_RCEFCIM
#define EMAC_CTRL_RE
#define EMAC_MIIADDR_PA
#define EMAC_CTRL_FES
#define EMAC_MMC_RIM_RUGFCIM
#define AT32F4XX_ETH_IRQ_GROUP_PRIORITY
#define EMAC_DMA_OPM_SSTC
unsigned int uint_t
Definition: compiler_port.h:50
int bool_t
Definition: compiler_port.h:53
Debugging facilities.
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t n
uint8_t opcode
Definition: dns_common.h:188
error_t
Error codes.
Definition: error.h:43
@ ERROR_BUFFER_EMPTY
Definition: error.h:141
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_PACKET
Definition: error.h:140
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:53
#define macIsMulticastAddr(macAddr)
Definition: ethernet.h:133
#define ETH_MTU
Definition: ethernet.h:116
uint8_t data[]
Definition: ethernet.h:222
MacAddr
Definition: ethernet.h:195
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
uint16_t regAddr
uint8_t p
Definition: ndp.h:300
TCP/IP stack core.
#define NetInterface
Definition: net.h:36
#define netEvent
Definition: net_legacy.h:196
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
size_t netBufferRead(void *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Read data from a multi-part buffer.
Definition: net_mem.c:674
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:101
#define NetRxAncillary
Definition: net_misc.h:40
#define NetTxAncillary
Definition: net_misc.h:36
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:391
#define SMI_OPCODE_WRITE
Definition: nic.h:66
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83
#define SMI_OPCODE_READ
Definition: nic.h:67
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
#define MIN(a, b)
Definition: os_port.h:63
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
#define sleep(delay)
Definition: os_port.h:301
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