uc-sdk
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
lpc17xx_emac.c
Go to the documentation of this file.
1 
20 /* Peripheral group ----------------------------------------------------------- */
25 /* Includes ------------------------------------------------------------------- */
26 #include "lpc17xx_emac.h"
27 #include "lpc17xx_clkpwr.h"
28 
29 /* If this source file built with example, the LPC17xx FW library configuration
30  * file in each example directory ("lpc17xx_libcfg.h") must be included,
31  * otherwise the default FW library configuration file must be included instead
32  */
33 #ifdef __BUILD_WITH_EXAMPLE__
34 #include "lpc17xx_libcfg.h"
35 #else
36 #include "lpc17xx_libcfg_default.h"
37 #endif /* __BUILD_WITH_EXAMPLE__ */
38 
39 
40 #ifdef _EMAC
41 
42 /* Private Variables ---------------------------------------------------------- */
47 /* MII Mgmt Configuration register - Clock divider setting */
48 const uint8_t EMAC_clkdiv[] = { 4, 6, 8, 10, 14, 20, 28 };
49 
50 /* EMAC local DMA Descriptors */
51 
53 static RX_Desc Rx_Desc[EMAC_NUM_RX_FRAG];
54 
56 #if defined ( __CC_ARM )
57 static __align(8) RX_Stat Rx_Stat[EMAC_NUM_RX_FRAG];
58 #elif defined ( __ICCARM__ )
59 #pragma data_alignment=8
60 static RX_Stat Rx_Stat[EMAC_NUM_RX_FRAG];
61 #elif defined ( __GNUC__ )
62 static __attribute__ ((aligned (8))) RX_Stat Rx_Stat[EMAC_NUM_RX_FRAG];
63 #endif
64 
66 static TX_Desc Tx_Desc[EMAC_NUM_TX_FRAG];
67 static uint32_t Tx_Len[EMAC_NUM_TX_FRAG];
69 static TX_Stat Tx_Stat[EMAC_NUM_TX_FRAG];
70 
71 /* EMAC local DMA buffers */
73 static __attribute__((section(".eth_ram"))) uint32_t rx_buf[EMAC_NUM_RX_FRAG][EMAC_ETH_MAX_FLEN>>2];
75 static __attribute__((section(".eth_ram"))) uint32_t tx_buf[EMAC_NUM_TX_FRAG][EMAC_ETH_MAX_FLEN>>2];
76 
81 /* Private Functions ---------------------------------------------------------- */
82 static void rx_descr_init (void);
83 static void tx_descr_init (void);
84 static int32_t write_PHY (uint32_t PhyReg, uint16_t Value);
85 static int32_t read_PHY (uint32_t PhyReg);
86 
87 static void setEmacAddr(uint8_t abStationAddr[]);
88 static int32_t emac_CRCCalc(uint8_t frame_no_fcs[], int32_t frame_len);
89 
90 
91 /*--------------------------- rx_descr_init ---------------------------------*/
92 /*********************************************************************/
97 static void rx_descr_init (void)
98 {
99  /* Initialize Receive Descriptor and Status array. */
100  uint32_t i;
101 
102  for (i = 0; i < EMAC_NUM_RX_FRAG; i++) {
103  Rx_Desc[i].Packet = (uint32_t)&rx_buf[i];
104  Rx_Desc[i].Ctrl = EMAC_RCTRL_INT | (EMAC_ETH_MAX_FLEN - 1);
105  Rx_Stat[i].Info = 0;
106  Rx_Stat[i].HashCRC = 0;
107  }
108 
109  /* Set EMAC Receive Descriptor Registers. */
110  LPC_EMAC->RxDescriptor = (uint32_t)&Rx_Desc[0];
111  LPC_EMAC->RxStatus = (uint32_t)&Rx_Stat[0];
112  LPC_EMAC->RxDescriptorNumber = EMAC_NUM_RX_FRAG - 1;
113 
114  /* Rx Descriptors Point to 0 */
115  LPC_EMAC->RxConsumeIndex = 0;
116 }
117 
118 
119 /*--------------------------- tx_descr_init ---- ----------------------------*/
120 /*********************************************************************/
125 static void tx_descr_init (void) {
126  /* Initialize Transmit Descriptor and Status array. */
127  uint32_t i;
128 
129  for (i = 0; i < EMAC_NUM_TX_FRAG; i++) {
130  Tx_Desc[i].Packet = (uint32_t)&tx_buf[i];
131  Tx_Desc[i].Ctrl = 0;
132  Tx_Stat[i].Info = 0;
133  Tx_Len[i] = 0;
134  }
135 
136  /* Set EMAC Transmit Descriptor Registers. */
137  LPC_EMAC->TxDescriptor = (uint32_t)&Tx_Desc[0];
138  LPC_EMAC->TxStatus = (uint32_t)&Tx_Stat[0];
139  LPC_EMAC->TxDescriptorNumber = EMAC_NUM_TX_FRAG - 1;
140 
141  /* Tx Descriptors Point to 0 */
142  LPC_EMAC->TxProduceIndex = 0;
143 }
144 
145 
146 /*--------------------------- write_PHY -------------------------------------*/
147 /*********************************************************************/
154 static int32_t write_PHY (uint32_t PhyReg, uint16_t Value)
155 {
156  /* Write a data 'Value' to PHY register 'PhyReg'. */
157  uint32_t tout;
158 
159  LPC_EMAC->MADR = EMAC_DEF_ADR | PhyReg;
160  LPC_EMAC->MWTD = Value;
161 
162  /* Wait until operation completed */
163  tout = 0;
164  for (tout = 0; tout < EMAC_MII_WR_TOUT; tout++) {
165  if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0) {
166  return (0);
167  }
168  }
169  // Time out!
170  return (-1);
171 }
172 
173 
174 /*--------------------------- read_PHY --------------------------------------*/
175 /*********************************************************************/
181 static int32_t read_PHY (uint32_t PhyReg)
182 {
183  /* Read a PHY register 'PhyReg'. */
184  uint32_t tout;
185 
186  LPC_EMAC->MADR = EMAC_DEF_ADR | PhyReg;
187  LPC_EMAC->MCMD = EMAC_MCMD_READ;
188 
189  /* Wait until operation completed */
190  tout = 0;
191  for (tout = 0; tout < EMAC_MII_RD_TOUT; tout++) {
192  if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0) {
193  LPC_EMAC->MCMD = 0;
194  return (LPC_EMAC->MRDD);
195  }
196  }
197  // Time out!
198  return (-1);
199 }
200 
201 /*********************************************************************/
207 static void setEmacAddr(uint8_t abStationAddr[])
208 {
209  /* Set the Ethernet MAC Address registers */
210  LPC_EMAC->SA0 = ((uint32_t)abStationAddr[5] << 8) | (uint32_t)abStationAddr[4];
211  LPC_EMAC->SA1 = ((uint32_t)abStationAddr[3] << 8) | (uint32_t)abStationAddr[2];
212  LPC_EMAC->SA2 = ((uint32_t)abStationAddr[1] << 8) | (uint32_t)abStationAddr[0];
213 }
214 
215 
216 /*********************************************************************/
222 static int32_t emac_CRCCalc(uint8_t frame_no_fcs[], int32_t frame_len)
223 {
224  int i; // iterator
225  int j; // another iterator
226  char byte; // current byte
227  int crc; // CRC result
228  int q0, q1, q2, q3; // temporary variables
229  crc = 0xFFFFFFFF;
230  for (i = 0; i < frame_len; i++) {
231  byte = *frame_no_fcs++;
232  for (j = 0; j < 2; j++) {
233  if (((crc >> 28) ^ (byte >> 3)) & 0x00000001) {
234  q3 = 0x04C11DB7;
235  } else {
236  q3 = 0x00000000;
237  }
238  if (((crc >> 29) ^ (byte >> 2)) & 0x00000001) {
239  q2 = 0x09823B6E;
240  } else {
241  q2 = 0x00000000;
242  }
243  if (((crc >> 30) ^ (byte >> 1)) & 0x00000001) {
244  q1 = 0x130476DC;
245  } else {
246  q1 = 0x00000000;
247  }
248  if (((crc >> 31) ^ (byte >> 0)) & 0x00000001) {
249  q0 = 0x2608EDB8;
250  } else {
251  q0 = 0x00000000;
252  }
253  crc = (crc << 4) ^ q3 ^ q2 ^ q1 ^ q0;
254  byte >>= 4;
255  }
256  }
257  return crc;
258 }
259 /* End of Private Functions --------------------------------------------------- */
260 
261 
262 /* Public Functions ----------------------------------------------------------- */
268 /*********************************************************************/
287 Status EMAC_Init(EMAC_CFG_Type *EMAC_ConfigStruct)
288 {
289  /* Initialize the EMAC Ethernet controller. */
290  int32_t regv,tout, tmp;
291 
292  /* Set up clock and power for Ethernet module */
294 
295  /* Reset all EMAC internal modules */
298 
300 
301  /* A short delay after reset. */
302  for (tout = 100; tout; tout--);
303 
304  /* Initialize MAC control registers. */
307  LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN;
308  /*
309  * Find the clock that close to desired target clock
310  */
312  for (tout = 0; tout < sizeof (EMAC_clkdiv); tout++){
313  if (EMAC_clkdiv[tout] >= tmp) break;
314  }
315  tout++;
316  // Write to MAC configuration register and reset
318  // release reset
319  LPC_EMAC->MCFG &= ~(EMAC_MCFG_RES_MII);
320  LPC_EMAC->CLRT = EMAC_CLRT_DEF;
321  LPC_EMAC->IPGR = EMAC_IPGR_P2_DEF;
322 
323  /* Enable Reduced MII interface. */
325 
326  /* Reset Reduced MII Logic. */
328 
329  for (tout = 100; tout; tout--);
330  LPC_EMAC->SUPP = 0;
331 
332  /* Put the DP83848C in reset mode */
334 
335  /* Wait for hardware reset to end. */
336  for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
337  regv = read_PHY (EMAC_PHY_REG_BMCR);
338  if (!(regv & (EMAC_PHY_BMCR_RESET | EMAC_PHY_BMCR_POWERDOWN))) {
339  /* Reset complete, device not Power Down. */
340  break;
341  }
342  if (tout == 0){
343  // Time out, return ERROR
344  return (ERROR);
345  }
346  }
347 
348  // Set PHY mode
349  if (EMAC_SetPHYMode(EMAC_ConfigStruct->Mode) < 0){
350  return (ERROR);
351  }
352 
353  // Set EMAC address
354  setEmacAddr(EMAC_ConfigStruct->pbEMAC_Addr);
355 
356  /* Initialize Tx and Rx DMA Descriptors */
357  rx_descr_init ();
358  tx_descr_init ();
359 
360  // Set Receive Filter register: enable broadcast and multicast
362 
363  /* Enable Rx Done and Tx Done interrupt for EMAC */
365 
366  /* Reset all interrupts */
367  LPC_EMAC->IntClear = 0xFFFF;
368 
369  /* Enable receive and transmit mode of MAC Ethernet core */
370  LPC_EMAC->Command |= (EMAC_CR_RX_EN | EMAC_CR_TX_EN);
371  LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN;
372 
373  return SUCCESS;
374 }
375 
376 
377 /*********************************************************************/
383 void EMAC_DeInit(void)
384 {
385  // Disable all interrupt
386  LPC_EMAC->IntEnable = 0x00;
387  // Clear all pending interrupt
388  LPC_EMAC->IntClear = (0xFF) | (EMAC_INT_SOFT_INT | EMAC_INT_WAKEUP);
389 
390  /* TurnOff clock and power for Ethernet module */
392 }
393 
394 
395 /*********************************************************************/
415 int32_t EMAC_CheckPHYStatus(uint32_t ulPHYState)
416 {
417  int32_t regv, tmp;
418 #ifdef MCB_LPC_1768
419  regv = read_PHY (EMAC_PHY_REG_STS);
420  switch(ulPHYState){
421  case EMAC_PHY_STAT_LINK:
422  tmp = (regv & EMAC_PHY_SR_LINK) ? 1 : 0;
423  break;
424  case EMAC_PHY_STAT_SPEED:
425  tmp = (regv & EMAC_PHY_SR_SPEED) ? 0 : 1;
426  break;
427  case EMAC_PHY_STAT_DUP:
428  tmp = (regv & EMAC_PHY_SR_FULL_DUP) ? 1 : 0;
429  break;
430 #elif defined(IAR_LPC_1768)
431  /* Use IAR_LPC_1768 board:
432  * FSZ8721BL doesn't have Status Register
433  * so we read Basic Mode Status Register (0x01h) instead
434  */
435  regv = read_PHY (EMAC_PHY_REG_BMSR);
436  switch(ulPHYState){
437  case EMAC_PHY_STAT_LINK:
438  tmp = (regv & EMAC_PHY_BMSR_LINK_STATUS) ? 1 : 0;
439  break;
440  case EMAC_PHY_STAT_SPEED:
441  tmp = (regv & EMAC_PHY_SR_100_SPEED) ? 1 : 0;
442  break;
443  case EMAC_PHY_STAT_DUP:
444  tmp = (regv & EMAC_PHY_SR_FULL_DUP) ? 1 : 0;
445  break;
446 #endif
447  default:
448  tmp = -1;
449  break;
450  }
451  return (tmp);
452 }
453 
454 
455 /*********************************************************************/
465 int32_t EMAC_SetPHYMode(uint32_t ulPHYMode)
466 {
467  int32_t id1, id2, tout, regv;
468 
469  /* Check if this is a DP83848C PHY. */
470  id1 = read_PHY (EMAC_PHY_REG_IDR1);
471  id2 = read_PHY (EMAC_PHY_REG_IDR2);
472 
473 #ifdef MCB_LPC_1768
474  if (((id1 << 16) | (id2 & 0xFFF0)) == EMAC_DP83848C_ID) {
475  switch(ulPHYMode){
476  case EMAC_MODE_AUTO:
478 #elif defined(IAR_LPC_1768) /* Use IAR LPC1768 KickStart board */
479  if (((id1 << 16) | id2) == EMAC_KSZ8721BL_ID) {
480  /* Configure the PHY device */
481  switch(ulPHYMode){
482  case EMAC_MODE_AUTO:
483  /* Use auto-negotiation about the link speed. */
485 // write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_BMCR_AN);
486 #endif
487  /* Wait to complete Auto_Negotiation */
488  for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
489  regv = read_PHY (EMAC_PHY_REG_BMSR);
490  if (regv & EMAC_PHY_BMSR_AUTO_DONE) {
491  /* Auto-negotiation Complete. */
492  break;
493  }
494  if (tout == 0){
495  // Time out, return error
496  return (-1);
497  }
498  }
499  break;
500  case EMAC_MODE_10M_FULL:
501  /* Connect at 10MBit full-duplex */
503  break;
504  case EMAC_MODE_10M_HALF:
505  /* Connect at 10MBit half-duplex */
507  break;
508  case EMAC_MODE_100M_FULL:
509  /* Connect at 100MBit full-duplex */
511  break;
512  case EMAC_MODE_100M_HALF:
513  /* Connect at 100MBit half-duplex */
515  break;
516  default:
517  // un-supported
518  return (-1);
519  }
520  }
521  // It's not correct module ID
522  else {
523  return (-1);
524  }
525 
526  // Update EMAC configuration with current PHY status
527  if (EMAC_UpdatePHYStatus() < 0){
528  return (-1);
529  }
530 
531  // Complete
532  return (0);
533 }
534 
535 
536 /*********************************************************************/
546 int32_t EMAC_UpdatePHYStatus(void)
547 {
548  int32_t regv, tout;
549 
550  /* Check the link status. */
551 #ifdef MCB_LPC_1768
552  for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
553  regv = read_PHY (EMAC_PHY_REG_STS);
554  if (regv & EMAC_PHY_SR_LINK) {
555  /* Link is on. */
556  break;
557  }
558  if (tout == 0){
559  // time out
560  return (-1);
561  }
562  }
563  /* Configure Full/Half Duplex mode. */
564  if (regv & EMAC_PHY_SR_DUP) {
565  /* Full duplex is enabled. */
566  LPC_EMAC->MAC2 |= EMAC_MAC2_FULL_DUP;
567  LPC_EMAC->Command |= EMAC_CR_FULL_DUP;
569  } else {
570  /* Half duplex mode. */
572  }
573  if (regv & EMAC_PHY_SR_SPEED) {
574  /* 10MBit mode. */
575  LPC_EMAC->SUPP = 0;
576  } else {
577  /* 100MBit mode. */
578  LPC_EMAC->SUPP = EMAC_SUPP_SPEED;
579  }
580 #elif defined(IAR_LPC_1768)
581  for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) {
582  regv = read_PHY (EMAC_PHY_REG_BMSR);
583  if (regv & EMAC_PHY_BMSR_LINK_STATUS) {
584  /* Link is on. */
585  break;
586  }
587  if (tout == 0){
588  // time out
589  return (-1);
590  }
591  }
592 
593  /* Configure Full/Half Duplex mode. */
594  if (regv & EMAC_PHY_SR_FULL_DUP) {
595  /* Full duplex is enabled. */
596  LPC_EMAC->MAC2 |= EMAC_MAC2_FULL_DUP;
597  LPC_EMAC->Command |= EMAC_CR_FULL_DUP;
599  } else {
600  /* Half duplex mode. */
602  }
603 
604  /* Configure 100MBit/10MBit mode. */
605  if (!(regv & EMAC_PHY_SR_100_SPEED)) {
606  /* 10MBit mode. */
607  LPC_EMAC->SUPP = 0;
608  } else {
609  /* 100MBit mode. */
610  LPC_EMAC->SUPP = EMAC_SUPP_SPEED;
611  }
612 #endif
613  // Complete
614  return (0);
615 }
616 
617 
618 /*********************************************************************/
637 void EMAC_SetHashFilter(uint8_t dstMAC_addr[], FunctionalState NewState)
638 {
639  uint32_t *pReg;
640  uint32_t tmp;
641  int32_t crc;
642 
643  // Calculate the CRC from the destination MAC address
644  crc = emac_CRCCalc(dstMAC_addr, 6);
645  // Extract the value from CRC to get index value for hash filter table
646  crc = (crc >> 23) & 0x3F;
647 
648  pReg = (crc > 31) ? ((uint32_t *)&LPC_EMAC->HashFilterH) \
649  : ((uint32_t *)&LPC_EMAC->HashFilterL);
650  tmp = (crc > 31) ? (crc - 32) : crc;
651  if (NewState == ENABLE) {
652  (*pReg) |= (1UL << tmp);
653  } else {
654  (*pReg) &= ~(1UL << tmp);
655  }
656  // Enable Rx Filter
657  LPC_EMAC->Command &= ~EMAC_CR_PASS_RX_FILT;
658 }
659 
660 /*********************************************************************/
687 void EMAC_SetFilterMode(uint32_t ulFilterMode, FunctionalState NewState)
688 {
689  if (NewState == ENABLE){
690  LPC_EMAC->RxFilterCtrl |= ulFilterMode;
691  } else {
692  LPC_EMAC->RxFilterCtrl &= ~ulFilterMode;
693  }
694 }
695 
696 /*********************************************************************/
713 FlagStatus EMAC_GetWoLStatus(uint32_t ulWoLMode)
714 {
715  if (LPC_EMAC->RxFilterWoLStatus & ulWoLMode) {
716  LPC_EMAC->RxFilterWoLClear = ulWoLMode;
717  return SET;
718  } else {
719  return RESET;
720  }
721 }
722 
723 
724 /*********************************************************************/
732 void EMAC_WritePacketBuffer(EMAC_PACKETBUF_Type *pDataStruct, Bool Finalize)
733 {
734  uint32_t idx,len;
735  uint8_t *sp,*dp;
736 
737  idx = LPC_EMAC->TxProduceIndex;
738  sp = (uint8_t *)pDataStruct->pbDataBuf;
739  dp = ((uint8_t *)Tx_Desc[idx].Packet) + Tx_Len[idx];
740  /* Copy frame data to EMAC packet buffers. */
741  for (len = pDataStruct->ulDataLen; len; len--) {
742  *dp++ = *sp++;
743  }
744  Tx_Len[idx] += pDataStruct->ulDataLen;
745  if (Finalize) {
746  Tx_Desc[idx].Ctrl = (Tx_Len[idx] - 1) | (EMAC_TCTRL_INT | EMAC_TCTRL_LAST);
747  Tx_Len[idx] = 0;
748  }
749 }
750 
751 /*********************************************************************/
760 {
761  uint32_t idx, len;
762  uint32_t *dp, *sp;
763 
764  idx = LPC_EMAC->RxConsumeIndex;
765  dp = (uint32_t *)pDataStruct->pbDataBuf;
766  sp = (uint32_t *)Rx_Desc[idx].Packet;
767 
768  if (pDataStruct->pbDataBuf != NULL) {
769  for (len = (pDataStruct->ulDataLen + 3) >> 2; len; len--) {
770  *dp++ = *sp++;
771  }
772  }
773 }
774 
775 /*********************************************************************/
793 void EMAC_IntCmd(uint32_t ulIntType, FunctionalState NewState)
794 {
795  if (NewState == ENABLE) {
796  LPC_EMAC->IntEnable |= ulIntType;
797  } else {
798  LPC_EMAC->IntEnable &= ~(ulIntType);
799  }
800 }
801 
802 /*********************************************************************/
819 IntStatus EMAC_IntGetStatus(uint32_t ulIntType)
820 {
821  if (LPC_EMAC->IntStatus & ulIntType) {
822  LPC_EMAC->IntClear = ulIntType;
823  return SET;
824  } else {
825  return RESET;
826  }
827 }
828 
829 
830 /*********************************************************************/
841 {
842  if (LPC_EMAC->RxConsumeIndex != LPC_EMAC->RxProduceIndex) {
843  return TRUE;
844  } else {
845  return FALSE;
846  }
847 }
848 
849 
850 /*********************************************************************/
861 {
862  uint32_t tmp = LPC_EMAC->TxConsumeIndex -1;
863  if (LPC_EMAC->TxProduceIndex == tmp) {
864  return FALSE;
865  } else {
866  return TRUE;
867  }
868 }
869 
870 
871 /*********************************************************************/
890 FlagStatus EMAC_CheckReceiveDataStatus(uint32_t ulRxStatType)
891 {
892  uint32_t idx;
893  idx = LPC_EMAC->RxConsumeIndex;
894  return (((Rx_Stat[idx].Info) & ulRxStatType) ? SET : RESET);
895 }
896 
897 
898 /*********************************************************************/
904 uint32_t EMAC_GetReceiveDataSize(void)
905 {
906  uint32_t idx;
907  idx =LPC_EMAC->RxConsumeIndex;
908  return ((Rx_Stat[idx].Info) & EMAC_RINFO_SIZE);
909 }
910 
911 /*********************************************************************/
918 void EMAC_UpdateRxConsumeIndex(void)
919 {
920  // Get current Rx consume index
921  uint32_t idx = LPC_EMAC->RxConsumeIndex;
922 
923  /* Release frame from EMAC buffer */
924  if (++idx == EMAC_NUM_RX_FRAG) idx = 0;
925  LPC_EMAC->RxConsumeIndex = idx;
926 }
927 
928 /*********************************************************************/
935 void EMAC_UpdateTxProduceIndex(void)
936 {
937  // Get current Tx produce index
938  uint32_t idx = LPC_EMAC->TxProduceIndex;
939 
940  /* Start frame transmission */
941  if (++idx == EMAC_NUM_TX_FRAG) idx = 0;
942  LPC_EMAC->TxProduceIndex = idx;
943 }
944 
945 
950 #endif /* _EMAC */
951 
956 /* --------------------------------- End Of File ------------------------------ */