stm32h7rsxx_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file stm32h7rsxx_eth_driver.c
3  * @brief STM32H7Rx/Sx 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.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include "stm32h7rsxx.h"
36 #include "stm32h7rsxx_hal.h"
37 #include "core/net.h"
39 #include "debug.h"
40 
41 //Underlying network interface
42 static NetInterface *nicDriverInterface;
43 
44 //IAR EWARM compiler?
45 #if defined(__ICCARM__)
46 
47 //Transmit buffer
48 #pragma data_alignment = 4
49 #pragma location = STM32H7RSXX_ETH_RAM_SECTION
51 //Receive buffer
52 #pragma data_alignment = 4
53 #pragma location = STM32H7RSXX_ETH_RAM_SECTION
55 //Transmit DMA descriptors
56 #pragma data_alignment = 4
57 #pragma location = STM32H7RSXX_ETH_RAM_SECTION
59 //Receive DMA descriptors
60 #pragma data_alignment = 4
61 #pragma location = STM32H7RSXX_ETH_RAM_SECTION
63 
64 //Keil MDK-ARM or GCC compiler?
65 #else
66 
67 //Transmit buffer
69  __attribute__((aligned(4), __section__(STM32H7RSXX_ETH_RAM_SECTION)));
70 //Receive buffer
72  __attribute__((aligned(4), __section__(STM32H7RSXX_ETH_RAM_SECTION)));
73 //Transmit DMA descriptors
75  __attribute__((aligned(4), __section__(STM32H7RSXX_ETH_RAM_SECTION)));
76 //Receive DMA descriptors
78  __attribute__((aligned(4), __section__(STM32H7RSXX_ETH_RAM_SECTION)));
79 
80 #endif
81 
82 //Current transmit descriptor
83 static uint_t txIndex;
84 //Current receive descriptor
85 static uint_t rxIndex;
86 
87 
88 /**
89  * @brief STM32H7Rx/Sx Ethernet MAC driver
90  **/
91 
93 {
95  ETH_MTU,
106  TRUE,
107  TRUE,
108  TRUE,
109  FALSE
110 };
111 
112 
113 /**
114  * @brief STM32H7Rx/Sx Ethernet MAC initialization
115  * @param[in] interface Underlying network interface
116  * @return Error code
117  **/
118 
120 {
121  error_t error;
122  uint32_t temp;
123 
124  //Debug message
125  TRACE_INFO("Initializing STM32H7Rx/Sx Ethernet MAC...\r\n");
126 
127  //Save underlying network interface
128  nicDriverInterface = interface;
129 
130  //GPIO configuration
131  stm32h7rsxxEthInitGpio(interface);
132 
133  //Enable Ethernet MAC clock
134  __HAL_RCC_ETH1MAC_CLK_ENABLE();
135  __HAL_RCC_ETH1TX_CLK_ENABLE();
136  __HAL_RCC_ETH1RX_CLK_ENABLE();
137 
138  //Reset Ethernet MAC peripheral
139  __HAL_RCC_ETH1_FORCE_RESET();
140  __HAL_RCC_ETH1_RELEASE_RESET();
141 
142  //Perform a software reset
143  ETH->DMAMR |= ETH_DMAMR_SWR;
144  //Wait for the reset to complete
145  while((ETH->DMAMR & ETH_DMAMR_SWR) != 0)
146  {
147  }
148 
149  //Adjust MDC clock range depending on HCLK frequency
150  ETH->MACMDIOAR = ETH_MACMDIOAR_CR_DIV124;
151 
152  //Valid Ethernet PHY or switch driver?
153  if(interface->phyDriver != NULL)
154  {
155  //Ethernet PHY initialization
156  error = interface->phyDriver->init(interface);
157  }
158  else if(interface->switchDriver != NULL)
159  {
160  //Ethernet switch initialization
161  error = interface->switchDriver->init(interface);
162  }
163  else
164  {
165  //The interface is not properly configured
166  error = ERROR_FAILURE;
167  }
168 
169  //Any error to report?
170  if(error)
171  {
172  return error;
173  }
174 
175  //Use default MAC configuration
176  ETH->MACCR = ETH_MACCR_GPSLCE | ETH_MACCR_RESERVED15 | ETH_MACCR_DO;
177 
178  //Set the maximum packet size that can be accepted
179  temp = ETH->MACECR & ~ETH_MACECR_GPSL;
180  ETH->MACECR = temp | STM32H7RSXX_ETH_RX_BUFFER_SIZE;
181 
182  //Configure MAC address filtering
184 
185  //Disable flow control
186  ETH->MACTFCR = 0;
187  ETH->MACRFCR = 0;
188 
189  //Configure DMA operating mode
190  ETH->DMAMR = ETH_DMAMR_INTM_0 | ETH_DMAMR_PR_1_1;
191  //Configure system bus mode
192  ETH->DMASBMR |= ETH_DMASBMR_AAL;
193  //The DMA takes the descriptor table as contiguous
194  ETH->DMACCR = ETH_DMACCR_DSL_0BIT;
195 
196  //Configure TX features
197  ETH->DMACTCR = ETH_DMACTCR_TPBL_32PBL;
198 
199  //Configure RX features
200  ETH->DMACRCR = ETH_DMACRCR_RPBL_32PBL;
201  ETH->DMACRCR |= (STM32H7RSXX_ETH_RX_BUFFER_SIZE << 1) & ETH_DMACRCR_RBSZ;
202 
203  //Enable store and forward mode
204  ETH->MTLTQOMR |= ETH_MTLTQOMR_TSF;
205  ETH->MTLRQOMR |= ETH_MTLRQOMR_RSF;
206 
207  //Initialize DMA descriptor lists
208  stm32h7rsxxEthInitDmaDesc(interface);
209 
210  //Prevent interrupts from being generated when the transmit statistic
211  //counters reach half their maximum value
214 
215  //Prevent interrupts from being generated when the receive statistic
216  //counters reach half their maximum value
219 
220  //Disable MAC interrupts
221  ETH->MACIER = 0;
222  //Enable the desired DMA interrupts
223  ETH->DMACIER = ETH_DMACIER_NIE | ETH_DMACIER_RIE | ETH_DMACIER_TIE;
224 
225  //Set priority grouping (4 bits for pre-emption priority, no bits for subpriority)
226  NVIC_SetPriorityGrouping(STM32H7RSXX_ETH_IRQ_PRIORITY_GROUPING);
227 
228  //Configure Ethernet interrupt priority
229  NVIC_SetPriority(ETH_IRQn, NVIC_EncodePriority(STM32H7RSXX_ETH_IRQ_PRIORITY_GROUPING,
231 
232  //Enable MAC transmission and reception
233  ETH->MACCR |= ETH_MACCR_TE | ETH_MACCR_RE;
234 
235  //Enable DMA transmission and reception
236  ETH->DMACTCR |= ETH_DMACTCR_ST;
237  ETH->DMACRCR |= ETH_DMACRCR_SR;
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 stm32h7rsxxEthInitGpio(NetInterface *interface)
253 {
254 //Nucleo-H7S3L8 evaluation board?
255 #if defined(USE_STM32H7RSxx_NUCLEO)
256  GPIO_InitTypeDef GPIO_InitStructure;
257 
258  //Enable SBS clock
259  __HAL_RCC_SBS_CLK_ENABLE();
260 
261  //Enable GPIO clocks
262  __HAL_RCC_GPIOA_CLK_ENABLE();
263  __HAL_RCC_GPIOB_CLK_ENABLE();
264  __HAL_RCC_GPIOG_CLK_ENABLE();
265 
266  //Select RMII interface mode
267  HAL_SBS_ConfigEthernetPHY(SBS_ETHERNET_PHY_RMII);
268 
269  //Configure RMII pins
270  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
271  GPIO_InitStructure.Pull = GPIO_NOPULL;
272  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
273  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
274 
275  //Configure ETH_MDIO (PA2) and ETH_RMII_CRS_DV (PA7)
276  GPIO_InitStructure.Pin = GPIO_PIN_2 | GPIO_PIN_7;
277  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
278 
279  //Configure ETH_RMII_REF_CLK (PB6)
280  GPIO_InitStructure.Pin = GPIO_PIN_6;
281  HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
282 
283  //Configure ETH_RMII_RXD0 (PG4), ETH_RMII_RXD1 (PG5), ETH_MDC (PG6),
284  //RMII_TX_EN (PG11), ETH_RMII_TXD1 (PG12) and ETH_RMII_TXD0 (PG13)
285  GPIO_InitStructure.Pin = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 |
286  GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13;
287  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
288 
289 //STM32H7S78-DK evaluation board?
290 #elif defined(USE_STM32H7S78_DK)
291  GPIO_InitTypeDef GPIO_InitStructure;
292 
293  //Enable SBS clock
294  __HAL_RCC_SBS_CLK_ENABLE();
295 
296  //Enable GPIO clocks
297  __HAL_RCC_GPIOA_CLK_ENABLE();
298  __HAL_RCC_GPIOB_CLK_ENABLE();
299  __HAL_RCC_GPIOC_CLK_ENABLE();
300  __HAL_RCC_GPIOD_CLK_ENABLE();
301  __HAL_RCC_GPIOG_CLK_ENABLE();
302 
303  //Select RMII interface mode
304  HAL_SBS_ConfigEthernetPHY(SBS_ETHERNET_PHY_RMII);
305 
306  //Configure MDIO/MDC pins
307  if(interface->smiDriver == NULL)
308  {
309  //Configure ETH_MDIO (PA2)
310  GPIO_InitStructure.Pin = GPIO_PIN_2;
311  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
312  GPIO_InitStructure.Pull = GPIO_PULLUP;
313  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM;
314  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
315  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
316 
317  //Configure ETH_MDC (PC1)
318  GPIO_InitStructure.Pin = GPIO_PIN_1;
319  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
320  GPIO_InitStructure.Pull = GPIO_NOPULL;
321  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM;
322  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
323  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
324  }
325 
326  //Configure RMII pins
327  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
328  GPIO_InitStructure.Pull = GPIO_NOPULL;
329  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
330  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
331 
332  //Configure ETH_RMII_CRS_DV (PA7)
333  GPIO_InitStructure.Pin = GPIO_PIN_7;
334  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
335 
336  //Configure ETH_RMII_TXD0 (PB0), ETH_RMII_TXD1 (PB1) and RMII_RX_ER (PB10)
337  GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_10;
338  HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
339 
340  //Configure ETH_RMII_RXD0 (PC4) and ETH_RMII_RXD1 (PC5)
341  GPIO_InitStructure.Pin = GPIO_PIN_4 | GPIO_PIN_5;
342  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
343 
344  //Configure RMII_TX_EN (PG11)
345  GPIO_InitStructure.Pin = GPIO_PIN_11;
346  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
347 
348  //Configure ETH_RMII_REF_CLK (PD7)
349  GPIO_InitStructure.Pin = GPIO_PIN_7;
350  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
351  GPIO_InitStructure.Pull = GPIO_NOPULL;
352  GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
353  GPIO_InitStructure.Alternate = GPIO_AF4_ETH;
354  HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
355 #endif
356 }
357 
358 
359 /**
360  * @brief Initialize DMA descriptor lists
361  * @param[in] interface Underlying network interface
362  **/
363 
365 {
366  uint_t i;
367 
368  //Initialize TX DMA descriptor list
369  for(i = 0; i < STM32H7RSXX_ETH_TX_BUFFER_COUNT; i++)
370  {
371  //The descriptor is initially owned by the application
372  txDmaDesc[i].tdes0 = 0;
373  txDmaDesc[i].tdes1 = 0;
374  txDmaDesc[i].tdes2 = 0;
375  txDmaDesc[i].tdes3 = 0;
376  }
377 
378  //Initialize TX descriptor index
379  txIndex = 0;
380 
381  //Initialize RX DMA descriptor list
382  for(i = 0; i < STM32H7RSXX_ETH_RX_BUFFER_COUNT; i++)
383  {
384  //The descriptor is initially owned by the DMA
385  rxDmaDesc[i].rdes0 = (uint32_t) rxBuffer[i];
386  rxDmaDesc[i].rdes1 = 0;
387  rxDmaDesc[i].rdes2 = 0;
389  }
390 
391  //Initialize RX descriptor index
392  rxIndex = 0;
393 
394  //Start location of the TX descriptor list
395  ETH->DMACTDLAR = (uint32_t) &txDmaDesc[0];
396  //Length of the transmit descriptor ring
397  ETH->DMACTDRLR = STM32H7RSXX_ETH_TX_BUFFER_COUNT - 1;
398 
399  //Start location of the RX descriptor list
400  ETH->DMACRDLAR = (uint32_t) &rxDmaDesc[0];
401  //Length of the receive descriptor ring
402  ETH->DMACRDRLR = STM32H7RSXX_ETH_RX_BUFFER_COUNT - 1;
403 }
404 
405 
406 /**
407  * @brief STM32H7Rx/Sx Ethernet MAC timer handler
408  *
409  * This routine is periodically called by the TCP/IP stack to handle periodic
410  * operations such as polling the link state
411  *
412  * @param[in] interface Underlying network interface
413  **/
414 
416 {
417  //Valid Ethernet PHY or switch driver?
418  if(interface->phyDriver != NULL)
419  {
420  //Handle periodic operations
421  interface->phyDriver->tick(interface);
422  }
423  else if(interface->switchDriver != NULL)
424  {
425  //Handle periodic operations
426  interface->switchDriver->tick(interface);
427  }
428  else
429  {
430  //Just for sanity
431  }
432 }
433 
434 
435 /**
436  * @brief Enable interrupts
437  * @param[in] interface Underlying network interface
438  **/
439 
441 {
442  //Enable Ethernet MAC interrupts
443  NVIC_EnableIRQ(ETH_IRQn);
444 
445  //Valid Ethernet PHY or switch driver?
446  if(interface->phyDriver != NULL)
447  {
448  //Enable Ethernet PHY interrupts
449  interface->phyDriver->enableIrq(interface);
450  }
451  else if(interface->switchDriver != NULL)
452  {
453  //Enable Ethernet switch interrupts
454  interface->switchDriver->enableIrq(interface);
455  }
456  else
457  {
458  //Just for sanity
459  }
460 }
461 
462 
463 /**
464  * @brief Disable interrupts
465  * @param[in] interface Underlying network interface
466  **/
467 
469 {
470  //Disable Ethernet MAC interrupts
471  NVIC_DisableIRQ(ETH_IRQn);
472 
473  //Valid Ethernet PHY or switch driver?
474  if(interface->phyDriver != NULL)
475  {
476  //Disable Ethernet PHY interrupts
477  interface->phyDriver->disableIrq(interface);
478  }
479  else if(interface->switchDriver != NULL)
480  {
481  //Disable Ethernet switch interrupts
482  interface->switchDriver->disableIrq(interface);
483  }
484  else
485  {
486  //Just for sanity
487  }
488 }
489 
490 
491 /**
492  * @brief STM32H7Rx/Sx Ethernet MAC interrupt service routine
493  **/
494 
495 void ETH_IRQHandler(void)
496 {
497  bool_t flag;
498  uint32_t status;
499 
500  //Interrupt service routine prologue
501  osEnterIsr();
502 
503  //This flag will be set if a higher priority task must be woken
504  flag = FALSE;
505 
506  //Read DMA status register
507  status = ETH->DMACSR;
508 
509  //Packet transmitted?
510  if((status & ETH_DMACSR_TI) != 0)
511  {
512  //Clear TI interrupt flag
513  ETH->DMACSR = ETH_DMACSR_TI;
514 
515  //Check whether the TX buffer is available for writing
516  if((txDmaDesc[txIndex].tdes3 & ETH_TDES3_OWN) == 0)
517  {
518  //Notify the TCP/IP stack that the transmitter is ready to send
519  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
520  }
521  }
522 
523  //Packet received?
524  if((status & ETH_DMACSR_RI) != 0)
525  {
526  //Clear RI interrupt flag
527  ETH->DMACSR = ETH_DMACSR_RI;
528 
529  //Set event flag
530  nicDriverInterface->nicEvent = TRUE;
531  //Notify the TCP/IP stack of the event
532  flag |= osSetEventFromIsr(&netEvent);
533  }
534 
535  //Clear NIS interrupt flag
536  ETH->DMACSR = ETH_DMACSR_NIS;
537 
538  //Interrupt service routine epilogue
539  osExitIsr(flag);
540 }
541 
542 
543 /**
544  * @brief STM32H7Rx/Sx Ethernet MAC event handler
545  * @param[in] interface Underlying network interface
546  **/
547 
549 {
550  error_t error;
551 
552  //Process all pending packets
553  do
554  {
555  //Read incoming packet
556  error = stm32h7rsxxEthReceivePacket(interface);
557 
558  //No more data in the receive buffer?
559  } while(error != ERROR_BUFFER_EMPTY);
560 }
561 
562 
563 /**
564  * @brief Send a packet
565  * @param[in] interface Underlying network interface
566  * @param[in] buffer Multi-part buffer containing the data to send
567  * @param[in] offset Offset to the first data byte
568  * @param[in] ancillary Additional options passed to the stack along with
569  * the packet
570  * @return Error code
571  **/
572 
574  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
575 {
576  size_t length;
577 
578  //Retrieve the length of the packet
579  length = netBufferGetLength(buffer) - offset;
580 
581  //Check the frame length
583  {
584  //The transmitter can accept another packet
585  osSetEvent(&interface->nicTxEvent);
586  //Report an error
587  return ERROR_INVALID_LENGTH;
588  }
589 
590  //Make sure the current buffer is available for writing
591  if((txDmaDesc[txIndex].tdes3 & ETH_TDES3_OWN) != 0)
592  {
593  return ERROR_FAILURE;
594  }
595 
596  //Copy user data to the transmit buffer
597  netBufferRead(txBuffer[txIndex], buffer, offset, length);
598 
599  //Set the start address of the buffer
600  txDmaDesc[txIndex].tdes0 = (uint32_t) txBuffer[txIndex];
601  //Write the number of bytes to send
602  txDmaDesc[txIndex].tdes2 = ETH_TDES2_IOC | (length & ETH_TDES2_B1L);
603  //Give the ownership of the descriptor to the DMA
604  txDmaDesc[txIndex].tdes3 = ETH_TDES3_OWN | ETH_TDES3_FD | ETH_TDES3_LD;
605 
606  //Data synchronization barrier
607  __DSB();
608 
609  //Clear TBU flag to resume processing
610  ETH->DMACSR = ETH_DMACSR_TBU;
611  //Instruct the DMA to poll the transmit descriptor list
612  ETH->DMACTDTPR = 0;
613 
614  //Increment index and wrap around if necessary
615  if(++txIndex >= STM32H7RSXX_ETH_TX_BUFFER_COUNT)
616  {
617  txIndex = 0;
618  }
619 
620  //Check whether the next buffer is available for writing
621  if((txDmaDesc[txIndex].tdes3 & ETH_TDES3_OWN) == 0)
622  {
623  //The transmitter can accept another packet
624  osSetEvent(&interface->nicTxEvent);
625  }
626 
627  //Data successfully written
628  return NO_ERROR;
629 }
630 
631 
632 /**
633  * @brief Receive a packet
634  * @param[in] interface Underlying network interface
635  * @return Error code
636  **/
637 
639 {
640  error_t error;
641  size_t n;
642  uint32_t status;
643  NetRxAncillary ancillary;
644 
645  //Current buffer available for reading?
646  if((rxDmaDesc[rxIndex].rdes3 & ETH_RDES3_OWN) == 0)
647  {
648  //FD and LD flags should be set
649  if((rxDmaDesc[rxIndex].rdes3 & ETH_RDES3_FD) != 0 &&
650  (rxDmaDesc[rxIndex].rdes3 & ETH_RDES3_LD) != 0)
651  {
652  //Check error bits
653  status = rxDmaDesc[rxIndex].rdes3 & (ETH_RDES3_CE | ETH_RDES3_GP |
655 
656  //The dribble bit error is valid only in the MII mode
657  if((SBS->PMCR & SBS_PMCR_ETH_PHYSEL) != SBS_ETHERNET_PHY_GMII_OR_MII)
658  {
659  status &= ~ETH_RDES3_DE;
660  }
661 
662  //Make sure no error occurred
663  if(status == 0)
664  {
665  //Retrieve the length of the frame
666  n = rxDmaDesc[rxIndex].rdes3 & ETH_RDES3_PL;
667  //Limit the number of data to read
669 
670  //Additional options can be passed to the stack along with the packet
671  ancillary = NET_DEFAULT_RX_ANCILLARY;
672 
673  //Pass the packet to the upper layer
674  nicProcessPacket(interface, rxBuffer[rxIndex], n, &ancillary);
675 
676  //Valid packet received
677  error = NO_ERROR;
678  }
679  else
680  {
681  //The received packet contains an error
682  error = ERROR_INVALID_PACKET;
683  }
684  }
685  else
686  {
687  //The packet is not valid
688  error = ERROR_INVALID_PACKET;
689  }
690 
691  //Set the start address of the buffer
692  rxDmaDesc[rxIndex].rdes0 = (uint32_t) rxBuffer[rxIndex];
693  //Give the ownership of the descriptor back to the DMA
695 
696  //Increment index and wrap around if necessary
697  if(++rxIndex >= STM32H7RSXX_ETH_RX_BUFFER_COUNT)
698  {
699  rxIndex = 0;
700  }
701  }
702  else
703  {
704  //No more data in the receive buffer
705  error = ERROR_BUFFER_EMPTY;
706  }
707 
708  //Clear RBU flag to resume processing
709  ETH->DMACSR = ETH_DMACSR_RBU;
710  //Instruct the DMA to poll the receive descriptor list
711  ETH->DMACRDTPR = 0;
712 
713  //Return status code
714  return error;
715 }
716 
717 
718 /**
719  * @brief Configure MAC address filtering
720  * @param[in] interface Underlying network interface
721  * @return Error code
722  **/
723 
725 {
726  uint_t i;
727  uint_t j;
728  uint_t k;
729  uint32_t crc;
730  uint32_t hashTable[2];
731  MacAddr unicastMacAddr[3];
732  MacFilterEntry *entry;
733 
734  //Debug message
735  TRACE_DEBUG("Updating MAC filter...\r\n");
736 
737  //Promiscuous mode?
738  if(interface->promiscuous)
739  {
740  //Pass all incoming frames regardless of their destination address
741  ETH->MACPFR = ETH_MACPFR_PR;
742  }
743  else
744  {
745  //Set the MAC address of the station
746  ETH->MACA0LR = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
747  ETH->MACA0HR = interface->macAddr.w[2];
748 
749  //The MAC supports 3 additional addresses for unicast perfect filtering
750  unicastMacAddr[0] = MAC_UNSPECIFIED_ADDR;
751  unicastMacAddr[1] = MAC_UNSPECIFIED_ADDR;
752  unicastMacAddr[2] = MAC_UNSPECIFIED_ADDR;
753 
754  //The hash table is used for multicast address filtering
755  hashTable[0] = 0;
756  hashTable[1] = 0;
757 
758  //The MAC address filter contains the list of MAC addresses to accept
759  //when receiving an Ethernet frame
760  for(i = 0, j = 0; i < MAC_ADDR_FILTER_SIZE; i++)
761  {
762  //Point to the current entry
763  entry = &interface->macAddrFilter[i];
764 
765  //Valid entry?
766  if(entry->refCount > 0)
767  {
768  //Multicast address?
769  if(macIsMulticastAddr(&entry->addr))
770  {
771  //Compute CRC over the current MAC address
772  crc = stm32h7rsxxEthCalcCrc(&entry->addr, sizeof(MacAddr));
773 
774  //The upper 6 bits in the CRC register are used to index the
775  //contents of the hash table
776  k = (crc >> 26) & 0x3F;
777 
778  //Update hash table contents
779  hashTable[k / 32] |= (1 << (k % 32));
780  }
781  else
782  {
783  //Up to 3 additional MAC addresses can be specified
784  if(j < 3)
785  {
786  //Save the unicast address
787  unicastMacAddr[j++] = entry->addr;
788  }
789  }
790  }
791  }
792 
793  //Configure the first unicast address filter
794  if(j >= 1)
795  {
796  //When the AE bit is set, the entry is used for perfect filtering
797  ETH->MACA1LR = unicastMacAddr[0].w[0] | (unicastMacAddr[0].w[1] << 16);
798  ETH->MACA1HR = unicastMacAddr[0].w[2] | ETH_MACAHR_AE;
799  }
800  else
801  {
802  //When the AE bit is cleared, the entry is ignored
803  ETH->MACA1LR = 0;
804  ETH->MACA1HR = 0;
805  }
806 
807  //Configure the second unicast address filter
808  if(j >= 2)
809  {
810  //When the AE bit is set, the entry is used for perfect filtering
811  ETH->MACA2LR = unicastMacAddr[1].w[0] | (unicastMacAddr[1].w[1] << 16);
812  ETH->MACA2HR = unicastMacAddr[1].w[2] | ETH_MACAHR_AE;
813  }
814  else
815  {
816  //When the AE bit is cleared, the entry is ignored
817  ETH->MACA2LR = 0;
818  ETH->MACA2HR = 0;
819  }
820 
821  //Configure the third unicast address filter
822  if(j >= 3)
823  {
824  //When the AE bit is set, the entry is used for perfect filtering
825  ETH->MACA3LR = unicastMacAddr[2].w[0] | (unicastMacAddr[2].w[1] << 16);
826  ETH->MACA3HR = unicastMacAddr[2].w[2] | ETH_MACAHR_AE;
827  }
828  else
829  {
830  //When the AE bit is cleared, the entry is ignored
831  ETH->MACA3LR = 0;
832  ETH->MACA3HR = 0;
833  }
834 
835  //Check whether frames with a multicast destination address should be
836  //accepted
837  if(interface->acceptAllMulticast)
838  {
839  //Configure the receive filter
840  ETH->MACPFR = ETH_MACPFR_HPF | ETH_MACPFR_PM;
841  }
842  else
843  {
844  //Configure the receive filter
845  ETH->MACPFR = ETH_MACPFR_HPF | ETH_MACPFR_HMC;
846 
847  //Configure the multicast hash table
848  ETH->MACHT0R = hashTable[0];
849  ETH->MACHT1R = hashTable[1];
850 
851  //Debug message
852  TRACE_DEBUG(" MACHT0R = %08" PRIX32 "\r\n", ETH->MACHT0R);
853  TRACE_DEBUG(" MACHT1R = %08" PRIX32 "\r\n", ETH->MACHT1R);
854  }
855  }
856 
857  //Successful processing
858  return NO_ERROR;
859 }
860 
861 
862 /**
863  * @brief Adjust MAC configuration parameters for proper operation
864  * @param[in] interface Underlying network interface
865  * @return Error code
866  **/
867 
869 {
870  uint32_t config;
871 
872  //Read current MAC configuration
873  config = ETH->MACCR;
874 
875  //10BASE-T or 100BASE-TX operation mode?
876  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
877  {
878  config |= ETH_MACCR_FES;
879  }
880  else
881  {
882  config &= ~ETH_MACCR_FES;
883  }
884 
885  //Half-duplex or full-duplex mode?
886  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
887  {
888  config |= ETH_MACCR_DM;
889  }
890  else
891  {
892  config &= ~ETH_MACCR_DM;
893  }
894 
895  //Update MAC configuration register
896  ETH->MACCR = config;
897 
898  //Successful processing
899  return NO_ERROR;
900 }
901 
902 
903 /**
904  * @brief Write PHY register
905  * @param[in] opcode Access type (2 bits)
906  * @param[in] phyAddr PHY address (5 bits)
907  * @param[in] regAddr Register address (5 bits)
908  * @param[in] data Register value
909  **/
910 
911 void stm32h7rsxxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
912  uint8_t regAddr, uint16_t data)
913 {
914  uint32_t temp;
915 
916  //Valid opcode?
917  if(opcode == SMI_OPCODE_WRITE)
918  {
919  //Take care not to alter MDC clock configuration
920  temp = ETH->MACMDIOAR & ETH_MACMDIOAR_CR;
921  //Set up a write operation
922  temp |= ETH_MACMDIOAR_MOC_WR | ETH_MACMDIOAR_MB;
923  //PHY address
924  temp |= (phyAddr << 21) & ETH_MACMDIOAR_PA;
925  //Register address
926  temp |= (regAddr << 16) & ETH_MACMDIOAR_RDA;
927 
928  //Data to be written in the PHY register
929  ETH->MACMDIODR = data & ETH_MACMDIODR_MD;
930 
931  //Start a write operation
932  ETH->MACMDIOAR = temp;
933  //Wait for the write to complete
934  while((ETH->MACMDIOAR & ETH_MACMDIOAR_MB) != 0)
935  {
936  }
937  }
938  else
939  {
940  //The MAC peripheral only supports standard Clause 22 opcodes
941  }
942 }
943 
944 
945 /**
946  * @brief Read PHY register
947  * @param[in] opcode Access type (2 bits)
948  * @param[in] phyAddr PHY address (5 bits)
949  * @param[in] regAddr Register address (5 bits)
950  * @return Register value
951  **/
952 
953 uint16_t stm32h7rsxxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
954  uint8_t regAddr)
955 {
956  uint16_t data;
957  uint32_t temp;
958 
959  //Valid opcode?
960  if(opcode == SMI_OPCODE_READ)
961  {
962  //Take care not to alter MDC clock configuration
963  temp = ETH->MACMDIOAR & ETH_MACMDIOAR_CR;
964  //Set up a read operation
965  temp |= ETH_MACMDIOAR_MOC_RD | ETH_MACMDIOAR_MB;
966  //PHY address
967  temp |= (phyAddr << 21) & ETH_MACMDIOAR_PA;
968  //Register address
969  temp |= (regAddr << 16) & ETH_MACMDIOAR_RDA;
970 
971  //Start a read operation
972  ETH->MACMDIOAR = temp;
973  //Wait for the read to complete
974  while((ETH->MACMDIOAR & ETH_MACMDIOAR_MB) != 0)
975  {
976  }
977 
978  //Get register value
979  data = ETH->MACMDIODR & ETH_MACMDIODR_MD;
980  }
981  else
982  {
983  //The MAC peripheral only supports standard Clause 22 opcodes
984  data = 0;
985  }
986 
987  //Return the value of the PHY register
988  return data;
989 }
990 
991 
992 /**
993  * @brief CRC calculation
994  * @param[in] data Pointer to the data over which to calculate the CRC
995  * @param[in] length Number of bytes to process
996  * @return Resulting CRC value
997  **/
998 
999 uint32_t stm32h7rsxxEthCalcCrc(const void *data, size_t length)
1000 {
1001  uint_t i;
1002  uint_t j;
1003  uint32_t crc;
1004  const uint8_t *p;
1005 
1006  //Point to the data over which to calculate the CRC
1007  p = (uint8_t *) data;
1008  //CRC preset value
1009  crc = 0xFFFFFFFF;
1010 
1011  //Loop through data
1012  for(i = 0; i < length; i++)
1013  {
1014  //The message is processed bit by bit
1015  for(j = 0; j < 8; j++)
1016  {
1017  //Update CRC value
1018  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
1019  {
1020  crc = (crc << 1) ^ 0x04C11DB7;
1021  }
1022  else
1023  {
1024  crc = crc << 1;
1025  }
1026  }
1027  }
1028 
1029  //Return CRC value
1030  return ~crc;
1031 }
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
Transmit descriptor.
#define ETH_MMCRIMR_RXLPITRCIM
uint8_t opcode
Definition: dns_common.h:188
int bool_t
Definition: compiler_port.h:53
#define ETH_MMCRIMR_RXALGNERPIM
#define netEvent
Definition: net_legacy.h:196
#define ETH_MMCRIMR_RXCRCERPIM
#define ETH_RDES3_DE
void ETH_IRQHandler(void)
STM32H7Rx/Sx Ethernet MAC interrupt service routine.
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
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
error_t stm32h7rsxxEthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
#define ETH_RDES3_LD
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
void stm32h7rsxxEthEnableIrq(NetInterface *interface)
Enable interrupts.
#define TRUE
Definition: os_port.h:50
uint8_t data[]
Definition: ethernet.h:222
#define ETH_TDES3_LD
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:264
#define STM32H7RSXX_ETH_IRQ_PRIORITY_GROUPING
#define ETH_RDES3_GP
#define ETH_RDES3_CE
error_t stm32h7rsxxEthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
void stm32h7rsxxEthTick(NetInterface *interface)
STM32H7Rx/Sx Ethernet MAC timer handler.
void stm32h7rsxxEthDisableIrq(NetInterface *interface)
Disable interrupts.
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:392
#define macIsMulticastAddr(macAddr)
Definition: ethernet.h:133
#define osExitIsr(flag)
#define ETH_MMCRIMR_RXLPIUSCIM
error_t stm32h7rsxxEthReceivePacket(NetInterface *interface)
Receive a packet.
#define SMI_OPCODE_WRITE
Definition: nic.h:66
#define ETH_RDES3_RE
#define STM32H7RSXX_ETH_IRQ_SUB_PRIORITY
#define FALSE
Definition: os_port.h:46
#define ETH_MMCTIMR_TXLPITRCIM
#define ETH_RDES3_RWT
error_t
Error codes.
Definition: error.h:43
STM32H7Rx/Sx Ethernet MAC driver.
#define ETH_TDES2_B1L
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:104
#define STM32H7RSXX_ETH_RX_BUFFER_SIZE
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
#define txBuffer
#define NetRxAncillary
Definition: net_misc.h:40
@ ERROR_INVALID_PACKET
Definition: error.h:140
#define NetInterface
Definition: net.h:36
void stm32h7rsxxEthEventHandler(NetInterface *interface)
STM32H7Rx/Sx Ethernet MAC event handler.
MacAddr addr
MAC address.
Definition: ethernet.h:263
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_BUFFER_EMPTY
Definition: error.h:141
#define ETH_MMCTIMR_TXLPIUSCIM
#define ETH_MMCTIMR_TXGPKTIM
#define NetTxAncillary
Definition: net_misc.h:36
#define ETH_RDES3_BUF1V
#define SMI_OPCODE_READ
Definition: nic.h:67
#define ETH_TDES2_IOC
__weak_func void stm32h7rsxxEthInitGpio(NetInterface *interface)
GPIO configuration.
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t length
Definition: tcp.h:368
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
#define MIN(a, b)
Definition: os_port.h:63
void stm32h7rsxxEthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
#define ETH_RDES3_OWN
uint16_t stm32h7rsxxEthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
#define ETH_TDES3_OWN
#define rxBuffer
MacAddr
Definition: ethernet.h:195
error_t stm32h7rsxxEthInit(NetInterface *interface)
STM32H7Rx/Sx Ethernet MAC initialization.
#define STM32H7RSXX_ETH_RAM_SECTION
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define STM32H7RSXX_ETH_IRQ_GROUP_PRIORITY
const NicDriver stm32h7rsxxEthDriver
STM32H7Rx/Sx Ethernet MAC driver.
uint16_t regAddr
#define ETH_MTU
Definition: ethernet.h:116
uint8_t n
#define STM32H7RSXX_ETH_RX_BUFFER_COUNT
MAC filter table entry.
Definition: ethernet.h:262
#define ETH_RDES3_FD
#define ETH_MMCRIMR_RXUCGPIM
#define osEnterIsr()
uint32_t stm32h7rsxxEthCalcCrc(const void *data, size_t length)
CRC calculation.
error_t stm32h7rsxxEthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
#define rxDmaDesc
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define ETH_TDES3_FD
#define STM32H7RSXX_ETH_TX_BUFFER_COUNT
#define ETH_RDES3_OE
#define txDmaDesc
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
unsigned int uint_t
Definition: compiler_port.h:50
TCP/IP stack core.
#define ETH_MACCR_RESERVED15
NIC driver.
Definition: nic.h:286
void stm32h7rsxxEthInitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
#define ETH_RDES3_IOC
#define STM32H7RSXX_ETH_TX_BUFFER_SIZE
#define ETH_MMCTIMR_TXMCOLGPIM
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:53
@ NO_ERROR
Success.
Definition: error.h:44
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
Debugging facilities.
#define ETH_RDES3_PL
#define ETH_MMCTIMR_TXSCOLGPIM
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83