2 FreeRTOS V7.0.0 - Copyright (C) 2011 Real Time Engineers Ltd.
\r
5 ***************************************************************************
\r
7 * FreeRTOS tutorial books are available in pdf and paperback. *
\r
8 * Complete, revised, and edited pdf reference manuals are also *
\r
11 * Purchasing FreeRTOS documentation will not only help you, by *
\r
12 * ensuring you get running as quickly as possible and with an *
\r
13 * in-depth knowledge of how to use FreeRTOS, it will also help *
\r
14 * the FreeRTOS project to continue with its mission of providing *
\r
15 * professional grade, cross platform, de facto standard solutions *
\r
16 * for microcontrollers - completely free of charge! *
\r
18 * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
\r
20 * Thank you for using FreeRTOS, and thank you for your support! *
\r
22 ***************************************************************************
\r
25 This file is part of the FreeRTOS distribution.
\r
27 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
28 the terms of the GNU General Public License (version 2) as published by the
\r
29 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
\r
30 >>>NOTE<<< The modification to the GPL is included to allow you to
\r
31 distribute a combined work that includes FreeRTOS without being obliged to
\r
32 provide the source code for proprietary components outside of the FreeRTOS
\r
33 kernel. FreeRTOS is distributed in the hope that it will be useful, but
\r
34 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
\r
35 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
\r
36 more details. You should have received a copy of the GNU General Public
\r
37 License and the FreeRTOS license exception along with FreeRTOS; if not it
\r
38 can be viewed here: http://www.freertos.org/a00114.html and also obtained
\r
39 by writing to Richard Barry, contact details for whom are available on the
\r
44 http://www.FreeRTOS.org - Documentation, latest information, license and
\r
47 http://www.SafeRTOS.com - A version that is certified for use in safety
\r
50 http://www.OpenRTOS.com - Commercial support, development, porting,
\r
51 licensing and training services.
\r
54 /* Originally adapted from file written by Andreas Dannenberg. Supplied with permission. */
\r
56 * Modified for MiMic by R.Iizuka. 2011.08.27
\r
57 * http://nyatla.jp/mimic
\r
61 #include "NyLPC_config.h"
\r
62 #if NyLPC_MCU==NyLPC_MCU_LPC17xx
\r
63 #include "EtherDev_LAN8720_protected.h"
\r
64 #include "../NyLPC_cEthernetMM.h"
\r
65 #include "LPC17xx.h"
\r
66 #include "NyLPC_os.h"
\r
68 #define LAN8720_ID 0x0007C0F0 /* PHY Identifier */
\r
70 /* LAN8720 PHY Registers */
\r
71 #define PHY_REG_BMCR 0x00 /* Basic Mode Control Register */
\r
72 #define PHY_REG_BMSR 0x01 /* Basic Mode Status Register */
\r
73 #define PHY_REG_IDR1 0x02 /* PHY Identifier 1 */
\r
74 #define PHY_REG_IDR2 0x03 /* PHY Identifier 2 */
\r
75 #define PHY_REG_ANAR 0x04 /* Auto-Negotiation Advertisement */
\r
76 #define PHY_REG_ANLPAR 0x05 /* Auto-Neg. Link Partner Abitily */
\r
77 #define PHY_REG_ANER 0x06 /* Auto-Neg. Expansion Register */
\r
79 /* PHY Extended Registers */
\r
80 #define PHY_REG_MODE_CTRL 17
\r
81 #define PHY_REG_SPECIAL_MODE 18
\r
82 #define PHY_REG_SYMBOL_ERR_CNT 26
\r
83 #define PHY_REG_SPECIAL_CTRL 27
\r
84 #define PHY_REG_INT_SOURCE 29
\r
85 #define PHY_REG_INT_MASK 30
\r
86 #define PHY_REG_PHY_CTRL 31
\r
88 #define PHY_AUTO_NEG 0x3000 /* Select Auto Negotiation */
\r
89 #define PHY_AUTO_NEG_COMPLETE 0x1000 /* Auto negotiation have finished. */
\r
91 #define PHY_SPEED_FDUPLX 0x0010 /* Full Duplex */
\r
92 #define PHY_SPEED_100 0x0008 /* 100Mbit */
\r
93 #define ETHDEV_PHY_DEF_ADR 0x0100 /* Default PHY device address */
\r
95 #ifndef configEMAC_INTERRUPT_PRIORITY
\r
96 #define configEMAC_INTERRUPT_PRIORITY 5
\r
99 /* Time to wait between each inspection of the link status. */
\r
100 #define emacWAIT_FOR_LINK_TO_ESTABLISH_MS 500
\r
102 /* Short delay used in several places during the initialisation process. */
\r
103 #define emacSHORT_DELAY_MS 10
\r
105 /* Hardware specific bit definitions. */
\r
106 #define emacPINSEL2_VALUE ( 0x50150105 )
\r
109 /*-----------------------------------------------------------*/
\r
111 /* Setup the IO and peripherals required for Ethernet communication.*/
\r
112 static void prvSetupEMACHardware( void );
\r
113 /* Control the auto negotiate process.*/
\r
114 static void prvConfigurePHY( void );
\r
116 * Wait for a link to be established, then setup the PHY according to the link
\r
119 static long prvSetupLinkStatus( void );
\r
121 * Send lValue to the lPhyReg within the PHY.
\r
123 static long prvWritePHY( long lPhyReg, long lValue );
\r
125 * Read a value from ucPhyReg within the PHY. *plStatus will be set to
\r
126 * pdFALSE if there is an error.
\r
128 static unsigned short prvReadPHY( unsigned int ucPhyReg, NyLPC_TBool* o_status);
\r
131 static NyLPC_TBool start(const struct NyLPC_TEthAddr* i_eth_addr,NyLPC_TiEthernetDevice_onEvent i_handler,void* i_param);
\r
132 static void stop(void);
\r
133 static struct NyLPC_TTxBufferHeader* allocTxBuf(NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_size);
\r
134 static void releaseTxBuf(struct NyLPC_TTxBufferHeader* i_buf);
\r
137 static void emacIsrHandler(unsigned long i_status);
\r
139 /*-----------------------------------------------------------*/
\r
142 const static struct TiEthernetDevice _interface=
\r
147 EthDev_LPC17xx_getRxEthFrame,
\r
148 EthDev_LPC17xx_nextRxEthFrame,
\r
151 EthDev_LPC17xx_sendTxEthFrame,
\r
152 EthDev_LPC17xx_processTx
\r
154 static void* _event_param;
\r
155 static NyLPC_TiEthernetDevice_onEvent _event_handler;
\r
158 * EthernetDeviceのファクトリー関数。インターフェイスを生成できればtrue
\r
161 NyLPC_TBool EthDev_LAN8720_getInterface(
\r
162 const struct TiEthernetDevice** o_dev)
\r
164 unsigned long ulID1, ulID2;
\r
165 NyLPC_TBool ret=NyLPC_TBool_TRUE;
\r
166 //Reset MCU Interface. and wait for reset.
\r
167 prvSetupEMACHardware();
\r
168 //Check peripheral name
\r
169 ulID1 = prvReadPHY( PHY_REG_IDR1, &ret );
\r
170 ulID2 = prvReadPHY( PHY_REG_IDR2, &ret );
\r
171 if( ( (ulID1 << 16UL ) | ( ulID2 & 0xFFF0UL ) ) != LAN8720_ID)
\r
173 return NyLPC_TBool_FALSE;
\r
175 *o_dev=&_interface;
\r
176 LPC_EMAC->TxProduceIndex = 0;
\r
177 LPC_EMAC->RxConsumeIndex = 0;
\r
178 return NyLPC_TBool_TRUE;
\r
183 /***********************************************************************
\r
185 ***********************************************************************/
\r
186 #define ETH_TX_BUF_BASE (void*)(ETH_BUF_BASE+ETH_FRAG_SIZE*NUM_RX_FRAG)
\r
188 static NyLPC_TBool start(const struct NyLPC_TEthAddr* i_eth_addr,NyLPC_TiEthernetDevice_onEvent i_handler,void* i_param)
\r
191 NyLPC_cIsr_setEnetISR(emacIsrHandler);
\r
192 _event_handler=i_handler;
\r
193 _event_param=i_param;
\r
194 /* Set the Ethernet MAC Address registers */
\r
195 LPC_EMAC->SA0 = (((uint32_t)(i_eth_addr->addr[0])) << 8 ) | i_eth_addr->addr[1];
\r
196 LPC_EMAC->SA1 = (((uint32_t)(i_eth_addr->addr[2])) << 8 ) | i_eth_addr->addr[3];
\r
197 LPC_EMAC->SA2 = (((uint32_t)(i_eth_addr->addr[4])) << 8 ) | i_eth_addr->addr[5];
\r
200 NyLPC_cEthernetMM_initialize(ETH_TX_BUF_BASE);
\r
201 /* Initialize Tx and Rx DMA Descriptors */
\r
202 EthDev_LPC17xx_prevRxDescriptor();
\r
203 EthDev_LPC17xx_prevTxDescriptor();
\r
205 /* Setup the PHY. */
\r
208 //wait for Link up...
\r
209 while(!prvSetupLinkStatus())
\r
211 NyLPC_cThread_sleep(100);
\r
214 /* Receive Broadcast and Perfect Match Packets */
\r
215 LPC_EMAC->RxFilterCtrl = RFC_BCAST_EN | RFC_PERFECT_EN | RFC_MCAST_EN;
\r
218 NyLPC_cIsr_enterCritical();
\r
220 /* Reset all interrupts */
\r
221 LPC_EMAC->IntClear = 0xffff;
\r
222 LPC_EMAC->IntEnable = ( INT_RX_DONE | INT_TX_DONE );
\r
223 /* Enable receive and transmit mode of MAC Ethernet core */
\r
224 LPC_EMAC->Command |= ( CR_RX_EN | CR_TX_EN );
\r
225 LPC_EMAC->MAC1 |= MAC1_REC_EN;
\r
227 /* Set the interrupt priority to the max permissible to cause some
\r
228 interrupt nesting. */
\r
229 NVIC_SetPriority( ENET_IRQn, configEMAC_INTERRUPT_PRIORITY );
\r
231 /* Enable the interrupt. */
\r
232 NVIC_EnableIRQ( ENET_IRQn );
\r
234 NyLPC_cIsr_exitCritical();
\r
236 return NyLPC_TBool_TRUE;
\r
238 static void stop(void)
\r
240 NyLPC_cIsr_enterCritical();
\r
242 LPC_EMAC->IntEnable = (~(INT_RX_DONE|INT_TX_DONE))&LPC_EMAC->IntEnable;
\r
243 NVIC_DisableIRQ( ENET_IRQn );
\r
245 NyLPC_cIsr_exitCritical();
\r
246 LPC_EMAC->Command &= ~( CR_RX_EN | CR_TX_EN );
\r
247 LPC_EMAC->MAC1 &= ~MAC1_REC_EN;
\r
249 NyLPC_cIsr_setEnetISR(NULL);
\r
251 NyLPC_cEthernetMM_finalize();
\r
255 static struct NyLPC_TTxBufferHeader* allocTxBuf(NyLPC_TUInt16 i_hint,NyLPC_TUInt16* o_size)
\r
257 return NyLPC_cEthernetMM_alloc(i_hint,o_size);
\r
259 static void releaseTxBuf(struct NyLPC_TTxBufferHeader* i_buf)
\r
261 NyLPC_cEthernetMM_release(i_buf);
\r
266 /********************************************************************************
\r
267 * Private functions
\r
268 *******************************************************************************/
\r
270 /*-----------------------------------------------------------*/
\r
272 /*-----------------------------------------------------------*/
\r
274 static void prvSetupEMACHardware( void )
\r
278 NyLPC_TBool lDummy;
\r
280 /* Power Up the EMAC controller. */
\r
281 LPC_SC->PCONP |= 0x40000000;
\r
282 NyLPC_cThread_sleep( emacSHORT_DELAY_MS);
\r
284 /* Enable P1 Ethernet Pins. */
\r
285 LPC_PINCON->PINSEL2 = emacPINSEL2_VALUE;
\r
286 LPC_PINCON->PINSEL3 = ( LPC_PINCON->PINSEL3 & ~0x0000000F ) | 0x00000005;
\r
288 /* Reset all EMAC internal modules. */
\r
289 LPC_EMAC->MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX | MAC1_SIM_RES | MAC1_SOFT_RES;
\r
290 LPC_EMAC->Command = CR_REG_RES | CR_TX_RES | CR_RX_RES| CR_PASS_RUNT_FRM;
\r
291 /* A short delay after reset. */
\r
292 NyLPC_cThread_sleep( emacSHORT_DELAY_MS);
\r
294 /* Initialize MAC control registers. */
\r
295 LPC_EMAC->MAC1 = MAC1_PASS_ALL;
\r
296 LPC_EMAC->MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;
\r
297 LPC_EMAC->MAXF = ETH_MAX_FLEN;
\r
298 LPC_EMAC->CLRT = CLRT_DEF;
\r
299 LPC_EMAC->IPGR = IPGR_DEF;
\r
301 /*PCLK=18MHz, clock select=6, MDC=18/6=3MHz */ // I don't think so!
\r
302 /* Enable Reduced MII interface. */
\r
303 LPC_EMAC->MCFG = MCFG_CLK_DIV20 | MCFG_RES_MII;
\r
304 NyLPC_cThread_sleep( emacSHORT_DELAY_MS);
\r
305 LPC_EMAC->MCFG = MCFG_CLK_DIV20;
\r
307 /* Enable Reduced MII interface. */
\r
308 LPC_EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM | CR_PASS_RX_FILT;
\r
310 /* Reset Reduced MII Logic. */
\r
311 LPC_EMAC->SUPP = SUPP_RES_RMII | SUPP_SPEED;
\r
312 NyLPC_cThread_sleep( emacSHORT_DELAY_MS);
\r
313 LPC_EMAC->SUPP = SUPP_SPEED;
\r
315 /* Put the PHY in reset mode */
\r
316 prvWritePHY( PHY_REG_BMCR, MCFG_RES_MII );
\r
317 NyLPC_cThread_sleep( emacSHORT_DELAY_MS * 5);
\r
319 /* Wait for hardware reset to end. */
\r
320 for( x = 0; x < 100; x++ )
\r
322 NyLPC_cThread_sleep( emacSHORT_DELAY_MS * 5 );
\r
323 us = prvReadPHY( PHY_REG_BMCR, &lDummy );
\r
324 if( !( us & MCFG_RES_MII ) )
\r
326 /* Reset complete */
\r
331 /*-----------------------------------------------------------*/
\r
334 /*-----------------------------------------------------------*/
\r
336 static NyLPC_TBool prvWritePHY( long lPhyReg, long lValue )
\r
338 const long lMaxTime = 10;
\r
341 LPC_EMAC->MCMD = 0;
\r
342 LPC_EMAC->MADR = ETHDEV_PHY_DEF_ADR | lPhyReg;
\r
343 LPC_EMAC->MWTD = lValue;
\r
345 for( x = 0; x < lMaxTime; x++ )
\r
347 if( ( LPC_EMAC->MIND & MIND_BUSY ) == 0 )
\r
349 /* Operation has finished. */
\r
353 NyLPC_cThread_sleep( emacSHORT_DELAY_MS);
\r
358 return NyLPC_TBool_TRUE;
\r
362 return NyLPC_TBool_FALSE;
\r
365 /*-----------------------------------------------------------*/
\r
367 static unsigned short prvReadPHY( unsigned int ucPhyReg, NyLPC_TBool *o_status)
\r
370 const long lMaxTime = 10;
\r
372 LPC_EMAC->MCMD = 1;
\r
373 LPC_EMAC->MADR = ETHDEV_PHY_DEF_ADR | ucPhyReg;
\r
374 LPC_EMAC->MCMD = MCMD_READ;
\r
376 for( x = 0; x < lMaxTime; x++ )
\r
378 /* Operation has finished. */
\r
379 if( ( LPC_EMAC->MIND & MIND_BUSY ) == 0 )
\r
383 NyLPC_cThread_sleep( emacSHORT_DELAY_MS);
\r
386 LPC_EMAC->MCMD = 0;
\r
388 if( x >= lMaxTime )
\r
390 *o_status =NyLPC_TBool_FALSE;
\r
393 return( LPC_EMAC->MRDD );
\r
396 * Private function depend on configulation.
\r
403 static void prvConfigurePHY( void )
\r
407 NyLPC_TBool lDummy;
\r
408 /* Auto negotiate the configuration. */
\r
409 if( prvWritePHY( PHY_REG_BMCR, PHY_AUTO_NEG ) )
\r
411 NyLPC_cThread_sleep( emacSHORT_DELAY_MS * 5 );
\r
413 for( x = 0; x < 10; x++ )
\r
415 us = prvReadPHY( PHY_REG_PHY_CTRL, &lDummy );
\r
416 if( us & PHY_AUTO_NEG_COMPLETE )
\r
420 NyLPC_cThread_sleep( emacWAIT_FOR_LINK_TO_ESTABLISH_MS);
\r
425 static long prvSetupLinkStatus( void )
\r
428 unsigned short usLinkStatus;
\r
429 NyLPC_TBool lReturn=NyLPC_TBool_TRUE;
\r
431 /* Wait with timeout for the link to be established. */
\r
432 for( x = 0; x < 10; x++ )
\r
434 usLinkStatus = prvReadPHY (PHY_REG_PHY_CTRL, &lReturn );
\r
435 if( usLinkStatus & PHY_AUTO_NEG_COMPLETE )
\r
437 /* Link is established. */
\r
438 lReturn = NyLPC_TBool_TRUE;
\r
441 NyLPC_cThread_sleep( emacWAIT_FOR_LINK_TO_ESTABLISH_MS);
\r
444 if( lReturn == NyLPC_TBool_TRUE )
\r
446 /* Configure Full/Half Duplex mode. */
\r
447 if (usLinkStatus & PHY_SPEED_FDUPLX )
\r
449 /* Full duplex is enabled. */
\r
450 LPC_EMAC->MAC2 |= MAC2_FULL_DUP;
\r
451 LPC_EMAC->Command |= CR_FULL_DUP;
\r
452 LPC_EMAC->IPGT = IPGT_FULL_DUP;
\r
456 /* Half duplex mode. */
\r
457 LPC_EMAC->IPGT = IPGT_HALF_DUP;
\r
460 /* Configure 100MBit/10MBit mode. */
\r
461 if( !(usLinkStatus & PHY_SPEED_100) )
\r
464 LPC_EMAC->SUPP = 0;
\r
468 /* 100MBit mode. */
\r
469 LPC_EMAC->SUPP = SUPP_SPEED;
\r
474 //--------------------------------------------------------------------------------
\r
476 //--------------------------------------------------------------------------------
\r
481 static void emacIsrHandler(unsigned long i_status)
\r
483 if( i_status & INT_RX_DONE )
\r
485 _event_handler(_event_param,NyLPC_TiEthernetDevice_EVENT_ON_RX);
\r
487 if( i_status & INT_TX_DONE )
\r
489 _event_handler(_event_param,NyLPC_TiEthernetDevice_EVENT_ON_TX);
\r