]> begriffs open source - cmsis-freertos/blob - Demo/ARM7_LPC2368_Rowley/webserver/emac.c
Update cmsis_os2.c
[cmsis-freertos] / Demo / ARM7_LPC2368_Rowley / webserver / emac.c
1 /******************************************************************
2  *****                                                        *****
3  *****  Name: cs8900.c                                        *****
4  *****  Ver.: 1.0                                             *****
5  *****  Date: 07/05/2001                                      *****
6  *****  Auth: Andreas Dannenberg                              *****
7  *****        HTWK Leipzig                                    *****
8  *****        university of applied sciences                  *****
9  *****        Germany                                         *****
10  *****  Func: ethernet packet-driver for use with LAN-        *****
11  *****        controller CS8900 from Crystal/Cirrus Logic     *****
12  *****                                                        *****
13  *****  Keil: Module modified for use with Philips            *****
14  *****        LPC2378 EMAC Ethernet controller                *****
15  *****                                                        *****
16  ******************************************************************/
17
18 /* Adapted from file originally written by Andreas Dannenberg.  Supplied with permission. */
19
20 #include "FreeRTOS.h"
21 #include "semphr.h" 
22 #include "task.h"
23 #include "emac.h"
24
25 /* The semaphore used to wake the uIP task when data arives. */
26 SemaphoreHandle_t xEMACSemaphore = NULL;
27
28 static unsigned short *rptr;
29 static unsigned short *tptr;
30
31 // easyWEB internal function
32 // help function to swap the byte order of a WORD
33
34 static unsigned short SwapBytes(unsigned short Data)
35 {
36   return (Data >> 8) | (Data << 8);
37 }
38
39 // Keil: function added to write PHY
40 void write_PHY (int PhyReg, int Value)
41 {
42   unsigned int tout;
43
44   MADR = DP83848C_DEF_ADR | PhyReg;
45   MWTD = Value;
46
47   /* Wait utill operation completed */
48   tout = 0;
49   for (tout = 0; tout < MII_WR_TOUT; tout++) {
50     if ((MIND & MIND_BUSY) == 0) {
51       break;
52     }
53   }
54 }
55
56
57 // Keil: function added to read PHY
58 unsigned short read_PHY (unsigned char PhyReg) 
59 {
60   unsigned int tout;
61
62   MADR = DP83848C_DEF_ADR | PhyReg;
63   MCMD = MCMD_READ;
64
65   /* Wait until operation completed */
66   tout = 0;
67   for (tout = 0; tout < MII_RD_TOUT; tout++) {
68     if ((MIND & MIND_BUSY) == 0) {
69       break;
70     }
71   }
72   MCMD = 0;
73   return (MRDD);
74 }
75
76
77 // Keil: function added to initialize Rx Descriptors
78 void rx_descr_init (void)
79 {
80   unsigned int i;
81
82   for (i = 0; i < NUM_RX_FRAG; i++) {
83     RX_DESC_PACKET(i)  = RX_BUF(i);
84     RX_DESC_CTRL(i)    = RCTRL_INT | (ETH_FRAG_SIZE-1);
85     RX_STAT_INFO(i)    = 0;
86     RX_STAT_HASHCRC(i) = 0;
87   }
88
89   /* Set EMAC Receive Descriptor Registers. */
90   RxDescriptor    = RX_DESC_BASE;
91   RxStatus        = RX_STAT_BASE;
92   RxDescriptorNumber = NUM_RX_FRAG-1;
93
94   /* Rx Descriptors Point to 0 */
95   RxConsumeIndex  = 0;
96 }
97
98
99 // Keil: function added to initialize Tx Descriptors
100 void tx_descr_init (void) {
101   unsigned int i;
102
103   for (i = 0; i < NUM_TX_FRAG; i++) {
104     TX_DESC_PACKET(i) = TX_BUF(i);
105     TX_DESC_CTRL(i)   = 0;
106     TX_STAT_INFO(i)   = 0;
107   }
108
109   /* Set EMAC Transmit Descriptor Registers. */
110   TxDescriptor    = TX_DESC_BASE;
111   TxStatus        = TX_STAT_BASE;
112   TxDescriptorNumber = NUM_TX_FRAG-1;
113
114   /* Tx Descriptors Point to 0 */
115   TxProduceIndex  = 0;
116 }
117
118
119 // configure port-pins for use with LAN-controller,
120 // reset it and send the configuration-sequence
121
122 portBASE_TYPE Init_EMAC(void)
123 {
124 portBASE_TYPE xReturn = pdPASS;
125 static portBASE_TYPE xAttempt = 0;
126 // Keil: function modified to access the EMAC
127 // Initializes the EMAC ethernet controller
128   volatile unsigned int regv,tout,id1,id2;
129
130   /* Enable P1 Ethernet Pins. */
131   PINSEL2 = configPINSEL2_VALUE;
132   PINSEL3 = (PINSEL3 & ~0x0000000F) | 0x00000005;
133
134   /* Power Up the EMAC controller. */
135   PCONP |= 0x40000000;
136   vTaskDelay( 10 );
137
138   /* Reset all EMAC internal modules. */
139   MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX |
140              MAC1_SIM_RES | MAC1_SOFT_RES;
141   Command = CR_REG_RES | CR_TX_RES | CR_RX_RES;
142
143   /* A short delay after reset. */
144   vTaskDelay( 10 );
145
146   /* Initialize MAC control registers. */
147   MAC1 = MAC1_PASS_ALL;
148   MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;
149   MAXF = ETH_MAX_FLEN;
150   CLRT = CLRT_DEF;
151   IPGR = IPGR_DEF;
152
153   /* Enable Reduced MII interface. */
154   Command = CR_RMII | CR_PASS_RUNT_FRM;
155
156   /* Reset Reduced MII Logic. */
157   SUPP = SUPP_RES_RMII;
158   SUPP = 0;
159
160   /* Put the DP83848C in reset mode */
161   write_PHY (PHY_REG_BMCR, 0x8000);
162   write_PHY (PHY_REG_BMCR, 0x8000);
163
164   /* Wait for hardware reset to end. */
165   for (tout = 0; tout < 100; tout++) {
166     vTaskDelay( 200 );
167     regv = read_PHY (PHY_REG_BMCR);
168     if (!(regv & 0x8000)) {
169       /* Reset complete */
170       break;
171     }
172   }
173
174   /* Check if this is a DP83848C PHY. */
175   id1 = read_PHY (PHY_REG_IDR1);
176   id2 = read_PHY (PHY_REG_IDR2);
177   if (((id1 << 16) | (id2 & 0xFFF0)) == DP83848C_ID) {
178     /* Configure the PHY device */
179
180     /* Use autonegotiation about the link speed. */
181     write_PHY (PHY_REG_BMCR, PHY_AUTO_NEG);
182     /* Wait to complete Auto_Negotiation. */
183     for (tout = 0; tout < 10; tout++) {
184       vTaskDelay( 200 );
185       regv = read_PHY (PHY_REG_BMSR);
186       if (regv & 0x0020) {
187         /* Autonegotiation Complete. */
188         break;
189       }
190     }
191   }
192   else
193   {
194     xReturn = pdFAIL;
195   }
196
197   /* Check the link status. */
198   if( xReturn == pdPASS )
199   {
200     xReturn = pdFAIL;
201     for (tout = 0; tout < 10; tout++) {
202       vTaskDelay( 200 );
203       regv = read_PHY (PHY_REG_STS);
204       if (regv & 0x0001) {
205         /* Link is on. */
206         xReturn = pdPASS;
207         break;
208       }
209     }
210   }
211
212   if( xReturn == pdPASS )
213   {
214     /* Configure Full/Half Duplex mode. */
215     if (regv & 0x0004) {
216       /* Full duplex is enabled. */
217       MAC2    |= MAC2_FULL_DUP;
218       Command |= CR_FULL_DUP;
219       IPGT     = IPGT_FULL_DUP;
220     }
221     else {
222       /* Half duplex mode. */
223       IPGT = IPGT_HALF_DUP;
224     }
225
226     /* Configure 100MBit/10MBit mode. */
227     if (regv & 0x0002) {
228       /* 10MBit mode. */
229       SUPP = 0;
230     }
231     else {
232       /* 100MBit mode. */
233       SUPP = SUPP_SPEED;
234     }
235
236     /* Set the Ethernet MAC Address registers */
237     SA0 = (emacETHADDR0 << 8) | emacETHADDR1;
238     SA1 = (emacETHADDR2 << 8) | emacETHADDR3;
239     SA2 = (emacETHADDR4 << 8) | emacETHADDR5;
240
241     /* Initialize Tx and Rx DMA Descriptors */
242     rx_descr_init ();
243     tx_descr_init ();
244
245     /* Receive Broadcast and Perfect Match Packets */
246     RxFilterCtrl = RFC_UCAST_EN | RFC_BCAST_EN | RFC_PERFECT_EN;
247
248     /* Create the semaphore used ot wake the uIP task. */
249     vSemaphoreCreateBinary( xEMACSemaphore );
250
251     /* Reset all interrupts */
252     IntClear  = 0xFFFF;
253
254     /* Enable receive and transmit mode of MAC Ethernet core */
255     Command  |= (CR_RX_EN | CR_TX_EN);
256     MAC1     |= MAC1_REC_EN;
257   }
258
259   return xReturn;
260 }
261
262
263 // reads a word in little-endian byte order from RX_BUFFER
264
265 unsigned short ReadFrame_EMAC(void)
266 {
267   return (*rptr++);
268 }
269
270 // reads a word in big-endian byte order from RX_FRAME_PORT
271 // (useful to avoid permanent byte-swapping while reading
272 // TCP/IP-data)
273
274 unsigned short ReadFrameBE_EMAC(void)
275 {
276   unsigned short ReturnValue;
277
278   ReturnValue = SwapBytes (*rptr++);
279   return (ReturnValue);
280 }
281
282
283 // copies bytes from frame port to MCU-memory
284 // NOTES: * an odd number of byte may only be transfered
285 //          if the frame is read to the end!
286 //        * MCU-memory MUST start at word-boundary
287
288 void CopyFromFrame_EMAC(void *Dest, unsigned short Size)
289 {
290   unsigned short * piDest;                       // Keil: Pointer added to correct expression
291
292   piDest = Dest;                                 // Keil: Line added
293   while (Size > 1) {
294     *piDest++ = ReadFrame_EMAC();
295     Size -= 2;
296   }
297   
298   if (Size) {                                         // check for leftover byte...
299     *(unsigned char *)piDest = (char)ReadFrame_EMAC();// the LAN-Controller will return 0
300   }                                                   // for the highbyte
301 }
302
303 // does a dummy read on frame-I/O-port
304 // NOTE: only an even number of bytes is read!
305
306 void DummyReadFrame_EMAC(unsigned short Size)    // discards an EVEN number of bytes
307 {                                                // from RX-fifo
308   while (Size > 1) {
309     ReadFrame_EMAC();
310     Size -= 2;
311   }
312 }
313
314 // Reads the length of the received ethernet frame and checks if the 
315 // destination address is a broadcast message or not
316 // returns the frame length
317 unsigned short StartReadFrame(void) {
318   unsigned short RxLen;
319   unsigned int idx;
320
321   idx = RxConsumeIndex;
322   RxLen = (RX_STAT_INFO(idx) & RINFO_SIZE) - 3;
323   rptr = (unsigned short *)RX_DESC_PACKET(idx);
324   return(RxLen);
325 }
326
327 void EndReadFrame(void) {
328   unsigned int idx;
329
330   /* DMA free packet. */
331   idx = RxConsumeIndex;
332
333   if (++idx == NUM_RX_FRAG)
334     idx = 0;
335
336   RxConsumeIndex = idx;
337 }
338
339 unsigned int CheckFrameReceived(void) {             // Packet received ?
340
341   if (RxProduceIndex != RxConsumeIndex)     // more packets received ?
342     return(1);
343   else 
344     return(0);
345 }
346
347 unsigned int uiGetEMACRxData( unsigned char *ucBuffer )
348 {
349 unsigned int uiLen = 0;
350
351     if( RxProduceIndex != RxConsumeIndex )
352     {
353         uiLen = StartReadFrame();
354         CopyFromFrame_EMAC( ucBuffer, uiLen );
355         EndReadFrame();
356     }
357
358     return uiLen;
359 }
360
361 // requests space in EMAC memory for storing an outgoing frame
362
363 void RequestSend(void)
364 {
365   unsigned int idx;
366
367   idx  = TxProduceIndex;
368   tptr = (unsigned short *)TX_DESC_PACKET(idx);
369 }
370
371 // check if ethernet controller is ready to accept the
372 // frame we want to send
373
374 unsigned int Rdy4Tx(void)
375 {
376   return (1);   // the ethernet controller transmits much faster
377 }               // than the CPU can load its buffers
378
379
380 // writes a word in little-endian byte order to TX_BUFFER
381 void WriteFrame_EMAC(unsigned short Data)
382 {
383   *tptr++ = Data;
384 }
385
386 // copies bytes from MCU-memory to frame port
387 // NOTES: * an odd number of byte may only be transfered
388 //          if the frame is written to the end!
389 //        * MCU-memory MUST start at word-boundary
390
391 void CopyToFrame_EMAC(void *Source, unsigned int Size)
392 {
393   unsigned short * piSource;
394
395   piSource = Source;
396   Size = (Size + 1) & 0xFFFE;    // round Size up to next even number
397   while (Size > 0) {
398     WriteFrame_EMAC(*piSource++);
399     Size -= 2;
400   }
401 }
402
403 void DoSend_EMAC(unsigned short FrameSize)
404 {
405   unsigned int idx;
406
407   idx = TxProduceIndex;
408   TX_DESC_CTRL(idx) = FrameSize | TCTRL_LAST;
409   if (++idx == NUM_TX_FRAG) idx = 0;
410   TxProduceIndex = idx;
411 }
412