msp432e4_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file msp432e4_eth_driver.c
3  * @brief MSP432E4 Ethernet controller
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include <stdint.h>
36 #include "msp432.h"
37 #include "inc/hw_emac.h"
38 #include "driverlib/types.h"
39 #include "driverlib/gpio.h"
40 #include "driverlib/interrupt.h"
41 #include "driverlib/pin_map.h"
42 #include "driverlib/sysctl.h"
43 #include "core/net.h"
45 #include "debug.h"
46 
47 //Underlying network interface
48 static NetInterface *nicDriverInterface;
49 
50 //IAR EWARM compiler?
51 #if defined(__ICCARM__)
52 
53 //Transmit buffer
54 #pragma data_alignment = 4
56 //Receive buffer
57 #pragma data_alignment = 4
59 //Transmit DMA descriptors
60 #pragma data_alignment = 4
62 //Receive DMA descriptors
63 #pragma data_alignment = 4
65 
66 //Keil MDK-ARM or GCC compiler?
67 #else
68 
69 //Transmit buffer
71  __attribute__((aligned(4)));
72 //Receive buffer
74  __attribute__((aligned(4)));
75 //Transmit DMA descriptors
77  __attribute__((aligned(4)));
78 //Receive DMA descriptors
80  __attribute__((aligned(4)));
81 
82 #endif
83 
84 //Pointer to the current TX DMA descriptor
85 static Msp432e4TxDmaDesc *txCurDmaDesc;
86 //Pointer to the current RX DMA descriptor
87 static Msp432e4RxDmaDesc *rxCurDmaDesc;
88 
89 
90 /**
91  * @brief MSP432E4 Ethernet MAC driver
92  **/
93 
95 {
97  ETH_MTU,
108  TRUE,
109  TRUE,
110  TRUE,
111  FALSE
112 };
113 
114 
115 /**
116  * @brief MSP432E4 Ethernet MAC initialization
117  * @param[in] interface Underlying network interface
118  * @return Error code
119  **/
120 
122 {
123  error_t error;
124 #ifdef ti_sysbios_BIOS___VERS
125  Hwi_Params hwiParams;
126 #endif
127 
128  //Debug message
129  TRACE_INFO("Initializing MSP432E4 Ethernet controller...\r\n");
130 
131  //Save underlying network interface
132  nicDriverInterface = interface;
133 
134  //Enable and reset EMAC peripheral
135  SysCtlPeripheralEnable(SYSCTL_PERIPH_EMAC0);
136  SysCtlPeripheralReset(SYSCTL_PERIPH_EMAC0);
137 
138  //Wait for the EMAC peripheral to be ready
139  while(!SysCtlPeripheralReady(SYSCTL_PERIPH_EMAC0))
140  {
141  }
142 
143  //Enable and reset PHY peripheral
144  SysCtlPeripheralEnable(SYSCTL_PERIPH_EPHY0);
145  SysCtlPeripheralReset(SYSCTL_PERIPH_EPHY0);
146 
147  //Wait for the PHY peripheral to be ready
148  while(!SysCtlPeripheralReady(SYSCTL_PERIPH_EPHY0))
149  {
150  }
151 
152  //GPIO configuration
153  msp432e4EthInitGpio(interface);
154 
155  //Perform a software reset
156  EMAC0_DMABUSMOD_R |= EMAC_DMABUSMOD_SWR;
157  //Wait for the reset to complete
158  while((EMAC0_DMABUSMOD_R & EMAC_DMABUSMOD_SWR) != 0)
159  {
160  }
161 
162  //Adjust MDC clock range depending on SYSCLK frequency
163  EMAC0_MIIADDR_R = EMAC_MIIADDR_CR_100_150;
164 
165  //Internal or external Ethernet PHY?
166  if(interface->phyDriver != NULL)
167  {
168  //Ethernet PHY initialization
169  error = interface->phyDriver->init(interface);
170  }
171  else if(interface->switchDriver != NULL)
172  {
173  //Ethernet switch initialization
174  error = interface->switchDriver->init(interface);
175  }
176  else
177  {
178  //Reset internal PHY transceiver
180  EPHY_BMCR_MIIRESET);
181 
182  //Wait for the reset to complete
183  while(msp432e4EthReadPhyReg(SMI_OPCODE_READ, 0, EPHY_BMCR) &
184  EPHY_BMCR_MIIRESET)
185  {
186  }
187 
188  //Dump PHY registers for debugging purpose
190 
191  //Configure LED0, LED1 and LED2
193  EPHY_LEDCFG_LED0_TX | EPHY_LEDCFG_LED1_RX | EPHY_LEDCFG_LED2_LINK);
194 
195  //Configure PHY interrupts as desired
197  EPHY_MISR1_LINKSTATEN);
198 
199  //Enable PHY interrupts
200  msp432e4EthWritePhyReg(SMI_OPCODE_WRITE, 0, EPHY_SCR, EPHY_SCR_INTEN);
201 
202  //The internal Ethernet PHY is initialized
203  error = NO_ERROR;
204  }
205 
206  //Any error to report?
207  if(error)
208  {
209  return error;
210  }
211 
212  //Use default MAC configuration
213  EMAC0_CFG_R = EMAC_CFG_DRO;
214 
215  //Set the MAC address of the station
216  EMAC0_ADDR0L_R = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
217  EMAC0_ADDR0H_R = interface->macAddr.w[2];
218 
219  //The MAC supports 3 additional addresses for unicast perfect filtering
220  EMAC0_ADDR1L_R = 0;
221  EMAC0_ADDR1H_R = 0;
222  EMAC0_ADDR2L_R = 0;
223  EMAC0_ADDR2H_R = 0;
224  EMAC0_ADDR3L_R = 0;
225  EMAC0_ADDR3H_R = 0;
226 
227  //Initialize hash table
228  EMAC0_HASHTBLL_R = 0;
229  EMAC0_HASHTBLH_R = 0;
230 
231  //Configure the receive filter
232  EMAC0_FRAMEFLTR_R = EMAC_FRAMEFLTR_HPF | EMAC_FRAMEFLTR_HMC;
233  //Disable flow control
234  EMAC0_FLOWCTL_R = 0;
235  //Enable store and forward mode
236  EMAC0_DMAOPMODE_R = EMAC_DMAOPMODE_RSF | EMAC_DMAOPMODE_TSF;
237 
238  //Configure DMA bus mode
239  EMAC0_DMABUSMOD_R = EMAC_DMABUSMOD_AAL | EMAC_DMABUSMOD_USP |
241  EMAC_DMABUSMOD_ATDS;
242 
243  //Initialize DMA descriptor lists
244  msp432e4EthInitDmaDesc(interface);
245 
246  //Prevent interrupts from being generated when the transmit statistic
247  //counters reach half their maximum value
248  EMAC0_MMCTXIM_R = EMAC_MMCTXIM_OCTCNT | EMAC_MMCTXIM_MCOLLGF |
249  EMAC_MMCTXIM_SCOLLGF | EMAC_MMCTXIM_GBF;
250 
251  //Prevent interrupts from being generated when the receive statistic
252  //counters reach half their maximum value
253  EMAC0_MMCRXIM_R = EMAC_MMCRXIM_UCGF | EMAC_MMCRXIM_ALGNERR |
254  EMAC_MMCRXIM_CRCERR | EMAC_MMCRXIM_GBF;
255 
256  //Disable MAC interrupts
257  EMAC0_IM_R = EMAC_IM_TSI | EMAC_IM_PMT;
258  //Enable the desired DMA interrupts
259  EMAC0_DMAIM_R = EMAC_DMAIM_NIE | EMAC_DMAIM_RIE | EMAC_DMAIM_TIE;
260  //Enable PHY interrupts
261  EMAC0_EPHYIM_R = EMAC_EPHYIM_INT;
262 
263 #ifdef ti_sysbios_BIOS___VERS
264  //Configure Ethernet interrupt
265  Hwi_Params_init(&hwiParams);
266  hwiParams.enableInt = FALSE;
267  hwiParams.priority = MSP432E4_ETH_IRQ_PRIORITY;
268 
269  //Register interrupt handler
270  Hwi_create(INT_EMAC0, (Hwi_FuncPtr) msp432e4EthIrqHandler, &hwiParams, NULL);
271 #else
272  //Set priority grouping (3 bits for pre-emption priority, no bits for subpriority)
273  IntPriorityGroupingSet(MSP432E4_ETH_IRQ_PRIORITY_GROUPING);
274  //Configure Ethernet interrupt priority
275  IntPrioritySet(INT_EMAC0, MSP432E4_ETH_IRQ_PRIORITY);
276 #endif
277 
278  //Enable MAC transmission and reception
279  EMAC0_CFG_R |= EMAC_CFG_TE | EMAC_CFG_RE;
280  //Enable DMA transmission and reception
281  EMAC0_DMAOPMODE_R |= EMAC_DMAOPMODE_ST | EMAC_DMAOPMODE_SR;
282 
283  //Accept any packets from the upper layer
284  osSetEvent(&interface->nicTxEvent);
285 
286  //Successful initialization
287  return NO_ERROR;
288 }
289 
290 
291 /**
292  * @brief GPIO configuration
293  * @param[in] interface Underlying network interface
294  **/
295 
296 __weak_func void msp432e4EthInitGpio(NetInterface *interface)
297 {
298 //MSP-EXP432E401Y evaluation board?
299 #if defined(USE_MSP_EXP432E401Y)
300  //Enable GPIO clock
301  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
302 
303  //Select the relevant alternate function for PF0 and PF4
304  GPIOPinConfigure(GPIO_PF0_EN0LED0);
305  GPIOPinConfigure(GPIO_PF4_EN0LED1);
306 
307  //Configure Ethernet LED pins for proper operation
308  GPIOPinTypeEthernetLED(GPIO_PORTF_BASE, GPIO_PIN_0 | GPIO_PIN_4);
309 #endif
310 }
311 
312 
313 /**
314  * @brief Initialize DMA descriptor lists
315  * @param[in] interface Underlying network interface
316  **/
317 
319 {
320  uint_t i;
321 
322  //Initialize TX DMA descriptor list
323  for(i = 0; i < MSP432E4_ETH_TX_BUFFER_COUNT; i++)
324  {
325  //Use chain structure rather than ring structure
327  //Initialize transmit buffer size
328  txDmaDesc[i].tdes1 = 0;
329  //Transmit buffer address
330  txDmaDesc[i].tdes2 = (uint32_t) txBuffer[i];
331  //Next descriptor address
332  txDmaDesc[i].tdes3 = (uint32_t) &txDmaDesc[i + 1];
333  //Reserved fields
334  txDmaDesc[i].tdes4 = 0;
335  txDmaDesc[i].tdes5 = 0;
336  //Transmit frame time stamp
337  txDmaDesc[i].tdes6 = 0;
338  txDmaDesc[i].tdes7 = 0;
339  }
340 
341  //The last descriptor is chained to the first entry
342  txDmaDesc[i - 1].tdes3 = (uint32_t) &txDmaDesc[0];
343  //Point to the very first descriptor
344  txCurDmaDesc = &txDmaDesc[0];
345 
346  //Initialize RX DMA descriptor list
347  for(i = 0; i < MSP432E4_ETH_RX_BUFFER_COUNT; i++)
348  {
349  //The descriptor is initially owned by the DMA
350  rxDmaDesc[i].rdes0 = EMAC_RDES0_OWN;
351  //Use chain structure rather than ring structure
353  //Receive buffer address
354  rxDmaDesc[i].rdes2 = (uint32_t) rxBuffer[i];
355  //Next descriptor address
356  rxDmaDesc[i].rdes3 = (uint32_t) &rxDmaDesc[i + 1];
357  //Extended status
358  rxDmaDesc[i].rdes4 = 0;
359  //Reserved field
360  rxDmaDesc[i].rdes5 = 0;
361  //Receive frame time stamp
362  rxDmaDesc[i].rdes6 = 0;
363  rxDmaDesc[i].rdes7 = 0;
364  }
365 
366  //The last descriptor is chained to the first entry
367  rxDmaDesc[i - 1].rdes3 = (uint32_t) &rxDmaDesc[0];
368  //Point to the very first descriptor
369  rxCurDmaDesc = &rxDmaDesc[0];
370 
371  //Start location of the TX descriptor list
372  EMAC0_TXDLADDR_R = (uint32_t) txDmaDesc;
373  //Start location of the RX descriptor list
374  EMAC0_RXDLADDR_R = (uint32_t) rxDmaDesc;
375 }
376 
377 
378 /**
379  * @brief MSP432E4 Ethernet MAC timer handler
380  *
381  * This routine is periodically called by the TCP/IP stack to handle periodic
382  * operations such as polling the link state
383  *
384  * @param[in] interface Underlying network interface
385  **/
386 
388 {
389  //Valid Ethernet PHY or switch driver?
390  if(interface->phyDriver != NULL)
391  {
392  //Handle periodic operations
393  interface->phyDriver->tick(interface);
394  }
395  else if(interface->switchDriver != NULL)
396  {
397  //Handle periodic operations
398  interface->switchDriver->tick(interface);
399  }
400  else
401  {
402  //Just for sanity
403  }
404 }
405 
406 
407 /**
408  * @brief Enable interrupts
409  * @param[in] interface Underlying network interface
410  **/
411 
413 {
414 #ifdef ti_sysbios_BIOS___VERS
415  //Enable Ethernet MAC interrupts
416  Hwi_enableInterrupt(INT_EMAC0);
417 #else
418  //Enable Ethernet MAC interrupts
419  IntEnable(INT_EMAC0);
420 #endif
421 
422  //Valid Ethernet PHY or switch driver?
423  if(interface->phyDriver != NULL)
424  {
425  //Enable Ethernet PHY interrupts
426  interface->phyDriver->enableIrq(interface);
427  }
428  else if(interface->switchDriver != NULL)
429  {
430  //Enable Ethernet switch interrupts
431  interface->switchDriver->enableIrq(interface);
432  }
433  else
434  {
435  //Just for sanity
436  }
437 }
438 
439 
440 /**
441  * @brief Disable interrupts
442  * @param[in] interface Underlying network interface
443  **/
444 
446 {
447 #ifdef ti_sysbios_BIOS___VERS
448  //Disable Ethernet MAC interrupts
449  Hwi_disableInterrupt(INT_EMAC0);
450 #else
451  //Disable Ethernet MAC interrupts
452  IntDisable(INT_EMAC0);
453 #endif
454 
455  //Valid Ethernet PHY or switch driver?
456  if(interface->phyDriver != NULL)
457  {
458  //Disable Ethernet PHY interrupts
459  interface->phyDriver->disableIrq(interface);
460  }
461  else if(interface->switchDriver != NULL)
462  {
463  //Disable Ethernet switch interrupts
464  interface->switchDriver->disableIrq(interface);
465  }
466  else
467  {
468  //Just for sanity
469  }
470 }
471 
472 
473 /**
474  * @brief MSP432E4 Ethernet MAC interrupt service routine
475  **/
476 
478 {
479  bool_t flag;
480  uint32_t status;
481 
482  //Interrupt service routine prologue
483  osEnterIsr();
484 
485  //This flag will be set if a higher priority task must be woken
486  flag = FALSE;
487 
488  //Read PHY status register
489  status = EMAC0_EPHYRIS_R;
490 
491  //PHY interrupt?
492  if((status & EMAC_EPHYRIS_INT) != 0)
493  {
494  //Disable PHY interrupt
495  EMAC0_EPHYIM_R &= ~EMAC_EPHYIM_INT;
496 
497  //Set event flag
498  nicDriverInterface->nicEvent = TRUE;
499  //Notify the TCP/IP stack of the event
500  flag |= osSetEventFromIsr(&netEvent);
501  }
502 
503  //Read DMA status register
504  status = EMAC0_DMARIS_R;
505 
506  //Packet transmitted?
507  if((status & EMAC_DMARIS_TI) != 0)
508  {
509  //Clear TI interrupt flag
510  EMAC0_DMARIS_R = EMAC_DMARIS_TI;
511 
512  //Check whether the TX buffer is available for writing
513  if((txCurDmaDesc->tdes0 & EMAC_TDES0_OWN) == 0)
514  {
515  //Notify the TCP/IP stack that the transmitter is ready to send
516  flag |= osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
517  }
518  }
519 
520  //Packet received?
521  if((status & EMAC_DMARIS_RI) != 0)
522  {
523  //Disable RIE interrupt
524  EMAC0_DMAIM_R &= ~EMAC_DMAIM_RIE;
525 
526  //Set event flag
527  nicDriverInterface->nicEvent = TRUE;
528  //Notify the TCP/IP stack of the event
529  flag |= osSetEventFromIsr(&netEvent);
530  }
531 
532  //Clear NIS interrupt flag
533  EMAC0_DMARIS_R = EMAC_DMARIS_NIS;
534 
535  //Interrupt service routine epilogue
536  osExitIsr(flag);
537 }
538 
539 
540 /**
541  * @brief MSP432E4 Ethernet MAC event handler
542  * @param[in] interface Underlying network interface
543  **/
544 
546 {
547  error_t error;
548  uint32_t status;
549 
550  //PHY interrupt?
551  if((EMAC0_EPHYRIS_R & EMAC_EPHYRIS_INT) != 0)
552  {
553  //Clear PHY interrupt flag
554  EMAC0_EPHYMISC_R = EMAC_EPHYMISC_INT;
555 
556  //Internal or external Ethernet PHY?
557  if(interface->phyDriver != NULL)
558  {
559  //Handle events
560  interface->phyDriver->eventHandler(interface);
561  }
562  else if(interface->switchDriver != NULL)
563  {
564  //Handle events
565  interface->switchDriver->eventHandler(interface);
566  }
567  else
568  {
569  //Read PHY interrupt status register
570  status = msp432e4EthReadPhyReg(SMI_OPCODE_READ, 0, EPHY_MISR1);
571 
572  //Check whether the link state has changed?
573  if((status & EPHY_MISR1_LINKSTAT) != 0)
574  {
575  //Read BMSR register
576  status = msp432e4EthReadPhyReg(SMI_OPCODE_READ, 0, EPHY_BMSR);
577 
578  //Check whether the link is up
579  if((status & EPHY_BMSR_LINKSTAT) != 0)
580  {
581  //Read PHY status register
582  status = msp432e4EthReadPhyReg(SMI_OPCODE_READ, 0, EPHY_STS);
583 
584  //Check current speed
585  if((status & EPHY_STS_SPEED) != 0)
586  {
587  interface->linkSpeed = NIC_LINK_SPEED_10MBPS;
588  }
589  else
590  {
591  interface->linkSpeed = NIC_LINK_SPEED_100MBPS;
592  }
593 
594  //Check duplex mode
595  if((status & EPHY_STS_DUPLEX) != 0)
596  {
597  interface->duplexMode = NIC_FULL_DUPLEX_MODE;
598  }
599  else
600  {
601  interface->duplexMode = NIC_HALF_DUPLEX_MODE;
602  }
603 
604  //Update link state
605  interface->linkState = TRUE;
606 
607  //Adjust MAC configuration parameters for proper operation
608  msp432e4EthUpdateMacConfig(interface);
609  }
610  else
611  {
612  //Update link state
613  interface->linkState = FALSE;
614  }
615 
616  //Process link state change event
617  nicNotifyLinkChange(interface);
618  }
619  }
620  }
621 
622  //Packet received?
623  if((EMAC0_DMARIS_R & EMAC_DMARIS_RI) != 0)
624  {
625  //Clear interrupt flag
626  EMAC0_DMARIS_R = EMAC_DMARIS_RI;
627 
628  //Process all pending packets
629  do
630  {
631  //Read incoming packet
632  error = msp432e4EthReceivePacket(interface);
633 
634  //No more data in the receive buffer?
635  } while(error != ERROR_BUFFER_EMPTY);
636  }
637 
638  //Re-enable DMA interrupts
639  EMAC0_DMAIM_R = EMAC_DMAIM_NIE | EMAC_DMAIM_RIE | EMAC_DMAIM_TIE;
640  //Re-enable PHY interrupts
641  EMAC0_EPHYIM_R = EMAC_EPHYIM_INT;
642 }
643 
644 
645 /**
646  * @brief Send a packet
647  * @param[in] interface Underlying network interface
648  * @param[in] buffer Multi-part buffer containing the data to send
649  * @param[in] offset Offset to the first data byte
650  * @param[in] ancillary Additional options passed to the stack along with
651  * the packet
652  * @return Error code
653  **/
654 
656  const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
657 {
658  size_t length;
659 
660  //Retrieve the length of the packet
661  length = netBufferGetLength(buffer) - offset;
662 
663  //Check the frame length
665  {
666  //The transmitter can accept another packet
667  osSetEvent(&interface->nicTxEvent);
668  //Report an error
669  return ERROR_INVALID_LENGTH;
670  }
671 
672  //Make sure the current buffer is available for writing
673  if((txCurDmaDesc->tdes0 & EMAC_TDES0_OWN) != 0)
674  {
675  return ERROR_FAILURE;
676  }
677 
678  //Copy user data to the transmit buffer
679  netBufferRead((uint8_t *) txCurDmaDesc->tdes2, buffer, offset, length);
680 
681  //Write the number of bytes to send
682  txCurDmaDesc->tdes1 = length & EMAC_TDES1_TBS1;
683  //Set LS and FS flags as the data fits in a single buffer
684  txCurDmaDesc->tdes0 |= EMAC_TDES0_LS | EMAC_TDES0_FS;
685  //Give the ownership of the descriptor to the DMA
686  txCurDmaDesc->tdes0 |= EMAC_TDES0_OWN;
687 
688  //Clear TU flag to resume processing
689  EMAC0_DMARIS_R = EMAC_DMARIS_TU;
690  //Instruct the DMA to poll the transmit descriptor list
691  EMAC0_TXPOLLD_R = 0;
692 
693  //Point to the next descriptor in the list
694  txCurDmaDesc = (Msp432e4TxDmaDesc *) txCurDmaDesc->tdes3;
695 
696  //Check whether the next buffer is available for writing
697  if((txCurDmaDesc->tdes0 & EMAC_TDES0_OWN) == 0)
698  {
699  //The transmitter can accept another packet
700  osSetEvent(&interface->nicTxEvent);
701  }
702 
703  //Data successfully written
704  return NO_ERROR;
705 }
706 
707 
708 /**
709  * @brief Receive a packet
710  * @param[in] interface Underlying network interface
711  * @return Error code
712  **/
713 
715 {
716  error_t error;
717  size_t n;
718  NetRxAncillary ancillary;
719 
720  //Current buffer available for reading?
721  if((rxCurDmaDesc->rdes0 & EMAC_RDES0_OWN) == 0)
722  {
723  //FS and LS flags should be set
724  if((rxCurDmaDesc->rdes0 & EMAC_RDES0_FS) != 0 &&
725  (rxCurDmaDesc->rdes0 & EMAC_RDES0_LS) != 0)
726  {
727  //Make sure no error occurred
728  if((rxCurDmaDesc->rdes0 & EMAC_RDES0_ES) == 0)
729  {
730  //Retrieve the length of the frame
731  n = (rxCurDmaDesc->rdes0 & EMAC_RDES0_FL) >> 16;
732  //Limit the number of data to read
734 
735  //Additional options can be passed to the stack along with the packet
736  ancillary = NET_DEFAULT_RX_ANCILLARY;
737 
738  //Pass the packet to the upper layer
739  nicProcessPacket(interface, (uint8_t *) rxCurDmaDesc->rdes2, n,
740  &ancillary);
741 
742  //Valid packet received
743  error = NO_ERROR;
744  }
745  else
746  {
747  //The received packet contains an error
748  error = ERROR_INVALID_PACKET;
749  }
750  }
751  else
752  {
753  //The packet is not valid
754  error = ERROR_INVALID_PACKET;
755  }
756 
757  //Give the ownership of the descriptor back to the DMA
758  rxCurDmaDesc->rdes0 = EMAC_RDES0_OWN;
759  //Point to the next descriptor in the list
760  rxCurDmaDesc = (Msp432e4RxDmaDesc *) rxCurDmaDesc->rdes3;
761  }
762  else
763  {
764  //No more data in the receive buffer
765  error = ERROR_BUFFER_EMPTY;
766  }
767 
768  //Clear RU flag to resume processing
769  EMAC0_DMARIS_R = EMAC_DMARIS_RU;
770  //Instruct the DMA to poll the receive descriptor list
771  EMAC0_RXPOLLD_R = 0;
772 
773  //Return status code
774  return error;
775 }
776 
777 
778 /**
779  * @brief Configure MAC address filtering
780  * @param[in] interface Underlying network interface
781  * @return Error code
782  **/
783 
785 {
786  uint_t i;
787  uint_t j;
788  uint_t k;
789  uint32_t crc;
790  uint32_t hashTable[2];
791  MacAddr unicastMacAddr[3];
792  MacFilterEntry *entry;
793 
794  //Debug message
795  TRACE_DEBUG("Updating MAC filter...\r\n");
796 
797  //Set the MAC address of the station
798  EMAC0_ADDR0L_R = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
799  EMAC0_ADDR0H_R = interface->macAddr.w[2];
800 
801  //The MAC supports 3 additional addresses for unicast perfect filtering
802  unicastMacAddr[0] = MAC_UNSPECIFIED_ADDR;
803  unicastMacAddr[1] = MAC_UNSPECIFIED_ADDR;
804  unicastMacAddr[2] = MAC_UNSPECIFIED_ADDR;
805 
806  //The hash table is used for multicast address filtering
807  hashTable[0] = 0;
808  hashTable[1] = 0;
809 
810  //The MAC address filter contains the list of MAC addresses to accept
811  //when receiving an Ethernet frame
812  for(i = 0, j = 0; i < MAC_ADDR_FILTER_SIZE; i++)
813  {
814  //Point to the current entry
815  entry = &interface->macAddrFilter[i];
816 
817  //Valid entry?
818  if(entry->refCount > 0)
819  {
820  //Multicast address?
821  if(macIsMulticastAddr(&entry->addr))
822  {
823  //Compute CRC over the current MAC address
824  crc = msp432e4EthCalcCrc(&entry->addr, sizeof(MacAddr));
825 
826  //The upper 6 bits in the CRC register are used to index the
827  //contents of the hash table
828  k = (crc >> 26) & 0x3F;
829 
830  //Update hash table contents
831  hashTable[k / 32] |= (1 << (k % 32));
832  }
833  else
834  {
835  //Up to 3 additional MAC addresses can be specified
836  if(j < 3)
837  {
838  //Save the unicast address
839  unicastMacAddr[j++] = entry->addr;
840  }
841  }
842  }
843  }
844 
845  //Configure the first unicast address filter
846  if(j >= 1)
847  {
848  //When the AE bit is set, the entry is used for perfect filtering
849  EMAC0_ADDR1L_R = unicastMacAddr[0].w[0] | (unicastMacAddr[0].w[1] << 16);
850  EMAC0_ADDR1H_R = unicastMacAddr[0].w[2] | EMAC_ADDR1H_AE;
851  }
852  else
853  {
854  //When the AE bit is cleared, the entry is ignored
855  EMAC0_ADDR1L_R = 0;
856  EMAC0_ADDR1H_R = 0;
857  }
858 
859  //Configure the second unicast address filter
860  if(j >= 2)
861  {
862  //When the AE bit is set, the entry is used for perfect filtering
863  EMAC0_ADDR2L_R = unicastMacAddr[1].w[0] | (unicastMacAddr[1].w[1] << 16);
864  EMAC0_ADDR2H_R = unicastMacAddr[1].w[2] | EMAC_ADDR2H_AE;
865  }
866  else
867  {
868  //When the AE bit is cleared, the entry is ignored
869  EMAC0_ADDR2L_R = 0;
870  EMAC0_ADDR2H_R = 0;
871  }
872 
873  //Configure the third unicast address filter
874  if(j >= 3)
875  {
876  //When the AE bit is set, the entry is used for perfect filtering
877  EMAC0_ADDR3L_R = unicastMacAddr[2].w[0] | (unicastMacAddr[2].w[1] << 16);
878  EMAC0_ADDR3H_R = unicastMacAddr[2].w[2] | EMAC_ADDR3H_AE;
879  }
880  else
881  {
882  //When the AE bit is cleared, the entry is ignored
883  EMAC0_ADDR3L_R = 0;
884  EMAC0_ADDR3H_R = 0;
885  }
886 
887  //Configure the multicast hash table
888  EMAC0_HASHTBLL_R = hashTable[0];
889  EMAC0_HASHTBLH_R = hashTable[1];
890 
891  //Debug message
892  TRACE_DEBUG(" HASHTBLL = %08" PRIX32 "\r\n", EMAC0_HASHTBLL_R);
893  TRACE_DEBUG(" HASHTBLH = %08" PRIX32 "\r\n", EMAC0_HASHTBLH_R);
894 
895  //Successful processing
896  return NO_ERROR;
897 }
898 
899 
900 /**
901  * @brief Adjust MAC configuration parameters for proper operation
902  * @param[in] interface Underlying network interface
903  * @return Error code
904  **/
905 
907 {
908  uint32_t config;
909 
910  //Read current MAC configuration
911  config = EMAC0_CFG_R;
912 
913  //10BASE-T or 100BASE-TX operation mode?
914  if(interface->linkSpeed == NIC_LINK_SPEED_100MBPS)
915  {
916  config |= EMAC_CFG_FES;
917  }
918  else
919  {
920  config &= ~EMAC_CFG_FES;
921  }
922 
923  //Half-duplex or full-duplex mode?
924  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
925  {
926  config |= EMAC_CFG_DUPM;
927  }
928  else
929  {
930  config &= ~EMAC_CFG_DUPM;
931  }
932 
933  //Update MAC configuration register
934  EMAC0_CFG_R = config;
935 
936  //Successful processing
937  return NO_ERROR;
938 }
939 
940 
941 /**
942  * @brief Write PHY register
943  * @param[in] opcode Access type (2 bits)
944  * @param[in] phyAddr PHY address (5 bits)
945  * @param[in] regAddr Register address (5 bits)
946  * @param[in] data Register value
947  **/
948 
949 void msp432e4EthWritePhyReg(uint8_t opcode, uint8_t phyAddr,
950  uint8_t regAddr, uint16_t data)
951 {
952  uint32_t temp;
953 
954  //Valid opcode?
955  if(opcode == SMI_OPCODE_WRITE)
956  {
957  //Take care not to alter MDC clock configuration
958  temp = EMAC0_MIIADDR_R & EMAC_MIIADDR_CR_M;
959  //Set up a write operation
960  temp |= EMAC_MIIADDR_MIIW | EMAC_MIIADDR_MIIB;
961  //PHY address
962  temp |= (phyAddr << EMAC_MIIADDR_PLA_S) & EMAC_MIIADDR_PLA_M;
963  //Register address
964  temp |= (regAddr << EMAC_MIIADDR_MII_S) & EMAC_MIIADDR_MII_M;
965 
966  //Data to be written in the PHY register
967  EMAC0_MIIDATA_R = data & EMAC_MIIDATA_DATA_M;
968 
969  //Start a write operation
970  EMAC0_MIIADDR_R = temp;
971  //Wait for the write to complete
972  while((EMAC0_MIIADDR_R & EMAC_MIIADDR_MIIB) != 0)
973  {
974  }
975  }
976  else
977  {
978  //The MAC peripheral only supports standard Clause 22 opcodes
979  }
980 }
981 
982 
983 /**
984  * @brief Read PHY register
985  * @param[in] opcode Access type (2 bits)
986  * @param[in] phyAddr PHY address (5 bits)
987  * @param[in] regAddr Register address (5 bits)
988  * @return Register value
989  **/
990 
991 uint16_t msp432e4EthReadPhyReg(uint8_t opcode, uint8_t phyAddr,
992  uint8_t regAddr)
993 {
994  uint16_t data;
995  uint32_t temp;
996 
997  //Valid opcode?
998  if(opcode == SMI_OPCODE_READ)
999  {
1000  //Take care not to alter MDC clock configuration
1001  temp = EMAC0_MIIADDR_R & EMAC_MIIADDR_CR_M;
1002  //Set up a read operation
1003  temp |= EMAC_MIIADDR_MIIB;
1004  //PHY address
1005  temp |= (phyAddr << EMAC_MIIADDR_PLA_S) & EMAC_MIIADDR_PLA_M;
1006  //Register address
1007  temp |= (regAddr << EMAC_MIIADDR_MII_S) & EMAC_MIIADDR_MII_M;
1008 
1009  //Start a read operation
1010  EMAC0_MIIADDR_R = temp;
1011  //Wait for the read to complete
1012  while((EMAC0_MIIADDR_R & EMAC_MIIADDR_MIIB) != 0)
1013  {
1014  }
1015 
1016  //Get register value
1017  data = EMAC0_MIIDATA_R & EMAC_MIIDATA_DATA_M;
1018  }
1019  else
1020  {
1021  //The MAC peripheral only supports standard Clause 22 opcodes
1022  data = 0;
1023  }
1024 
1025  //Return the value of the PHY register
1026  return data;
1027 }
1028 
1029 
1030 /**
1031  * @brief Dump PHY registers for debugging purpose
1032  **/
1033 
1035 {
1036  uint8_t i;
1037 
1038  //Loop through PHY registers
1039  for(i = 0; i < 32; i++)
1040  {
1041  //Display current PHY register
1042  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
1044  }
1045 
1046  //Terminate with a line feed
1047  TRACE_DEBUG("\r\n");
1048 }
1049 
1050 
1051 /**
1052  * @brief CRC calculation
1053  * @param[in] data Pointer to the data over which to calculate the CRC
1054  * @param[in] length Number of bytes to process
1055  * @return Resulting CRC value
1056  **/
1057 
1058 uint32_t msp432e4EthCalcCrc(const void *data, size_t length)
1059 {
1060  uint_t i;
1061  uint_t j;
1062  uint32_t crc;
1063  const uint8_t *p;
1064 
1065  //Point to the data over which to calculate the CRC
1066  p = (uint8_t *) data;
1067  //CRC preset value
1068  crc = 0xFFFFFFFF;
1069 
1070  //Loop through data
1071  for(i = 0; i < length; i++)
1072  {
1073  //The message is processed bit by bit
1074  for(j = 0; j < 8; j++)
1075  {
1076  //Update CRC value
1077  if((((crc >> 31) ^ (p[i] >> j)) & 0x01) != 0)
1078  {
1079  crc = (crc << 1) ^ 0x04C11DB7;
1080  }
1081  else
1082  {
1083  crc = crc << 1;
1084  }
1085  }
1086  }
1087 
1088  //Return CRC value
1089  return ~crc;
1090 }
#define txDmaDesc
#define rxBuffer
#define txBuffer
#define rxDmaDesc
#define EMAC_TDES0_LS
#define EMAC_RDES0_FL
#define EMAC_TDES0_TCH
#define EMAC_RDES0_FS
#define EMAC_TDES0_OWN
#define EMAC_RDES0_OWN
#define EMAC_RDES1_RCH
#define EMAC_TDES1_TBS1
#define EMAC_TDES0_IC
#define EMAC_TDES0_FS
#define EMAC_RDES1_RBS1
#define EMAC_RDES0_ES
#define EMAC_RDES0_LS
__attribute__((naked))
AVR32 Ethernet MAC interrupt wrapper.
unsigned int uint_t
Definition: compiler_port.h:50
int bool_t
Definition: compiler_port.h:53
Debugging facilities.
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t n
uint8_t opcode
Definition: dns_common.h:188
error_t
Error codes.
Definition: error.h:43
@ ERROR_BUFFER_EMPTY
Definition: error.h:141
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_PACKET
Definition: error.h:140
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:53
#define macIsMulticastAddr(macAddr)
Definition: ethernet.h:133
#define ETH_MTU
Definition: ethernet.h:116
uint8_t data[]
Definition: ethernet.h:222
MacAddr
Definition: ethernet.h:195
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:95
uint16_t regAddr
error_t msp432e4EthInit(NetInterface *interface)
MSP432E4 Ethernet MAC initialization.
uint16_t msp432e4EthReadPhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
void msp432e4EthIrqHandler(void)
MSP432E4 Ethernet MAC interrupt service routine.
__weak_func void msp432e4EthInitGpio(NetInterface *interface)
GPIO configuration.
void msp432e4EthWritePhyReg(uint8_t opcode, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
error_t msp432e4EthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
void msp432e4EthDumpPhyReg(void)
Dump PHY registers for debugging purpose.
const NicDriver msp432e4EthDriver
MSP432E4 Ethernet MAC driver.
uint32_t msp432e4EthCalcCrc(const void *data, size_t length)
CRC calculation.
void msp432e4EthEnableIrq(NetInterface *interface)
Enable interrupts.
error_t msp432e4EthReceivePacket(NetInterface *interface)
Receive a packet.
void msp432e4EthEventHandler(NetInterface *interface)
MSP432E4 Ethernet MAC event handler.
error_t msp432e4EthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
void msp432e4EthDisableIrq(NetInterface *interface)
Disable interrupts.
void msp432e4EthInitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
void msp432e4EthTick(NetInterface *interface)
MSP432E4 Ethernet MAC timer handler.
error_t msp432e4EthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a packet.
MSP432E4 Ethernet controller.
#define EMAC0_DMAIM_R
#define EMAC0_MIIDATA_R
#define EMAC0_EPHYIM_R
#define EMAC0_ADDR1L_R
#define EMAC_DMABUSMOD_PBL_32
#define EMAC0_ADDR3L_R
#define EMAC0_FRAMEFLTR_R
#define EMAC0_ADDR3H_R
#define EMAC0_ADDR2L_R
#define EMAC0_IM_R
#define EMAC0_EPHYRIS_R
#define MSP432E4_ETH_IRQ_PRIORITY_GROUPING
#define EMAC0_TXPOLLD_R
#define EMAC0_MIIADDR_R
#define EMAC0_DMARIS_R
#define EMAC0_MMCRXIM_R
#define EMAC0_HASHTBLL_R
#define EMAC0_EPHYMISC_R
#define EMAC0_RXDLADDR_R
#define EMAC0_ADDR2H_R
#define EMAC0_RXPOLLD_R
#define EMAC0_MMCTXIM_R
#define EMAC0_ADDR1H_R
#define EMAC0_FLOWCTL_R
#define EMAC0_HASHTBLH_R
#define MSP432E4_ETH_TX_BUFFER_SIZE
#define EMAC0_DMABUSMOD_R
#define MSP432E4_ETH_TX_BUFFER_COUNT
#define MSP432E4_ETH_RX_BUFFER_SIZE
#define EMAC_DMABUSMOD_RPBL_32
#define EMAC0_ADDR0L_R
#define EMAC_DMABUSMOD_PR_1_1
#define EMAC0_CFG_R
#define MSP432E4_ETH_RX_BUFFER_COUNT
#define EMAC0_DMAOPMODE_R
#define EMAC0_ADDR0H_R
#define MSP432E4_ETH_IRQ_PRIORITY
#define EMAC0_TXDLADDR_R
uint8_t p
Definition: ndp.h:300
TCP/IP stack core.
#define NetInterface
Definition: net.h:36
#define netEvent
Definition: net_legacy.h:196
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
size_t netBufferRead(void *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Read data from a multi-part buffer.
Definition: net_mem.c:674
const NetRxAncillary NET_DEFAULT_RX_ANCILLARY
Definition: net_misc.c:101
#define NetRxAncillary
Definition: net_misc.h:40
#define NetTxAncillary
Definition: net_misc.h:36
void nicProcessPacket(NetInterface *interface, uint8_t *packet, size_t length, NetRxAncillary *ancillary)
Handle a packet received by the network controller.
Definition: nic.c:391
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:548
#define SMI_OPCODE_WRITE
Definition: nic.h:66
@ NIC_TYPE_ETHERNET
Ethernet interface.
Definition: nic.h:83
#define SMI_OPCODE_READ
Definition: nic.h:67
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
@ NIC_HALF_DUPLEX_MODE
Definition: nic.h:124
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:111
#define MIN(a, b)
Definition: os_port.h:63
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define osEnterIsr()
#define osExitIsr(flag)
MAC filter table entry.
Definition: ethernet.h:262
MacAddr addr
MAC address.
Definition: ethernet.h:263
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:264
Enhanced RX DMA descriptor.
Enhanced TX DMA descriptor.
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
NIC driver.
Definition: nic.h:283
uint8_t length
Definition: tcp.h:368