2 * FreeRTOS Kernel V10.3.1
3 * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
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:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
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.
22 * http://www.FreeRTOS.org
23 * http://aws.amazon.com/freertos
28 /* FreeRTOS includes. */
33 /* Hardware specific includes. */
40 /* The time to wait between attempts to obtain a free buffer. */
41 #define emacBUFFER_WAIT_DELAY_ms ( 3 / portTICK_PERIOD_MS )
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 )
47 /* The number of Rx descriptors. */
48 #define emacNUM_RX_DESCRIPTORS 8
50 /* The number of Tx descriptors. When using uIP there is not point in having
52 #define emacNUM_TX_BUFFERS 2
54 /* The total number of EMAC buffers to allocate. */
55 #define emacNUM_BUFFERS ( emacNUM_RX_DESCRIPTORS + emacNUM_TX_BUFFERS )
57 /* The time to wait for the Tx descriptor to become free. */
58 #define emacTX_WAIT_DELAY_ms ( 10 / portTICK_PERIOD_MS )
60 /* The total number of times to wait emacTX_WAIT_DELAY_ms for the Tx descriptor to
62 #define emacTX_WAIT_ATTEMPTS ( 50 )
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 )
68 /*-----------------------------------------------------------*/
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
78 unsigned long ulAlignmentVariable;
79 char cBuffer[ emacNUM_BUFFERS ][ UIP_BUFSIZE ];
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 ];
91 /*-----------------------------------------------------------*/
94 * Initialise both the Rx and Tx descriptors.
96 static void prvInitialiseDescriptors( void );
99 * Return a pointer to a free buffer within xEthernetBuffers.
101 static unsigned char *prvGetNextBuffer( void );
104 * Return a buffer to the list of free buffers.
106 static void prvReturnBuffer( unsigned char *pucBuffer );
109 * Examine the status of the next Rx FIFO to see if it contains new data.
111 static unsigned long prvCheckRxFifoStatus( void );
114 * Setup the microcontroller for communication with the PHY.
116 static void prvResetMAC( void );
119 * Configure the Ethernet interface peripherals.
121 static void prvConfigureEtherCAndEDMAC( void );
124 * Something has gone wrong with the descriptor usage. Reset all the buffers
127 static void prvResetEverything( void );
129 /*-----------------------------------------------------------*/
131 /* Points to the Rx descriptor currently in use. */
132 static ethfifo *pxCurrentRxDesc = NULL;
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;
138 /*-----------------------------------------------------------*/
140 void vInitEmac( void )
142 /* Software reset. */
145 /* Set the Rx and Tx descriptors into their initial state. */
146 prvInitialiseDescriptors();
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;
154 ETHERC.MALR.BIT.MA = ( ( unsigned long ) configMAC_ADDR4 << 8UL ) |
155 ( unsigned long ) configMAC_ADDR5;
157 /* Perform rest of interface hardware configuration. */
158 prvConfigureEtherCAndEDMAC();
160 /* Nothing received yet, so uip_buf points nowhere. */
163 /* Initialize the PHY */
164 configASSERT( phy_init() == R_PHY_OK );
166 /*-----------------------------------------------------------*/
168 void vEMACWrite( void )
172 /* Wait until the second transmission of the last packet has completed. */
173 for( x = 0; x < emacTX_WAIT_ATTEMPTS; x++ )
175 if( ( xTxDescriptors[ 1 ].status & ACT ) != 0 )
177 /* Descriptor is still active. */
178 vTaskDelay( emacTX_WAIT_DELAY_ms );
186 /* Is the descriptor free after waiting for it? */
187 if( ( xTxDescriptors[ 1 ].status & ACT ) != 0 )
189 /* Something has gone wrong. */
190 prvResetEverything();
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;
199 /* uip_buf is being sent by the Tx descriptor. Allocate a new buffer
200 for use by the stack. */
201 uip_buf = prvGetNextBuffer();
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 );
209 EDMAC.EDTRR.LONG = 0x00000001;
211 /*-----------------------------------------------------------*/
213 unsigned long ulEMACRead( void )
215 unsigned long ulBytesReceived;
217 ulBytesReceived = prvCheckRxFifoStatus();
219 if( ulBytesReceived > 0 )
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 );
225 /* Point uip_buf to the data about ot be processed. */
226 uip_buf = ( void * ) pxCurrentRxDesc->buf_p;
228 /* Allocate a new buffer to the descriptor, as uip_buf is now using it's
230 pxCurrentRxDesc->buf_p = prvGetNextBuffer();
232 /* Prepare the descriptor to go again. */
233 pxCurrentRxDesc->status &= ~( FP1 | FP0 );
234 pxCurrentRxDesc->status |= ACT;
236 /* Move onto the next buffer in the ring. */
237 pxCurrentRxDesc = pxCurrentRxDesc->next;
239 if( EDMAC.EDRRR.LONG == 0x00000000L )
241 /* Restart Ethernet if it has stopped */
242 EDMAC.EDRRR.LONG = 0x00000001L;
246 return ulBytesReceived;
248 /*-----------------------------------------------------------*/
250 long lEMACWaitForLink( void )
254 /* Set the link status. */
255 switch( phy_set_autonegotiate() )
257 /* Half duplex link */
259 ETHERC.ECMR.BIT.DM = 0;
260 ETHERC.ECMR.BIT.RTM = 1;
265 ETHERC.ECMR.BIT.DM = 0;
266 ETHERC.ECMR.BIT.RTM = 0;
271 /* Full duplex link */
273 ETHERC.ECMR.BIT.DM = 1;
274 ETHERC.ECMR.BIT.RTM = 1;
279 ETHERC.ECMR.BIT.DM = 1;
280 ETHERC.ECMR.BIT.RTM = 0;
289 if( lReturn == pdPASS )
291 /* Enable receive and transmit. */
292 ETHERC.ECMR.BIT.RE = 1;
293 ETHERC.ECMR.BIT.TE = 1;
295 /* Enable EDMAC receive */
296 EDMAC.EDRRR.LONG = 0x1;
301 /*-----------------------------------------------------------*/
303 static void prvInitialiseDescriptors( void )
305 ethfifo *pxDescriptor;
308 for( x = 0; x < emacNUM_BUFFERS; x++ )
310 /* Ensure none of the buffers are shown as in use at the start. */
311 ucBufferInUse[ x ] = pdFALSE;
314 /* Initialise the Rx descriptors. */
315 for( x = 0; x < emacNUM_RX_DESCRIPTORS; x++ )
317 pxDescriptor = &( xRxDescriptors[ x ] );
318 pxDescriptor->buf_p = &( xEthernetBuffers.cBuffer[ x ][ 0 ] );
320 pxDescriptor->bufsize = UIP_BUFSIZE;
321 pxDescriptor->size = 0;
322 pxDescriptor->status = ACT;
323 pxDescriptor->next = &xRxDescriptors[ x + 1 ];
325 /* Mark this buffer as in use. */
326 ucBufferInUse[ x ] = pdTRUE;
329 /* The last descriptor points back to the start. */
330 pxDescriptor->status |= DL;
331 pxDescriptor->next = &xRxDescriptors[ 0 ];
333 /* Initialise the Tx descriptors. */
334 for( x = 0; x < emacNUM_TX_BUFFERS; x++ )
336 pxDescriptor = &( xTxDescriptors[ x ] );
338 /* A buffer is not allocated to the Tx descriptor until a send is
339 actually required. */
340 pxDescriptor->buf_p = NULL;
342 pxDescriptor->bufsize = UIP_BUFSIZE;
343 pxDescriptor->size = 0;
344 pxDescriptor->status = 0;
345 pxDescriptor->next = &xTxDescriptors[ x + 1 ];
348 /* The last descriptor points back to the start. */
349 pxDescriptor->status |= DL;
350 pxDescriptor->next = &( xTxDescriptors[ 0 ] );
352 /* Use the first Rx descriptor to start with. */
353 pxCurrentRxDesc = &( xRxDescriptors[ 0 ] );
355 /*-----------------------------------------------------------*/
357 static unsigned char *prvGetNextBuffer( void )
360 unsigned char *pucReturn = NULL;
361 unsigned long ulAttempts = 0;
363 while( pucReturn == NULL )
365 /* Look through the buffers to find one that is not in use by
367 for( x = 0; x < emacNUM_BUFFERS; x++ )
369 if( ucBufferInUse[ x ] == pdFALSE )
371 ucBufferInUse[ x ] = pdTRUE;
372 pucReturn = ( unsigned char * ) &( xEthernetBuffers.cBuffer[ x ][ 0 ] );
377 /* Was a buffer found? */
378 if( pucReturn == NULL )
382 if( ulAttempts >= emacBUFFER_WAIT_ATTEMPTS )
387 /* Wait then look again. */
388 vTaskDelay( emacBUFFER_WAIT_DELAY_ms );
394 /*-----------------------------------------------------------*/
396 static void prvReturnBuffer( unsigned char *pucBuffer )
400 /* Return a buffer to the pool of free buffers. */
401 for( ul = 0; ul < emacNUM_BUFFERS; ul++ )
403 if( &( xEthernetBuffers.cBuffer[ ul ][ 0 ] ) == ( void * ) pucBuffer )
405 ucBufferInUse[ ul ] = pdFALSE;
410 /*-----------------------------------------------------------*/
412 static void prvResetEverything( void )
414 /* Temporary code just to see if this gets called. This function has not
416 portDISABLE_INTERRUPTS();
419 /*-----------------------------------------------------------*/
421 static unsigned long prvCheckRxFifoStatus( void )
423 unsigned long ulReturn = 0;
425 if( ( pxCurrentRxDesc->status & ACT ) != 0 )
427 /* Current descriptor is still active. */
429 else if( ( pxCurrentRxDesc->status & FE ) != 0 )
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;
437 if( EDMAC.EDRRR.LONG == 0x00000000UL )
439 /* Restart Ethernet if it has stopped. */
440 EDMAC.EDRRR.LONG = 0x00000001UL;
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 )
449 ulReturn = pxCurrentRxDesc->size;
453 /* Do not expect to get here. */
454 prvResetEverything();
460 /*-----------------------------------------------------------*/
462 static void prvResetMAC( void )
464 /* Ensure the EtherC and EDMAC are enabled. */
465 SYSTEM.MSTPCRB.BIT.MSTPB15 = 0;
466 vTaskDelay( 100 / portTICK_PERIOD_MS );
468 EDMAC.EDMR.BIT.SWR = 1;
470 /* Crude wait for reset to complete. */
471 vTaskDelay( 500 / portTICK_PERIOD_MS );
473 /*-----------------------------------------------------------*/
475 static void prvConfigureEtherCAndEDMAC( void )
477 /* Initialisation code taken from Renesas example project. */
479 /* TODO: Check bit 5 */
480 ETHERC.ECSR.LONG = 0x00000037; /* Clear all ETHERC statuS BFR, PSRTO, LCHNG, MPD, ICD */
482 /* Set the EDMAC interrupt priority. */
483 _IPR( _ETHER_EINT ) = configKERNEL_INTERRUPT_PRIORITY;
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 */
492 EDMAC.EESR.LONG = 0x47FF0F9F; /* Clear all ETHERC and EDMAC status bits */
494 EDMAC.EDMR.BIT.DE = 1;
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. */
504 /* Enable the interrupt... */
505 _IEN( _ETHER_EINT ) = 1;
507 /*-----------------------------------------------------------*/
509 #pragma interrupt ( vEMAC_ISR_Handler( vect = VECT_ETHER_EINT, enable ) )
510 void vEMAC_ISR_Handler( void )
512 unsigned long ul = EDMAC.EESR.LONG;
513 long lHigherPriorityTaskWoken = pdFALSE;
514 extern QueueHandle_t xEMACEventQueue;
515 const unsigned long ulRxEvent = uipETHERNET_RX_EVENT;
517 /* Has a Tx end occurred? */
518 if( ul & emacTX_END_INTERRUPT )
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;
525 /* Has an Rx end occurred? */
526 if( ul & emacRX_END_INTERRUPT )
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;