stm32f4x9_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file stm32f4x9_eth_driver.c
3  * @brief STM32F429/439 Ethernet MAC controller
4  *
5  * @section License
6  *
7  * Copyright (C) 2010-2018 Oryx Embedded SARL. All rights reserved.
8  *
9  * This file is part of CycloneTCP Open.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  * @author Oryx Embedded SARL (www.oryx-embedded.com)
26  * @version 1.9.0
27  **/
28 
29 //Switch to the appropriate trace level
30 #define TRACE_LEVEL NIC_TRACE_LEVEL
31 
32 //Dependencies
33 #include "stm32f4xx.h"
34 #include "core/net.h"
36 #include "debug.h"
37 
38 //Underlying network interface
39 static NetInterface *nicDriverInterface;
40 
41 //IAR EWARM compiler?
42 #if defined(__ICCARM__)
43 
44 //Transmit buffer
45 #pragma data_alignment = 4
47 //Receive buffer
48 #pragma data_alignment = 4
50 //Transmit DMA descriptors
51 #pragma data_alignment = 4
53 //Receive DMA descriptors
54 #pragma data_alignment = 4
56 
57 //Keil MDK-ARM or GCC compiler?
58 #else
59 
60 //Transmit buffer
62  __attribute__((aligned(4)));
63 //Receive buffer
65  __attribute__((aligned(4)));
66 //Transmit DMA descriptors
68  __attribute__((aligned(4)));
69 //Receive DMA descriptors
71  __attribute__((aligned(4)));
72 
73 #endif
74 
75 //Pointer to the current TX DMA descriptor
76 static Stm32f4x9TxDmaDesc *txCurDmaDesc;
77 //Pointer to the current RX DMA descriptor
78 static Stm32f4x9RxDmaDesc *rxCurDmaDesc;
79 
80 
81 /**
82  * @brief STM32F429/439 Ethernet MAC driver
83  **/
84 
86 {
88  ETH_MTU,
99  TRUE,
100  TRUE,
101  TRUE,
102  FALSE
103 };
104 
105 
106 /**
107  * @brief STM32F429/439 Ethernet MAC initialization
108  * @param[in] interface Underlying network interface
109  * @return Error code
110  **/
111 
113 {
114  error_t error;
115 
116  //Debug message
117  TRACE_INFO("Initializing STM32F4x9 Ethernet MAC...\r\n");
118 
119  //Save underlying network interface
120  nicDriverInterface = interface;
121 
122  //GPIO configuration
123  stm32f4x9EthInitGpio(interface);
124 
125  //Enable Ethernet MAC clock
126  __HAL_RCC_ETHMAC_CLK_ENABLE();
127  __HAL_RCC_ETHMACTX_CLK_ENABLE();
128  __HAL_RCC_ETHMACRX_CLK_ENABLE();
129 
130  //Reset Ethernet MAC peripheral
131  __HAL_RCC_ETHMAC_FORCE_RESET();
132  __HAL_RCC_ETHMAC_RELEASE_RESET();
133 
134  //Perform a software reset
135  ETH->DMABMR |= ETH_DMABMR_SR;
136  //Wait for the reset to complete
137  while(ETH->DMABMR & ETH_DMABMR_SR);
138 
139  //Adjust MDC clock range depending on HCLK frequency
140  ETH->MACMIIAR = ETH_MACMIIAR_CR_Div102;
141 
142  //PHY transceiver initialization
143  error = interface->phyDriver->init(interface);
144  //Failed to initialize PHY transceiver?
145  if(error)
146  return error;
147 
148  //Use default MAC configuration
149  ETH->MACCR = ETH_MACCR_ROD;
150 
151  //Set the MAC address
152  ETH->MACA0LR = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
153  ETH->MACA0HR = interface->macAddr.w[2];
154 
155  //Initialize hash table
156  ETH->MACHTLR = 0;
157  ETH->MACHTHR = 0;
158 
159  //Configure the receive filter
160  ETH->MACFFR = ETH_MACFFR_HPF | ETH_MACFFR_HM;
161  //Disable flow control
162  ETH->MACFCR = 0;
163  //Enable store and forward mode
164  ETH->DMAOMR = ETH_DMAOMR_RSF | ETH_DMAOMR_TSF;
165 
166  //Configure DMA bus mode
167  ETH->DMABMR = ETH_DMABMR_AAB | ETH_DMABMR_USP | ETH_DMABMR_RDP_1Beat |
168  ETH_DMABMR_RTPR_1_1 | ETH_DMABMR_PBL_1Beat | ETH_DMABMR_EDE;
169 
170  //Initialize DMA descriptor lists
171  stm32f4x9EthInitDmaDesc(interface);
172 
173  //Prevent interrupts from being generated when the transmit statistic
174  //counters reach half their maximum value
175  ETH->MMCTIMR = ETH_MMCTIMR_TGFM | ETH_MMCTIMR_TGFMSCM | ETH_MMCTIMR_TGFSCM;
176 
177  //Prevent interrupts from being generated when the receive statistic
178  //counters reach half their maximum value
179  ETH->MMCRIMR = ETH_MMCRIMR_RGUFM | ETH_MMCRIMR_RFAEM | ETH_MMCRIMR_RFCEM;
180 
181  //Disable MAC interrupts
182  ETH->MACIMR = ETH_MACIMR_TSTIM | ETH_MACIMR_PMTIM;
183  //Enable the desired DMA interrupts
184  ETH->DMAIER = ETH_DMAIER_NISE | ETH_DMAIER_RIE | ETH_DMAIER_TIE;
185 
186  //Set priority grouping (4 bits for pre-emption priority, no bits for subpriority)
187  NVIC_SetPriorityGrouping(STM32F4X9_ETH_IRQ_PRIORITY_GROUPING);
188 
189  //Configure Ethernet interrupt priority
190  NVIC_SetPriority(ETH_IRQn, NVIC_EncodePriority(STM32F4X9_ETH_IRQ_PRIORITY_GROUPING,
192 
193  //Enable MAC transmission and reception
194  ETH->MACCR |= ETH_MACCR_TE | ETH_MACCR_RE;
195  //Enable DMA transmission and reception
196  ETH->DMAOMR |= ETH_DMAOMR_ST | ETH_DMAOMR_SR;
197 
198  //Accept any packets from the upper layer
199  osSetEvent(&interface->nicTxEvent);
200 
201  //Successful initialization
202  return NO_ERROR;
203 }
204 
205 
206 //STM324x9I-EVAL, STM32469I-EVAL, Nucleo-F429ZI or Nucleo-F446ZE evaluation board?
207 #if defined(USE_STM324x9I_EVAL) || defined(USE_STM32F469I_EVAL) || \
208  defined(USE_STM32F4XX_NUCLEO_144)
209 
210 /**
211  * @brief GPIO configuration
212  * @param[in] interface Underlying network interface
213  **/
214 
215 void stm32f4x9EthInitGpio(NetInterface *interface)
216 {
217  GPIO_InitTypeDef GPIO_InitStructure;
218 
219 //STM324x9I-EVAL evaluation board?
220 #if defined(USE_STM324x9I_EVAL)
221  //Enable SYSCFG clock
222  __HAL_RCC_SYSCFG_CLK_ENABLE();
223 
224  //Enable GPIO clocks
225  __HAL_RCC_GPIOA_CLK_ENABLE();
226  __HAL_RCC_GPIOB_CLK_ENABLE();
227  __HAL_RCC_GPIOC_CLK_ENABLE();
228  __HAL_RCC_GPIOG_CLK_ENABLE();
229  __HAL_RCC_GPIOH_CLK_ENABLE();
230  __HAL_RCC_GPIOI_CLK_ENABLE();
231 
232  //Configure MCO1 (PA8) as an output
233  GPIO_InitStructure.Pin = GPIO_PIN_8;
234  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
235  GPIO_InitStructure.Pull = GPIO_NOPULL;
236  GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
237  GPIO_InitStructure.Alternate = GPIO_AF0_MCO;
238  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
239 
240  //Configure MCO1 pin to output the HSE clock (25MHz)
241  HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSE, RCC_MCODIV_1);
242 
243  //Select MII interface mode
244  SYSCFG->PMC &= ~SYSCFG_PMC_MII_RMII_SEL;
245 
246  //Configure MII pins
247  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
248  GPIO_InitStructure.Pull = GPIO_NOPULL;
249  GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
250  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
251 
252  //Configure ETH_MII_CRS (PA0)
253  //GPIO_InitStructure.Pin = GPIO_PIN_0;
254  //HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
255 
256  //Configure ETH_MII_RX_CLK (PA1), ETH_MDIO (PA2) and ETH_MII_RX_DV (PA7)
257  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
258  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
259 
260  //Configure ETH_MII_TXD3 (PB8)
261  GPIO_InitStructure.Pin = GPIO_PIN_8;
262  HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
263 
264  //Configure ETH_MDC (PC1), ETH_MII_TXD2 (PC2), ETH_MII_TX_CLK (PC3),
265  //ETH_MII_RXD0 (PC4) and ETH_MII_RXD1 (PC5)
266  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5;
267  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
268 
269  //Configure ETH_MII_TX_EN (PG11), ETH_MII_TXD0 (PG13) and ETH_MII_TXD1 (PG14)
270  GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14;
271  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
272 
273  //Configure ETH_MII_COL (PH3)
274  //GPIO_InitStructure.Pin = GPIO_PIN_3;
275  //HAL_GPIO_Init(GPIOH, &GPIO_InitStructure);
276 
277  //Configure ETH_MII_RXD2 (PH6) and ETH_MII_RXD3 (PH7)
278  GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7;
279  HAL_GPIO_Init(GPIOH, &GPIO_InitStructure);
280 
281  //Configure ETH_MII_RX_ER (PI10)
282  //GPIO_InitStructure.Pin = GPIO_PIN_10;
283  //HAL_GPIO_Init(GPIOI, &GPIO_InitStructure);
284 
285 //STM32469I-EVAL evaluation board?
286 #elif defined(USE_STM32F469I_EVAL)
287  //Enable SYSCFG clock
288  __HAL_RCC_SYSCFG_CLK_ENABLE();
289 
290  //Enable GPIO clocks
291  __HAL_RCC_GPIOA_CLK_ENABLE();
292  __HAL_RCC_GPIOC_CLK_ENABLE();
293  __HAL_RCC_GPIOE_CLK_ENABLE();
294  __HAL_RCC_GPIOG_CLK_ENABLE();
295  __HAL_RCC_GPIOH_CLK_ENABLE();
296  __HAL_RCC_GPIOI_CLK_ENABLE();
297 
298  //Configure MCO1 (PA8) as an output
299  GPIO_InitStructure.Pin = GPIO_PIN_8;
300  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
301  GPIO_InitStructure.Pull = GPIO_NOPULL;
302  GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
303  GPIO_InitStructure.Alternate = GPIO_AF0_MCO;
304  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
305 
306  //Configure MCO1 pin to output the HSE clock (25MHz)
307  HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSE, RCC_MCODIV_1);
308 
309  //Select MII interface mode
310  SYSCFG->PMC &= ~SYSCFG_PMC_MII_RMII_SEL;
311 
312  //Configure MII pins
313  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
314  GPIO_InitStructure.Pull = GPIO_NOPULL;
315  GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
316  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
317 
318  //Configure ETH_MII_CRS (PA0)
319  //GPIO_InitStructure.Pin = GPIO_PIN_0;
320  //HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
321 
322  //Configure ETH_MII_RX_CLK (PA1), ETH_MDIO (PA2) and ETH_MII_RX_DV (PA7)
323  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
324  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
325 
326  //Configure ETH_MDC (PC1), ETH_MII_TXD2 (PC2), ETH_MII_TX_CLK (PC3),
327  //ETH_MII_RXD0 (PC4) and ETH_MII_RXD1 (PC5)
328  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5;
329  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
330 
331  //Configure ETH_MII_TXD3 (PE2)
332  GPIO_InitStructure.Pin = GPIO_PIN_2;
333  HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
334 
335  //Configure ETH_MII_TX_EN (PG11), ETH_MII_TXD0 (PG13) and ETH_MII_TXD1 (PG14)
336  GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13 | GPIO_PIN_14;
337  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
338 
339  //Configure ETH_MII_COL (PH3)
340  //GPIO_InitStructure.Pin = GPIO_PIN_3;
341  //HAL_GPIO_Init(GPIOH, &GPIO_InitStructure);
342 
343  //Configure ETH_MII_RXD2 (PH6) and ETH_MII_RXD3 (PH7)
344  GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7;
345  HAL_GPIO_Init(GPIOH, &GPIO_InitStructure);
346 
347  //Configure ETH_MII_RX_ER (PI10)
348  //GPIO_InitStructure.Pin = GPIO_PIN_10;
349  //HAL_GPIO_Init(GPIOI, &GPIO_InitStructure);
350 
351 //Nucleo-F429ZI or Nucleo-F446ZE evaluation board?
352 #elif defined(USE_STM32F4XX_NUCLEO_144)
353  //Enable SYSCFG clock
354  __HAL_RCC_SYSCFG_CLK_ENABLE();
355 
356  //Enable GPIO clocks
357  __HAL_RCC_GPIOA_CLK_ENABLE();
358  __HAL_RCC_GPIOB_CLK_ENABLE();
359  __HAL_RCC_GPIOC_CLK_ENABLE();
360  __HAL_RCC_GPIOG_CLK_ENABLE();
361 
362  //Select RMII interface mode
363  SYSCFG->PMC |= SYSCFG_PMC_MII_RMII_SEL;
364 
365  //Configure RMII pins
366  GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
367  GPIO_InitStructure.Pull = GPIO_NOPULL;
368  GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
369  GPIO_InitStructure.Alternate = GPIO_AF11_ETH;
370 
371  //Configure ETH_RMII_REF_CLK (PA1), ETH_MDIO (PA2) and ETH_RMII_CRS_DV (PA7)
372  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_7;
373  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
374 
375  //Configure ETH_RMII_TXD1 (PB13)
376  GPIO_InitStructure.Pin = GPIO_PIN_13;
377  HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
378 
379  //Configure ETH_MDC (PC1), ETH_RMII_RXD0 (PC4) and ETH_RMII_RXD1 (PC5)
380  GPIO_InitStructure.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5;
381  HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
382 
383  //Configure RMII_TX_EN (PG11), ETH_RMII_TXD0 (PG13)
384  GPIO_InitStructure.Pin = GPIO_PIN_11 | GPIO_PIN_13;
385  HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
386 #endif
387 }
388 
389 #endif
390 
391 
392 /**
393  * @brief Initialize DMA descriptor lists
394  * @param[in] interface Underlying network interface
395  **/
396 
398 {
399  uint_t i;
400 
401  //Initialize TX DMA descriptor list
402  for(i = 0; i < STM32F4X9_ETH_TX_BUFFER_COUNT; i++)
403  {
404  //Use chain structure rather than ring structure
405  txDmaDesc[i].tdes0 = ETH_TDES0_IC | ETH_TDES0_TCH;
406  //Initialize transmit buffer size
407  txDmaDesc[i].tdes1 = 0;
408  //Transmit buffer address
409  txDmaDesc[i].tdes2 = (uint32_t) txBuffer[i];
410  //Next descriptor address
411  txDmaDesc[i].tdes3 = (uint32_t) &txDmaDesc[i + 1];
412  //Reserved fields
413  txDmaDesc[i].tdes4 = 0;
414  txDmaDesc[i].tdes5 = 0;
415  //Transmit frame time stamp
416  txDmaDesc[i].tdes6 = 0;
417  txDmaDesc[i].tdes7 = 0;
418  }
419 
420  //The last descriptor is chained to the first entry
421  txDmaDesc[i - 1].tdes3 = (uint32_t) &txDmaDesc[0];
422  //Point to the very first descriptor
423  txCurDmaDesc = &txDmaDesc[0];
424 
425  //Initialize RX DMA descriptor list
426  for(i = 0; i < STM32F4X9_ETH_RX_BUFFER_COUNT; i++)
427  {
428  //The descriptor is initially owned by the DMA
429  rxDmaDesc[i].rdes0 = ETH_RDES0_OWN;
430  //Use chain structure rather than ring structure
432  //Receive buffer address
433  rxDmaDesc[i].rdes2 = (uint32_t) rxBuffer[i];
434  //Next descriptor address
435  rxDmaDesc[i].rdes3 = (uint32_t) &rxDmaDesc[i + 1];
436  //Extended status
437  rxDmaDesc[i].rdes4 = 0;
438  //Reserved field
439  rxDmaDesc[i].rdes5 = 0;
440  //Receive frame time stamp
441  rxDmaDesc[i].rdes6 = 0;
442  rxDmaDesc[i].rdes7 = 0;
443  }
444 
445  //The last descriptor is chained to the first entry
446  rxDmaDesc[i - 1].rdes3 = (uint32_t) &rxDmaDesc[0];
447  //Point to the very first descriptor
448  rxCurDmaDesc = &rxDmaDesc[0];
449 
450  //Start location of the TX descriptor list
451  ETH->DMATDLAR = (uint32_t) txDmaDesc;
452  //Start location of the RX descriptor list
453  ETH->DMARDLAR = (uint32_t) rxDmaDesc;
454 }
455 
456 
457 /**
458  * @brief STM32F429/439 Ethernet MAC timer handler
459  *
460  * This routine is periodically called by the TCP/IP stack to
461  * handle periodic operations such as polling the link state
462  *
463  * @param[in] interface Underlying network interface
464  **/
465 
467 {
468  //Handle periodic operations
469  interface->phyDriver->tick(interface);
470 }
471 
472 
473 /**
474  * @brief Enable interrupts
475  * @param[in] interface Underlying network interface
476  **/
477 
479 {
480  //Enable Ethernet MAC interrupts
481  NVIC_EnableIRQ(ETH_IRQn);
482  //Enable Ethernet PHY interrupts
483  interface->phyDriver->enableIrq(interface);
484 }
485 
486 
487 /**
488  * @brief Disable interrupts
489  * @param[in] interface Underlying network interface
490  **/
491 
493 {
494  //Disable Ethernet MAC interrupts
495  NVIC_DisableIRQ(ETH_IRQn);
496  //Disable Ethernet PHY interrupts
497  interface->phyDriver->disableIrq(interface);
498 }
499 
500 
501 /**
502  * @brief STM32F429/439 Ethernet MAC interrupt service routine
503  **/
504 
505 void ETH_IRQHandler(void)
506 {
507  bool_t flag;
508  uint32_t status;
509 
510  //Enter interrupt service routine
511  osEnterIsr();
512 
513  //This flag will be set if a higher priority task must be woken
514  flag = FALSE;
515 
516  //Read DMA status register
517  status = ETH->DMASR;
518 
519  //A packet has been transmitted?
520  if(status & ETH_DMASR_TS)
521  {
522  //Clear TS interrupt flag
523  ETH->DMASR = ETH_DMASR_TS;
524 
525  //Check whether the TX buffer is available for writing
526  if(!(txCurDmaDesc->tdes0 & ETH_TDES0_OWN))
527  {
528  //Notify the TCP/IP stack that the transmitter is ready to send
529  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
530  }
531  }
532 
533  //A packet has been received?
534  if(status & ETH_DMASR_RS)
535  {
536  //Disable RIE interrupt
537  ETH->DMAIER &= ~ETH_DMAIER_RIE;
538 
539  //Set event flag
540  nicDriverInterface->nicEvent = TRUE;
541  //Notify the TCP/IP stack of the event
542  flag |= osSetEventFromIsr(&netEvent);
543  }
544 
545  //Clear NIS interrupt flag
546  ETH->DMASR = ETH_DMASR_NIS;
547 
548  //Leave interrupt service routine
549  osExitIsr(flag);
550 }
551 
552 
553 /**
554  * @brief STM32F429/439 Ethernet MAC event handler
555  * @param[in] interface Underlying network interface
556  **/
557 
559 {
560  error_t error;
561 
562  //Packet received?
563  if(ETH->DMASR & ETH_DMASR_RS)
564  {
565  //Clear interrupt flag
566  ETH->DMASR = ETH_DMASR_RS;
567 
568  //Process all pending packets
569  do
570  {
571  //Read incoming packet
572  error = stm32f4x9EthReceivePacket(interface);
573 
574  //No more data in the receive buffer?
575  } while(error != ERROR_BUFFER_EMPTY);
576  }
577 
578  //Re-enable DMA interrupts
579  ETH->DMAIER |= ETH_DMAIER_NISE | ETH_DMAIER_RIE | ETH_DMAIER_TIE;
580 }
581 
582 
583 /**
584  * @brief Send a packet
585  * @param[in] interface Underlying network interface
586  * @param[in] buffer Multi-part buffer containing the data to send
587  * @param[in] offset Offset to the first data byte
588  * @return Error code
589  **/
590 
592  const NetBuffer *buffer, size_t offset)
593 {
594  size_t length;
595 
596  //Retrieve the length of the packet
597  length = netBufferGetLength(buffer) - offset;
598 
599  //Check the frame length
601  {
602  //The transmitter can accept another packet
603  osSetEvent(&interface->nicTxEvent);
604  //Report an error
605  return ERROR_INVALID_LENGTH;
606  }
607 
608  //Make sure the current buffer is available for writing
609  if(txCurDmaDesc->tdes0 & ETH_TDES0_OWN)
610  return ERROR_FAILURE;
611 
612  //Copy user data to the transmit buffer
613  netBufferRead((uint8_t *) txCurDmaDesc->tdes2, buffer, offset, length);
614 
615  //Write the number of bytes to send
616  txCurDmaDesc->tdes1 = length & ETH_TDES1_TBS1;
617  //Set LS and FS flags as the data fits in a single buffer
618  txCurDmaDesc->tdes0 |= ETH_TDES0_LS | ETH_TDES0_FS;
619  //Give the ownership of the descriptor to the DMA
620  txCurDmaDesc->tdes0 |= ETH_TDES0_OWN;
621 
622  //Clear TBUS flag to resume processing
623  ETH->DMASR = ETH_DMASR_TBUS;
624  //Instruct the DMA to poll the transmit descriptor list
625  ETH->DMATPDR = 0;
626 
627  //Point to the next descriptor in the list
628  txCurDmaDesc = (Stm32f4x9TxDmaDesc *) txCurDmaDesc->tdes3;
629 
630  //Check whether the next buffer is available for writing
631  if(!(txCurDmaDesc->tdes0 & ETH_TDES0_OWN))
632  {
633  //The transmitter can accept another packet
634  osSetEvent(&interface->nicTxEvent);
635  }
636 
637  //Data successfully written
638  return NO_ERROR;
639 }
640 
641 
642 /**
643  * @brief Receive a packet
644  * @param[in] interface Underlying network interface
645  * @return Error code
646  **/
647 
649 {
650  error_t error;
651  size_t n;
652 
653  //The current buffer is available for reading?
654  if(!(rxCurDmaDesc->rdes0 & ETH_RDES0_OWN))
655  {
656  //FS and LS flags should be set
657  if((rxCurDmaDesc->rdes0 & ETH_RDES0_FS) && (rxCurDmaDesc->rdes0 & ETH_RDES0_LS))
658  {
659  //Make sure no error occurred
660  if(!(rxCurDmaDesc->rdes0 & ETH_RDES0_ES))
661  {
662  //Retrieve the length of the frame
663  n = (rxCurDmaDesc->rdes0 & ETH_RDES0_FL) >> 16;
664  //Limit the number of data to read
666 
667  //Pass the packet to the upper layer
668  nicProcessPacket(interface, (uint8_t *) rxCurDmaDesc->rdes2, n);
669 
670  //Valid packet received
671  error = NO_ERROR;
672  }
673  else
674  {
675  //The received packet contains an error
676  error = ERROR_INVALID_PACKET;
677  }
678  }
679  else
680  {
681  //The packet is not valid
682  error = ERROR_INVALID_PACKET;
683  }
684 
685  //Give the ownership of the descriptor back to the DMA
686  rxCurDmaDesc->rdes0 = ETH_RDES0_OWN;
687  //Point to the next descriptor in the list
688  rxCurDmaDesc = (Stm32f4x9RxDmaDesc *) rxCurDmaDesc->rdes3;
689  }
690  else
691  {
692  //No more data in the receive buffer
693  error = ERROR_BUFFER_EMPTY;
694  }
695 
696  //Clear RBUS flag to resume processing
697  ETH->DMASR = ETH_DMASR_RBUS;
698  //Instruct the DMA to poll the receive descriptor list
699  ETH->DMARPDR = 0;
700 
701  //Return status code
702  return error;
703 }
704 
705 
706 /**
707  * @brief Configure MAC address filtering
708  * @param[in] interface Underlying network interface
709  * @return Error code
710  **/
711 
713 {
714  uint_t i;
715  uint_t k;
716  uint32_t crc;
717  uint32_t hashTable[2];
718  MacFilterEntry *entry;
719 
720  //Debug message
721  TRACE_DEBUG("Updating STM32F4x9 hash table...\r\n");
722 
723  //Clear hash table
724  hashTable[0] = 0;
725  hashTable[1] = 0;
726 
727  //The MAC address filter contains the list of MAC addresses to accept
728  //when receiving an Ethernet frame
729  for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
730  {
731  //Point to the current entry
732  entry = &interface->macAddrFilter[i];
733 
734  //Valid entry?
735  if(entry->refCount > 0)
736  {
737  //Compute CRC over the current MAC address
738  crc = stm32f4x9EthCalcCrc(&entry->addr, sizeof(MacAddr));
739 
740  //The upper 6 bits in the CRC register are used to index the
741  //contents of the hash table
742  k = (crc >> 26) & 0x3F;
743 
744  //Update hash table contents
745  hashTable[k / 32] |= (1 << (k % 32));
746  }
747  }
748 
749  //Write the hash table
750  ETH->MACHTLR = hashTable[0];
751  ETH->MACHTHR = hashTable[1];
752 
753  //Debug message
754  TRACE_DEBUG(" MACHTLR = %08" PRIX32 "\r\n", ETH->MACHTLR);
755  TRACE_DEBUG(" MACHTHR = %08" PRIX32 "\r\n", ETH->MACHTHR);
756 
757  //Successful processing
758  return NO_ERROR;
759 }
760 
761 
762 /**
763  * @brief Adjust MAC configuration parameters for proper operation
764  * @param[in] interface Underlying network interface
765  * @return Error code
766  **/
767 
769 {
770  uint32_t config;
771 
772  //Read current MAC configuration
773  config = ETH->MACCR;
774 
775  //10BASE-T or 100BASE-TX operation mode?
776  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
777  config |= ETH_MACCR_FES;
778  else
779  config &= ~ETH_MACCR_FES;
780 
781  //Half-duplex or full-duplex mode?
782  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
783  config |= ETH_MACCR_DM;
784  else
785  config &= ~ETH_MACCR_DM;
786 
787  //Update MAC configuration register
788  ETH->MACCR = config;
789 
790  //Successful processing
791  return NO_ERROR;
792 }
793 
794 
795 /**
796  * @brief Write PHY register
797  * @param[in] phyAddr PHY address
798  * @param[in] regAddr Register address
799  * @param[in] data Register value
800  **/
801 
802 void stm32f4x9EthWritePhyReg(uint8_t phyAddr, uint8_t regAddr, uint16_t data)
803 {
804  uint32_t value;
805 
806  //Take care not to alter MDC clock configuration
807  value = ETH->MACMIIAR & ETH_MACMIIAR_CR;
808  //Set up a write operation
809  value |= ETH_MACMIIAR_MW | ETH_MACMIIAR_MB;
810  //PHY address
811  value |= (phyAddr << 11) & ETH_MACMIIAR_PA;
812  //Register address
813  value |= (regAddr << 6) & ETH_MACMIIAR_MR;
814 
815  //Data to be written in the PHY register
816  ETH->MACMIIDR = data & ETH_MACMIIDR_MD;
817 
818  //Start a write operation
819  ETH->MACMIIAR = value;
820  //Wait for the write to complete
821  while(ETH->MACMIIAR & ETH_MACMIIAR_MB);
822 }
823 
824 
825 /**
826  * @brief Read PHY register
827  * @param[in] phyAddr PHY address
828  * @param[in] regAddr Register address
829  * @return Register value
830  **/
831 
832 uint16_t stm32f4x9EthReadPhyReg(uint8_t phyAddr, uint8_t regAddr)
833 {
834  uint32_t value;
835 
836  //Take care not to alter MDC clock configuration
837  value = ETH->MACMIIAR & ETH_MACMIIAR_CR;
838  //Set up a read operation
839  value |= ETH_MACMIIAR_MB;
840  //PHY address
841  value |= (phyAddr << 11) & ETH_MACMIIAR_PA;
842  //Register address
843  value |= (regAddr << 6) & ETH_MACMIIAR_MR;
844 
845  //Start a read operation
846  ETH->MACMIIAR = value;
847  //Wait for the read to complete
848  while(ETH->MACMIIAR & ETH_MACMIIAR_MB);
849 
850  //Return PHY register contents
851  return ETH->MACMIIDR & ETH_MACMIIDR_MD;
852 }
853 
854 
855 /**
856  * @brief CRC calculation
857  * @param[in] data Pointer to the data over which to calculate the CRC
858  * @param[in] length Number of bytes to process
859  * @return Resulting CRC value
860  **/
861 
862 uint32_t stm32f4x9EthCalcCrc(const void *data, size_t length)
863 {
864  uint_t i;
865  uint_t j;
866 
867  //Point to the data over which to calculate the CRC
868  const uint8_t *p = (uint8_t *) data;
869  //CRC preset value
870  uint32_t crc = 0xFFFFFFFF;
871 
872  //Loop through data
873  for(i = 0; i < length; i++)
874  {
875  //The message is processed bit by bit
876  for(j = 0; j < 8; j++)
877  {
878  //Update CRC value
879  if(((crc >> 31) ^ (p[i] >> j)) & 0x01)
880  crc = (crc << 1) ^ 0x04C11DB7;
881  else
882  crc = crc << 1;
883  }
884  }
885 
886  //Return CRC value
887  return ~crc;
888 }
#define txDmaDesc
MacAddr addr
MAC address.
Definition: ethernet.h:210
error_t stm32f4x9EthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset)
Send a packet.
void stm32f4x9EthInitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
void stm32f4x9EthEventHandler(NetInterface *interface)
STM32F429/439 Ethernet MAC event handler.
TCP/IP stack core.
#define STM32F4X9_ETH_IRQ_PRIORITY_GROUPING
Debugging facilities.
uint8_t p
Definition: ndp.h:295
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:295
error_t stm32f4x9EthReceivePacket(NetInterface *interface)
Receive a packet.
Generic error code.
Definition: error.h:43
#define rxDmaDesc
#define txBuffer
uint32_t stm32f4x9EthCalcCrc(const void *data, size_t length)
CRC calculation.
error_t stm32f4x9EthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
#define ETH_RDES0_OWN
#define STM32F4X9_ETH_IRQ_SUB_PRIORITY
Enhanced TX DMA descriptor.
#define ETH_RDES0_FL
#define TRUE
Definition: os_port.h:48
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:65
error_t stm32f4x9EthInit(NetInterface *interface)
STM32F429/439 Ethernet MAC initialization.
void stm32f4x9EthWritePhyReg(uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
#define ETH_TDES0_IC
STM32F429/439 Ethernet MAC controller.
Enhanced RX DMA descriptor.
void ETH_IRQHandler(void)
STM32F429/439 Ethernet MAC interrupt service routine.
#define ETH_TDES0_OWN
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:670
NIC driver.
Definition: nic.h:161
#define ETH_TDES0_FS
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:86
#define MIN(a, b)
Definition: os_port.h:60
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
#define STM32F4X9_ETH_IRQ_GROUP_PRIORITY
#define ETH_TDES0_LS
#define TRACE_INFO(...)
Definition: debug.h:86
uint16_t regAddr
#define ETH_MTU
Definition: ethernet.h:82
Ethernet interface.
Definition: nic.h:69
Success.
Definition: error.h:42
#define rxBuffer
void stm32f4x9EthEnableIrq(NetInterface *interface)
Enable interrupts.
void stm32f4x9EthDisableIrq(NetInterface *interface)
Disable interrupts.
#define STM32F4X9_ETH_RX_BUFFER_SIZE
#define ETH_RDES0_LS
OsEvent netEvent
Definition: net.c:72
#define STM32F4X9_ETH_RX_BUFFER_COUNT
void nicProcessPacket(NetInterface *interface, void *packet, size_t length)
Handle a packet received by the network controller.
Definition: nic.c:239
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:211
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
error_t
Error codes.
Definition: error.h:40
const NicDriver stm32f4x9EthDriver
STM32F429/439 Ethernet MAC driver.
void stm32f4x9EthTick(NetInterface *interface)
STM32F429/439 Ethernet MAC timer handler.
#define STM32F4X9_ETH_TX_BUFFER_COUNT
unsigned int uint_t
Definition: compiler_port.h:43
__start_packed struct @112 MacAddr
MAC address.
uint8_t data[]
Definition: dtls_misc.h:167
#define NetInterface
Definition: net.h:34
#define ETH_RDES1_RCH
uint8_t value[]
Definition: dtls_misc.h:141
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
uint16_t stm32f4x9EthReadPhyReg(uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
#define osExitIsr(flag)
#define ETH_TDES0_TCH
#define STM32F4X9_ETH_TX_BUFFER_SIZE
#define ETH_TDES1_TBS1
#define osEnterIsr()
#define ETH_RDES1_RBS1
uint8_t length
Definition: dtls_misc.h:140
uint8_t n
#define FALSE
Definition: os_port.h:44
void stm32f4x9EthInitGpio(NetInterface *interface)
int bool_t
Definition: compiler_port.h:47
error_t stm32f4x9EthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
#define ETH_RDES0_FS
MAC filter table entry.
Definition: ethernet.h:208
#define ETH_RDES0_ES
#define TRACE_DEBUG(...)
Definition: debug.h:98