apm32f4xx_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file apm32f4xx_eth_driver.c
3  * @brief APM32F4 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 "apm32f4xx.h"
36 #include "apm32f4xx_rcm.h"
37 #include "apm32f4xx_syscfg.h"
38 #include "apm32f4xx_gpio.h"
39 #include "core/net.h"
41 #include "debug.h"
42 
43 //Underlying network interface
44 static NetInterface *nicDriverInterface;
45 
46 //IAR EWARM compiler?
47 #if defined(__ICCARM__)
48 
49 //Transmit buffer
50 #pragma data_alignment = 4
52 //Receive buffer
53 #pragma data_alignment = 4
55 //Transmit DMA descriptors
56 #pragma data_alignment = 4
58 //Receive DMA descriptors
59 #pragma data_alignment = 4
61 
62 //Keil MDK-ARM or GCC compiler?
63 #else
64 
65 //Transmit buffer
67  __attribute__((aligned(4)));
68 //Receive buffer
70  __attribute__((aligned(4)));
71 //Transmit DMA descriptors
73  __attribute__((aligned(4)));
74 //Receive DMA descriptors
76  __attribute__((aligned(4)));
77 
78 #endif
79 
80 //Pointer to the current TX DMA descriptor
81 static Apm32f4xxTxDmaDesc *txCurDmaDesc;
82 //Pointer to the current RX DMA descriptor
83 static Apm32f4xxRxDmaDesc *rxCurDmaDesc;
84 
85 
86 /**
87  * @brief APM32F4 Ethernet MAC driver
88  **/
89 
91 {
93  ETH_MTU,
104  TRUE,
105  TRUE,
106  TRUE,
107  FALSE
108 };
109 
110 
111 /**
112  * @brief APM32F4 Ethernet MAC initialization
113  * @param[in] interface Underlying network interface
114  * @return Error code
115  **/
116 
118 {
119  error_t error;
120 
121  //Debug message
122  TRACE_INFO("Initializing APM32F4 Ethernet MAC...\r\n");
123 
124  //Save underlying network interface
125  nicDriverInterface = interface;
126 
127  //GPIO configuration
128  apm32f4xxEthInitGpio(interface);
129 
130  //Enable Ethernet MAC clock
131  RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_ETH_MAC |
132  RCM_AHB1_PERIPH_ETH_MAC_Tx | RCM_AHB1_PERIPH_ETH_MAC_Rx);
133 
134  //Reset Ethernet MAC peripheral
135  RCM_EnableAHB1PeriphReset(RCM_AHB1_PERIPH_ETH_MAC);
136  RCM_DisableAHB1PeriphReset(RCM_AHB1_PERIPH_ETH_MAC);
137 
138  //Perform a software reset
139  ETH->DMABMOD |= ETH_DMABMOD_SWR;
140  //Wait for the reset to complete
141  while((ETH->DMABMOD & ETH_DMABMOD_SWR) != 0)
142  {
143  }
144 
145  //Adjust MDC clock range depending on HCLK frequency
146  ETH->ADDR = ETH_ADDR_CR_DIV_102;
147 
148  //Valid Ethernet PHY or switch driver?
149  if(interface->phyDriver != NULL)
150  {
151  //Ethernet PHY initialization
152  error = interface->phyDriver->init(interface);
153  }
154  else if(interface->switchDriver != NULL)
155  {
156  //Ethernet switch initialization
157  error = interface->switchDriver->init(interface);
158  }
159  else
160  {
161  //The interface is not properly configured
162  error = ERROR_FAILURE;
163  }
164 
165  //Any error to report?
166  if(error)
167  {
168  return error;
169  }
170 
171  //Use default MAC configuration
172  ETH->CFG = ETH_CFG_RESERVED15 | ETH_CFG_DISRXO;
173 
174  //Set the MAC address of the station
175  ETH->ADDR0L = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
176  ETH->ADDR0H = interface->macAddr.w[2] | ETH_ADDR0H_AL1;
177 
178  //The MAC supports 3 additional addresses for unicast perfect filtering
179  ETH->ADDR1L = 0;
180  ETH->ADDR1H = 0;
181  ETH->ADDR2L = 0;
182  ETH->ADDR2H = 0;
183  ETH->ADDR3L = 0;
184  ETH->ADDR3H = 0;
185 
186  //Initialize hash table
187  ETH->HTL = 0;
188  ETH->HTH = 0;
189 
190  //Configure the receive filter
191  ETH->FRAF = ETH_FRAF_HPF | ETH_FRAF_HMC;
192  //Disable flow control
193  ETH->FCTRL = 0;
194  //Enable store and forward mode
195  ETH->DMAOPMOD = ETH_DMAOPMOD_RXSF | ETH_DMAOPMOD_TXSF;
196 
197  //Configure DMA bus mode
200 
201  //Initialize DMA descriptor lists
202  apm32f4xxEthInitDmaDesc(interface);
203 
204  //Prevent interrupts from being generated when the transmit statistic
205  //counters reach half their maximum value
207 
208  //Prevent interrupts from being generated when the receive statistic
209  //counters reach half their maximum value
211 
212  //Disable MAC interrupts
213  ETH->IMASK = ETH_IMASK_TSTIM | ETH_IMASK_PMTIM;
214  //Enable the desired DMA interrupts
216 
217  //Set priority grouping (4 bits for pre-emption priority, no bits for subpriority)
218  NVIC_SetPriorityGrouping(APM32F4XX_ETH_IRQ_PRIORITY_GROUPING);
219 
220  //Configure Ethernet interrupt priority
221  NVIC_SetPriority(ETH_IRQn, NVIC_EncodePriority(APM32F4XX_ETH_IRQ_PRIORITY_GROUPING,
223 
224  //Enable MAC transmission and reception
225  ETH->CFG |= ETH_CFG_TXEN | ETH_CFG_RXEN;
226  //Enable DMA transmission and reception
227  ETH->DMAOPMOD |= ETH_DMAOPMOD_STTX | ETH_DMAOPMOD_STRX;
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 apm32f4xxEthInitGpio(NetInterface *interface)
243 {
244 //APM32F407IG Tiny Board?
245 #if defined(USE_APM32F407IG_TINY_BOARD)
246  GPIO_Config_T gpioConfig;
247 
248  //Enable SYSCFG clock
249  RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);
250 
251  //Enable GPIO clocks
252  RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA);
253  RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOC);
254  RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOG);
255 
256  //Select RMII interface mode
257  SYSCFG_ConfigMediaInterface(SYSCFG_INTERFACE_RMII);
258 
259  //Configure RMII pins
260  gpioConfig.mode = GPIO_MODE_AF;
261  gpioConfig.otype = GPIO_OTYPE_PP;
262  gpioConfig.pupd = GPIO_PUPD_NOPULL;
263  gpioConfig.speed = GPIO_SPEED_100MHz;
264 
265  //Configure ETH_RMII_REF_CLK (PA1), ETH_MDIO (PA2) and ETH_RMII_CRS_DV (PA7)
266  gpioConfig.pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
267  GPIO_Config(GPIOA, &gpioConfig);
268 
269  //Configure ETH_MDC (PC1), ETH_RMII_RXD0 (PC4) and ETH_RMII_RXD1 (PC5)
270  gpioConfig.pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
271  GPIO_Config(GPIOC, &gpioConfig);
272 
273  //Configure ETH_RMII_TX_EN (PG11), ETH_RMII_TXD0 (PG13) and
274  //ETH_RMII_TXD1 (PG14)
275  gpioConfig.pin = GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14;
276  GPIO_Config(GPIOG, &gpioConfig);
277 
278  //Remap Ethernet pins
279  GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_1, GPIO_AF_ETH);
280  GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_2, GPIO_AF_ETH);
281  GPIO_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_7, GPIO_AF_ETH);
282  GPIO_ConfigPinAF(GPIOC, GPIO_PIN_SOURCE_1, GPIO_AF_ETH);
283  GPIO_ConfigPinAF(GPIOC, GPIO_PIN_SOURCE_4, GPIO_AF_ETH);
284  GPIO_ConfigPinAF(GPIOC, GPIO_PIN_SOURCE_5, GPIO_AF_ETH);
285  GPIO_ConfigPinAF(GPIOG, GPIO_PIN_SOURCE_11, GPIO_AF_ETH);
286  GPIO_ConfigPinAF(GPIOG, GPIO_PIN_SOURCE_13, GPIO_AF_ETH);
287  GPIO_ConfigPinAF(GPIOG, GPIO_PIN_SOURCE_14, GPIO_AF_ETH);
288 #endif
289 }
290 
291 
292 /**
293  * @brief Initialize DMA descriptor lists
294  * @param[in] interface Underlying network interface
295  **/
296 
298 {
299  uint_t i;
300 
301  //Initialize TX DMA descriptor list
302  for(i = 0; i < APM32F4XX_ETH_TX_BUFFER_COUNT; i++)
303  {
304  //Use chain structure rather than ring structure
306  //Initialize transmit buffer size
307  txDmaDesc[i].tdes1 = 0;
308  //Transmit buffer address
309  txDmaDesc[i].tdes2 = (uint32_t) txBuffer[i];
310  //Next descriptor address
311  txDmaDesc[i].tdes3 = (uint32_t) &txDmaDesc[i + 1];
312  //Reserved fields
313  txDmaDesc[i].tdes4 = 0;
314  txDmaDesc[i].tdes5 = 0;
315  //Transmit frame time stamp
316  txDmaDesc[i].tdes6 = 0;
317  txDmaDesc[i].tdes7 = 0;
318  }
319 
320  //The last descriptor is chained to the first entry
321  txDmaDesc[i - 1].tdes3 = (uint32_t) &txDmaDesc[0];
322  //Point to the very first descriptor
323  txCurDmaDesc = &txDmaDesc[0];
324 
325  //Initialize RX DMA descriptor list
326  for(i = 0; i < APM32F4XX_ETH_RX_BUFFER_COUNT; i++)
327  {
328  //The descriptor is initially owned by the DMA
329  rxDmaDesc[i].rdes0 = ETH_RXDES0_OWN;
330  //Use chain structure rather than ring structure
332  //Receive buffer address
333  rxDmaDesc[i].rdes2 = (uint32_t) rxBuffer[i];
334  //Next descriptor address
335  rxDmaDesc[i].rdes3 = (uint32_t) &rxDmaDesc[i + 1];
336  //Extended status
337  rxDmaDesc[i].rdes4 = 0;
338  //Reserved field
339  rxDmaDesc[i].rdes5 = 0;
340  //Receive frame time stamp
341  rxDmaDesc[i].rdes6 = 0;
342  rxDmaDesc[i].rdes7 = 0;
343  }
344 
345  //The last descriptor is chained to the first entry
346  rxDmaDesc[i - 1].rdes3 = (uint32_t) &rxDmaDesc[0];
347  //Point to the very first descriptor
348  rxCurDmaDesc = &rxDmaDesc[0];
349 
350  //Start location of the TX descriptor list
351  ETH->DMATXDLADDR = (uint32_t) txDmaDesc;
352  //Start location of the RX descriptor list
353  ETH->DMARXDLADDR = (uint32_t) rxDmaDesc;
354 }
355 
356 
357 /**
358  * @brief APM32F4 Ethernet MAC timer handler
359  *
360  * This routine is periodically called by the TCP/IP stack to handle periodic
361  * operations such as polling the link state
362  *
363  * @param[in] interface Underlying network interface
364  **/
365 
367 {
368  //Valid Ethernet PHY or switch driver?
369  if(interface->phyDriver != NULL)
370  {
371  //Handle periodic operations
372  interface->phyDriver->tick(interface);
373  }
374  else if(interface->switchDriver != NULL)
375  {
376  //Handle periodic operations
377  interface->switchDriver->tick(interface);
378  }
379  else
380  {
381  //Just for sanity
382  }
383 }
384 
385 
386 /**
387  * @brief Enable interrupts
388  * @param[in] interface Underlying network interface
389  **/
390 
392 {
393  //Enable Ethernet MAC interrupts
394  NVIC_EnableIRQ(ETH_IRQn);
395 
396  //Valid Ethernet PHY or switch driver?
397  if(interface->phyDriver != NULL)
398  {
399  //Enable Ethernet PHY interrupts
400  interface->phyDriver->enableIrq(interface);
401  }
402  else if(interface->switchDriver != NULL)
403  {
404  //Enable Ethernet switch interrupts
405  interface->switchDriver->enableIrq(interface);
406  }
407  else
408  {
409  //Just for sanity
410  }
411 }
412 
413 
414 /**
415  * @brief Disable interrupts
416  * @param[in] interface Underlying network interface
417  **/
418 
420 {
421  //Disable Ethernet MAC interrupts
422  NVIC_DisableIRQ(ETH_IRQn);
423 
424  //Valid Ethernet PHY or switch driver?
425  if(interface->phyDriver != NULL)
426  {
427  //Disable Ethernet PHY interrupts
428  interface->phyDriver->disableIrq(interface);
429  }
430  else if(interface->switchDriver != NULL)
431  {
432  //Disable Ethernet switch interrupts
433  interface->switchDriver->disableIrq(interface);
434  }
435  else
436  {
437  //Just for sanity
438  }
439 }
440 
441 
442 /**
443  * @brief APM32F4 Ethernet MAC interrupt service routine
444  **/
445 
446 void ETH_IRQHandler(void)
447 {
448  bool_t flag;
449  uint32_t status;
450 
451  //Interrupt service routine prologue
452  osEnterIsr();
453 
454  //This flag will be set if a higher priority task must be woken
455  flag = FALSE;
456 
457  //Read DMA status register
458  status = ETH->DMASTS;
459 
460  //Packet transmitted?
461  if((status & ETH_DMASTS_TXFLG) != 0)
462  {
463  //Clear TXFLG interrupt flag
464  ETH->DMASTS = ETH_DMASTS_TXFLG;
465 
466  //Check whether the TX buffer is available for writing
467  if((txCurDmaDesc->tdes0 & ETH_TXDES0_OWN) == 0)
468  {
469  //Notify the TCP/IP stack that the transmitter is ready to send
470  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
471  }
472  }
473 
474  //Packet received?
475  if((status & ETH_DMASTS_RXFLG) != 0)
476  {
477  //Clear RXFLG interrupt flag
478  ETH->DMASTS = ETH_DMASTS_RXFLG;
479 
480  //Set event flag
481  nicDriverInterface->nicEvent = TRUE;
482  //Notify the TCP/IP stack of the event
483  flag |= osSetEventFromIsr(&netEvent);
484  }
485 
486  //Clear NIS interrupt flag
487  ETH->DMASTS = ETH_DMASTS_NINTS;
488 
489  //Interrupt service routine epilogue
490  osExitIsr(flag);
491 }
492 
493 
494 /**
495  * @brief APM32F4 Ethernet MAC event handler
496  * @param[in] interface Underlying network interface
497  **/
498 
500 {
501  error_t error;
502 
503  //Process all pending packets
504  do
505  {
506  //Read incoming packet
507  error = apm32f4xxEthReceivePacket(interface);
508 
509  //No more data in the receive buffer?
510  } while(error != ERROR_BUFFER_EMPTY);
511 }
512 
513 
514 /**
515  * @brief Send a packet
516  * @param[in] interface Underlying network interface
517  * @param[in] buffer Multi-part buffer containing the data to send
518  * @param[in] offset Offset to the first data byte
519  * @param[in] ancillary Additional options passed to the stack along with
520  * the packet
521  * @return Error code
522  **/
523 
525  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
526 {
527  size_t length;
528 
529  //Retrieve the length of the packet
530  length = netBufferGetLength(buffer) - offset;
531 
532  //Check the frame length
534  {
535  //The transmitter can accept another packet
536  osSetEvent(&interface->nicTxEvent);
537  //Report an error
538  return ERROR_INVALID_LENGTH;
539  }
540 
541  //Make sure the current buffer is available for writing
542  if((txCurDmaDesc->tdes0 & ETH_TXDES0_OWN) != 0)
543  {
544  return ERROR_FAILURE;
545  }
546 
547  //Copy user data to the transmit buffer
548  netBufferRead((uint8_t *) txCurDmaDesc->tdes2, buffer, offset, length);
549 
550  //Write the number of bytes to send
551  txCurDmaDesc->tdes1 = length & ETH_TXDES1_TXBS1;
552  //Set LS and FS flags as the data fits in a single buffer
553  txCurDmaDesc->tdes0 |= ETH_TXDES0_LS | ETH_TXDES0_FS;
554  //Give the ownership of the descriptor to the DMA
555  txCurDmaDesc->tdes0 |= ETH_TXDES0_OWN;
556 
557  //Clear TXBU flag to resume processing
558  ETH->DMASTS = ETH_DMASTS_TXBU;
559  //Instruct the DMA to poll the transmit descriptor list
560  ETH->DMATXPD = 0;
561 
562  //Point to the next descriptor in the list
563  txCurDmaDesc = (Apm32f4xxTxDmaDesc *) txCurDmaDesc->tdes3;
564 
565  //Check whether the next buffer is available for writing
566  if((txCurDmaDesc->tdes0 & ETH_TXDES0_OWN) == 0)
567  {
568  //The transmitter can accept another packet
569  osSetEvent(&interface->nicTxEvent);
570  }
571 
572  //Data successfully written
573  return NO_ERROR;
574 }
575 
576 
577 /**
578  * @brief Receive a packet
579  * @param[in] interface Underlying network interface
580  * @return Error code
581  **/
582 
584 {
585  error_t error;
586  size_t n;
587  NetRxAncillary ancillary;
588 
589  //Current buffer available for reading?
590  if((rxCurDmaDesc->rdes0 & ETH_RXDES0_OWN) == 0)
591  {
592  //FS and LS flags should be set
593  if((rxCurDmaDesc->rdes0 & ETH_RXDES0_FDES) != 0 &&
594  (rxCurDmaDesc->rdes0 & ETH_RXDES0_LDES) != 0)
595  {
596  //Make sure no error occurred
597  if((rxCurDmaDesc->rdes0 & ETH_RXDES0_ERRS) == 0)
598  {
599  //Retrieve the length of the frame
600  n = (rxCurDmaDesc->rdes0 & ETH_RXDES0_FL) >> 16;
601  //Limit the number of data to read
603 
604  //Additional options can be passed to the stack along with the packet
605  ancillary = NET_DEFAULT_RX_ANCILLARY;
606 
607  //Pass the packet to the upper layer
608  nicProcessPacket(interface, (uint8_t *) rxCurDmaDesc->rdes2, n,
609  &ancillary);
610 
611  //Valid packet received
612  error = NO_ERROR;
613  }
614  else
615  {
616  //The received packet contains an error
617  error = ERROR_INVALID_PACKET;
618  }
619  }
620  else
621  {
622  //The packet is not valid
623  error = ERROR_INVALID_PACKET;
624  }
625 
626  //Give the ownership of the descriptor back to the DMA
627  rxCurDmaDesc->rdes0 = ETH_RXDES0_OWN;
628  //Point to the next descriptor in the list
629  rxCurDmaDesc = (Apm32f4xxRxDmaDesc *) rxCurDmaDesc->rdes3;
630  }
631  else
632  {
633  //No more data in the receive buffer
634  error = ERROR_BUFFER_EMPTY;
635  }
636 
637  //Clear RXBU flag to resume processing
638  ETH->DMASTS = ETH_DMASTS_RXBU;
639  //Instruct the DMA to poll the receive descriptor list
640  ETH->DMARXPD = 0;
641 
642  //Return status code
643  return error;
644 }
645 
646 
647 /**
648  * @brief Configure MAC address filtering
649  * @param[in] interface Underlying network interface
650  * @return Error code
651  **/
652 
654 {
655  uint_t i;
656  uint_t j;
657  uint_t k;
658  uint32_t crc;
659  uint32_t hashTable[2];
660  MacAddr unicastMacAddr[3];
661  MacFilterEntry *entry;
662 
663  //Debug message
664  TRACE_DEBUG("Updating MAC filter...\r\n");
665 
666  //Set the MAC address of the station
667  ETH->ADDR0L = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
668  ETH->ADDR0H = interface->macAddr.w[2] | ETH_ADDR0H_AL1;
669 
670  //The MAC supports 3 additional addresses for unicast perfect filtering
671  unicastMacAddr[0] = MAC_UNSPECIFIED_ADDR;
672  unicastMacAddr[1] = MAC_UNSPECIFIED_ADDR;
673  unicastMacAddr[2] = MAC_UNSPECIFIED_ADDR;
674 
675  //The hash table is used for multicast address filtering
676  hashTable[0] = 0;
677  hashTable[1] = 0;
678 
679  //The MAC address filter contains the list of MAC addresses to accept
680  //when receiving an Ethernet frame
681  for(i = 0, j = 0; i < MAC_ADDR_FILTER_SIZE; i++)
682  {
683  //Point to the current entry
684  entry = &interface->macAddrFilter[i];
685 
686  //Valid entry?
687  if(entry->refCount > 0)
688  {
689  //Multicast address?
690  if(macIsMulticastAddr(&entry->addr))
691  {
692  //Compute CRC over the current MAC address
693  crc = apm32f4xxEthCalcCrc(&entry->addr, sizeof(MacAddr));
694 
695  //The upper 6 bits in the CRC register are used to index the
696  //contents of the hash table
697  k = (crc >> 26) & 0x3F;
698 
699  //Update hash table contents
700  hashTable[k / 32] |= (1 << (k % 32));
701  }
702  else
703  {
704  //Up to 3 additional MAC addresses can be specified
705  if(j < 3)
706  {
707  //Save the unicast address
708  unicastMacAddr[j++] = entry->addr;
709  }
710  }
711  }
712  }
713 
714  //Configure the first unicast address filter
715  if(j >= 1)
716  {
717  //When the AE bit is set, the entry is used for perfect filtering
718  ETH->ADDR1L = unicastMacAddr[0].w[0] | (unicastMacAddr[0].w[1] << 16);
719  ETH->ADDR1H = unicastMacAddr[0].w[2] | ETH_ADDR1H_ADDREN;
720  }
721  else
722  {
723  //When the AE bit is cleared, the entry is ignored
724  ETH->ADDR1L = 0;
725  ETH->ADDR1H = 0;
726  }
727 
728  //Configure the second unicast address filter
729  if(j >= 2)
730  {
731  //When the AE bit is set, the entry is used for perfect filtering
732  ETH->ADDR2L = unicastMacAddr[1].w[0] | (unicastMacAddr[1].w[1] << 16);
733  ETH->ADDR2H = unicastMacAddr[1].w[2] | ETH_ADDR2H_ADDREN;
734  }
735  else
736  {
737  //When the AE bit is cleared, the entry is ignored
738  ETH->ADDR2L = 0;
739  ETH->ADDR2H = 0;
740  }
741 
742  //Configure the third unicast address filter
743  if(j >= 3)
744  {
745  //When the AE bit is set, the entry is used for perfect filtering
746  ETH->ADDR3L = unicastMacAddr[2].w[0] | (unicastMacAddr[2].w[1] << 16);
747  ETH->ADDR3H = unicastMacAddr[2].w[2] | ETH_ADDR3H_ADDREN;
748  }
749  else
750  {
751  //When the AE bit is cleared, the entry is ignored
752  ETH->ADDR3L = 0;
753  ETH->ADDR3H = 0;
754  }
755 
756  //Configure the multicast hash table
757  ETH->HTL = hashTable[0];
758  ETH->HTH = hashTable[1];
759 
760  //Debug message
761  TRACE_DEBUG(" HTL = %08" PRIX32 "\r\n", ETH->HTL);
762  TRACE_DEBUG(" HTH = %08" PRIX32 "\r\n", ETH->HTH);
763 
764  //Successful processing
765  return NO_ERROR;
766 }
767 
768 
769 /**
770  * @brief Adjust MAC configuration parameters for proper operation
771  * @param[in] interface Underlying network interface
772  * @return Error code
773  **/
774 
776 {
777  uint32_t config;
778 
779  //Read current MAC configuration
780  config = ETH->CFG;
781 
782  //10BASE-T or 100BASE-TX operation mode?
783  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
784  {
785  config |= ETH_CFG_SSEL;
786  }
787  else
788  {
789  config &= ~ETH_CFG_SSEL;
790  }
791 
792  //Half-duplex or full-duplex mode?
793  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
794  {
795  config |= ETH_CFG_DM;
796  }
797  else
798  {
799  config &= ~ETH_CFG_DM;
800  }
801 
802  //Update MAC configuration register
803  ETH->CFG = config;
804 
805  //Successful processing
806  return NO_ERROR;
807 }
808 
809 
810 /**
811  * @brief Write PHY register
812  * @param[in] opcode Access type (2 bits)
813  * @param[in] phyAddr PHY address (5 bits)
814  * @param[in] regAddr Register address (5 bits)
815  * @param[in] data Register value
816  **/
817 
818 void apm32f4xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
819  uint8_t regAddr, uint16_t data)
820 {
821  uint32_t temp;
822 
823  //Valid opcode?
824  if(opcode == SMI_OPCODE_WRITE)
825  {
826  //Take care not to alter MDC clock configuration
827  temp = ETH->ADDR & ETH_ADDR_CR;
828  //Set up a write operation
829  temp |= ETH_ADDR_MW | ETH_ADDR_MB;
830  //PHY address
831  temp |= (phyAddr << 11) & ETH_ADDR_PA;
832  //Register address
833  temp |= (regAddr << 6) & ETH_ADDR_MR;
834 
835  //Data to be written in the PHY register
836  ETH->DATA = data & ETH_DATA_MD;
837 
838  //Start a write operation
839  ETH->ADDR = temp;
840  //Wait for the write to complete
841  while((ETH->ADDR & ETH_ADDR_MB) != 0)
842  {
843  }
844  }
845  else
846  {
847  //The MAC peripheral only supports standard Clause 22 opcodes
848  }
849 }
850 
851 
852 /**
853  * @brief Read PHY register
854  * @param[in] opcode Access type (2 bits)
855  * @param[in] phyAddr PHY address (5 bits)
856  * @param[in] regAddr Register address (5 bits)
857  * @return Register value
858  **/
859 
860 uint16_t apm32f4xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
861  uint8_t regAddr)
862 {
863  uint16_t data;
864  uint32_t temp;
865 
866  //Valid opcode?
867  if(opcode == SMI_OPCODE_READ)
868  {
869  //Take care not to alter MDC clock configuration
870  temp = ETH->ADDR & ETH_ADDR_CR;
871  //Set up a read operation
872  temp |= ETH_ADDR_MB;
873  //PHY address
874  temp |= (phyAddr << 11) & ETH_ADDR_PA;
875  //Register address
876  temp |= (regAddr << 6) & ETH_ADDR_MR;
877 
878  //Start a read operation
879  ETH->ADDR = temp;
880  //Wait for the read to complete
881  while((ETH->ADDR & ETH_ADDR_MB) != 0)
882  {
883  }
884 
885  //Get register value
886  data = ETH->DATA & ETH_DATA_MD;
887  }
888  else
889  {
890  //The MAC peripheral only supports standard Clause 22 opcodes
891  data = 0;
892  }
893 
894  //Return the value of the PHY register
895  return data;
896 }
897 
898 
899 /**
900  * @brief CRC calculation
901  * @param[in] data Pointer to the data over which to calculate the CRC
902  * @param[in] length Number of bytes to process
903  * @return Resulting CRC value
904  **/
905 
906 uint32_t apm32f4xxEthCalcCrc(const void *data, size_t length)
907 {
908  uint_t i;
909  uint_t j;
910  uint32_t crc;
911  const uint8_t *p;
912 
913  //Point to the data over which to calculate the CRC
914  p = (uint8_t *) data;
915  //CRC preset value
916  crc = 0xFFFFFFFF;
917 
918  //Loop through data
919  for(i = 0; i < length; i++)
920  {
921  //The message is processed bit by bit
922  for(j = 0; j < 8; j++)
923  {
924  //Update CRC value
925  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
926  {
927  crc = (crc << 1) ^ 0x04C11DB7;
928  }
929  else
930  {
931  crc = crc << 1;
932  }
933  }
934  }
935 
936  //Return CRC value
937  return ~crc;
938 }
__weak_func void apm32f4xxEthInitGpio(NetInterface *interface)
GPIO configuration.
const NicDriver apm32f4xxEthDriver
APM32F4 Ethernet MAC driver.
void apm32f4xxEthInitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
void apm32f4xxEthTick(NetInterface *interface)
APM32F4 Ethernet MAC timer handler.
uint32_t apm32f4xxEthCalcCrc(const void *data, size_t length)
CRC calculation.
void apm32f4xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
error_t apm32f4xxEthReceivePacket(NetInterface *interface)
Receive a packet.
error_t apm32f4xxEthInit(NetInterface *interface)
APM32F4 Ethernet MAC initialization.
error_t apm32f4xxEthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
void apm32f4xxEthDisableIrq(NetInterface *interface)
Disable interrupts.
void apm32f4xxEthEventHandler(NetInterface *interface)
APM32F4 Ethernet MAC event handler.
uint16_t apm32f4xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
void ETH_IRQHandler(void)
APM32F4 Ethernet MAC interrupt service routine.
void apm32f4xxEthEnableIrq(NetInterface *interface)
Enable interrupts.
error_t apm32f4xxEthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
error_t apm32f4xxEthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
APM32F4 Ethernet MAC driver.
#define ETH_ADDR1H_ADDREN
#define ETH_DMASTS_RXBU
#define ETH_TXINT_TXGFSCOL
#define ETH_TXDES0_FS
#define APM32F4XX_ETH_RX_BUFFER_SIZE
#define ETH_DMAOPMOD_STRX
#define ETH_CFG_RESERVED15
#define ETH_ADDR_MW
#define ETH_RXDES0_FL
#define ETH_RXDES0_ERRS
#define ETH_CFG_TXEN
#define ETH_CFG_SSEL
#define ETH_ADDR_PA
#define ETH_ADDR_CR_DIV_102
#define ETH_RXINT_RXFCE
#define ETH_DMAINTEN_TXIEN
#define ETH_DMAOPMOD_STTX
#define ETH_DMAINTEN_RXIEN
#define ETH_RXDES0_FDES
#define ETH_DMABMOD_USP
#define ETH_RXDES1_RBS1
#define ETH_CFG_RXEN
#define ETH_TXDES0_TXCH
#define ETH_RXDES1_RXCH
#define APM32F4XX_ETH_TX_BUFFER_SIZE
#define APM32F4XX_ETH_IRQ_GROUP_PRIORITY
#define ETH_DMAOPMOD_RXSF
#define ETH_DMAINTEN_NINTSEN
#define ETH_TXINT_TXGF
#define ETH_TXINT_TXGFMCOL
#define ETH_DMASTS_TXFLG
#define ETH_DMASTS_RXFLG
#define ETH_TXDES1_TXBS1
#define ETH_RXDES0_LDES
#define ETH_ADDR_MB
#define ETH_ADDR2H_ADDREN
#define ETH_DMABMOD_AAL
#define ETH_RXINT_RXGUNF
#define ETH_DMASTS_TXBU
#define ETH_TXDES0_LS
#define ETH_CFG_DM
#define ETH_DMAOPMOD_TXSF
#define ETH_DMABMOD_RPBL_32
#define ETH_CFG_DISRXO
#define ETH_RXINT_RXFAE
#define ETH_ADDR_MR
#define ETH_DMABMOD_EDFEN
#define ETH_DMASTS_NINTS
#define ETH_TXDES0_OWN
#define ETH_IMASK_TSTIM
#define APM32F4XX_ETH_TX_BUFFER_COUNT
#define ETH_DMABMOD_PR_1_1
#define ETH_IMASK_PMTIM
#define ETH_DMABMOD_PBL_32
#define ETH_FRAF_HPF
#define APM32F4XX_ETH_IRQ_SUB_PRIORITY
#define APM32F4XX_ETH_IRQ_PRIORITY_GROUPING
#define ETH_DMABMOD_SWR
#define ETH_RXDES0_OWN
#define ETH_FRAF_HMC
#define ETH_ADDR3H_ADDREN
#define ETH_ADDR_CR
#define ETH_DATA_MD
#define ETH_TXDES0_INTC
#define ETH_ADDR0H_AL1
#define APM32F4XX_ETH_RX_BUFFER_COUNT
#define txDmaDesc
#define rxBuffer
#define txBuffer
#define rxDmaDesc
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
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