]> begriffs open source - cmsis-freertos/blob - Demo/RX600_RX63N-RDK_Renesas/RTOSDemo/webserver/EMAC.c
Updated pack to FreeRTOS 10.3.1
[cmsis-freertos] / Demo / RX600_RX63N-RDK_Renesas / RTOSDemo / webserver / EMAC.c
1 /*
2  * FreeRTOS Kernel V10.3.1
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * http://www.FreeRTOS.org
23  * http://aws.amazon.com/freertos
24  *
25  * 1 tab == 4 spaces!
26  */
27
28 /* FreeRTOS includes. */
29 #include "FreeRTOS.h"
30 #include "task.h"
31 #include "semphr.h"
32
33 /* Hardware specific includes. */
34 #include "r_ether.h"
35 #include "phy.h"
36
37 /* uIP includes. */
38 #include "net/uip.h"
39
40 /* The time to wait between attempts to obtain a free buffer. */
41 #define emacBUFFER_WAIT_DELAY_ms                ( 3 / portTICK_PERIOD_MS )
42
43 /* The number of times emacBUFFER_WAIT_DELAY_ms should be waited before giving
44 up on attempting to obtain a free buffer all together. */
45 #define emacBUFFER_WAIT_ATTEMPTS        ( 30 )
46
47 /* The number of Rx descriptors. */
48 #define emacNUM_RX_DESCRIPTORS  8
49
50 /* The number of Tx descriptors.  When using uIP there is not point in having
51 more than two. */
52 #define emacNUM_TX_BUFFERS      2
53
54 /* The total number of EMAC buffers to allocate. */
55 #define emacNUM_BUFFERS         ( emacNUM_RX_DESCRIPTORS + emacNUM_TX_BUFFERS )
56
57 /* The time to wait for the Tx descriptor to become free. */
58 #define emacTX_WAIT_DELAY_ms ( 10 / portTICK_PERIOD_MS )
59
60 /* The total number of times to wait emacTX_WAIT_DELAY_ms for the Tx descriptor to
61 become free. */
62 #define emacTX_WAIT_ATTEMPTS ( 50 )
63
64 /* Only Rx end and Tx end interrupts are used by this driver. */
65 #define emacTX_END_INTERRUPT    ( 1UL << 21UL )
66 #define emacRX_END_INTERRUPT    ( 1UL << 18UL )
67
68 /*-----------------------------------------------------------*/
69
70 /* The buffers and descriptors themselves.  */
71 #pragma section _RX_DESC
72         volatile ethfifo xRxDescriptors[ emacNUM_RX_DESCRIPTORS ];
73 #pragma section _TX_DESC
74         volatile ethfifo xTxDescriptors[ emacNUM_TX_BUFFERS ];
75 #pragma section _ETHERNET_BUFFERS
76         struct
77         {
78                 unsigned long ulAlignmentVariable;
79                 char cBuffer[ emacNUM_BUFFERS ][ UIP_BUFSIZE ];
80         } xEthernetBuffers;
81 #pragma section
82
83
84
85
86 /* Used to indicate which buffers are free and which are in use.  If an index
87 contains 0 then the corresponding buffer in xEthernetBuffers is free, otherwise 
88 the buffer is in use or about to be used. */
89 static unsigned char ucBufferInUse[ emacNUM_BUFFERS ];
90
91 /*-----------------------------------------------------------*/
92
93 /*
94  * Initialise both the Rx and Tx descriptors.
95  */
96 static void prvInitialiseDescriptors( void );
97
98 /*
99  * Return a pointer to a free buffer within xEthernetBuffers.
100  */
101 static unsigned char *prvGetNextBuffer( void );
102
103 /*
104  * Return a buffer to the list of free buffers.
105  */
106 static void prvReturnBuffer( unsigned char *pucBuffer );
107
108 /*
109  * Examine the status of the next Rx FIFO to see if it contains new data.
110  */
111 static unsigned long prvCheckRxFifoStatus( void );
112
113 /*
114  * Setup the microcontroller for communication with the PHY.
115  */
116 static void prvResetMAC( void );
117
118 /*
119  * Configure the Ethernet interface peripherals.
120  */
121 static void prvConfigureEtherCAndEDMAC( void );
122
123 /*
124  * Something has gone wrong with the descriptor usage.  Reset all the buffers
125  * and descriptors.
126  */
127 static void prvResetEverything( void );
128
129 /*-----------------------------------------------------------*/
130
131 /* Points to the Rx descriptor currently in use. */
132 static ethfifo *pxCurrentRxDesc = NULL;
133
134 /* The buffer used by the uIP stack to both receive and send.  This points to
135 one of the Ethernet buffers when its actually in use. */
136 unsigned char *uip_buf = NULL;
137
138 /*-----------------------------------------------------------*/
139
140 void vInitEmac( void )
141 {
142         /* Software reset. */
143         prvResetMAC();
144         
145         /* Set the Rx and Tx descriptors into their initial state. */
146         prvInitialiseDescriptors();
147
148         /* Set the MAC address into the ETHERC */
149         ETHERC.MAHR =   ( ( unsigned long ) configMAC_ADDR0 << 24UL ) | 
150                                         ( ( unsigned long ) configMAC_ADDR1 << 16UL ) | 
151                                         ( ( unsigned long ) configMAC_ADDR2 << 8UL ) | 
152                                         ( unsigned long ) configMAC_ADDR3;
153                                         
154         ETHERC.MALR.BIT.MA = ( ( unsigned long ) configMAC_ADDR4 << 8UL ) |
155                                                  ( unsigned long ) configMAC_ADDR5;
156
157         /* Perform rest of interface hardware configuration. */
158         prvConfigureEtherCAndEDMAC();
159         
160         /* Nothing received yet, so uip_buf points nowhere. */
161         uip_buf = NULL;
162
163         /* Initialize the PHY */
164         configASSERT( phy_init() == R_PHY_OK );
165 }
166 /*-----------------------------------------------------------*/
167
168 void vEMACWrite( void )
169 {
170 long x;
171
172         /* Wait until the second transmission of the last packet has completed. */
173         for( x = 0; x < emacTX_WAIT_ATTEMPTS; x++ )
174         {
175                 if( ( xTxDescriptors[ 1 ].status & ACT ) != 0 )
176                 {
177                         /* Descriptor is still active. */
178                         vTaskDelay( emacTX_WAIT_DELAY_ms );
179                 }
180                 else
181                 {
182                         break;
183                 }
184         }
185         
186         /* Is the descriptor free after waiting for it? */
187         if( ( xTxDescriptors[ 1 ].status & ACT ) != 0 )
188         {
189                 /* Something has gone wrong. */
190                 prvResetEverything();
191         }
192         
193         /* Setup both descriptors to transmit the frame. */
194         xTxDescriptors[ 0 ].buf_p = ( char * ) uip_buf;
195         xTxDescriptors[ 0 ].bufsize = uip_len;  
196         xTxDescriptors[ 1 ].buf_p = ( char * ) uip_buf;
197         xTxDescriptors[ 1 ].bufsize = uip_len;
198
199         /* uip_buf is being sent by the Tx descriptor.  Allocate a new buffer
200         for use by the stack. */
201         uip_buf = prvGetNextBuffer();
202
203         /* Clear previous settings and go. */
204         xTxDescriptors[0].status &= ~( FP1 | FP0 );
205         xTxDescriptors[0].status |= ( FP1 | FP0 | ACT );
206         xTxDescriptors[1].status &= ~( FP1 | FP0 );
207         xTxDescriptors[1].status |= ( FP1 | FP0 | ACT );
208
209         EDMAC.EDTRR.LONG = 0x00000001;
210 }
211 /*-----------------------------------------------------------*/
212
213 unsigned long ulEMACRead( void )
214 {
215 unsigned long ulBytesReceived;
216
217         ulBytesReceived = prvCheckRxFifoStatus();
218
219         if( ulBytesReceived > 0 )
220         {
221                 /* Mark the pxDescriptor buffer as free as uip_buf is going to be set to
222                 the buffer that contains the received data. */
223                 prvReturnBuffer( uip_buf );
224
225                 /* Point uip_buf to the data about ot be processed. */
226                 uip_buf = ( void * ) pxCurrentRxDesc->buf_p;
227                 
228                 /* Allocate a new buffer to the descriptor, as uip_buf is now using it's
229                 old descriptor. */
230                 pxCurrentRxDesc->buf_p = prvGetNextBuffer();
231
232                 /* Prepare the descriptor to go again. */
233                 pxCurrentRxDesc->status &= ~( FP1 | FP0 );
234                 pxCurrentRxDesc->status |= ACT;
235
236                 /* Move onto the next buffer in the ring. */
237                 pxCurrentRxDesc = pxCurrentRxDesc->next;
238                 
239                 if( EDMAC.EDRRR.LONG == 0x00000000L )
240                 {
241                         /* Restart Ethernet if it has stopped */
242                         EDMAC.EDRRR.LONG = 0x00000001L;
243                 }
244         }
245
246         return ulBytesReceived;
247 }
248 /*-----------------------------------------------------------*/
249
250 long lEMACWaitForLink( void )
251 {
252 long lReturn;
253
254         /* Set the link status. */
255         switch( phy_set_autonegotiate() )
256         {
257                 /* Half duplex link */
258                 case PHY_LINK_100H:
259                                                                 ETHERC.ECMR.BIT.DM = 0;
260                                                                 ETHERC.ECMR.BIT.RTM = 1;
261                                                                 lReturn = pdPASS;
262                                                                 break;
263
264                 case PHY_LINK_10H:
265                                                                 ETHERC.ECMR.BIT.DM = 0;
266                                                                 ETHERC.ECMR.BIT.RTM = 0;
267                                                                 lReturn = pdPASS;
268                                                                 break;
269
270
271                 /* Full duplex link */
272                 case PHY_LINK_100F:
273                                                                 ETHERC.ECMR.BIT.DM = 1;
274                                                                 ETHERC.ECMR.BIT.RTM = 1;
275                                                                 lReturn = pdPASS;
276                                                                 break;
277                 
278                 case PHY_LINK_10F:
279                                                                 ETHERC.ECMR.BIT.DM = 1;
280                                                                 ETHERC.ECMR.BIT.RTM = 0;
281                                                                 lReturn = pdPASS;
282                                                                 break;
283
284                 default:
285                                                                 lReturn = pdFAIL;
286                                                                 break;
287         }
288
289         if( lReturn == pdPASS )
290         {
291                 /* Enable receive and transmit. */
292                 ETHERC.ECMR.BIT.RE = 1;
293                 ETHERC.ECMR.BIT.TE = 1;
294
295                 /* Enable EDMAC receive */
296                 EDMAC.EDRRR.LONG = 0x1;
297         }
298         
299         return lReturn;
300 }
301 /*-----------------------------------------------------------*/
302
303 static void prvInitialiseDescriptors( void )
304 {
305 ethfifo *pxDescriptor;
306 long x;
307
308         for( x = 0; x < emacNUM_BUFFERS; x++ )
309         {
310                 /* Ensure none of the buffers are shown as in use at the start. */
311                 ucBufferInUse[ x ] = pdFALSE;
312         }
313
314         /* Initialise the Rx descriptors. */
315         for( x = 0; x < emacNUM_RX_DESCRIPTORS; x++ )
316         {
317                 pxDescriptor = &( xRxDescriptors[ x ] );
318                 pxDescriptor->buf_p = &( xEthernetBuffers.cBuffer[ x ][ 0 ] );
319
320                 pxDescriptor->bufsize = UIP_BUFSIZE;
321                 pxDescriptor->size = 0;
322                 pxDescriptor->status = ACT;
323                 pxDescriptor->next = &xRxDescriptors[ x + 1 ];  
324                 
325                 /* Mark this buffer as in use. */
326                 ucBufferInUse[ x ] = pdTRUE;
327         }
328
329         /* The last descriptor points back to the start. */
330         pxDescriptor->status |= DL;
331         pxDescriptor->next = &xRxDescriptors[ 0 ];
332         
333         /* Initialise the Tx descriptors. */
334         for( x = 0; x < emacNUM_TX_BUFFERS; x++ )
335         {
336                 pxDescriptor = &( xTxDescriptors[ x ] );
337                 
338                 /* A buffer is not allocated to the Tx descriptor until a send is
339                 actually required. */
340                 pxDescriptor->buf_p = NULL;
341
342                 pxDescriptor->bufsize = UIP_BUFSIZE;
343                 pxDescriptor->size = 0;
344                 pxDescriptor->status = 0;
345                 pxDescriptor->next = &xTxDescriptors[ x + 1 ];  
346         }
347
348         /* The last descriptor points back to the start. */
349         pxDescriptor->status |= DL;
350         pxDescriptor->next = &( xTxDescriptors[ 0 ] );
351         
352         /* Use the first Rx descriptor to start with. */
353         pxCurrentRxDesc = &( xRxDescriptors[ 0 ] );
354 }
355 /*-----------------------------------------------------------*/
356
357 static unsigned char *prvGetNextBuffer( void )
358 {
359 long x;
360 unsigned char *pucReturn = NULL;
361 unsigned long ulAttempts = 0;
362
363         while( pucReturn == NULL )
364         {
365                 /* Look through the buffers to find one that is not in use by
366                 anything else. */
367                 for( x = 0; x < emacNUM_BUFFERS; x++ )
368                 {
369                         if( ucBufferInUse[ x ] == pdFALSE )
370                         {
371                                 ucBufferInUse[ x ] = pdTRUE;
372                                 pucReturn = ( unsigned char * ) &( xEthernetBuffers.cBuffer[ x ][ 0 ] );
373                                 break;
374                         }
375                 }
376
377                 /* Was a buffer found? */
378                 if( pucReturn == NULL )
379                 {
380                         ulAttempts++;
381
382                         if( ulAttempts >= emacBUFFER_WAIT_ATTEMPTS )
383                         {
384                                 break;
385                         }
386
387                         /* Wait then look again. */
388                         vTaskDelay( emacBUFFER_WAIT_DELAY_ms );
389                 }
390         }
391
392         return pucReturn;
393 }
394 /*-----------------------------------------------------------*/
395
396 static void prvReturnBuffer( unsigned char *pucBuffer )
397 {
398 unsigned long ul;
399
400         /* Return a buffer to the pool of free buffers. */
401         for( ul = 0; ul < emacNUM_BUFFERS; ul++ )
402         {
403                 if( &( xEthernetBuffers.cBuffer[ ul ][ 0 ] ) == ( void * ) pucBuffer )
404                 {
405                         ucBufferInUse[ ul ] = pdFALSE;
406                         break;
407                 }
408         }
409 }
410 /*-----------------------------------------------------------*/
411
412 static void prvResetEverything( void )
413 {
414         /* Temporary code just to see if this gets called.  This function has not
415         been implemented. */
416         portDISABLE_INTERRUPTS();
417         for( ;; );
418 }
419 /*-----------------------------------------------------------*/
420
421 static unsigned long prvCheckRxFifoStatus( void )
422 {
423 unsigned long ulReturn = 0;
424
425         if( ( pxCurrentRxDesc->status & ACT ) != 0 )
426         {
427                 /* Current descriptor is still active. */
428         }
429         else if( ( pxCurrentRxDesc->status & FE ) != 0 )
430         {
431                 /* Frame error.  Clear the error. */
432                 pxCurrentRxDesc->status &= ~( FP1 | FP0 | FE );
433                 pxCurrentRxDesc->status &= ~( RMAF | RRF | RTLF | RTSF | PRE | CERF );
434                 pxCurrentRxDesc->status |= ACT;
435                 pxCurrentRxDesc = pxCurrentRxDesc->next;
436
437                 if( EDMAC.EDRRR.LONG == 0x00000000UL )
438                 {
439                         /* Restart Ethernet if it has stopped. */
440                         EDMAC.EDRRR.LONG = 0x00000001UL;
441                 }       
442         }
443         else
444         {
445                 /* The descriptor contains a frame.  Because of the size of the buffers
446                 the frame should always be complete. */
447                 if( ( pxCurrentRxDesc->status & FP0 ) == FP0 )
448                 {
449                         ulReturn = pxCurrentRxDesc->size;
450                 }
451                 else
452                 {
453                         /* Do not expect to get here. */
454                         prvResetEverything();
455                 }
456         }
457         
458         return ulReturn;
459 }
460 /*-----------------------------------------------------------*/
461
462 static void prvResetMAC( void )
463 {
464         /* Ensure the EtherC and EDMAC are enabled. */
465         SYSTEM.MSTPCRB.BIT.MSTPB15 = 0;
466         vTaskDelay( 100 / portTICK_PERIOD_MS );
467         
468         EDMAC.EDMR.BIT.SWR = 1; 
469         
470         /* Crude wait for reset to complete. */
471         vTaskDelay( 500 / portTICK_PERIOD_MS ); 
472 }
473 /*-----------------------------------------------------------*/
474
475 static void prvConfigureEtherCAndEDMAC( void )
476 {
477         /* Initialisation code taken from Renesas example project. */
478         
479         /* TODO:    Check   bit 5   */
480         ETHERC.ECSR.LONG = 0x00000037;                          /* Clear all ETHERC statuS BFR, PSRTO, LCHNG, MPD, ICD */
481
482         /* Set the EDMAC interrupt priority. */
483         _IPR( _ETHER_EINT ) = configKERNEL_INTERRUPT_PRIORITY;
484
485         /* TODO:    Check   bit 5   */
486         /* Enable interrupts of interest only. */
487         EDMAC.EESIPR.LONG = emacTX_END_INTERRUPT | emacRX_END_INTERRUPT;
488         ETHERC.RFLR.LONG = 1518;                                        /* Ether payload is 1500+ CRC */
489         ETHERC.IPGR.LONG = 0x00000014;                          /* Intergap is 96-bit time */
490
491         /* EDMAC */
492         EDMAC.EESR.LONG = 0x47FF0F9F;                           /* Clear all ETHERC and EDMAC status bits */
493         #ifdef __LIT
494                 EDMAC.EDMR.BIT.DE = 1;
495         #endif
496         EDMAC.RDLAR = ( void * ) pxCurrentRxDesc;       /* Initialaize Rx Descriptor List Address */
497         EDMAC.TDLAR = &( xTxDescriptors[ 0 ] );         /* Initialaize Tx Descriptor List Address */
498         EDMAC.TRSCER.LONG = 0x00000000;                         /* Copy-back status is RFE & TFE only   */
499         EDMAC.TFTR.LONG = 0x00000000;                           /* Threshold of Tx_FIFO */
500         EDMAC.FDR.LONG = 0x00000000;                            /* Transmit fifo & receive fifo is 256 bytes */
501         EDMAC.RMCR.LONG = 0x00000003;                           /* Receive function is normal mode(continued) */
502         ETHERC.ECMR.BIT.PRM = 0;                                        /* Ensure promiscuous mode is off. */
503                 
504         /* Enable the interrupt... */
505         _IEN( _ETHER_EINT ) = 1;        
506 }
507 /*-----------------------------------------------------------*/
508
509 #pragma interrupt ( vEMAC_ISR_Handler( vect = VECT_ETHER_EINT, enable ) )
510 void vEMAC_ISR_Handler( void )
511 {
512 unsigned long ul = EDMAC.EESR.LONG;
513 long lHigherPriorityTaskWoken = pdFALSE;
514 extern QueueHandle_t xEMACEventQueue;
515 const unsigned long ulRxEvent = uipETHERNET_RX_EVENT;
516
517         /* Has a Tx end occurred? */
518         if( ul & emacTX_END_INTERRUPT )
519         {
520                 /* Only return the buffer to the pool once both Txes have completed. */
521                 prvReturnBuffer( ( void * ) xTxDescriptors[ 0 ].buf_p );
522                 EDMAC.EESR.LONG = emacTX_END_INTERRUPT;
523         }
524
525         /* Has an Rx end occurred? */
526         if( ul & emacRX_END_INTERRUPT )
527         {
528                 /* Make sure the Ethernet task is not blocked waiting for a packet. */
529                 xQueueSendFromISR( xEMACEventQueue, &ulRxEvent, &lHigherPriorityTaskWoken );
530                 portYIELD_FROM_ISR( lHigherPriorityTaskWoken );
531                 EDMAC.EESR.LONG = emacRX_END_INTERRUPT;
532         }
533 }
534