]> git.sur5r.net Git - freertos/blob - Demo/RX600_RX62N-RDK_Renesas/RTOSDemo/webserver/EMAC.c
2824ca066f87757b835afb7c14579d1aa474d0fb
[freertos] / Demo / RX600_RX62N-RDK_Renesas / RTOSDemo / webserver / EMAC.c
1 /*\r
2     FreeRTOS V6.0.5 - Copyright (C) 2010 Real Time Engineers Ltd.\r
3 \r
4     ***************************************************************************\r
5     *                                                                         *\r
6     * If you are:                                                             *\r
7     *                                                                         *\r
8     *    + New to FreeRTOS,                                                   *\r
9     *    + Wanting to learn FreeRTOS or multitasking in general quickly       *\r
10     *    + Looking for basic training,                                        *\r
11     *    + Wanting to improve your FreeRTOS skills and productivity           *\r
12     *                                                                         *\r
13     * then take a look at the FreeRTOS eBook                                  *\r
14     *                                                                         *\r
15     *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *\r
16     *                  http://www.FreeRTOS.org/Documentation                  *\r
17     *                                                                         *\r
18     * A pdf reference manual is also available.  Both are usually delivered   *\r
19     * to your inbox within 20 minutes to two hours when purchased between 8am *\r
20     * and 8pm GMT (although please allow up to 24 hours in case of            *\r
21     * exceptional circumstances).  Thank you for your support!                *\r
22     *                                                                         *\r
23     ***************************************************************************\r
24 \r
25     This file is part of the FreeRTOS distribution.\r
26 \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 exception to the GPL is included to allow you to distribute\r
31     a combined work that includes FreeRTOS without being obliged to provide the\r
32     source code for proprietary components outside of the FreeRTOS kernel.\r
33     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT\r
34     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
35     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
40     FreeRTOS WEB site.\r
41 \r
42     1 tab == 4 spaces!\r
43 \r
44     http://www.FreeRTOS.org - Documentation, latest information, license and\r
45     contact details.\r
46 \r
47     http://www.SafeRTOS.com - A version that is certified for use in safety\r
48     critical systems.\r
49 \r
50     http://www.OpenRTOS.com - Commercial support, development, porting,\r
51     licensing and training services.\r
52 */\r
53 \r
54 /* Hardware specific includes. */\r
55 #include "iodefine.h"\r
56 #include "typedefine.h"\r
57 #include "r_ether.h"\r
58 #include "phy.h"\r
59 \r
60 /* FreeRTOS includes. */\r
61 #include "FreeRTOS.h"\r
62 #include "task.h"\r
63 #include "semphr.h"\r
64 \r
65 /* uIP includes. */\r
66 #include "net/uip.h"\r
67 \r
68 /* The time to wait between attempts to obtain a free buffer. */\r
69 #define emacBUFFER_WAIT_DELAY_ms                ( 3 / portTICK_RATE_MS )\r
70 \r
71 /* The number of times emacBUFFER_WAIT_DELAY_ms should be waited before giving\r
72 up on attempting to obtain a free buffer all together. */\r
73 #define emacBUFFER_WAIT_ATTEMPTS        ( 30 )\r
74 \r
75 /* The number of Rx descriptors. */\r
76 #define emacNUM_RX_DESCRIPTORS  3\r
77 \r
78 /* The number of Tx descriptors.  When using uIP there is not point in having\r
79 more than two. */\r
80 #define emacNUM_TX_BUFFERS      2\r
81 \r
82 /* The total number of EMAC buffers to allocate. */\r
83 #define emacNUM_BUFFERS         ( emacNUM_RX_DESCRIPTORS + emacNUM_TX_BUFFERS )\r
84 \r
85 /* The time to wait for the Tx descriptor to become free. */\r
86 #define emacTX_WAIT_DELAY_ms ( 10 / portTICK_RATE_MS )\r
87 \r
88 /* The total number of times to wait emacTX_WAIT_DELAY_ms for the Tx descriptor to\r
89 become free. */\r
90 #define emacTX_WAIT_ATTEMPTS ( 5 )\r
91 \r
92 /* Only Rx end and Tx end interrupts are used by this driver. */\r
93 #define emacTX_END_INTERRUPT    ( 1UL << 21UL )\r
94 #define emacRX_END_INTERRUPT    ( 1UL << 18UL )\r
95 \r
96 /*-----------------------------------------------------------*/\r
97 \r
98 /* The buffers and descriptors themselves. */\r
99 static union x_RX_Desc\r
100 {\r
101         unsigned long long ullAlignmentVariable;\r
102         ethfifo xDescriptorArray[ emacNUM_RX_DESCRIPTORS ];\r
103 } xRxDescriptors;\r
104 \r
105 static union x_TX_Desc\r
106 {\r
107         unsigned long long ullAlignmentVariable;\r
108         ethfifo xDescriptorArray[ emacNUM_TX_BUFFERS ];\r
109 } xTxDescriptors;\r
110 \r
111 static union x_ETH_Buffers\r
112 {\r
113         unsigned long long ullAlignmentVariable;\r
114         char xDataBuffers[ emacNUM_BUFFERS ][ UIP_BUFSIZE ];\r
115 } xEthernetBuffers;\r
116 \r
117 \r
118 /* Used to indicate which buffers are free and which are in use.  If an index\r
119 contains 0 then the corresponding buffer in xEthernetBuffers.xDataBuffers is free, otherwise \r
120 the buffer is in use or about to be used. */\r
121 static unsigned char ucBufferInUse[ emacNUM_BUFFERS ];\r
122 \r
123 /*-----------------------------------------------------------*/\r
124 \r
125 /*\r
126  * Initialise both the Rx and Tx descriptors.\r
127  */\r
128 static void prvInitialiseDescriptors( void );\r
129 \r
130 /*\r
131  * Return a pointer to a free buffer within xEthernetBuffers.xDataBuffers.\r
132  */\r
133 static unsigned char *prvGetNextBuffer( void );\r
134 \r
135 /*\r
136  * Return a buffer to the list of free buffers.\r
137  */\r
138 static void prvReturnBuffer( unsigned char *pucBuffer );\r
139 \r
140 /*\r
141  * Examine the status of the next Rx FIFO to see if it contains new data.\r
142  */\r
143 static unsigned long prvCheckRxFifoStatus( void );\r
144 \r
145 /*\r
146  * Setup the microcontroller for communication with the PHY.\r
147  */\r
148 static void prvResetMAC( void );\r
149 \r
150 /*\r
151  * Configure the Ethernet interface peripherals.\r
152  */\r
153 static void prvConfigureEtherCAndEDMAC( void );\r
154 \r
155 /*\r
156  * Something has gone wrong with the descriptor usage.  Reset all the buffers\r
157  * and descriptors.\r
158  */\r
159 static void prvResetEverything( void );\r
160 \r
161 /*-----------------------------------------------------------*/\r
162 \r
163 /* Points to the Rx descriptor currently in use. */\r
164 static ethfifo *xCurrentRxDesc = NULL;\r
165 \r
166 /* The buffer used by the uIP stack to both receive and send.  This points to\r
167 one of the Ethernet buffers when its actually in use. */\r
168 unsigned char *uip_buf = NULL;\r
169 \r
170 /*-----------------------------------------------------------*/\r
171 \r
172 void vInitEmac( void )\r
173 {\r
174         /* Software reset. */\r
175         prvResetMAC();\r
176         \r
177         /* Set the Rx and Tx descriptors into their initial state. */\r
178         prvInitialiseDescriptors();\r
179 \r
180         /* Set the MAC address into the ETHERC */\r
181         ETHERC.MAHR =   ( ( unsigned long ) configMAC_ADDR0 << 24UL ) | \r
182                                         ( ( unsigned long ) configMAC_ADDR1 << 16UL ) | \r
183                                         ( ( unsigned long ) configMAC_ADDR2 << 8UL ) | \r
184                                         ( unsigned long ) configMAC_ADDR3;\r
185                                         \r
186         ETHERC.MALR.BIT.MA = ( ( unsigned long ) configMAC_ADDR4 << 8UL ) |\r
187                                                  ( unsigned long ) configMAC_ADDR5;\r
188 \r
189         /* Perform rest of interface hardware configuration. */\r
190         prvConfigureEtherCAndEDMAC();\r
191         \r
192         /* Nothing received yet, so uip_buf points nowhere. */\r
193         uip_buf = NULL;\r
194 \r
195         /* Initialize the PHY */\r
196         phy_init();\r
197 }\r
198 /*-----------------------------------------------------------*/\r
199 \r
200 void vEMACWrite( void )\r
201 {\r
202 long x;\r
203 \r
204         /* Wait until the second transmission of the last packet has completed. */\r
205         for( x = 0; x < emacTX_WAIT_ATTEMPTS; x++ )\r
206         {\r
207                 if( ( xTxDescriptors.xDescriptorArray[ 1 ].status & ACT ) != 0 )\r
208                 {\r
209                         /* Descriptor is still active. */\r
210                         vTaskDelay( emacTX_WAIT_DELAY_ms );\r
211                 }\r
212                 else\r
213                 {\r
214                         break;\r
215                 }\r
216         }\r
217         \r
218         /* Is the descriptor free after waiting for it? */\r
219         if( ( xTxDescriptors.xDescriptorArray[ 1 ].status & ACT ) != 0 )\r
220         {\r
221                 /* Something has gone wrong. */\r
222                 prvResetEverything();\r
223         }\r
224         \r
225         /* Setup both descriptors to transmit the frame. */\r
226         xTxDescriptors.xDescriptorArray[ 0 ].buf_p = ( char * ) uip_buf;\r
227         xTxDescriptors.xDescriptorArray[ 0 ].bufsize = uip_len; \r
228         xTxDescriptors.xDescriptorArray[ 1 ].buf_p = ( char * ) uip_buf;\r
229         xTxDescriptors.xDescriptorArray[ 1 ].bufsize = uip_len;\r
230 \r
231         /* uip_buf is being sent by the Tx descriptor.  Allocate a new buffer\r
232         for use by the stack. */\r
233         uip_buf = prvGetNextBuffer();\r
234 \r
235         /* Clear previous settings and go. */\r
236         xTxDescriptors.xDescriptorArray[0].status &= ~( FP1 | FP0 );\r
237         xTxDescriptors.xDescriptorArray[0].status |= ( FP1 | FP0 | ACT );\r
238         xTxDescriptors.xDescriptorArray[1].status &= ~( FP1 | FP0 );\r
239         xTxDescriptors.xDescriptorArray[1].status |= ( FP1 | FP0 | ACT );\r
240 \r
241         EDMAC.EDTRR.LONG = 0x00000001;\r
242 }\r
243 /*-----------------------------------------------------------*/\r
244 \r
245 unsigned long ulEMACRead( void )\r
246 {\r
247 unsigned long ulBytesReceived;\r
248 \r
249         ulBytesReceived = prvCheckRxFifoStatus();\r
250 \r
251         if( ulBytesReceived > 0 )\r
252         {\r
253                 xCurrentRxDesc->status &= ~( FP1 | FP0 );\r
254                 xCurrentRxDesc->status |= ACT;                  \r
255 \r
256                 if( EDMAC.EDRRR.LONG == 0x00000000L )\r
257                 {\r
258                         /* Restart Ethernet if it has stopped */\r
259                         EDMAC.EDRRR.LONG = 0x00000001L;\r
260                 }\r
261 \r
262                 /* Mark the pxDescriptor buffer as free as uip_buf is going to be set to\r
263                 the buffer that contains the received data. */\r
264                 prvReturnBuffer( uip_buf );\r
265                 \r
266                 uip_buf = ( void * ) xCurrentRxDesc->buf_p;\r
267 \r
268                 /* Move onto the next buffer in the ring. */\r
269                 xCurrentRxDesc = xCurrentRxDesc->next;\r
270         }\r
271 \r
272         return ulBytesReceived;\r
273 }\r
274 /*-----------------------------------------------------------*/\r
275 \r
276 long lEMACWaitForLink( void )\r
277 {\r
278 long lReturn;\r
279 \r
280         /* Set the link status. */\r
281         switch( phy_set_autonegotiate() )\r
282         {\r
283                 /* Half duplex link */\r
284                 case PHY_LINK_100H:\r
285                 case PHY_LINK_10H:\r
286                                                                 ETHERC.ECMR.BIT.DM = 0;\r
287                                                                 lReturn = pdPASS;\r
288                                                                 break;\r
289 \r
290                 /* Full duplex link */\r
291                 case PHY_LINK_100F:\r
292                 case PHY_LINK_10F:\r
293                                                                 ETHERC.ECMR.BIT.DM = 1;\r
294                                                                 lReturn = pdPASS;\r
295                                                                 break;\r
296 \r
297                 default:\r
298                                                                 lReturn = pdFAIL;\r
299                                                                 break;\r
300         }\r
301 \r
302         if( lReturn == pdPASS )\r
303         {\r
304                 /* Enable receive and transmit. */\r
305                 ETHERC.ECMR.BIT.RE = 1;\r
306                 ETHERC.ECMR.BIT.TE = 1;\r
307 \r
308                 /* Enable EDMAC receive */\r
309                 EDMAC.EDRRR.LONG = 0x1;\r
310         }\r
311         \r
312         return lReturn;\r
313 }\r
314 /*-----------------------------------------------------------*/\r
315 \r
316 static void prvInitialiseDescriptors( void )\r
317 {\r
318 ethfifo *pxDescriptor;\r
319 long x;\r
320 \r
321         for( x = 0; x < emacNUM_BUFFERS; x++ )\r
322         {\r
323                 /* Ensure none of the buffers are shown as in use at the start. */\r
324                 ucBufferInUse[ x ] = pdFALSE;\r
325         }\r
326 \r
327         /* Initialise the Rx descriptors. */\r
328         for( x = 0; x < emacNUM_RX_DESCRIPTORS; x++ )\r
329         {\r
330                 pxDescriptor = &( xRxDescriptors.xDescriptorArray[ x ] );\r
331                 pxDescriptor->buf_p = &( xEthernetBuffers.xDataBuffers[ x ][ 0 ] );\r
332 \r
333                 pxDescriptor->bufsize = UIP_BUFSIZE;\r
334                 pxDescriptor->size = 0;\r
335                 pxDescriptor->status = ACT;\r
336                 pxDescriptor->next = &xRxDescriptors.xDescriptorArray[ x + 1 ]; \r
337                 \r
338                 /* Mark this buffer as in use. */\r
339                 ucBufferInUse[ x ] = pdTRUE;\r
340         }\r
341 \r
342         /* The last descriptor points back to the start. */\r
343         pxDescriptor->status |= DL;\r
344         pxDescriptor->next = &xRxDescriptors.xDescriptorArray[ 0 ];\r
345         \r
346         /* Initialise the Tx descriptors. */\r
347         for( x = 0; x < emacNUM_TX_BUFFERS; x++ )\r
348         {\r
349                 pxDescriptor = &( xTxDescriptors.xDescriptorArray[ x ] );\r
350                 \r
351                 /* A buffer is not allocated to the Tx descriptor until a send is\r
352                 actually required. */\r
353                 pxDescriptor->buf_p = NULL;\r
354 \r
355                 pxDescriptor->bufsize = UIP_BUFSIZE;\r
356                 pxDescriptor->size = 0;\r
357                 pxDescriptor->status = 0;\r
358                 pxDescriptor->next = &xTxDescriptors.xDescriptorArray[ x + 1 ]; \r
359         }\r
360 \r
361         /* The last descriptor points back to the start. */\r
362         pxDescriptor->status |= DL;\r
363         pxDescriptor->next = &( xTxDescriptors.xDescriptorArray[ 0 ] );\r
364         \r
365         /* Use the first Rx descriptor to start with. */\r
366         xCurrentRxDesc = &( xRxDescriptors.xDescriptorArray[ 0 ] );\r
367 }\r
368 /*-----------------------------------------------------------*/\r
369 \r
370 static unsigned char *prvGetNextBuffer( void )\r
371 {\r
372 long x;\r
373 unsigned char *pucReturn = NULL;\r
374 unsigned long ulAttempts = 0;\r
375 \r
376         while( pucReturn == NULL )\r
377         {\r
378                 /* Look through the buffers to find one that is not in use by\r
379                 anything else. */\r
380                 for( x = 0; x < emacNUM_BUFFERS; x++ )\r
381                 {\r
382                         if( ucBufferInUse[ x ] == pdFALSE )\r
383                         {\r
384                                 ucBufferInUse[ x ] = pdTRUE;\r
385                                 pucReturn = ( unsigned char * ) &( xEthernetBuffers.xDataBuffers[ x ][ 0 ] );\r
386                                 break;\r
387                         }\r
388                 }\r
389 \r
390                 /* Was a buffer found? */\r
391                 if( pucReturn == NULL )\r
392                 {\r
393                         ulAttempts++;\r
394 \r
395                         if( ulAttempts >= emacBUFFER_WAIT_ATTEMPTS )\r
396                         {\r
397                                 break;\r
398                         }\r
399 \r
400                         /* Wait then look again. */\r
401                         vTaskDelay( emacBUFFER_WAIT_DELAY_ms );\r
402                 }\r
403         }\r
404 \r
405         return pucReturn;\r
406 }\r
407 /*-----------------------------------------------------------*/\r
408 \r
409 static void prvReturnBuffer( unsigned char *pucBuffer )\r
410 {\r
411 unsigned long ul;\r
412 \r
413         /* Return a buffer to the pool of free buffers. */\r
414         for( ul = 0; ul < emacNUM_BUFFERS; ul++ )\r
415         {\r
416                 if( &( xEthernetBuffers.xDataBuffers[ ul ][ 0 ] ) == ( void * ) pucBuffer )\r
417                 {\r
418                         ucBufferInUse[ ul ] = pdFALSE;\r
419                         break;\r
420                 }\r
421         }\r
422 }\r
423 /*-----------------------------------------------------------*/\r
424 \r
425 static void prvResetEverything( void )\r
426 {\r
427         /* Temporary code just to see if this gets called.  This function has not\r
428         been implemented. */\r
429         portDISABLE_INTERRUPTS();\r
430         for( ;; );\r
431 }\r
432 /*-----------------------------------------------------------*/\r
433 \r
434 static unsigned long prvCheckRxFifoStatus( void )\r
435 {\r
436 unsigned long ulReturn = 0;\r
437 \r
438         if( ( xCurrentRxDesc->status & ACT ) != 0 )\r
439         {\r
440                 /* Current descriptor is still active. */\r
441         }\r
442         else if( ( xCurrentRxDesc->status & FE ) != 0 )\r
443         {\r
444                 /* Frame error.  Clear the error. */\r
445                 xCurrentRxDesc->status &= ~( FP1 | FP0 | FE );\r
446                 xCurrentRxDesc->status &= ~( RMAF | RRF | RTLF | RTSF | PRE | CERF );\r
447                 xCurrentRxDesc->status |= ACT;\r
448                 xCurrentRxDesc = xCurrentRxDesc->next;\r
449 \r
450                 if( EDMAC.EDRRR.LONG == 0x00000000UL )\r
451                 {\r
452                         /* Restart Ethernet if it has stopped. */\r
453                         EDMAC.EDRRR.LONG = 0x00000001UL;\r
454                 }       \r
455         }\r
456         else\r
457         {\r
458                 /* The descriptor contains a frame.  Because of the size of the buffers\r
459                 the frame should always be complete. */\r
460                 if( (xCurrentRxDesc->status & FP0) == FP0 )\r
461                 {\r
462                         ulReturn = xCurrentRxDesc->size;\r
463                 }\r
464                 else\r
465                 {\r
466                         /* Do not expect to get here. */\r
467                         prvResetEverything();\r
468                 }\r
469         }\r
470         \r
471         return ulReturn;\r
472 }\r
473 /*-----------------------------------------------------------*/\r
474 \r
475 static void prvResetMAC( void )\r
476 {\r
477         /* Ensure the EtherC and EDMAC are enabled. */\r
478         SYSTEM.MSTPCRB.BIT.MSTPB15 = 0;\r
479         vTaskDelay( 100 / portTICK_RATE_MS );\r
480         \r
481         EDMAC.EDMR.BIT.SWR = 1; \r
482         \r
483         /* Crude wait for reset to complete. */\r
484         vTaskDelay( 500 / portTICK_RATE_MS );   \r
485 }\r
486 /*-----------------------------------------------------------*/\r
487 \r
488 static void prvConfigureEtherCAndEDMAC( void )\r
489 {\r
490         /* Initialisation code taken from Renesas example project. */\r
491         \r
492         /* TODO:    Check   bit 5   */\r
493         ETHERC.ECSR.LONG = 0x00000037;                          /* Clear all ETHERC statuS BFR, PSRTO, LCHNG, MPD, ICD */\r
494 \r
495         /* Set the EDMAC interrupt priority. */\r
496         _IPR( _ETHER_EINT ) = configKERNEL_INTERRUPT_PRIORITY;\r
497 \r
498         /* TODO:    Check   bit 5   */\r
499         /* Enable interrupts of interest only. */\r
500         EDMAC.EESIPR.LONG = emacTX_END_INTERRUPT | emacRX_END_INTERRUPT;\r
501         ETHERC.RFLR.LONG = 1518;                                        /* Ether payload is 1500+ CRC */\r
502         ETHERC.IPGR.LONG = 0x00000014;                          /* Intergap is 96-bit time */\r
503 \r
504         /* EDMAC */\r
505         EDMAC.EESR.LONG = 0x47FF0F9F;                           /* Clear all ETHERC and EDMAC status bits */\r
506         EDMAC.RDLAR = ( void * ) xCurrentRxDesc;        /* Initialaize Rx Descriptor List Address */\r
507         EDMAC.TDLAR = &( xTxDescriptors.xDescriptorArray[ 0 ] );                /* Initialaize Tx Descriptor List Address */\r
508         EDMAC.TRSCER.LONG = 0x00000000;                         /* Copy-back status is RFE & TFE only   */\r
509         EDMAC.TFTR.LONG = 0x00000000;                           /* Threshold of Tx_FIFO */\r
510         EDMAC.FDR.LONG = 0x00000000;                            /* Transmit fifo & receive fifo is 256 bytes */\r
511         EDMAC.RMCR.LONG = 0x00000003;                           /* Receive function is normal mode(continued) */\r
512 }\r
513 /*-----------------------------------------------------------*/\r
514 \r
515 #pragma interrupt ( vEMAC_ISR_Handler( vect = VECT_ETHER_EINT, enable ) )\r
516 void vEMAC_ISR_Handler( void )\r
517 {\r
518 unsigned long ul = EDMAC.EESR.LONG;\r
519 long lHigherPriorityTaskWoken = pdFALSE;\r
520 extern xSemaphoreHandle xEMACSemaphore;\r
521 static long ulTxEndInts = 0;\r
522 \r
523         /* Has a Tx end occurred? */\r
524         if( ul & emacTX_END_INTERRUPT )\r
525         {\r
526                 ++ulTxEndInts;\r
527                 if( ulTxEndInts >= 2 )\r
528                 {\r
529                         /* Only return the buffer to the pool once both Txes have completed. */\r
530                         prvReturnBuffer( ( void * ) xTxDescriptors.xDescriptorArray[ 0 ].buf_p );\r
531                         ulTxEndInts = 0;\r
532                 }\r
533                 EDMAC.EESR.LONG = emacTX_END_INTERRUPT;\r
534         }\r
535 \r
536         /* Has an Rx end occurred? */\r
537         if( ul & emacRX_END_INTERRUPT )\r
538         {\r
539                 /* Make sure the Ethernet task is not blocked waiting for a packet. */\r
540                 xSemaphoreGiveFromISR( xEMACSemaphore, &lHigherPriorityTaskWoken );\r
541                 portYIELD_FROM_ISR( lHigherPriorityTaskWoken );\r
542                 EDMAC.EESR.LONG = emacRX_END_INTERRUPT;\r
543         }\r
544 }\r