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