stm32c5xx_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file stm32c5xx_eth_driver.c
3  * @brief STM32C5 Ethernet MAC driver
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 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.6.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include "stm32_hal.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 = ETH_BUS_DATA_WIDTH_BYTE
49 //Receive buffer
50 #pragma data_alignment = ETH_BUS_DATA_WIDTH_BYTE
52 //Transmit DMA descriptors
53 #pragma data_alignment = ETH_BUS_DATA_WIDTH_BYTE
55 //Receive DMA descriptors
56 #pragma data_alignment = ETH_BUS_DATA_WIDTH_BYTE
58 
59 //Keil MDK-ARM or GCC compiler?
60 #else
61 
62 //Transmit buffer
64  __attribute__((aligned(ETH_BUS_DATA_WIDTH_BYTE)));
65 //Receive buffer
67  __attribute__((aligned(ETH_BUS_DATA_WIDTH_BYTE)));
68 //Transmit DMA descriptors
70  __attribute__((aligned(ETH_BUS_DATA_WIDTH_BYTE)));
71 //Receive DMA descriptors
73  __attribute__((aligned(ETH_BUS_DATA_WIDTH_BYTE)));
74 
75 #endif
76 
77 //Current transmit descriptor
78 static uint_t txIndex;
79 //Current receive descriptor
80 static uint_t rxIndex;
81 
82 
83 /**
84  * @brief STM32C5 Ethernet MAC driver
85  **/
86 
88 {
90  ETH_MTU,
101  TRUE,
102  TRUE,
103  TRUE,
104  FALSE
105 };
106 
107 
108 /**
109  * @brief STM32C5 Ethernet MAC initialization
110  * @param[in] interface Underlying network interface
111  * @return Error code
112  **/
113 
115 {
116  error_t error;
117  uint32_t temp;
118 
119  //Debug message
120  TRACE_INFO("Initializing STM32C5 Ethernet MAC...\r\n");
121 
122  //Save underlying network interface
123  nicDriverInterface = interface;
124 
125  //GPIO configuration
126  stm32c5xxEthInitGpio(interface);
127 
128  //Enable Ethernet MAC clock
129  HAL_RCC_ETH1_EnableClock();
130  HAL_RCC_ETH1CK_EnableClock();
131  HAL_RCC_ETH1TX_EnableClock();
132  HAL_RCC_ETH1RX_EnableClock();
133 
134  //Reset Ethernet MAC peripheral
135  HAL_RCC_ETH1_Reset();
136 
137  //Perform a software reset
138  ETH1->DMAMR |= ETH_DMAMR_SWR;
139  //Wait for the reset to complete
140  while((ETH1->DMAMR & ETH_DMAMR_SWR) != 0)
141  {
142  }
143 
144  //Adjust MDC clock range depending on HCLK frequency
145  ETH1->MACMDIOAR = ETH_MACMDIOAR_CR_Val(5);
146 
147  //Valid Ethernet PHY or switch driver?
148  if(interface->phyDriver != NULL)
149  {
150  //Ethernet PHY initialization
151  error = interface->phyDriver->init(interface);
152  }
153  else if(interface->switchDriver != NULL)
154  {
155  //Ethernet switch initialization
156  error = interface->switchDriver->init(interface);
157  }
158  else
159  {
160  //The interface is not properly configured
161  error = ERROR_FAILURE;
162  }
163 
164  //Any error to report?
165  if(error)
166  {
167  return error;
168  }
169 
170  //Use default MAC configuration
171  ETH1->MACCR = ETH_MACCR_GPSLCE | ETH_MACCR_RESERVED15 | ETH_MACCR_DO;
172 
173  //Set the maximum packet size that can be accepted
174  temp = ETH1->MACECR & ~ETH_MACECR_GPSL;
175  ETH1->MACECR = temp | STM32C5XX_ETH_RX_BUFFER_SIZE;
176 
177  //Configure MAC address filtering
179 
180  //Disable flow control
181  ETH1->MACQTXFCR = 0;
182  ETH1->MACRXFCR = 0;
183 
184  //Configure DMA operating mode
185  ETH1->DMAMR = ETH_DMAMR_INTM_Val(0) | ETH_DMAMR_TXPR_Val(0);
186  //Configure system bus mode
187  ETH1->DMASBMR |= ETH_DMASBMR_AAL;
188  //The DMA takes the descriptor table as contiguous
189  ETH1->DMACCR = ETH_DMACCR_DSL_Val(0);
190 
191  //Configure TX features
192  ETH1->DMACTXCR = ETH_DMACTXCR_TXPBL_Val(32);
193 
194  //Configure RX features
195  ETH1->DMACRXCR = ETH_DMACRXCR_RXPBL_Val(32) |
197 
198  //Enable store and forward mode
199  ETH1->MTLTXQOMR |= ETH_MTLTXQOMR_TSF;
200  ETH1->MTLRXQOMR |= ETH_MTLRXQOMR_RSF;
201 
202  //Initialize DMA descriptor lists
203  stm32c5xxEthInitDmaDesc(interface);
204 
205  //Prevent interrupts from being generated when the transmit statistic
206  //counters reach half their maximum value
207  ETH1->MMC_TX_INTERRUPT_MASK = ETH_MMC_TX_INTERRUPT_MASK_TXLPITRCIM |
208  ETH_MMC_TX_INTERRUPT_MASK_TXLPIUSCIM | ETH_MMC_TX_INTERRUPT_MASK_TXGPKTIM |
209  ETH_MMC_TX_INTERRUPT_MASK_TXMCOLGPIM | ETH_MMC_TX_INTERRUPT_MASK_TXSCOLGPIM;
210 
211  //Prevent interrupts from being generated when the receive statistic
212  //counters reach half their maximum value
213  ETH1->MMC_RX_INTERRUPT_MASK = ETH_MMC_RX_INTERRUPT_MASK_RXLPITRCIM |
214  ETH_MMC_RX_INTERRUPT_MASK_RXLPIUSCIM | ETH_MMC_RX_INTERRUPT_MASK_RXUCGPIM |
215  ETH_MMC_RX_INTERRUPT_MASK_RXALGNERPIM | ETH_MMC_RX_INTERRUPT_MASK_RXCRCERPIM;
216 
217  //Disable MAC interrupts
218  ETH1->MACIER = 0;
219  //Enable the desired DMA interrupts
220  ETH1->DMACIER = ETH_DMACIER_NIE | ETH_DMACIER_RIE | ETH_DMACIER_TIE;
221 
222  //Set priority grouping (4 bits for pre-emption priority, no bits for subpriority)
223  NVIC_SetPriorityGrouping(STM32C5XX_ETH_IRQ_PRIORITY_GROUPING);
224 
225  //Configure Ethernet interrupt priority
226  NVIC_SetPriority(ETH1_IRQn, NVIC_EncodePriority(STM32C5XX_ETH_IRQ_PRIORITY_GROUPING,
228 
229  //Enable MAC transmission and reception
230  ETH1->MACCR |= ETH_MACCR_TE | ETH_MACCR_RE;
231 
232  //Enable DMA transmission and reception
233  ETH1->DMACTXCR |= ETH_DMACTXCR_ST;
234  ETH1->DMACRXCR |= ETH_DMACRXCR_SR;
235 
236  //Accept any packets from the upper layer
237  osSetEvent(&interface->nicTxEvent);
238 
239  //Successful initialization
240  return NO_ERROR;
241 }
242 
243 
244 /**
245  * @brief GPIO configuration
246  * @param[in] interface Underlying network interface
247  **/
248 
249 __weak_func void stm32c5xxEthInitGpio(NetInterface *interface)
250 {
251 //Nucleo-C5A3ZG evaluation board?
252 #if defined(USE_NUCLEO_C5A3ZG)
253  hal_gpio_config_t gpio_config;
254 
255  //Enable SBS clock
256  HAL_RCC_SBS_EnableClock();
257 
258  //Enable GPIO clocks
259  HAL_RCC_GPIOA_EnableClock();
260  HAL_RCC_GPIOC_EnableClock();
261  HAL_RCC_GPIOD_EnableClock();
262  HAL_RCC_GPIOE_EnableClock();
263  HAL_RCC_GPIOG_EnableClock();
264 
265  //Select RMII interface mode
266  HAL_SBS_SetETHPHYInterface(ETH1, HAL_SBS_ETHPHY_ITF_RMII);
267 
268  //Configure RMII pins
269  gpio_config.mode = HAL_GPIO_MODE_ALTERNATE;
270  gpio_config.output_type = HAL_GPIO_OUTPUT_PUSHPULL;
271  gpio_config.pull = HAL_GPIO_PULL_NO;
272  gpio_config.speed = HAL_GPIO_SPEED_FREQ_VERY_HIGH;
273 
274  //Configure ETH1_RMII_REF_CLK (PA1)
275  gpio_config.alternate = HAL_GPIO_AF_10;
276  HAL_GPIO_Init(HAL_GPIOA, HAL_GPIO_PIN_1, &gpio_config);
277 
278  //Configure ETH1_MDC (PC1)
279  gpio_config.alternate = HAL_GPIO_AF_10;
280  HAL_GPIO_Init(HAL_GPIOC, HAL_GPIO_PIN_1, &gpio_config);
281 
282  //Configure ETH1_RMII_RXD0 (PC4)
283  gpio_config.alternate = HAL_GPIO_AF_12;
284  HAL_GPIO_Init(HAL_GPIOC, HAL_GPIO_PIN_4, &gpio_config);
285 
286  //Configure ETH1_RMII_RXD1 (PC5)
287  gpio_config.alternate = HAL_GPIO_AF_13;
288  HAL_GPIO_Init(HAL_GPIOC, HAL_GPIO_PIN_5, &gpio_config);
289 
290  //Configure ETH1_RMII_CRS_DV (PD1)
291  gpio_config.alternate = HAL_GPIO_AF_10;
292  HAL_GPIO_Init(HAL_GPIOD, HAL_GPIO_PIN_1, &gpio_config);
293 
294  //Configure ETH1_MDIO (PE12)
295  gpio_config.alternate = HAL_GPIO_AF_10;
296  HAL_GPIO_Init(HAL_GPIOE, HAL_GPIO_PIN_12, &gpio_config);
297 
298  //Configure RMII_TX_EN (PG11)
299  gpio_config.alternate = HAL_GPIO_AF_10;
300  HAL_GPIO_Init(HAL_GPIOG, HAL_GPIO_PIN_11, &gpio_config);
301 
302  //Configure ETH1_RMII_TXD1 (PG12)
303  gpio_config.alternate = HAL_GPIO_AF_10;
304  HAL_GPIO_Init(HAL_GPIOG, HAL_GPIO_PIN_12, &gpio_config);
305 
306  //Configure ETH1_RMII_TXD0 (PG13)
307  gpio_config.alternate = HAL_GPIO_AF_10;
308  HAL_GPIO_Init(HAL_GPIOG, HAL_GPIO_PIN_13, &gpio_config);
309 
310  //Select ETH1 clock source
311  HAL_RCC_ETH1_SetKernelClkSource(HAL_RCC_ETH1_CLK_SRC_HSE);
312  //Select ETH1REF clock source
313  HAL_RCC_ETH1REF_SetKernelClkSource(HAL_RCC_ETH1REF_CLK_SRC_RMII);
314 #endif
315 }
316 
317 
318 /**
319  * @brief Initialize DMA descriptor lists
320  * @param[in] interface Underlying network interface
321  **/
322 
324 {
325  uint_t i;
326 
327  //Initialize TX DMA descriptor list
328  for(i = 0; i < STM32C5XX_ETH_TX_BUFFER_COUNT; i++)
329  {
330  //The descriptor is initially owned by the application
331  txDmaDesc[i].tdes0 = 0;
332  txDmaDesc[i].tdes1 = 0;
333  txDmaDesc[i].tdes2 = 0;
334  txDmaDesc[i].tdes3 = 0;
335  }
336 
337  //Initialize TX descriptor index
338  txIndex = 0;
339 
340  //Initialize RX DMA descriptor list
341  for(i = 0; i < STM32C5XX_ETH_RX_BUFFER_COUNT; i++)
342  {
343  //The descriptor is initially owned by the DMA
344  rxDmaDesc[i].rdes0 = (uint32_t) rxBuffer[i];
345  rxDmaDesc[i].rdes1 = 0;
346  rxDmaDesc[i].rdes2 = 0;
348  }
349 
350  //Initialize RX descriptor index
351  rxIndex = 0;
352 
353  //Start location of the TX descriptor list
354  ETH1->DMACTXDLAR = (uint32_t) &txDmaDesc[0];
355  //Length of the transmit descriptor ring
356  ETH1->DMACTXRLR = STM32C5XX_ETH_TX_BUFFER_COUNT - 1;
357 
358  //Start location of the RX descriptor list
359  ETH1->DMACRXDLAR = (uint32_t) &rxDmaDesc[0];
360  //Length of the receive descriptor ring
361  ETH1->DMACRXRLR = STM32C5XX_ETH_RX_BUFFER_COUNT - 1;
362 }
363 
364 
365 /**
366  * @brief STM32C5 Ethernet MAC timer handler
367  *
368  * This routine is periodically called by the TCP/IP stack to handle periodic
369  * operations such as polling the link state
370  *
371  * @param[in] interface Underlying network interface
372  **/
373 
375 {
376  //Valid Ethernet PHY or switch driver?
377  if(interface->phyDriver != NULL)
378  {
379  //Handle periodic operations
380  interface->phyDriver->tick(interface);
381  }
382  else if(interface->switchDriver != NULL)
383  {
384  //Handle periodic operations
385  interface->switchDriver->tick(interface);
386  }
387  else
388  {
389  //Just for sanity
390  }
391 }
392 
393 
394 /**
395  * @brief Enable interrupts
396  * @param[in] interface Underlying network interface
397  **/
398 
400 {
401  //Enable Ethernet MAC interrupts
402  NVIC_EnableIRQ(ETH1_IRQn);
403 
404  //Valid Ethernet PHY or switch driver?
405  if(interface->phyDriver != NULL)
406  {
407  //Enable Ethernet PHY interrupts
408  interface->phyDriver->enableIrq(interface);
409  }
410  else if(interface->switchDriver != NULL)
411  {
412  //Enable Ethernet switch interrupts
413  interface->switchDriver->enableIrq(interface);
414  }
415  else
416  {
417  //Just for sanity
418  }
419 }
420 
421 
422 /**
423  * @brief Disable interrupts
424  * @param[in] interface Underlying network interface
425  **/
426 
428 {
429  //Disable Ethernet MAC interrupts
430  NVIC_DisableIRQ(ETH1_IRQn);
431 
432  //Valid Ethernet PHY or switch driver?
433  if(interface->phyDriver != NULL)
434  {
435  //Disable Ethernet PHY interrupts
436  interface->phyDriver->disableIrq(interface);
437  }
438  else if(interface->switchDriver != NULL)
439  {
440  //Disable Ethernet switch interrupts
441  interface->switchDriver->disableIrq(interface);
442  }
443  else
444  {
445  //Just for sanity
446  }
447 }
448 
449 
450 /**
451  * @brief STM32C5 Ethernet MAC interrupt service routine
452  **/
453 
454 void ETH1_IRQHandler(void)
455 {
456  bool_t flag;
457  uint32_t status;
458 
459  //Interrupt service routine prologue
460  osEnterIsr();
461 
462  //This flag will be set if a higher priority task must be woken
463  flag = FALSE;
464 
465  //Read DMA status register
466  status = ETH1->DMACSR;
467 
468  //Packet transmitted?
469  if((status & ETH_DMACSR_TI) != 0)
470  {
471  //Clear TI interrupt flag
472  ETH1->DMACSR = ETH_DMACSR_TI;
473 
474  //Check whether the TX buffer is available for writing
475  if((txDmaDesc[txIndex].tdes3 & ETH_TDES3_OWN) == 0)
476  {
477  //Notify the TCP/IP stack that the transmitter is ready to send
478  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
479  }
480  }
481 
482  //Packet received?
483  if((status & ETH_DMACSR_RI) != 0)
484  {
485  //Clear RI interrupt flag
486  ETH1->DMACSR = ETH_DMACSR_RI;
487 
488  //Set event flag
489  nicDriverInterface->nicEvent = TRUE;
490  //Notify the TCP/IP stack of the event
491  flag |= osSetEventFromIsr(&nicDriverInterface->netContext->event);
492  }
493 
494  //Clear NIS interrupt flag
495  ETH1->DMACSR = ETH_DMACSR_NIS;
496 
497  //Interrupt service routine epilogue
498  osExitIsr(flag);
499 }
500 
501 
502 /**
503  * @brief STM32C5 Ethernet MAC event handler
504  * @param[in] interface Underlying network interface
505  **/
506 
508 {
509  error_t error;
510 
511  //Process all pending packets
512  do
513  {
514  //Read incoming packet
515  error = stm32c5xxEthReceivePacket(interface);
516 
517  //No more data in the receive buffer?
518  } while(error != ERROR_BUFFER_EMPTY);
519 }
520 
521 
522 /**
523  * @brief Send a packet
524  * @param[in] interface Underlying network interface
525  * @param[in] buffer Multi-part buffer containing the data to send
526  * @param[in] offset Offset to the first data byte
527  * @param[in] ancillary Additional options passed to the stack along with
528  * the packet
529  * @return Error code
530  **/
531 
533  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
534 {
535  size_t length;
536 
537  //Retrieve the length of the packet
538  length = netBufferGetLength(buffer) - offset;
539 
540  //Check the frame length
542  {
543  //The transmitter can accept another packet
544  osSetEvent(&interface->nicTxEvent);
545  //Report an error
546  return ERROR_INVALID_LENGTH;
547  }
548 
549  //Make sure the current buffer is available for writing
550  if((txDmaDesc[txIndex].tdes3 & ETH_TDES3_OWN) != 0)
551  {
552  return ERROR_FAILURE;
553  }
554 
555  //Copy user data to the transmit buffer
556  netBufferRead(txBuffer[txIndex], buffer, offset, length);
557 
558  //Set the start address of the buffer
559  txDmaDesc[txIndex].tdes0 = (uint32_t) txBuffer[txIndex];
560  //Write the number of bytes to send
561  txDmaDesc[txIndex].tdes2 = ETH_TDES2_IOC | (length & ETH_TDES2_B1L);
562  //Give the ownership of the descriptor to the DMA
563  txDmaDesc[txIndex].tdes3 = ETH_TDES3_OWN | ETH_TDES3_FD | ETH_TDES3_LD;
564 
565  //Data synchronization barrier
566  __DSB();
567 
568  //Clear TBU flag to resume processing
569  ETH1->DMACSR = ETH_DMACSR_TBU;
570  //Instruct the DMA to poll the transmit descriptor list
571  ETH1->DMACTXDTPR = 0;
572 
573  //Increment index and wrap around if necessary
574  if(++txIndex >= STM32C5XX_ETH_TX_BUFFER_COUNT)
575  {
576  txIndex = 0;
577  }
578 
579  //Check whether the next buffer is available for writing
580  if((txDmaDesc[txIndex].tdes3 & ETH_TDES3_OWN) == 0)
581  {
582  //The transmitter can accept another packet
583  osSetEvent(&interface->nicTxEvent);
584  }
585 
586  //Data successfully written
587  return NO_ERROR;
588 }
589 
590 
591 /**
592  * @brief Receive a packet
593  * @param[in] interface Underlying network interface
594  * @return Error code
595  **/
596 
598 {
599  error_t error;
600  size_t n;
601  uint32_t status;
602  NetRxAncillary ancillary;
603 
604  //Current buffer available for reading?
605  if((rxDmaDesc[rxIndex].rdes3 & ETH_RDES3_OWN) == 0)
606  {
607  //FD and LD flags should be set
608  if((rxDmaDesc[rxIndex].rdes3 & ETH_RDES3_FD) != 0 &&
609  (rxDmaDesc[rxIndex].rdes3 & ETH_RDES3_LD) != 0)
610  {
611  //Check error bits
612  status = rxDmaDesc[rxIndex].rdes3 & (ETH_RDES3_CE | ETH_RDES3_GP |
614 
615  //The dribble bit error is valid only in the MII mode
616  if((SBS->PMCR & SBS_PMCR_ETH1_SEL_PHY) != HAL_SBS_ETHPHY_ITF_GMII_MII)
617  {
618  status &= ~ETH_RDES3_DE;
619  }
620 
621  //Make sure no error occurred
622  if(status == 0)
623  {
624  //Retrieve the length of the frame
625  n = rxDmaDesc[rxIndex].rdes3 & ETH_RDES3_PL;
626  //Limit the number of data to read
628 
629  //Additional options can be passed to the stack along with the packet
630  ancillary = NET_DEFAULT_RX_ANCILLARY;
631 
632  //Pass the packet to the upper layer
633  nicProcessPacket(interface, rxBuffer[rxIndex], n, &ancillary);
634 
635  //Valid packet received
636  error = NO_ERROR;
637  }
638  else
639  {
640  //The received packet contains an error
641  error = ERROR_INVALID_PACKET;
642  }
643  }
644  else
645  {
646  //The packet is not valid
647  error = ERROR_INVALID_PACKET;
648  }
649 
650  //Set the start address of the buffer
651  rxDmaDesc[rxIndex].rdes0 = (uint32_t) rxBuffer[rxIndex];
652  //Give the ownership of the descriptor back to the DMA
654 
655  //Increment index and wrap around if necessary
656  if(++rxIndex >= STM32C5XX_ETH_RX_BUFFER_COUNT)
657  {
658  rxIndex = 0;
659  }
660  }
661  else
662  {
663  //No more data in the receive buffer
664  error = ERROR_BUFFER_EMPTY;
665  }
666 
667  //Clear RBU flag to resume processing
668  ETH1->DMACSR = ETH_DMACSR_RBU;
669  //Instruct the DMA to poll the receive descriptor list
670  ETH1->DMACRXDTPR = 0;
671 
672  //Return status code
673  return error;
674 }
675 
676 
677 /**
678  * @brief Configure MAC address filtering
679  * @param[in] interface Underlying network interface
680  * @return Error code
681  **/
682 
684 {
685  uint_t i;
686  uint_t j;
687  uint_t k;
688  uint32_t crc;
689  uint32_t hashTable[2];
690  MacAddr unicastMacAddr[3];
691  MacFilterEntry *entry;
692 
693  //Debug message
694  TRACE_DEBUG("Updating MAC filter...\r\n");
695 
696  //Promiscuous mode?
697  if(interface->promiscuous)
698  {
699  //Pass all incoming frames regardless of their destination address
700  ETH1->MACPFR = ETH_MACPFR_PR;
701  }
702  else
703  {
704  //Set the MAC address of the station
705  ETH1->MACA0LR = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
706  ETH1->MACA0HR = interface->macAddr.w[2];
707 
708  //The MAC supports 3 additional addresses for unicast perfect filtering
709  unicastMacAddr[0] = MAC_UNSPECIFIED_ADDR;
710  unicastMacAddr[1] = MAC_UNSPECIFIED_ADDR;
711  unicastMacAddr[2] = MAC_UNSPECIFIED_ADDR;
712 
713  //The hash table is used for multicast address filtering
714  hashTable[0] = 0;
715  hashTable[1] = 0;
716 
717  //The MAC address filter contains the list of MAC addresses to accept
718  //when receiving an Ethernet frame
719  for(i = 0, j = 0; i < MAC_ADDR_FILTER_SIZE; i++)
720  {
721  //Point to the current entry
722  entry = &interface->macAddrFilter[i];
723 
724  //Valid entry?
725  if(entry->refCount > 0)
726  {
727  //Multicast address?
728  if(macIsMulticastAddr(&entry->addr))
729  {
730  //Compute CRC over the current MAC address
731  crc = stm32c5xxEthCalcCrc(&entry->addr, sizeof(MacAddr));
732 
733  //The upper 6 bits in the CRC register are used to index the
734  //contents of the hash table
735  k = (crc >> 26) & 0x3F;
736 
737  //Update hash table contents
738  hashTable[k / 32] |= (1 << (k % 32));
739  }
740  else
741  {
742  //Up to 3 additional MAC addresses can be specified
743  if(j < 3)
744  {
745  //Save the unicast address
746  unicastMacAddr[j++] = entry->addr;
747  }
748  }
749  }
750  }
751 
752  //Configure the first unicast address filter
753  if(j >= 1)
754  {
755  //When the AE bit is set, the entry is used for perfect filtering
756  ETH1->MACA1LR = unicastMacAddr[0].w[0] | (unicastMacAddr[0].w[1] << 16);
757  ETH1->MACA1HR = unicastMacAddr[0].w[2] | ETH_MACA1HR_AE;
758  }
759  else
760  {
761  //When the AE bit is cleared, the entry is ignored
762  ETH1->MACA1LR = 0;
763  ETH1->MACA1HR = 0;
764  }
765 
766  //Configure the second unicast address filter
767  if(j >= 2)
768  {
769  //When the AE bit is set, the entry is used for perfect filtering
770  ETH1->MACA2LR = unicastMacAddr[1].w[0] | (unicastMacAddr[1].w[1] << 16);
771  ETH1->MACA2HR = unicastMacAddr[1].w[2] | ETH_MACA2HR_AE;
772  }
773  else
774  {
775  //When the AE bit is cleared, the entry is ignored
776  ETH1->MACA2LR = 0;
777  ETH1->MACA2HR = 0;
778  }
779 
780  //Configure the third unicast address filter
781  if(j >= 3)
782  {
783  //When the AE bit is set, the entry is used for perfect filtering
784  ETH1->MACA3LR = unicastMacAddr[2].w[0] | (unicastMacAddr[2].w[1] << 16);
785  ETH1->MACA3HR = unicastMacAddr[2].w[2] | ETH_MACA3HR_AE;
786  }
787  else
788  {
789  //When the AE bit is cleared, the entry is ignored
790  ETH1->MACA3LR = 0;
791  ETH1->MACA3HR = 0;
792  }
793 
794  //Check whether frames with a multicast destination address should be
795  //accepted
796  if(interface->acceptAllMulticast)
797  {
798  //Configure the receive filter
799  ETH1->MACPFR = ETH_MACPFR_HPF | ETH_MACPFR_PM;
800  }
801  else
802  {
803  //Configure the receive filter
804  ETH1->MACPFR = ETH_MACPFR_HPF | ETH_MACPFR_HMC;
805 
806  //Configure the multicast hash table
807  ETH1->MACHT0R = hashTable[0];
808  ETH1->MACHT1R = hashTable[1];
809 
810  //Debug message
811  TRACE_DEBUG(" MACHT0R = 0x%08" PRIX32 "\r\n", ETH1->MACHT0R);
812  TRACE_DEBUG(" MACHT1R = 0x%08" PRIX32 "\r\n", ETH1->MACHT1R);
813  }
814  }
815 
816  //Successful processing
817  return NO_ERROR;
818 }
819 
820 
821 /**
822  * @brief Adjust MAC configuration parameters for proper operation
823  * @param[in] interface Underlying network interface
824  * @return Error code
825  **/
826 
828 {
829  uint32_t config;
830 
831  //Read current MAC configuration
832  config = ETH1->MACCR;
833 
834  //10BASE-T or 100BASE-TX operation mode?
835  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
836  {
837  config |= ETH_MACCR_FES;
838  }
839  else
840  {
841  config &= ~ETH_MACCR_FES;
842  }
843 
844  //Half-duplex or full-duplex mode?
845  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
846  {
847  config |= ETH_MACCR_DM;
848  }
849  else
850  {
851  config &= ~ETH_MACCR_DM;
852  }
853 
854  //Update MAC configuration register
855  ETH1->MACCR = config;
856 
857  //Successful processing
858  return NO_ERROR;
859 }
860 
861 
862 /**
863  * @brief Write PHY register
864  * @param[in] opcode Access type (2 bits)
865  * @param[in] phyAddr PHY address (5 bits)
866  * @param[in] regAddr Register address (5 bits)
867  * @param[in] data Register value
868  **/
869 
870 void stm32c5xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
871  uint8_t regAddr, uint16_t data)
872 {
873  uint32_t temp;
874 
875  //Valid opcode?
876  if(opcode == SMI_OPCODE_WRITE)
877  {
878  //Take care not to alter MDC clock configuration
879  temp = ETH1->MACMDIOAR & ETH_MACMDIOAR_CR;
880  //Set up a write operation
881  temp |= ETH_MACMDIOAR_GOC_Val(1) | ETH_MACMDIOAR_MB;
882  //PHY address
883  temp |= (phyAddr << 21) & ETH_MACMDIOAR_PA;
884  //Register address
885  temp |= (regAddr << 16) & ETH_MACMDIOAR_RDA;
886 
887  //Data to be written in the PHY register
888  ETH1->MACMDIODR = data & ETH_MACMDIODR_MD;
889 
890  //Start a write operation
891  ETH1->MACMDIOAR = temp;
892  //Wait for the write to complete
893  while((ETH1->MACMDIOAR & ETH_MACMDIOAR_MB) != 0)
894  {
895  }
896  }
897  else
898  {
899  //The MAC peripheral only supports standard Clause 22 opcodes
900  }
901 }
902 
903 
904 /**
905  * @brief Read PHY register
906  * @param[in] opcode Access type (2 bits)
907  * @param[in] phyAddr PHY address (5 bits)
908  * @param[in] regAddr Register address (5 bits)
909  * @return Register value
910  **/
911 
912 uint16_t stm32c5xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
913  uint8_t regAddr)
914 {
915  uint16_t data;
916  uint32_t temp;
917 
918  //Valid opcode?
919  if(opcode == SMI_OPCODE_READ)
920  {
921  //Take care not to alter MDC clock configuration
922  temp = ETH1->MACMDIOAR & ETH_MACMDIOAR_CR;
923  //Set up a read operation
924  temp |= ETH_MACMDIOAR_GOC_Val(3) | ETH_MACMDIOAR_MB;
925  //PHY address
926  temp |= (phyAddr << 21) & ETH_MACMDIOAR_PA;
927  //Register address
928  temp |= (regAddr << 16) & ETH_MACMDIOAR_RDA;
929 
930  //Start a read operation
931  ETH1->MACMDIOAR = temp;
932  //Wait for the read to complete
933  while((ETH1->MACMDIOAR & ETH_MACMDIOAR_MB) != 0)
934  {
935  }
936 
937  //Get register value
938  data = ETH1->MACMDIODR & ETH_MACMDIODR_MD;
939  }
940  else
941  {
942  //The MAC peripheral only supports standard Clause 22 opcodes
943  data = 0;
944  }
945 
946  //Return the value of the PHY register
947  return data;
948 }
949 
950 
951 /**
952  * @brief CRC calculation
953  * @param[in] data Pointer to the data over which to calculate the CRC
954  * @param[in] length Number of bytes to process
955  * @return Resulting CRC value
956  **/
957 
958 uint32_t stm32c5xxEthCalcCrc(const void *data, size_t length)
959 {
960  uint_t i;
961  uint_t j;
962  uint32_t crc;
963  const uint8_t *p;
964 
965  //Point to the data over which to calculate the CRC
966  p = (uint8_t *) data;
967  //CRC preset value
968  crc = 0xFFFFFFFF;
969 
970  //Loop through data
971  for(i = 0; i < length; i++)
972  {
973  //The message is processed bit by bit
974  for(j = 0; j < 8; j++)
975  {
976  //Update CRC value
977  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
978  {
979  crc = (crc << 1) ^ 0x04C11DB7;
980  }
981  else
982  {
983  crc = crc << 1;
984  }
985  }
986  }
987 
988  //Return CRC value
989  return ~crc;
990 }
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
error_t stm32c5xxEthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
#define STM32C5XX_ETH_IRQ_SUB_PRIORITY
uint8_t opcode
Definition: dns_common.h:191
int bool_t
Definition: compiler_port.h:63
#define ETH_RDES3_DE
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
error_t stm32c5xxEthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
const NicDriver stm32c5xxEthDriver
STM32C5 Ethernet MAC driver.
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:690
#define ETH_DMAMR_TXPR_Val(n)
#define ETH_RDES3_LD
#define ETH_DMACRXCR_RBSZ_Val(n)
uint8_t p
Definition: ndp.h:300
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
#define TRUE
Definition: os_port.h:50
uint8_t data[]
Definition: ethernet.h:224
#define ETH_TDES3_LD
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:266
error_t stm32c5xxEthReceivePacket(NetInterface *interface)
Receive a packet.
void stm32c5xxEthTick(NetInterface *interface)
STM32C5 Ethernet MAC timer handler.
#define ETH_RDES3_GP
#define ETH_RDES3_CE
#define ETH_MACCR_RESERVED15
void stm32c5xxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:418
#define macIsMulticastAddr(macAddr)
Definition: ethernet.h:133
#define STM32C5XX_ETH_RX_BUFFER_COUNT
#define osExitIsr(flag)
#define ETH_DMAMR_INTM_Val(n)
#define ETH_MACMDIOAR_CR_Val(n)
#define SMI_OPCODE_WRITE
Definition: nic.h:66
#define ETH_RDES3_RE
#define FALSE
Definition: os_port.h:46
#define STM32C5XX_ETH_IRQ_PRIORITY_GROUPING
#define ETH_MACMDIOAR_GOC_Val(n)
void stm32c5xxEthEnableIrq(NetInterface *interface)
Enable interrupts.
#define ETH_RDES3_RWT
#define ETH_DMACCR_DSL_Val(n)
error_t stm32c5xxEthInit(NetInterface *interface)
STM32C5 Ethernet MAC initialization.
error_t
Error codes.
Definition: error.h:43
void ETH1_IRQHandler(void)
STM32C5 Ethernet MAC interrupt service routine.
void stm32c5xxEthEventHandler(NetInterface *interface)
STM32C5 Ethernet MAC event handler.
#define ETH_TDES2_B1L
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:103
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
void stm32c5xxEthDisableIrq(NetInterface *interface)
Disable interrupts.
#define txBuffer
error_t stm32c5xxEthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
#define NetRxAncillary
Definition: net_misc.h:40
STM32C5 Ethernet MAC driver.
@ ERROR_INVALID_PACKET
Definition: error.h:141
#define NetInterface
Definition: net.h:40
MacAddr addr
MAC address.
Definition: ethernet.h:265
void stm32c5xxEthInitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_BUFFER_EMPTY
Definition: error.h:142
#define STM32C5XX_ETH_TX_BUFFER_COUNT
#define NetTxAncillary
Definition: net_misc.h:36
#define ETH_RDES3_BUF1V
#define SMI_OPCODE_READ
Definition: nic.h:67
#define ETH_TDES2_IOC
#define STM32C5XX_ETH_TX_BUFFER_SIZE
uint16_t stm32c5xxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
#define TRACE_INFO(...)
Definition: debug.h:105
__weak_func void stm32c5xxEthInitGpio(NetInterface *interface)
GPIO configuration.
uint8_t length
Definition: tcp.h:375
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
#define STM32C5XX_ETH_IRQ_GROUP_PRIORITY
#define MIN(a, b)
Definition: os_port.h:63
#define ETH_RDES3_OWN
#define ETH_TDES3_OWN
#define rxBuffer
MacAddr
Definition: ethernet.h:197
#define TRACE_DEBUG(...)
Definition: debug.h:119
uint32_t stm32c5xxEthCalcCrc(const void *data, size_t length)
CRC calculation.
Transmit descriptor.
uint16_t regAddr
#define ETH_MTU
Definition: ethernet.h:116
uint8_t n
MAC filter table entry.
Definition: ethernet.h:264
#define ETH_RDES3_FD
#define osEnterIsr()
#define STM32C5XX_ETH_RX_BUFFER_SIZE
#define rxDmaDesc
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define ETH_TDES3_FD
#define ETH_RDES3_OE
Receive descriptor.
#define txDmaDesc
#define ETH_DMACRXCR_RXPBL_Val(n)
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
#define ETH_DMACTXCR_TXPBL_Val(n)
unsigned int uint_t
Definition: compiler_port.h:57
TCP/IP stack core.
NIC driver.
Definition: nic.h:286
#define ETH_RDES3_IOC
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:51
@ NO_ERROR
Success.
Definition: error.h:44
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
Debugging facilities.
#define ETH_RDES3_PL
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83