lpc_emac.c 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043
  1. /**********************************************************************
  2. * $Id$ lpc_emac.c 2011-06-02
  3. *//**
  4. * @file lpc_emac.c
  5. * @brief Contains all functions support for Ethernet MAC firmware
  6. * library on LPC
  7. * @version 1.0
  8. * @date 02. June. 2011
  9. * @author NXP MCU SW Application Team
  10. *
  11. * Copyright(C) 2011, NXP Semiconductor
  12. * All rights reserved.
  13. *
  14. ***********************************************************************
  15. * Software that is described herein is for illustrative purposes only
  16. * which provides customers with programming information regarding the
  17. * products. This software is supplied "AS IS" without any warranties.
  18. * NXP Semiconductors assumes no responsibility or liability for the
  19. * use of the software, conveys no license or title under any patent,
  20. * copyright, or mask work right to the product. NXP Semiconductors
  21. * reserves the right to make changes in the software without
  22. * notification. NXP Semiconductors also make no representation or
  23. * warranty that such application will be suitable for the specified
  24. * use without further testing or modification.
  25. * Permission to use, copy, modify, and distribute this software and its
  26. * documentation is hereby granted, under NXP Semiconductors'
  27. * relevant copyright in the software, without fee, provided that it
  28. * is used in conjunction with NXP Semiconductors microcontrollers. This
  29. * copyright, permission, and disclaimer notice must appear in all copies of
  30. * this code.
  31. **********************************************************************/
  32. #ifdef __BUILD_WITH_EXAMPLE__
  33. #include "lpc_libcfg.h"
  34. #else
  35. #include "lpc_libcfg_default.h"
  36. #endif /* __BUILD_WITH_EXAMPLE__ */
  37. #ifdef _EMAC
  38. #include "lpc_emac.h"
  39. #include "lpc_clkpwr.h"
  40. #include "lpc_pinsel.h"
  41. /* Peripheral group ----------------------------------------------------------- */
  42. /** @addtogroup EMAC
  43. * @{
  44. */
  45. /************************** PRIVATE VARIABLES *************************/
  46. /* MII Mgmt Configuration register - Clock divider setting */
  47. const uint8_t EMAC_clkdiv[] = { 4, 6, 8, 10, 14, 20, 28, 36, 40, 44, 48, 52, 56, 60, 64 };
  48. /* EMAC Config data */
  49. static EMAC_CFG_Type EMAC_Configs;
  50. /* EMAC local DMA Descriptors */
  51. #ifdef __IAR_SYSTEMS_ICC__
  52. /* Global Tx Buffer data */
  53. #pragma data_alignment=4
  54. static uint16_t saFrameBuffers[EMAC_MAX_FRAME_NUM][EMAC_MAX_FRAME_SIZE];
  55. #else
  56. /* Global Rx Buffer data */
  57. static uint16_t __attribute__ ((aligned (4))) saFrameBuffers[EMAC_MAX_FRAME_NUM][EMAC_MAX_FRAME_SIZE];
  58. #endif
  59. static uint32_t sulCurrFrameSz = 0;
  60. static uint8_t sbCurrFrameID = 0;
  61. /***************************** PRIVATE FUNCTION *****************************/
  62. static void EMAC_UpdateRxConsumeIndex(void);
  63. static void EMAC_UpdateTxProduceIndex(void);
  64. static uint32_t EMAC_AllocTxBuff(uint16_t nFrameSize, uint8_t bLastFrame);
  65. static uint32_t EMAC_GetRxFrameSize(void);
  66. /*********************************************************************//**
  67. * @brief
  68. * @param[in]
  69. * @return
  70. **********************************************************************/
  71. void rx_descr_init (void)
  72. {
  73. unsigned int i;
  74. for (i = 0; i < EMAC_NUM_RX_FRAG; i++)
  75. {
  76. RX_DESC_PACKET(i) = RX_BUF(i);
  77. RX_DESC_CTRL(i) = EMAC_RCTRL_INT | (EMAC_ETH_MAX_FLEN-1);
  78. RX_STAT_INFO(i) = 0;
  79. RX_STAT_HASHCRC(i) = 0;
  80. }
  81. /* Set EMAC Receive Descriptor Registers. */
  82. LPC_EMAC->RxDescriptor = RX_DESC_BASE;
  83. LPC_EMAC->RxStatus = RX_STAT_BASE;
  84. LPC_EMAC->RxDescriptorNumber = EMAC_NUM_RX_FRAG-1;
  85. /* Rx Descriptors Point to 0 */
  86. LPC_EMAC->RxConsumeIndex = 0;
  87. }
  88. /*********************************************************************//**
  89. * @brief
  90. * @param[in]
  91. * @return
  92. **********************************************************************/
  93. void tx_descr_init (void)
  94. {
  95. unsigned int i;
  96. for (i = 0; i < EMAC_NUM_TX_FRAG; i++)
  97. {
  98. TX_DESC_PACKET(i) = TX_BUF(i);
  99. TX_DESC_CTRL(i) = 0;
  100. TX_STAT_INFO(i) = 0;
  101. }
  102. /* Set EMAC Transmit Descriptor Registers. */
  103. LPC_EMAC->TxDescriptor = TX_DESC_BASE;
  104. LPC_EMAC->TxStatus = TX_STAT_BASE;
  105. LPC_EMAC->TxDescriptorNumber = EMAC_NUM_TX_FRAG-1;
  106. /* Tx Descriptors Point to 0 */
  107. LPC_EMAC->TxProduceIndex = 0;
  108. }
  109. /*********************************************************************//**
  110. * @brief Set Station MAC address for EMAC module
  111. * @param[in] abStationAddr Pointer to Station address that contains 6-bytes
  112. * of MAC address.
  113. * @return None
  114. **********************************************************************/
  115. void setEmacAddr(uint8_t abStationAddr[])
  116. {
  117. /* Set the Ethernet MAC Address registers */
  118. LPC_EMAC->SA0 = ((uint32_t)abStationAddr[5] << 8) | (uint32_t)abStationAddr[4];
  119. LPC_EMAC->SA1 = ((uint32_t)abStationAddr[3] << 8) | (uint32_t)abStationAddr[2];
  120. LPC_EMAC->SA2 = ((uint32_t)abStationAddr[1] << 8) | (uint32_t)abStationAddr[0];
  121. }
  122. /************************** GLOBAL/PUBLIC FUNCTIONS *************************/
  123. /** @defgroup EMAC_Public_Functions
  124. * @{
  125. */
  126. /*********************************************************************//**
  127. * @brief Write data to PHY
  128. * @param[in] PhyReg PHY register address
  129. * @param[in] Value Register Value
  130. * @return None
  131. **********************************************************************/
  132. void EMAC_Write_PHY (uint8_t PhyReg, uint16_t Value)
  133. {
  134. unsigned int tout;
  135. LPC_EMAC->MADR = ((EMAC_Configs.bPhyAddr & 0x1F) << 8 )| (PhyReg & 0x1F);
  136. LPC_EMAC->MWTD = Value;
  137. /* Wait utill operation completed */
  138. tout = 0;
  139. for (tout = 0; tout < EMAC_MII_WR_TOUT; tout++)
  140. {
  141. if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0)
  142. {
  143. break;
  144. }
  145. }
  146. }
  147. /*********************************************************************//**
  148. * @brief Read data from PHY register
  149. * @param[in] PhyReg PHY register address
  150. * @return Register value
  151. **********************************************************************/
  152. uint16_t EMAC_Read_PHY (uint8_t PhyReg)
  153. {
  154. unsigned int tout;
  155. LPC_EMAC->MADR = ((EMAC_Configs.bPhyAddr & 0x1F) << 8 )| (PhyReg & 0x1F);
  156. LPC_EMAC->MCMD = EMAC_MCMD_READ;
  157. /* Wait until operation completed */
  158. tout = 0;
  159. for (tout = 0; tout < EMAC_MII_RD_TOUT; tout++)
  160. {
  161. if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0)
  162. {
  163. break;
  164. }
  165. }
  166. LPC_EMAC->MCMD = 0;
  167. return (LPC_EMAC->MRDD);
  168. }
  169. /*********************************************************************//**
  170. * @brief Set Full/Half Duplex Mode
  171. * @param[in] full_duplex 0: Half-duplex, 1: Full-duplex
  172. * @return None
  173. **********************************************************************/
  174. void EMAC_SetFullDuplexMode(uint8_t full_duplex)
  175. {
  176. if(full_duplex)
  177. {
  178. LPC_EMAC->MAC2 |= EMAC_MAC2_FULL_DUP;
  179. LPC_EMAC->Command |= EMAC_CR_FULL_DUP;
  180. LPC_EMAC->IPGT = EMAC_IPGT_FULL_DUP;
  181. }
  182. else
  183. {
  184. LPC_EMAC->IPGT = EMAC_IPGT_HALF_DUP;
  185. }
  186. }
  187. /*********************************************************************//**
  188. * @brief Set PHY Speed
  189. * @param[in] mode_100Mbps 0: 10Mbps, 1: 100Mbps
  190. * @return None
  191. **********************************************************************/
  192. void EMAC_SetPHYSpeed(uint8_t mode_100Mbps)
  193. {
  194. if(mode_100Mbps)
  195. {
  196. LPC_EMAC->SUPP = EMAC_SUPP_SPEED;
  197. }
  198. else
  199. {
  200. LPC_EMAC->SUPP = 0;
  201. }
  202. }
  203. /*********************************************************************//**
  204. * @brief Initializes the EMAC peripheral according to the specified
  205. * parameters in the EMAC_ConfigStruct.
  206. * @param[in] EMAC_ConfigStruct Pointer to a EMAC_CFG_Type structure
  207. * that contains the configuration information for the
  208. * specified EMAC peripheral.
  209. * @return None
  210. *
  211. * Note: This function will initialize EMAC module according to procedure below:
  212. * - Remove the soft reset condition from the MAC
  213. * - Configure the PHY via the MIIM interface of the MAC
  214. * - Select RMII mode
  215. * - Configure the transmit and receive DMA engines, including the descriptor arrays
  216. * - Configure the host registers (MAC1,MAC2 etc.) in the MAC
  217. * - Enable the receive and transmit data paths
  218. * In default state after initializing, Rx Done and Tx Done interrupt are enabled,
  219. * nad all interrupts are also enabled
  220. * (Ref. from LPC17xx UM)
  221. **********************************************************************/
  222. int32_t EMAC_Init(EMAC_CFG_Type *EMAC_ConfigStruct)
  223. {
  224. /* Initialize the EMAC Ethernet controller. */
  225. volatile int32_t tout, tmp;
  226. EMAC_Configs = *EMAC_ConfigStruct;
  227. /* Set up power for Ethernet module */
  228. CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, ENABLE);
  229. /* Enable P1 Ethernet Pins. */
  230. /* Reset all EMAC internal modules */
  231. LPC_EMAC->MAC1 = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX | EMAC_MAC1_RES_RX |
  232. EMAC_MAC1_RES_MCS_RX | EMAC_MAC1_SIM_RES | EMAC_MAC1_SOFT_RES;
  233. LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES | EMAC_CR_PASS_RUNT_FRM;
  234. /* A short delay after reset. */
  235. for (tout = 100; tout; tout--);
  236. /* Initialize MAC control registers. */
  237. LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL;
  238. LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN;
  239. LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN;
  240. /*
  241. * Find the clock that close to desired target clock
  242. */
  243. tmp = CLKPWR_GetCLK(CLKPWR_CLKTYPE_CPU)/ EMAC_MCFG_MII_MAXCLK;
  244. for (tout = 0; tout < sizeof (EMAC_clkdiv); tout++)
  245. {
  246. if (EMAC_clkdiv[tout] >= tmp)
  247. break;
  248. }
  249. if(tout >= sizeof (EMAC_clkdiv))
  250. return ERROR;
  251. tout++;
  252. // Set Frame size
  253. LPC_EMAC->MAXF = EMAC_ConfigStruct->nMaxFrameSize;
  254. // Write to MAC configuration register and reset
  255. LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(tout) | EMAC_MCFG_RES_MII;
  256. // release reset
  257. LPC_EMAC->MCFG &= ~(EMAC_MCFG_RES_MII);
  258. LPC_EMAC->CLRT = EMAC_CLRT_DEF;
  259. LPC_EMAC->IPGR = EMAC_IPGR_P2_DEF;
  260. /* Enable Reduced MII interface. */
  261. LPC_EMAC->Command = EMAC_CR_RMII | EMAC_CR_PASS_RUNT_FRM;
  262. // Initilialize PHY
  263. if(EMAC_ConfigStruct->pfnPHYInit != NULL)
  264. {
  265. if(EMAC_ConfigStruct->pfnPHYInit(&EMAC_ConfigStruct->PhyCfg) != SUCCESS)
  266. {
  267. return ERROR;
  268. }
  269. }
  270. // Set EMAC address
  271. setEmacAddr(EMAC_ConfigStruct->pbEMAC_Addr);
  272. /* Initialize Tx and Rx DMA Descriptors */
  273. rx_descr_init ();
  274. tx_descr_init ();
  275. // Set Receive Filter register: enable broadcast and multicast
  276. LPC_EMAC->RxFilterCtrl = EMAC_RFC_MCAST_EN | EMAC_RFC_BCAST_EN | EMAC_RFC_PERFECT_EN;
  277. /* Enable Rx Done and Tx Done interrupt for EMAC */
  278. EMAC_IntCmd((EMAC_INT_RX_OVERRUN | EMAC_INT_RX_ERR | EMAC_INT_RX_FIN \
  279. | EMAC_INT_RX_DONE | EMAC_INT_TX_UNDERRUN | EMAC_INT_TX_ERR \
  280. | EMAC_INT_TX_FIN | EMAC_INT_TX_DONE), ENABLE);
  281. /* Reset all interrupts */
  282. LPC_EMAC->IntClear = 0xFFFF;
  283. /* Enable receive and transmit mode of MAC Ethernet core */
  284. EMAC_TxEnable();
  285. EMAC_RxEnable();
  286. NVIC_EnableIRQ(ENET_IRQn);
  287. return SUCCESS;
  288. }
  289. /*********************************************************************//**
  290. * @brief De-initializes the EMAC peripheral registers to their
  291. * default reset values.
  292. * @param[in] None
  293. * @return None
  294. **********************************************************************/
  295. void EMAC_DeInit(void)
  296. {
  297. // Disable all interrupt
  298. LPC_EMAC->IntEnable = 0x00;
  299. // Clear all pending interrupt
  300. LPC_EMAC->IntClear = (0xFF) | (EMAC_INT_SOFT_INT | EMAC_INT_WAKEUP);
  301. LPC_EMAC->Command = 0;
  302. /* TurnOff power for Ethernet module */
  303. CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, DISABLE);
  304. }
  305. /*********************************************************************//**
  306. * @brief EMAC TX API modules
  307. * @param[in] None
  308. * @return None
  309. **********************************************************************/
  310. void EMAC_TxEnable( void )
  311. {
  312. LPC_EMAC->Command |= EMAC_CR_TX_EN;
  313. return;
  314. }
  315. /*********************************************************************//**
  316. * @brief EMAC RX API modules
  317. * @param[in] None
  318. * @return None
  319. **********************************************************************/
  320. void EMAC_TxDisable( void )
  321. {
  322. LPC_EMAC->Command &= ~EMAC_CR_TX_EN;
  323. return;
  324. }
  325. /*********************************************************************//**
  326. * @brief EMAC RX API modules
  327. * @param[in] None
  328. * @return None
  329. **********************************************************************/
  330. void EMAC_RxEnable( void )
  331. {
  332. LPC_EMAC->Command |= EMAC_CR_RX_EN;
  333. LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN;
  334. return;
  335. }
  336. /*********************************************************************//**
  337. * @brief EMAC RX API modules
  338. * @param[in] None
  339. * @return None
  340. **********************************************************************/
  341. void EMAC_RxDisable( void )
  342. {
  343. LPC_EMAC->Command &= ~EMAC_CR_RX_EN;
  344. LPC_EMAC->MAC1 &= ~EMAC_MAC1_REC_EN;
  345. return;
  346. }
  347. /*********************************************************************//**
  348. * @brief Get the status of given buffer.
  349. * @param[in] idx Buffer index
  350. * @return EMAC_BUFF_AVAILABLE/EMAC_BUFF_FULL/EMAC_BUFF_PARTIAL_FULL
  351. *
  352. **********************************************************************/
  353. EMAC_BUFF_STATUS EMAC_GetBufferSts(EMAC_BUFF_IDX idx)
  354. {
  355. uint32_t consume_idx, produce_idx;
  356. uint32_t max_frag_num;
  357. // Get the consume index, produce index and the buffer size
  358. if(idx == EMAC_TX_BUFF)
  359. {
  360. consume_idx = LPC_EMAC->TxConsumeIndex;
  361. produce_idx = LPC_EMAC->TxProduceIndex;
  362. max_frag_num = LPC_EMAC->TxDescriptorNumber + 1;
  363. }
  364. else
  365. {
  366. consume_idx = LPC_EMAC->RxConsumeIndex;
  367. produce_idx = LPC_EMAC->RxProduceIndex;
  368. max_frag_num = LPC_EMAC->RxDescriptorNumber + 1;
  369. }
  370. // empty
  371. if(consume_idx == produce_idx)
  372. return EMAC_BUFF_EMPTY;
  373. // Full
  374. if(consume_idx == 0 &&
  375. produce_idx == max_frag_num - 1)
  376. return EMAC_BUFF_FULL;
  377. // Wrap-around
  378. if(consume_idx == produce_idx + 1)
  379. return EMAC_BUFF_FULL;
  380. return EMAC_BUFF_PARTIAL_FULL;
  381. }
  382. /*********************************************************************//**
  383. * @brief Allocate a descriptor for sending frame and get the coressponding buffer address
  384. * @param[in] FrameSize The size of frame you want to send
  385. * @return Address of the TX_DESC_PACKET buffer
  386. **********************************************************************/
  387. uint32_t EMAC_AllocTxBuff(uint16_t nFrameSize, uint8_t bLastFrame)
  388. {
  389. uint32_t idx;
  390. uint32_t dp;
  391. volatile uint32_t i;
  392. idx = LPC_EMAC->TxProduceIndex;
  393. while(EMAC_GetBufferSts(EMAC_TX_BUFF) == EMAC_BUFF_FULL)
  394. {
  395. for(i = 0; i < 1000000; i++) ;
  396. }
  397. dp = TX_DESC_PACKET(idx);
  398. if(bLastFrame)
  399. TX_DESC_CTRL(idx) = ((nFrameSize-1) & EMAC_TCTRL_SIZE) | (EMAC_TCTRL_INT | EMAC_TCTRL_LAST);
  400. else
  401. TX_DESC_CTRL(idx) = ((nFrameSize-1) & EMAC_TCTRL_SIZE) | (EMAC_TCTRL_INT);
  402. return dp;
  403. }
  404. /*********************************************************************//**
  405. * @brief Increase the TxProduceIndex (after writting to the Transmit buffer
  406. * to enable the Transmit buffer) and wrap-around the index if
  407. * it reaches the maximum Transmit Number
  408. * @param[in] None
  409. * @return None
  410. **********************************************************************/
  411. void EMAC_UpdateTxProduceIndex(void)
  412. {
  413. // Get current Tx produce index
  414. uint32_t idx = LPC_EMAC->TxProduceIndex;
  415. /* Start frame transmission */
  416. if (++idx == LPC_EMAC->TxDescriptorNumber + 1) idx = 0;
  417. LPC_EMAC->TxProduceIndex = idx;
  418. }
  419. /*********************************************************************//**
  420. * @brief Get current status value of receive data (due to TxProduceIndex)
  421. * @param[in] None
  422. * @return Current value of receive data (due to TxProduceIndex)
  423. **********************************************************************/
  424. uint32_t EMAC_GetTxFrameStatus(void)
  425. {
  426. uint32_t idx;
  427. idx = LPC_EMAC->TxProduceIndex;
  428. return (TX_STAT_INFO(idx));
  429. }
  430. /*********************************************************************//**
  431. * @brief Write data to Tx packet data buffer at current index due to
  432. * TxProduceIndex
  433. * @param[in] pDataStruct store the address and the size of buffer that saves data.
  434. * @return None
  435. **********************************************************************/
  436. void EMAC_WritePacketBuffer(EMAC_PACKETBUF_Type *pDataStruct)
  437. {
  438. uint16_t* pDest;
  439. uint16_t* pSource = (uint16_t*)pDataStruct->pbDataBuf;
  440. uint32_t size = pDataStruct->ulDataLen;
  441. int32_t frame_num;
  442. uint32_t tmp;
  443. uint32_t max_frame_size = LPC_EMAC->MAXF;
  444. size = (size + 1) & 0xFFFE; // round Size up to next even number
  445. frame_num = size/max_frame_size;
  446. if(size == 0)
  447. return;
  448. while(frame_num >= 0)
  449. {
  450. tmp = (frame_num > 0)? max_frame_size:size;
  451. if(tmp == 0)
  452. break;
  453. // Setup descriptors and data
  454. if(frame_num == 0)
  455. pDest = (uint16_t*)EMAC_AllocTxBuff(tmp, 1); // last frame
  456. else
  457. pDest = (uint16_t*)EMAC_AllocTxBuff(tmp, 0);
  458. // Copy data
  459. while (tmp > 0)
  460. {
  461. *pDest++ = *pSource++;
  462. tmp -= 2;
  463. }
  464. frame_num--;
  465. size -= tmp;
  466. // Update produce index
  467. EMAC_UpdateTxProduceIndex();
  468. }
  469. }
  470. /*********************************************************************//**
  471. * @brief Get current status value of receive data (due to RxConsumeIndex)
  472. * @param[in] None
  473. * @return Current value of receive data (due to RxConsumeIndex)
  474. **********************************************************************/
  475. uint32_t EMAC_GetRxFrameStatus(void)
  476. {
  477. uint32_t idx;
  478. idx = LPC_EMAC->RxConsumeIndex;
  479. return (RX_STAT_INFO(idx));
  480. }
  481. /*********************************************************************//**
  482. * @brief Get size of current Received data in received buffer (due to
  483. * RxConsumeIndex)
  484. * @param[in] None
  485. * @return Size of received data
  486. **********************************************************************/
  487. uint32_t EMAC_GetRxFrameSize(void)
  488. {
  489. uint32_t idx;
  490. idx = LPC_EMAC->RxConsumeIndex;
  491. return (((RX_STAT_INFO(idx)) & EMAC_RINFO_SIZE)+1);
  492. }
  493. /*********************************************************************//**
  494. * @brief Get the address of TX_DESC_PACKET buffer so that user can access from application
  495. * @param[in] None
  496. * @return Address of the TX_DESC_PACKET buffer
  497. **********************************************************************/
  498. uint32_t EMAC_GetRxBuffer(void)
  499. {
  500. uint32_t idx;
  501. idx = LPC_EMAC->RxConsumeIndex;
  502. return RX_DESC_PACKET(idx);
  503. }
  504. /*********************************************************************//**
  505. * @brief Increase the RxConsumeIndex (after reading the Receive buffer
  506. * to release the Receive buffer) and wrap-around the index if
  507. * it reaches the maximum Receive Number
  508. * @param[in] None
  509. * @return None
  510. **********************************************************************/
  511. void EMAC_UpdateRxConsumeIndex(void)
  512. {
  513. // Get current Rx consume index
  514. uint32_t idx = LPC_EMAC->RxConsumeIndex;
  515. /* Release frame from EMAC buffer */
  516. if (++idx == EMAC_NUM_RX_FRAG) idx = 0;
  517. LPC_EMAC->RxConsumeIndex = idx;
  518. }
  519. /*********************************************************************//**
  520. * @brief Standard EMAC IRQ Handler. This sub-routine will check
  521. * these following interrupt and call the call-back function
  522. * if they're already installed:
  523. * - Overrun Error interrupt in RX Queue
  524. * - Receive Error interrupt: AlignmentError, RangeError,
  525. * LengthError, SymbolError, CRCError or NoDescriptor or Overrun
  526. * - RX Finished Process Descriptors interrupt (ProduceIndex == ConsumeIndex)
  527. * - Receive Done interrupt: Read received frame to the internal buffer
  528. * - Transmit Under-run interrupt
  529. * - Transmit errors interrupt : LateCollision, ExcessiveCollision
  530. * and ExcessiveDefer, NoDescriptor or Under-run
  531. * - TX Finished Process Descriptors interrupt (ProduceIndex == ConsumeIndex)
  532. * - Transmit Done interrupt
  533. * - Interrupt triggered by software
  534. * - Interrupt triggered by a Wakeup event detected by the receive filter
  535. * @param[in] None
  536. * @return None
  537. **********************************************************************/
  538. void ENET_IRQHandler(void)
  539. {
  540. /* EMAC Ethernet Controller Interrupt function. */
  541. uint32_t int_stat;
  542. int32_t RxLen;
  543. // Get EMAC interrupt status
  544. while ((int_stat = (LPC_EMAC->IntStatus & LPC_EMAC->IntEnable)) != 0)
  545. {
  546. // Clear interrupt status
  547. LPC_EMAC->IntClear = int_stat;
  548. if(int_stat & (EMAC_INT_RX_OVERRUN |EMAC_INT_RX_ERR ))
  549. {
  550. uint32_t ulFrameSts = EMAC_GetRxFrameStatus();
  551. uint32_t ulErrCode = 0;
  552. ulErrCode |= (ulFrameSts & EMAC_RINFO_CRC_ERR) ? EMAC_CRC_ERR:0;
  553. ulErrCode |= (ulFrameSts & EMAC_RINFO_SYM_ERR) ? EMAC_SYMBOL_ERR:0;
  554. ulErrCode |= (ulFrameSts & EMAC_RINFO_LEN_ERR) ? EMAC_LENGTH_ERR:0;
  555. ulErrCode |= (ulFrameSts & EMAC_RINFO_ALIGN_ERR) ? EMAC_ALIGN_ERR:0;
  556. ulErrCode |= (ulFrameSts & EMAC_RINFO_OVERRUN) ? EMAC_OVERRUN_ERR:0;
  557. ulErrCode |= (ulFrameSts & EMAC_RINFO_NO_DESCR) ? EMAC_RX_NO_DESC_ERR:0;
  558. ulErrCode |= (ulFrameSts & EMAC_RINFO_FAIL_FILT) ? EMAC_FILTER_FAILED_ERR:0;
  559. if(ulErrCode == 0)
  560. {
  561. /* Note:
  562. * The EMAC doesn't distinguish the frame type and frame length,
  563. * so, e.g. when the IP(0x8000) or ARP(0x0806) packets are received,
  564. * it compares the frame type with the max length and gives the
  565. * "Range" error. In fact, this bit is not an error indication,
  566. * but simply a statement by the chip regarding the status of
  567. * the received frame
  568. */
  569. int_stat &= ~EMAC_INT_RX_ERR;
  570. }
  571. else
  572. {
  573. if(EMAC_Configs.pfnErrorReceive != NULL)
  574. EMAC_Configs.pfnErrorReceive(ulErrCode);
  575. }
  576. }
  577. if(int_stat & (EMAC_INT_TX_UNDERRUN|EMAC_INT_TX_ERR ))
  578. {
  579. uint32_t ulFrameSts = EMAC_GetTxFrameStatus();
  580. uint32_t ulErrCode = 0;
  581. ulErrCode |= (ulFrameSts & EMAC_TINFO_EXCESS_DEF) ? EMAC_EXCESSIVE_DEFER_ERR:0;
  582. ulErrCode |= (ulFrameSts & EMAC_TINFO_EXCESS_COL) ? EMAC_EXCESSIVE_COLLISION_ERR:0;
  583. ulErrCode |= (ulFrameSts & EMAC_TINFO_LATE_COL) ? EMAC_LATE_COLLISION_ERR:0;
  584. ulErrCode |= (ulFrameSts & EMAC_TINFO_UNDERRUN) ? EMAC_UNDERRUN_ERR:0;
  585. ulErrCode |= (ulFrameSts & EMAC_TINFO_NO_DESCR) ? EMAC_TX_NO_DESC_ERR:0;
  586. if(EMAC_Configs.pfnErrorReceive != NULL)
  587. EMAC_Configs.pfnErrorReceive(ulErrCode);
  588. }
  589. if(int_stat & EMAC_INT_RX_DONE)
  590. {
  591. /* Packet received. */
  592. if(EMAC_GetBufferSts(EMAC_RX_BUFF) != EMAC_BUFF_EMPTY)
  593. {
  594. // Get data size
  595. RxLen = EMAC_GetRxFrameSize();
  596. if(RxLen > 0)
  597. {
  598. // trip out 4-bytes CRC field, note that length in (-1) style format
  599. RxLen -= 3;
  600. if((EMAC_GetRxFrameStatus() & EMAC_RINFO_ERR_MASK )== 0)
  601. {
  602. uint16_t *pDest = (uint16_t*) &saFrameBuffers[sbCurrFrameID][sulCurrFrameSz];
  603. uint16_t *pSource = (uint16_t*)EMAC_GetRxBuffer();
  604. sulCurrFrameSz += RxLen;
  605. if(sulCurrFrameSz >= EMAC_MAX_FRAME_SIZE)
  606. {
  607. sulCurrFrameSz = 0;
  608. if(EMAC_Configs.pfnErrorReceive != NULL)
  609. EMAC_Configs.pfnErrorReceive(EMAC_LENGTH_ERR);
  610. }
  611. else
  612. {
  613. // Copy data
  614. while (RxLen > 0)
  615. {
  616. *pDest++ = *pSource++;
  617. RxLen -= 2;
  618. }
  619. if(EMAC_GetRxFrameStatus() & EMAC_RINFO_LAST_FLAG)
  620. {
  621. if(EMAC_Configs.pfnFrameReceive != NULL)
  622. {
  623. EMAC_Configs.pfnFrameReceive((uint16_t*)saFrameBuffers[sbCurrFrameID], sulCurrFrameSz);
  624. }
  625. sulCurrFrameSz = 0;
  626. sbCurrFrameID ++;
  627. if(sbCurrFrameID >= EMAC_MAX_FRAME_NUM)
  628. sbCurrFrameID = 0;
  629. }
  630. /* Release frame from EMAC buffer */
  631. EMAC_UpdateRxConsumeIndex();
  632. }
  633. }
  634. }
  635. }
  636. }
  637. if(int_stat & EMAC_INT_TX_FIN && (EMAC_Configs.pfnTransmitFinish != NULL))
  638. {
  639. EMAC_Configs.pfnTransmitFinish();
  640. }
  641. if(int_stat & EMAC_INT_SOFT_INT && (EMAC_Configs.pfnSoftInt!= NULL))
  642. {
  643. EMAC_Configs.pfnSoftInt();
  644. }
  645. if(int_stat & EMAC_INT_WAKEUP && (EMAC_Configs.pfnWakeup!= NULL))
  646. {
  647. EMAC_Configs.pfnWakeup();
  648. }
  649. }
  650. }
  651. /*********************************************************************//**
  652. * @brief Enable/Disable hash filter functionality for specified destination
  653. * MAC address in EMAC module
  654. * @param[in] dstMAC_addr Pointer to the first MAC destination address, should
  655. * be 6-bytes length, in order LSB to the MSB
  656. * @param[in] NewState New State of this command, should be:
  657. * - ENABLE.
  658. * - DISABLE.
  659. * @return None
  660. *
  661. * Note:
  662. * The standard Ethernet cyclic redundancy check (CRC) function is calculated from
  663. * the 6 byte destination address in the Ethernet frame (this CRC is calculated
  664. * anyway as part of calculating the CRC of the whole frame), then bits [28:23] out of
  665. * the 32 bits CRC result are taken to form the hash. The 6 bit hash is used to access
  666. * the hash table: it is used as an index in the 64 bit HashFilter register that has been
  667. * programmed with accept values. If the selected accept value is 1, the frame is
  668. * accepted.
  669. **********************************************************************/
  670. void EMAC_SetHashFilter(uint8_t dstMAC_addr[], FunctionalState NewState)
  671. {
  672. uint32_t *pReg;
  673. uint32_t tmp;
  674. int32_t crc;
  675. // Calculate the CRC from the destination MAC address
  676. crc = EMAC_CRCCalc(dstMAC_addr, 6);
  677. // Extract the value from CRC to get index value for hash filter table
  678. crc = (crc >> 23) & 0x3F;
  679. pReg = (crc > 31) ? ((uint32_t *)&LPC_EMAC->HashFilterH) \
  680. : ((uint32_t *)&LPC_EMAC->HashFilterL);
  681. tmp = (crc > 31) ? (crc - 32) : crc;
  682. if (NewState == ENABLE)
  683. {
  684. (*pReg) |= (1UL << tmp);
  685. }
  686. else
  687. {
  688. (*pReg) &= ~(1UL << tmp);
  689. }
  690. }
  691. /*********************************************************************//**
  692. * @brief Calculates CRC code for number of bytes in the frame
  693. * @param[in] frame_no_fcs Pointer to the first byte of the frame
  694. * @param[in] frame_len length of the frame without the FCS
  695. * @return the CRC as a 32 bit integer
  696. **********************************************************************/
  697. int32_t EMAC_CRCCalc(uint8_t frame_no_fcs[], int32_t frame_len)
  698. {
  699. int i; // iterator
  700. int j; // another iterator
  701. char byte; // current byte
  702. int crc; // CRC result
  703. int q0, q1, q2, q3; // temporary variables
  704. crc = 0xFFFFFFFF;
  705. for (i = 0; i < frame_len; i++)
  706. {
  707. byte = *frame_no_fcs++;
  708. for (j = 0; j < 2; j++)
  709. {
  710. if (((crc >> 28) ^ (byte >> 3)) & 0x00000001)
  711. {
  712. q3 = 0x04C11DB7;
  713. }
  714. else
  715. {
  716. q3 = 0x00000000;
  717. }
  718. if (((crc >> 29) ^ (byte >> 2)) & 0x00000001)
  719. {
  720. q2 = 0x09823B6E;
  721. }
  722. else
  723. {
  724. q2 = 0x00000000;
  725. }
  726. if (((crc >> 30) ^ (byte >> 1)) & 0x00000001)
  727. {
  728. q1 = 0x130476DC;
  729. }
  730. else
  731. {
  732. q1 = 0x00000000;
  733. }
  734. if (((crc >> 31) ^ (byte >> 0)) & 0x00000001)
  735. {
  736. q0 = 0x2608EDB8;
  737. }
  738. else
  739. {
  740. q0 = 0x00000000;
  741. }
  742. crc = (crc << 4) ^ q3 ^ q2 ^ q1 ^ q0;
  743. byte >>= 4;
  744. }
  745. }
  746. return crc;
  747. }
  748. /*********************************************************************//**
  749. * @brief Enable/Disable Filter mode for each specified type EMAC peripheral
  750. * @param[in] ulFilterMode Filter mode, should be:
  751. * - EMAC_RFC_UCAST_EN: all frames of unicast types
  752. * will be accepted
  753. * - EMAC_RFC_BCAST_EN: broadcast frame will be
  754. * accepted
  755. * - EMAC_RFC_MCAST_EN: all frames of multicast
  756. * types will be accepted
  757. * - EMAC_RFC_UCAST_HASH_EN: The imperfect hash
  758. * filter will be applied to unicast addresses
  759. * - EMAC_RFC_MCAST_HASH_EN: The imperfect hash
  760. * filter will be applied to multicast addresses
  761. * - EMAC_RFC_PERFECT_EN: the destination address
  762. * will be compared with the 6 byte station address
  763. * programmed in the station address by the filter
  764. * - EMAC_RFC_MAGP_WOL_EN: the result of the magic
  765. * packet filter will generate a WoL interrupt when
  766. * there is a match
  767. * - EMAC_RFC_PFILT_WOL_EN: the result of the perfect address
  768. * matching filter and the imperfect hash filter will
  769. * generate a WoL interrupt when there is a match
  770. * @param[in] NewState New State of this command, should be:
  771. * - ENABLE
  772. * - DISABLE
  773. * @return None
  774. **********************************************************************/
  775. void EMAC_SetFilterMode(uint32_t ulFilterMode, FunctionalState NewState)
  776. {
  777. if (NewState == ENABLE)
  778. {
  779. LPC_EMAC->RxFilterCtrl |= ulFilterMode;
  780. if((ulFilterMode & EMAC_RFC_MCAST_HASH_EN) &&
  781. ((ulFilterMode & EMAC_RFC_MCAST_EN) == 0))
  782. {
  783. LPC_EMAC->RxFilterCtrl &= ~EMAC_RFC_MCAST_EN;
  784. }
  785. if((ulFilterMode & EMAC_RFC_UCAST_HASH_EN) &&
  786. ((ulFilterMode & EMAC_RFC_UCAST_EN) == 0))
  787. {
  788. LPC_EMAC->RxFilterCtrl &= ~EMAC_RFC_UCAST_EN;
  789. }
  790. }
  791. else
  792. {
  793. LPC_EMAC->RxFilterCtrl &= ~ulFilterMode;
  794. }
  795. }
  796. /*********************************************************************//**
  797. * @brief Get status of Wake On LAN Filter for each specified
  798. * type in EMAC peripheral, clear this status if it is set
  799. * @param[in] ulFilterMode WoL Filter mode, should be:
  800. * - EMAC_WOL_UCAST: unicast frames caused WoL
  801. * - EMAC_WOL_UCAST: broadcast frame caused WoL
  802. * - EMAC_WOL_MCAST: multicast frame caused WoL
  803. * - EMAC_WOL_UCAST_HASH: unicast frame that passes the
  804. * imperfect hash filter caused WoL
  805. * - EMAC_WOL_MCAST_HASH: multicast frame that passes the
  806. * imperfect hash filter caused WoL
  807. * - EMAC_WOL_PERFECT:perfect address matching filter
  808. * caused WoL
  809. * - EMAC_WOL_RX_FILTER: the receive filter caused WoL
  810. * - EMAC_WOL_MAG_PACKET: the magic packet filter caused WoL
  811. * @return SET/RESET
  812. **********************************************************************/
  813. FlagStatus EMAC_GetWoLStatus(uint32_t ulWoLMode)
  814. {
  815. if (LPC_EMAC->RxFilterWoLStatus & ulWoLMode)
  816. {
  817. LPC_EMAC->RxFilterWoLClear = ulWoLMode;
  818. return SET;
  819. }
  820. else
  821. {
  822. return RESET;
  823. }
  824. }
  825. /*********************************************************************//**
  826. * @brief Enable/Disable interrupt for each type in EMAC
  827. * @param[in] ulIntType Interrupt Type, should be:
  828. * - EMAC_INT_RX_OVERRUN: Receive Overrun
  829. * - EMAC_INT_RX_ERR: Receive Error
  830. * - EMAC_INT_RX_FIN: Receive Descriptor Finish
  831. * - EMAC_INT_RX_DONE: Receive Done
  832. * - EMAC_INT_TX_UNDERRUN: Transmit Under-run
  833. * - EMAC_INT_TX_ERR: Transmit Error
  834. * - EMAC_INT_TX_FIN: Transmit descriptor finish
  835. * - EMAC_INT_TX_DONE: Transmit Done
  836. * - EMAC_INT_SOFT_INT: Software interrupt
  837. * - EMAC_INT_WAKEUP: Wakeup interrupt
  838. * @param[in] NewState New State of this function, should be:
  839. * - ENABLE.
  840. * - DISABLE.
  841. * @return None
  842. **********************************************************************/
  843. void EMAC_IntCmd(uint32_t ulIntType, FunctionalState NewState)
  844. {
  845. if (NewState == ENABLE)
  846. {
  847. LPC_EMAC->IntEnable |= ulIntType;
  848. }
  849. else
  850. {
  851. LPC_EMAC->IntEnable &= ~(ulIntType);
  852. }
  853. }
  854. /*********************************************************************//**
  855. * @brief Check whether if specified interrupt flag is set or not
  856. * for each interrupt type in EMAC and clear interrupt pending
  857. * if it is set.
  858. * @param[in] ulIntType Interrupt Type, should be:
  859. * - EMAC_INT_RX_OVERRUN: Receive Overrun
  860. * - EMAC_INT_RX_ERR: Receive Error
  861. * - EMAC_INT_RX_FIN: Receive Descriptor Finish
  862. * - EMAC_INT_RX_DONE: Receive Done
  863. * - EMAC_INT_TX_UNDERRUN: Transmit Under-run
  864. * - EMAC_INT_TX_ERR: Transmit Error
  865. * - EMAC_INT_TX_FIN: Transmit descriptor finish
  866. * - EMAC_INT_TX_DONE: Transmit Done
  867. * - EMAC_INT_SOFT_INT: Software interrupt
  868. * - EMAC_INT_WAKEUP: Wakeup interrupt
  869. * @return New state of specified interrupt (SET or RESET)
  870. **********************************************************************/
  871. IntStatus EMAC_IntGetStatus(uint32_t ulIntType)
  872. {
  873. if (LPC_EMAC->IntStatus & ulIntType)
  874. {
  875. LPC_EMAC->IntClear = ulIntType;
  876. return SET;
  877. }
  878. else
  879. {
  880. return RESET;
  881. }
  882. }
  883. /**
  884. * @}
  885. */
  886. /**
  887. * @}
  888. */
  889. #endif /*_EMAC*/