1 /******************************************************************
\r
3 ***** Ver.: 1.0 *****
\r
4 ***** Date: 07/05/2001 *****
\r
5 ***** Auth: Andreas Dannenberg *****
\r
6 ***** HTWK Leipzig *****
\r
7 ***** university of applied sciences *****
\r
9 ***** Func: ethernet packet-driver for use with LAN- *****
\r
10 ***** controller CS8900 from Crystal/Cirrus Logic *****
\r
12 ***** Keil: Module modified for use with Philips *****
\r
13 ***** LPC2378 EMAC Ethernet controller *****
\r
15 ******************************************************************/
\r
17 /* Adapted from file originally written by Andreas Dannenberg. Supplied with permission. */
\r
18 #include "FreeRTOS.h"
\r
22 #include "LPC17xx_defs.h"
\r
24 #define configPINSEL2_VALUE 0x50150105
\r
26 /* The semaphore used to wake the uIP task when data arives. */
\r
27 xSemaphoreHandle xEMACSemaphore = NULL;
\r
29 static unsigned short *rptr;
\r
30 static unsigned short *tptr;
\r
32 static unsigned short SwapBytes( unsigned short Data )
\r
34 return( Data >> 8 ) | ( Data << 8 );
\r
37 // Keil: function added to write PHY
\r
38 int write_PHY( int PhyReg, int Value )
\r
41 const unsigned int uiMaxTime = 10;
\r
43 MAC_MADR = DP83848C_DEF_ADR | PhyReg;
\r
46 /* Wait utill operation completed */
\r
48 for( tout = 0; tout < uiMaxTime; tout++ )
\r
50 if( (MAC_MIND & MIND_BUSY) == 0 )
\r
58 if( tout < uiMaxTime )
\r
68 // Keil: function added to read PHY
\r
69 unsigned short read_PHY( unsigned char PhyReg, portBASE_TYPE *pxStatus )
\r
72 const unsigned int uiMaxTime = 10;
\r
74 MAC_MADR = DP83848C_DEF_ADR | PhyReg;
\r
75 MAC_MCMD = MCMD_READ;
\r
77 /* Wait until operation completed */
\r
79 for( tout = 0; tout < uiMaxTime; tout++ )
\r
81 if( (MAC_MIND & MIND_BUSY) == 0 )
\r
91 if( tout >= uiMaxTime )
\r
99 // Keil: function added to initialize Rx Descriptors
\r
100 void rx_descr_init( void )
\r
104 for( i = 0; i < NUM_RX_FRAG; i++ )
\r
106 RX_DESC_PACKET( i ) = RX_BUF( i );
\r
107 RX_DESC_CTRL( i ) = RCTRL_INT | ( ETH_FRAG_SIZE - 1 );
\r
108 RX_STAT_INFO( i ) = 0;
\r
109 RX_STAT_HASHCRC( i ) = 0;
\r
112 /* Set EMAC Receive Descriptor Registers. */
\r
113 MAC_RXDESCRIPTOR = RX_DESC_BASE;
\r
114 MAC_RXSTATUS = RX_STAT_BASE;
\r
115 MAC_RXDESCRIPTORNUM = NUM_RX_FRAG - 1;
\r
117 /* Rx Descriptors Point to 0 */
\r
118 MAC_RXCONSUMEINDEX = 0;
\r
121 // Keil: function added to initialize Tx Descriptors
\r
122 void tx_descr_init( void )
\r
126 for( i = 0; i < NUM_TX_FRAG; i++ )
\r
128 TX_DESC_PACKET( i ) = TX_BUF( i );
\r
129 TX_DESC_CTRL( i ) = 0;
\r
130 TX_STAT_INFO( i ) = 0;
\r
133 /* Set EMAC Transmit Descriptor Registers. */
\r
134 MAC_TXDESCRIPTOR = TX_DESC_BASE;
\r
135 MAC_TXSTATUS = TX_STAT_BASE;
\r
136 MAC_TXDESCRIPTORNUM = NUM_TX_FRAG - 1;
\r
138 /* Tx Descriptors Point to 0 */
\r
139 MAC_TXPRODUCEINDEX = 0;
\r
142 // configure port-pins for use with LAN-controller,
\r
143 // reset it and send the configuration-sequence
\r
144 portBASE_TYPE Init_EMAC( void )
\r
146 portBASE_TYPE xReturn = pdPASS;
\r
148 // Keil: function modified to access the EMAC
\r
149 // Initializes the EMAC ethernet controller
\r
150 volatile unsigned int regv, tout, id1, id2;
\r
152 /* Enable P1 Ethernet Pins. */
\r
153 PINSEL2 = configPINSEL2_VALUE;
\r
154 PINSEL3 = ( PINSEL3 &~0x0000000F ) | 0x00000005;
\r
156 /* Power Up the EMAC controller. */
\r
157 PCONP |= PCONP_PCENET;
\r
160 /* Reset all EMAC internal modules. */
\r
161 MAC_MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX | MAC1_SIM_RES | MAC1_SOFT_RES;
\r
162 MAC_COMMAND = CR_REG_RES | CR_TX_RES | CR_RX_RES | CR_PASS_RUNT_FRM;
\r
164 /* A short delay after reset. */
\r
167 /* Initialize MAC control registers. */
\r
168 MAC_MAC1 = MAC1_PASS_ALL;
\r
169 MAC_MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;
\r
170 MAC_MAXF = ETH_MAX_FLEN;
\r
171 MAC_CLRT = CLRT_DEF;
\r
172 MAC_IPGR = IPGR_DEF;
\r
174 /* Enable Reduced MII interface. */
\r
175 MAC_COMMAND = CR_RMII | CR_PASS_RUNT_FRM;
\r
177 /* Reset Reduced MII Logic. */
\r
178 MAC_SUPP = SUPP_RES_RMII;
\r
182 /* Put the PHY in reset mode */
\r
183 write_PHY( PHY_REG_BMCR, 0x8000 );
\r
184 xReturn = write_PHY( PHY_REG_BMCR, 0x8000 );
\r
186 /* Wait for hardware reset to end. */
\r
187 for( tout = 0; tout < 100; tout++ )
\r
190 regv = read_PHY( PHY_REG_BMCR, &xReturn );
\r
191 if( !(regv & 0x8000) )
\r
193 /* Reset complete */
\r
198 /* Check if this is a DP83848C PHY. */
\r
199 id1 = read_PHY( PHY_REG_IDR1, &xReturn );
\r
200 id2 = read_PHY( PHY_REG_IDR2, &xReturn );
\r
201 if( ((id1 << 16) | (id2 & 0xFFF0)) == DP83848C_ID )
\r
203 /* Set the Ethernet MAC Address registers */
\r
204 MAC_SA0 = ( emacETHADDR0 << 8 ) | emacETHADDR1;
\r
205 MAC_SA1 = ( emacETHADDR2 << 8 ) | emacETHADDR3;
\r
206 MAC_SA2 = ( emacETHADDR4 << 8 ) | emacETHADDR5;
\r
208 /* Initialize Tx and Rx DMA Descriptors */
\r
212 /* Receive Broadcast and Perfect Match Packets */
\r
213 MAC_RXFILTERCTRL = RFC_UCAST_EN | RFC_BCAST_EN | RFC_PERFECT_EN;
\r
215 /* Create the semaphore used ot wake the uIP task. */
\r
216 vSemaphoreCreateBinary( xEMACSemaphore );
\r
218 /* Configure the PHY device */
\r
220 /* Use autonegotiation about the link speed. */
\r
221 if( write_PHY(PHY_REG_BMCR, PHY_AUTO_NEG) )
\r
223 /* Wait to complete Auto_Negotiation. */
\r
224 for( tout = 0; tout < 10; tout++ )
\r
227 regv = read_PHY( PHY_REG_BMSR, &xReturn );
\r
228 if( regv & 0x0020 )
\r
230 /* Autonegotiation Complete. */
\r
241 /* Check the link status. */
\r
242 if( xReturn == pdPASS )
\r
245 for( tout = 0; tout < 10; tout++ )
\r
248 regv = read_PHY( PHY_REG_STS, &xReturn );
\r
249 if( regv & 0x0001 )
\r
258 if( xReturn == pdPASS )
\r
260 /* Configure Full/Half Duplex mode. */
\r
261 if( regv & 0x0004 )
\r
263 /* Full duplex is enabled. */
\r
264 MAC_MAC2 |= MAC2_FULL_DUP;
\r
265 MAC_COMMAND |= CR_FULL_DUP;
\r
266 MAC_IPGT = IPGT_FULL_DUP;
\r
270 /* Half duplex mode. */
\r
271 MAC_IPGT = IPGT_HALF_DUP;
\r
274 /* Configure 100MBit/10MBit mode. */
\r
275 if( regv & 0x0002 )
\r
282 /* 100MBit mode. */
\r
283 MAC_SUPP = SUPP_SPEED;
\r
286 /* Reset all interrupts */
\r
287 MAC_INTCLEAR = 0xFFFF;
\r
289 /* Enable receive and transmit mode of MAC Ethernet core */
\r
290 MAC_COMMAND |= ( CR_RX_EN | CR_TX_EN );
\r
291 MAC_MAC1 |= MAC1_REC_EN;
\r
297 // reads a word in little-endian byte order from RX_BUFFER
\r
298 unsigned short ReadFrame_EMAC( void )
\r
303 // reads a word in big-endian byte order from RX_FRAME_PORT
\r
304 // (useful to avoid permanent byte-swapping while reading
\r
306 unsigned short ReadFrameBE_EMAC( void )
\r
308 unsigned short ReturnValue;
\r
310 ReturnValue = SwapBytes( *rptr++ );
\r
311 return( ReturnValue );
\r
314 // copies bytes from frame port to MCU-memory
\r
315 // NOTES: * an odd number of byte may only be transfered
\r
316 // if the frame is read to the end!
\r
317 // * MCU-memory MUST start at word-boundary
\r
318 void CopyFromFrame_EMAC( void *Dest, unsigned short Size )
\r
320 unsigned short *piDest; // Keil: Pointer added to correct expression
\r
321 piDest = Dest; // Keil: Line added
\r
324 *piDest++ = ReadFrame_EMAC();
\r
329 { // check for leftover byte...
\r
330 *( unsigned char * ) piDest = ( char ) ReadFrame_EMAC(); // the LAN-Controller will return 0
\r
331 } // for the highbyte
\r
334 // does a dummy read on frame-I/O-port
\r
335 // NOTE: only an even number of bytes is read!
\r
336 void DummyReadFrame_EMAC( unsigned short Size ) // discards an EVEN number of bytes
\r
345 // Reads the length of the received ethernet frame and checks if the
\r
346 // destination address is a broadcast message or not
\r
347 // returns the frame length
\r
348 unsigned short StartReadFrame( void )
\r
350 unsigned short RxLen;
\r
353 idx = MAC_RXCONSUMEINDEX;
\r
354 RxLen = ( RX_STAT_INFO(idx) & RINFO_SIZE ) - 3;
\r
355 rptr = ( unsigned short * ) RX_DESC_PACKET( idx );
\r
359 void EndReadFrame( void )
\r
363 /* DMA free packet. */
\r
364 idx = MAC_RXCONSUMEINDEX;
\r
366 if( ++idx == NUM_RX_FRAG )
\r
371 MAC_RXCONSUMEINDEX = idx;
\r
374 unsigned int CheckFrameReceived( void )
\r
376 // Packet received ?
\r
377 if( MAC_RXPRODUCEINDEX != MAC_RXCONSUMEINDEX )
\r
378 { // more packets received ?
\r
387 unsigned int uiGetEMACRxData( unsigned char *ucBuffer )
\r
389 unsigned int uiLen = 0;
\r
391 if( MAC_RXPRODUCEINDEX != MAC_RXCONSUMEINDEX )
\r
393 uiLen = StartReadFrame();
\r
394 CopyFromFrame_EMAC( ucBuffer, uiLen );
\r
401 // requests space in EMAC memory for storing an outgoing frame
\r
402 void RequestSend( void )
\r
406 idx = MAC_TXPRODUCEINDEX;
\r
407 tptr = ( unsigned short * ) TX_DESC_PACKET( idx );
\r
410 // check if ethernet controller is ready to accept the
\r
411 // frame we want to send
\r
412 unsigned int Rdy4Tx( void )
\r
414 return( 1 ); // the ethernet controller transmits much faster
\r
415 } // than the CPU can load its buffers
\r
417 // writes a word in little-endian byte order to TX_BUFFER
\r
418 void WriteFrame_EMAC( unsigned short Data )
\r
423 // copies bytes from MCU-memory to frame port
\r
424 // NOTES: * an odd number of byte may only be transfered
\r
425 // if the frame is written to the end!
\r
426 // * MCU-memory MUST start at word-boundary
\r
427 void CopyToFrame_EMAC( void *Source, unsigned int Size )
\r
429 unsigned short *piSource;
\r
432 Size = ( Size + 1 ) & 0xFFFE; // round Size up to next even number
\r
435 WriteFrame_EMAC( *piSource++ );
\r
440 void DoSend_EMAC( unsigned short FrameSize )
\r
444 idx = MAC_TXPRODUCEINDEX;
\r
445 TX_DESC_CTRL( idx ) = FrameSize | TCTRL_LAST;
\r
446 if( ++idx == NUM_TX_FRAG )
\r
451 MAC_TXPRODUCEINDEX = idx;
\r
454 void vEMAC_ISR( void )
\r
456 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
458 /* Clear the interrupt. */
\r
459 MAC_INTCLEAR = 0xffff;
\r
461 /* Ensure the uIP task is not blocked as data has arrived. */
\r
462 xSemaphoreGiveFromISR( xEMACSemaphore, &xHigherPriorityTaskWoken );
\r
464 portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
\r