1 /***********************************************************************************************************************
3 * This software is supplied by Renesas Electronics Corporation and is only intended for use with Renesas products. No
4 * other uses are authorized. This software is owned by Renesas Electronics Corporation and is protected under all
5 * applicable laws, including copyright laws.
6 * THIS SOFTWARE IS PROVIDED "AS IS" AND RENESAS MAKES NO WARRANTIES REGARDING
7 * THIS SOFTWARE, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY,
8 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. ALL SUCH WARRANTIES ARE EXPRESSLY DISCLAIMED. TO THE MAXIMUM
9 * EXTENT PERMITTED NOT PROHIBITED BY LAW, NEITHER RENESAS ELECTRONICS CORPORATION NOR ANY OF ITS AFFILIATED COMPANIES
10 * SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES FOR ANY REASON RELATED TO THIS
11 * SOFTWARE, EVEN IF RENESAS OR ITS AFFILIATES HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
12 * Renesas reserves the right, without notice, to make changes to this software and to discontinue the availability of
13 * this software. By using this software, you agree to the additional terms and conditions found by accessing the
15 * http://www.renesas.com/disclaimer
17 * Copyright (C) 2018 Renesas Electronics Corporation. All rights reserved.
18 ***********************************************************************************************************************/
20 /***********************************************************************************************************************
21 * File Name : NetworkInterface.c
23 * Description : Interfaces FreeRTOS TCP/IP stack to RX Ethernet driver.
24 ***********************************************************************************************************************/
26 /***********************************************************************************************************************
27 * History : DD.MM.YYYY Version Description
28 * : 07.03.2018 0.1 Development
29 ***********************************************************************************************************************/
31 /***********************************************************************************************************************
32 * Includes <System Includes> , "Project Includes"
33 ***********************************************************************************************************************/
39 /* FreeRTOS includes. */
42 #include "FreeRTOS_IP.h"
43 #include "FreeRTOS_IP_Private.h"
44 /*#include "FreeRTOS_DNS.h" */
45 #include "NetworkBufferManagement.h"
46 #include "NetworkInterface.h"
48 #include "r_ether_rx_if.h"
51 /***********************************************************************************************************************
53 **********************************************************************************************************************/
54 #define ETHER_BUFSIZE_MIN 60
56 #if defined( BSP_MCU_RX65N ) || defined( BSP_MCU_RX64M ) || defined( BSP_MCU_RX71M )
57 #if ETHER_CFG_MODE_SEL == 0
58 #define R_ETHER_PinSet_CHANNEL_0() R_ETHER_PinSet_ETHERC0_MII()
59 #elif ETHER_CFG_MODE_SEL == 1
60 #define R_ETHER_PinSet_CHANNEL_0() R_ETHER_PinSet_ETHERC0_RMII()
62 #elif defined( BSP_MCU_RX63N )
63 #if ETHER_CFG_MODE_SEL == 0
64 #define R_ETHER_PinSet_CHANNEL_0() R_ETHER_PinSet_ETHERC_MII()
65 #elif ETHER_CFG_MODE_SEL == 1
66 #define R_ETHER_PinSet_CHANNEL_0() R_ETHER_PinSet_ETHERC_RMII()
68 #endif /* if defined( BSP_MCU_RX65N ) || defined( BSP_MCU_RX64M ) || defined( BSP_MCU_RX71M ) */
70 #ifndef PHY_LS_HIGH_CHECK_TIME_MS
72 /* Check if the LinkSStatus in the PHY is still high after 2 seconds of not
73 * receiving packets. */
74 #define PHY_LS_HIGH_CHECK_TIME_MS 2000
77 #ifndef PHY_LS_LOW_CHECK_TIME_MS
78 /* Check if the LinkSStatus in the PHY is still low every second. */
79 #define PHY_LS_LOW_CHECK_TIME_MS 1000
82 /***********************************************************************************************************************
83 * Private global variables and functions
84 **********************************************************************************************************************/
87 eMACInit, /* Must initialise MAC. */
88 eMACPass, /* Initialisation was successful. */
89 eMACFailed, /* Initialisation failed. */
90 } eMAC_INIT_STATUS_TYPE;
92 static TaskHandle_t ether_receive_check_task_handle = 0;
93 static TaskHandle_t ether_link_check_task_handle = 0;
94 static TaskHandle_t xTaskToNotify = NULL;
95 static BaseType_t xPHYLinkStatus;
96 static BaseType_t xReportedStatus;
97 static eMAC_INIT_STATUS_TYPE xMacInitStatus = eMACInit;
99 static int16_t SendData( uint8_t * pucBuffer,
101 static int InitializeNetwork( void );
102 static void prvEMACDeferredInterruptHandlerTask( void * pvParameters );
103 static void clear_all_ether_rx_discriptors( uint32_t event );
105 int32_t callback_ether_regist( void );
106 void EINT_Trig_isr( void * );
107 void get_random_number( uint8_t * data,
110 void prvLinkStatusChange( BaseType_t xStatus );
111 #if ( ipconfigHAS_PRINTF != 0 )
112 static void prvMonitorResources( void );
115 /***********************************************************************************************************************
116 * Function Name: xNetworkInterfaceInitialise ()
117 * Description : Initialization of Ethernet driver.
119 * Return Value : pdPASS, pdFAIL
120 **********************************************************************************************************************/
121 BaseType_t xNetworkInterfaceInitialise( void )
125 if( xMacInitStatus == eMACInit )
128 * Perform the hardware specific network initialization here using the Ethernet driver library to initialize the
129 * Ethernet hardware, initialize DMA descriptors, and perform a PHY auto-negotiation to obtain a network link.
131 * InitialiseNetwork() uses Ethernet peripheral driver library function, and returns 0 if the initialization fails.
133 if( InitializeNetwork() == pdFALSE )
135 xMacInitStatus = eMACFailed;
139 /* Indicate that the MAC initialisation succeeded. */
140 xMacInitStatus = eMACPass;
143 FreeRTOS_printf( ( "InitializeNetwork returns %s\n", ( xMacInitStatus == eMACPass ) ? "OK" : " Fail" ) );
146 if( xMacInitStatus == eMACPass )
148 xReturn = xPHYLinkStatus;
155 FreeRTOS_printf( ( "xNetworkInterfaceInitialise returns %d\n", xReturn ) );
158 } /* End of function xNetworkInterfaceInitialise() */
161 /***********************************************************************************************************************
162 * Function Name: xNetworkInterfaceOutput ()
163 * Description : Simple network output interface.
164 * Arguments : pxDescriptor, xReleaseAfterSend
165 * Return Value : pdTRUE, pdFALSE
166 **********************************************************************************************************************/
167 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor,
168 BaseType_t xReleaseAfterSend )
170 BaseType_t xReturn = pdFALSE;
172 /* Simple network interfaces (as opposed to more efficient zero copy network
173 * interfaces) just use Ethernet peripheral driver library functions to copy
174 * data from the FreeRTOS+TCP buffer into the peripheral driver's own buffer.
175 * This example assumes SendData() is a peripheral driver library function that
176 * takes a pointer to the start of the data to be sent and the length of the
177 * data to be sent as two separate parameters. The start of the data is located
178 * by pxDescriptor->pucEthernetBuffer. The length of the data is located
179 * by pxDescriptor->xDataLength. */
180 if( xPHYLinkStatus != 0 )
182 if( SendData( pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength ) >= 0 )
185 /* Call the standard trace macro to log the send event. */
186 iptraceNETWORK_INTERFACE_TRANSMIT();
191 /* As the PHY Link Status is low, it makes no sense trying to deliver a packet. */
194 if( xReleaseAfterSend != pdFALSE )
196 /* It is assumed SendData() copies the data out of the FreeRTOS+TCP Ethernet
197 * buffer. The Ethernet buffer is therefore no longer needed, and must be
198 * freed for re-use. */
199 vReleaseNetworkBufferAndDescriptor( pxDescriptor );
203 } /* End of function xNetworkInterfaceOutput() */
206 #if ( ipconfigHAS_PRINTF != 0 )
207 static void prvMonitorResources()
209 static UBaseType_t uxLastMinBufferCount = 0u;
210 static UBaseType_t uxCurrentBufferCount = 0u;
211 static size_t uxMinLastSize = 0uL;
212 static size_t uxCurLastSize = 0uL;
216 uxCurrentBufferCount = uxGetMinimumFreeNetworkBuffers();
218 if( uxLastMinBufferCount != uxCurrentBufferCount )
220 /* The logging produced below may be helpful
221 * while tuning +TCP: see how many buffers are in use. */
222 uxLastMinBufferCount = uxCurrentBufferCount;
223 FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
224 uxGetNumberOfFreeNetworkBuffers(), uxCurrentBufferCount ) );
227 uxMinSize = xPortGetMinimumEverFreeHeapSize();
228 uxCurSize = xPortGetFreeHeapSize();
230 if( uxMinLastSize != uxMinSize )
232 uxCurLastSize = uxCurSize;
233 uxMinLastSize = uxMinSize;
234 FreeRTOS_printf( ( "Heap: current %lu lowest %lu\n", uxCurSize, uxMinSize ) );
237 #if ( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
239 static UBaseType_t uxLastMinQueueSpace = 0;
240 UBaseType_t uxCurrentCount = 0u;
242 uxCurrentCount = uxGetMinimumIPQueueSpace();
244 if( uxLastMinQueueSpace != uxCurrentCount )
246 /* The logging produced below may be helpful
247 * while tuning +TCP: see how many buffers are in use. */
248 uxLastMinQueueSpace = uxCurrentCount;
249 FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
252 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
254 #endif /* ( ipconfigHAS_PRINTF != 0 ) */
256 /***********************************************************************************************************************
257 * Function Name: prvEMACDeferredInterruptHandlerTask ()
258 * Description : The deferred interrupt handler is a standard RTOS task.
259 * Arguments : pvParameters
260 * Return Value : none
261 **********************************************************************************************************************/
262 static void prvEMACDeferredInterruptHandlerTask( void * pvParameters )
264 NetworkBufferDescriptor_t * pxBufferDescriptor;
265 int32_t xBytesReceived = 0;
267 /* Avoid compiler warning about unreferenced parameter. */
268 ( void ) pvParameters;
270 /* Used to indicate that xSendEventStructToIPTask() is being called because
271 * of an Ethernet receive event. */
272 IPStackEvent_t xRxEvent;
274 uint8_t * buffer_pointer;
276 /* Some variables related to monitoring the PHY. */
278 TickType_t xPhyRemTime;
279 const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( 100UL );
281 vTaskSetTimeOutState( &xPhyTime );
282 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
284 FreeRTOS_printf( ( "Deferred Interrupt Handler Task started\n" ) );
285 xTaskToNotify = ether_receive_check_task_handle;
289 #if ( ipconfigHAS_PRINTF != 0 )
291 prvMonitorResources();
293 #endif /* ipconfigHAS_PRINTF != 0 ) */
295 /* Wait for the Ethernet MAC interrupt to indicate that another packet
296 * has been received. */
297 if( xBytesReceived <= 0 )
299 ulTaskNotifyTake( pdFALSE, ulMaxBlockTime );
302 /* See how much data was received. */
303 xBytesReceived = R_ETHER_Read_ZC2( ETHER_CHANNEL_0, ( void ** ) &buffer_pointer );
305 if( xBytesReceived < 0 )
307 /* This is an error. Logged. */
308 FreeRTOS_printf( ( "R_ETHER_Read_ZC2: rc = %d\n", xBytesReceived ) );
310 else if( xBytesReceived > 0 )
312 /* Allocate a network buffer descriptor that points to a buffer
313 * large enough to hold the received frame. As this is the simple
314 * rather than efficient example the received data will just be copied
315 * into this buffer. */
316 pxBufferDescriptor = pxGetNetworkBufferWithDescriptor( ( size_t ) xBytesReceived, 0 );
318 if( pxBufferDescriptor != NULL )
320 /* pxBufferDescriptor->pucEthernetBuffer now points to an Ethernet
321 * buffer large enough to hold the received data. Copy the
322 * received data into pcNetworkBuffer->pucEthernetBuffer. Here it
323 * is assumed ReceiveData() is a peripheral driver function that
324 * copies the received data into a buffer passed in as the function's
325 * parameter. Remember! While is is a simple robust technique -
326 * it is not efficient. An example that uses a zero copy technique
327 * is provided further down this page. */
328 memcpy( pxBufferDescriptor->pucEthernetBuffer, buffer_pointer, ( size_t ) xBytesReceived );
329 /*ReceiveData( pxBufferDescriptor->pucEthernetBuffer ); */
331 /* Set the actual packet length, in case a larger buffer was returned. */
332 pxBufferDescriptor->xDataLength = ( size_t ) xBytesReceived;
334 R_ETHER_Read_ZC2_BufRelease( ETHER_CHANNEL_0 );
336 /* See if the data contained in the received Ethernet frame needs
337 * to be processed. NOTE! It is preferable to do this in
338 * the interrupt service routine itself, which would remove the need
339 * to unblock this task for packets that don't need processing. */
340 if( eConsiderFrameForProcessing( pxBufferDescriptor->pucEthernetBuffer ) == eProcessBuffer )
342 /* The event about to be sent to the TCP/IP is an Rx event. */
343 xRxEvent.eEventType = eNetworkRxEvent;
345 /* pvData is used to point to the network buffer descriptor that
346 * now references the received data. */
347 xRxEvent.pvData = ( void * ) pxBufferDescriptor;
349 /* Send the data to the TCP/IP stack. */
350 if( xSendEventStructToIPTask( &xRxEvent, 0 ) == pdFALSE )
352 /* The buffer could not be sent to the IP task so the buffer must be released. */
353 vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor );
355 /* Make a call to the standard trace macro to log the occurrence. */
356 iptraceETHERNET_RX_EVENT_LOST();
357 clear_all_ether_rx_discriptors( 0 );
361 /* The message was successfully sent to the TCP/IP stack.
362 * Call the standard trace macro to log the occurrence. */
363 iptraceNETWORK_INTERFACE_RECEIVE();
369 /* The Ethernet frame can be dropped, but the Ethernet buffer must be released. */
370 vReleaseNetworkBufferAndDescriptor( pxBufferDescriptor );
375 /* The event was lost because a network buffer was not available.
376 * Call the standard trace macro to log the occurrence. */
377 iptraceETHERNET_RX_EVENT_LOST();
378 clear_all_ether_rx_discriptors( 1 );
379 FreeRTOS_printf( ( "R_ETHER_Read_ZC2: Cleared descriptors\n" ) );
383 if( xBytesReceived > 0 )
385 /* A packet was received. No need to check for the PHY status now,
386 * but set a timer to check it later on. */
387 vTaskSetTimeOutState( &xPhyTime );
388 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
390 /* Indicate that the Link Status is high, so that
391 * xNetworkInterfaceOutput() can send packets. */
392 if( xPHYLinkStatus == 0 )
395 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS assume %d\n", xPHYLinkStatus ) );
398 else if( ( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE ) || ( FreeRTOS_IsNetworkUp() == pdFALSE ) )
400 R_ETHER_LinkProcess( 0 );
402 if( xPHYLinkStatus != xReportedStatus )
404 xPHYLinkStatus = xReportedStatus;
405 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", xPHYLinkStatus ) );
408 vTaskSetTimeOutState( &xPhyTime );
410 if( xPHYLinkStatus != 0 )
412 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
416 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
420 } /* End of function prvEMACDeferredInterruptHandlerTask() */
423 /***********************************************************************************************************************
424 * Function Name: vNetworkInterfaceAllocateRAMToBuffers ()
426 * Arguments : pxNetworkBuffers
427 * Return Value : none
428 **********************************************************************************************************************/
429 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )
432 uint8_t * buffer_address;
434 R_EXTERN_SEC( B_ETHERNET_BUFFERS_1 )
436 buffer_address = R_SECTOP( B_ETHERNET_BUFFERS_1 );
438 for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )
440 pxNetworkBuffers[ ul ].pucEthernetBuffer = ( buffer_address + ( ETHER_CFG_BUFSIZE * ul ) );
442 } /* End of function vNetworkInterfaceAllocateRAMToBuffers() */
445 /***********************************************************************************************************************
446 * Function Name: prvLinkStatusChange ()
447 * Description : Function will be called when the Link Status of the phy has changed ( see ether_callback.c )
448 * Arguments : xStatus : true when statyus has become high
449 * Return Value : void
450 **********************************************************************************************************************/
451 void prvLinkStatusChange( BaseType_t xStatus )
453 if( xReportedStatus != xStatus )
455 FreeRTOS_printf( ( "prvLinkStatusChange( %d )\n", xStatus ) );
456 xReportedStatus = xStatus;
460 /***********************************************************************************************************************
461 * Function Name: InitializeNetwork ()
464 * Return Value : pdTRUE, pdFALSE
465 **********************************************************************************************************************/
466 static int InitializeNetwork( void )
468 ether_return_t eth_ret;
469 BaseType_t return_code = pdFALSE;
471 uint8_t myethaddr[ 6 ] =
481 R_ETHER_PinSet_CHANNEL_0();
483 callback_ether_regist();
485 param.channel = ETHER_CHANNEL_0;
486 eth_ret = R_ETHER_Control( CONTROL_POWER_ON, param ); /* PHY mode settings, module stop cancellation */
488 if( ETHER_SUCCESS != eth_ret )
493 eth_ret = R_ETHER_Open_ZC2( ETHER_CHANNEL_0, myethaddr, ETHER_FLAG_OFF );
495 if( ETHER_SUCCESS != eth_ret )
500 return_code = xTaskCreate( prvEMACDeferredInterruptHandlerTask,
501 "ETHER_RECEIVE_CHECK_TASK",
504 configMAX_PRIORITIES - 1,
505 ðer_receive_check_task_handle );
507 if( pdFALSE == return_code )
513 } /* End of function InitializeNetwork() */
516 /***********************************************************************************************************************
517 * Function Name: SendData ()
519 * Arguments : pucBuffer, length
520 * Return Value : 0 success, negative fail
521 **********************************************************************************************************************/
522 static int16_t SendData( uint8_t * pucBuffer,
523 size_t length ) /*TODO complete stub function */
526 uint8_t * pwrite_buffer;
527 uint16_t write_buf_size;
529 /* (1) Retrieve the transmit buffer location controlled by the descriptor. */
530 ret = R_ETHER_Write_ZC2_GetBuf( ETHER_CHANNEL_0, ( void ** ) &pwrite_buffer, &write_buf_size );
532 if( ETHER_SUCCESS == ret )
534 if( write_buf_size >= length )
536 memcpy( pwrite_buffer, pucBuffer, length );
539 if( length < ETHER_BUFSIZE_MIN ) /*under minimum*/
541 memset( ( pwrite_buffer + length ), 0, ( ETHER_BUFSIZE_MIN - length ) ); /*padding*/
542 length = ETHER_BUFSIZE_MIN; /*resize*/
545 ret = R_ETHER_Write_ZC2_SetBuf( ETHER_CHANNEL_0, ( uint16_t ) length );
546 ret = R_ETHER_CheckWrite( ETHER_CHANNEL_0 );
549 if( ETHER_SUCCESS != ret )
551 return -5; /* XXX return meaningful value */
557 } /* End of function SendData() */
560 /***********************************************************************************************************************
561 * Function Name: EINT_Trig_isr
562 * Description : Standard frame received interrupt handler
563 * Arguments : ectrl - EDMAC and ETHERC control structure
564 * Return Value : None
565 * Note : This callback function is executed when EINT0 interrupt occurred.
566 ***********************************************************************************************************************/
567 void EINT_Trig_isr( void * ectrl )
569 ether_cb_arg_t * pdecode;
570 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
572 pdecode = ( ether_cb_arg_t * ) ectrl;
574 if( pdecode->status_eesr & 0x00040000 ) /* EDMAC FR (Frame Receive Event) interrupt */
576 if( xTaskToNotify != NULL )
578 vTaskNotifyGiveFromISR( ether_receive_check_task_handle, &xHigherPriorityTaskWoken );
581 /* If xHigherPriorityTaskWoken is now set to pdTRUE then a context switch
582 * should be performed to ensure the interrupt returns directly to the highest
583 * priority task. The macro used for this purpose is dependent on the port in
584 * use and may be called portEND_SWITCHING_ISR(). */
585 portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
586 /*TODO complete interrupt handler for other events. */
588 } /* End of function EINT_Trig_isr() */
591 static void clear_all_ether_rx_discriptors( uint32_t event )
593 int32_t xBytesReceived;
594 uint8_t * buffer_pointer;
596 /* Avoid compiler warning about unreferenced parameter. */
601 /* See how much data was received. */
602 xBytesReceived = R_ETHER_Read_ZC2( ETHER_CHANNEL_0, ( void ** ) &buffer_pointer );
604 if( 0 > xBytesReceived )
606 /* This is an error. Ignored. */
608 else if( 0 < xBytesReceived )
610 R_ETHER_Read_ZC2_BufRelease( ETHER_CHANNEL_0 );
611 iptraceETHERNET_RX_EVENT_LOST();
620 /***********************************************************************************************************************
621 * End of file "NetworkInterface.c"
622 **********************************************************************************************************************/