kamleshjgandhi wrote on Friday, June 24, 2016:
We have FreeRTOSPlusTCP Server application (developed using FreeRTOS Socket API) is running on NXP LPC1768 and modified FreeRTOS_Plus_TCP_Minimal_Windows_Simulator program runs as Client application on Dell Windows 10 Laptop. LAN card of LPC1768 is directly connected using cross-over cable with Laptop Live Tech USB 2.0 LAN Ethernet card. D-Link Router is used only for Internet connection purpose using WiFi mode. An static IP and Port (ip 192. 168.1.211 and port 27754) and MAC address are assigned to LPC1768 by Server application running on it. Static IP address(192.168.1.210) is assigned to LAN card of the Laptop.
LPC1768 application has been developed on Eclipse MARS platform using GNU Tools ARM Embedded, 5.3 2016q1 GCC Cross-compiler. FreeRTOS_Plus_TCP_Minimal_Windows_Simulator program runs on Visual Studio 2015 environment.
We have been expecting Laptop Client application to send data to the waiting Server application ready to receive data on LPC1768. But there is absolutely no data exchange between them. On using cmd NETSTAT –ano command on Laptop we never see any port of LPC1768 with status LISTENING. ARP –a command shows IP address (192.168.1.211) of LPC1768 for few seconds and as soon as FreeRTOS_accept start executing (if fact FreeRTOS_accept just hangs and does not connect with Laptop client application) the IP address disappears from Laptop ARP cache. The advance IP scanner (Free third party utility) always show LPC1768 IP (192.168.1.211) with correct MAC address. We are not able to PING LPC1768 from Laptop. We get message either Request Timed Out or Destination Host Unreachable. We think that NetworkInterface program developed by us for LPC1768 seems to be working.
We have explored on many possible options during the last 3 months to solve the connection problem between LPC1768 and Laptop but not successful at all. So as a last resort we are sending this SOS note to the FreeRTOS forum.
When we run Adam Dunkell’s UIP webserver application on LPC1768 we can PING LPC1768 from Laptop. Also we are able to connect with 192.168.1.211 from Laptop Chrome web-browser. This eliminates any physical network connection problem between LPC1768 and Laptop. Looks like it may be a problem related to the FreeRTOS TCP-IP Stack.
Consulted network engineer to check on our networking arrangements and no problem found in any physical connection related issues. Used Wireshark to monitor ARP and TCP transactions. When we use Adam Dunkell’s UIP Webserver we see TCP & ARP & IP transactions in Wireshark. But we see only gratuitous ARP entries only from 192.168.1.211. Checked Networkinterface.c and lpc17xx_emac.c programs but not able to find problems with them. Tried 3 versions of Networkinterface.c but none of them work as expected.
FreeRTOSTCPPlus are sourced from FreeRTOS+TCP Labs Build 160112.
Any help and guidance from the forum members will be highly appreciated.
The gist of the Server Application code on LPC1768 are as follows.
int main( void )
{
UARTInit( 0, 19200 );
NVIC_SetPriority( UART0_IRQn,29 ); // Display output text/message on COM3 port
sprintf(pBuff,"%s\n","WELCOME TO RTOS PROJECT WORLD:\n"); kgprint(pBuff);
/* Create the tasks that use the TCP/IP stack if they have not already been created. */
uint8_t ucMACAddress[ 6 ] = { 0x00,0x07,0x27,0x07,0x19,0x54 };
static const uint8_t ucIPAddress[4] = { 192,168,1,211 };
static const uint8_t ucNetMask[ 4 ] = { 255, 255, 255, 0 };
static const uint8_t ucGatewayAddress[ 4 ] = { 192, 168, 1, 210 };
static const uint8_t ucDNSServerAddress[ 4 ] = { 192, 168, 1, 210 };
/* Initialise the RTOS's TCP/IP stack. The tasks(IP-TASK) that use the
network are created in the vApplicationIPNetworkEventHook() hook function. The hook function is called when the network connects. */
FreeRTOS_IPInit(ucIPAddress,ucNetMask,ucGatewayAddress,ucDNSServerAddress,ucMACAddress );
/* Display the IP address, then create the uIP task. The WEB server runs in this task.*/
xTaskCreate( vuKGTCP_Task, “uIP WEBSERVER”, mainBASIC_UIP_WEB_STACK_SIZE, NULL, mainUIP_TASK_PRIORITY, &xUIPTaskHandle );
/* Start the scheduler so our tasks start executing. */
vTaskStartScheduler();
for( ;; )
{
}
return 0;
}
void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )
{
static BaseType_t xTasksAlreadyCreated = pdFALSE;
/* Both eNetworkUp and eNetworkDown events can be processed here. */
if( eNetworkEvent == eNetworkUp )
{
if( xTasksAlreadyCreated == pdFALSE )
{
sprintf(pBuff,"%s\n","Network UP\n"); kgprint(pBuff);
/** For convenience, tasks that use FreeRTOS+TCP can be created here to ensure they are not created before the network is usable.*/
xTaskCreate( vuKGTCP_Send_Receive_Task, "uIP SendReceive", mainBASIC_SndRCv_WEB_STACK_SIZE, NULL, mainUIPSendReceive_TASK_PRIORITY, &xUIPSndRcvTaskHandle );
xTasksAlreadyCreated = pdTRUE;
}
/* The network is up and configured. Print out the configuration */
FreeRTOS_GetAddressConfiguration(&ulIPAddress,&ulNetMask,&ulGatewayAddress,&ulDNSServerAddress );
/* Convert the IP address to a string then print it out. */
FreeRTOS_inet_ntoa( ulIPAddress, cBuffer );
sprintf(pBuff, "%s %s\n", "SERVER IP.......:", cBuffer); kgprint(pBuff);
}
}
void vuKGTCP_Send_Receive_Task(void)
static struct freertos_sockaddr xClient, xBindAdress;
Socket_t xListeningSocket, xConnectedSocket;
socklen_t xSize = sizeof(xClient);
xWinProperties_t xWinProps;
const BaseType_t xBacklog = 20;
//static const TickType_t xReceiveTimeOut = portMAX_DELAY;
//static const TickType_t xSendTimeOut = portMAX_DELAY;
static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 20 );
static const TickType_t xSendTimeOut = pdMS_TO_TICKS(100);
BaseType_t xBytesRecceived = 0;
#define Buffer_Size 30
static char RcvBuffer[Buffer_Size];
xListeningSocket = FreeRTOS_socket(FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP);
configASSERT(xListeningSocket != FREERTOS_INVALID_SOCKET);
if (xListeningSocket != FREERTOS_INVALID_SOCKET)
{
sprintf(pBuff, “%s\n”, “Server Socket Created Successfully…\n”); kgprint(pBuff);
}
else
{
sprintf(pBuff, “%s\n”, “Failed to Create Server Socket …\n”); kgprint(pBuff);
//goto Revive_UIP_WEBSERVER;
}
FreeRTOS_setsockopt(xListeningSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof(xReceiveTimeOut));
FreeRTOS_setsockopt(xListeningSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof(xSendTimeOut));
#if( ipconfigUSE_TCP_WIN == 1 )
/* Fill in the buffer and window sizes that will be used by the socket. */
xWinProps.lTxBufSize = 4 * ipconfigTCP_MSS;
xWinProps.lTxWinSize = 3;
xWinProps.lRxBufSize = 4 * ipconfigTCP_MSS;
xWinProps.lRxWinSize = 3;
/* Set the window and buffer sizes. */
FreeRTOS_setsockopt( xListeningSocket,0,FREERTOS_SO_WIN_PROPERTIES,&xWinProps, sizeof( xWinProps ) );
#endif /* ipconfigUSE_TCP_WIN */
xBindAdress.sin_addr = FreeRTOS_inet_addr_quick( 192,168,1,211);
xBindAdress.sin_port = FreeRTOS_htons( 27754);
if (FreeRTOS_bind( xListeningSocket, &xBindAdress, sizeof(xBindAdress) ) == 0)
{
sprintf(pBuff,"%s\n",“Server Bind AT PORT 27754 Successful…\n”);kgprint(pBuff); }
else
{
sprintf(pBuff,"%s\n",“Server Bind Failed…\n”);kgprint(pBuff);
}
if (FreeRTOS_listen(xListeningSocket, xBacklog) == 0)
{
sprintf(pBuff,"%s\n",“Listening for Client…\n”); kgprint(pBuff
}
sprintf(pBuff, “%s\n”, “Waiting For Accepting From 192.168.1.210 \n”); kgprint(pBuff);
for (;
{
xConnectedSocket = FreeRTOS_accept(xListeningSocket, &xClient, &xSize);
configASSERT(xConnectedSocket != FREERTOS_INVALID_SOCKET);
if (FreeRTOS_issocketconnected(xConnectedSocket) == pdTRUE)
{
sprintf(pBuff, "%s\n", "Connected with 192.168.1.210.....\n"); kgprint(pBuff);
sprintf(pBuff, "%s\n", "Receiving Data From Client...\n"); kgprint(pBuff);
}
xBytesRecceived = FreeRTOS_recv(xConnectedSocket, &RcvBuffer, Buffer_Size, 0);
if (xBytesRecceived > 0)
{
strcpy(pBuff, RcvBuffer);
sprintf(pBuff, "%s\n", "Received Data From PC Client:"); kgprint(pBuff);
}
vTaskDelay(100); //Delay for next receive send cycle
}
Soc_Shutdown:
/* Initiate graceful shutdown. */
FreeRTOS_shutdown( xListeningSocket, FREERTOS_SHUT_RDWR );
FreeRTOS_shutdown( xConnectedSocket, FREERTOS_SHUT_RDWR );
vTaskDelay(500 ); //wait for graceful disconnect
/* The socket has shut down and is safe to close. */
sprintf(pBuff,"%s\n",“Closing Sockets…\n”); kgprint(pBuff);
FreeRTOS_closesocket( xListeningSocket );
FreeRTOS_closesocket( xConnectedSocket );
}
void kgprint( const char *str )
{
unsigned int i;
for( i = 0 ; str[i] !=’\0’; i++ )
{
putch0( str[i] );
if( str[i] == '\n' )
{
putch0( 0x0a );
putch0( 0x0d );
}
}
return;
}
The one of the versions of the Networkinteface.c that we use is as follows.
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
/* FreeRTOS includes. */
#include “FreeRTOS.h”
#include “task.h”
#include “queue.h”
#include “semphr.h”
#include “KG_lpc17xx_emac.h”
//#include “lpc17xx.h”
/* FreeRTOS+TCP includes. */
#include “FreeRTOS_IP.h”
#include “FreeRTOS_Sockets.h”
#include “FreeRTOS_IP_Private.h”
#include “NetworkBufferManagement.h”
#include “KG_NetworkInterface.h”
//#include “uart.h”
#if ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES != 1
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
#else
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
#endif
/-------------------------------------------------------------------------------------/
static int32_t EMAC_PHYLinkStatus;
#ifndef EMAC_MAX_BLOCK_TIME_MS
#define EMAC_MAX_BLOCK_TIME_MS 100ul
#endif
/* When a packet is ready to be sent, if it cannot be sent immediately then the task performing the transmit will block for niTX_BUFFER_FREE_WAIT
milliseconds. It will do this a maximum of niMAX_TX_ATTEMPTS before giving up. */
#define niTX_BUFFER_FREE_WAIT ( ( TickType_t ) 2UL / portTICK_RATE_MS )
#define niMAX_TX_ATTEMPTS ( 5 )
/* Default the size of the stack used by the EMAC deferred handler task to 4x
the size of the stack used by the idle task - but allow this to be overridden in
FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
#ifndef configEMAC_TASK_STACK_SIZE
#define configEMAC_TASK_STACK_SIZE ( 4 * configMINIMAL_STACK_SIZE )
#endif
#define configMAC_INTERRUPT_PRIORITY 6
/-----------------------------------------------------------/
/*
- A deferred interrupt handler task that processes LPC1768 EMAC interrupts.*/
static void prvEMACHandlerTask( void *pvParameters );
static int32_t KG_GetPhyLinkStatus( void);
/* LLMNR multicast address. */
//static const uint8_t llmnr_mac_address[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
static int CAX = 0;
static int Init_Cnt = 0;
/* MAC address to use. */
extern const uint8_t ucMACAddress[ 6 ];
/* Holds the handle of the task used as a deferred interrupt processor. The
handle is used so direct notifications can be sent to the task for all EMAC/DMA
related interrupts. /
static TaskHandle_t xEMACTaskHandle = NULL;
/ The queue used to communicate Ethernet events with the IP task. */
extern xQueueHandle xNetworkEventQueue;
BaseType_t xNetworkInterfaceInitialise( void )
{
//const TickType_t x5_Seconds = 5000UL;
UNS_16 i;
if( xEMACTaskHandle == NULL )
{
Init_Eth:
if (EMAC_Init() == FALSE) //Try 3 times to Init
{
if (Init_Cnt > 3)
{
configASSERT( CAX != 0 );
return pdFAIL;
}
else
{
Init_Cnt = Init_Cnt + 1;
goto Init_Eth;
}
}
if (KG_GetPhyLinkStatus() != 1) //PHY Link - Value 1 means Link is UP , 0 Link is Down
{
configASSERT( CAX != 0 );
return pdFAIL;
}
/* The handler task is created at the highest possible priority to ensure the interrupt handler can return directly to it. */
xTaskCreate( prvEMACHandlerTask, "EMAC", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
configASSERT( xEMACTaskHandle );
/* Enable the interrupt and set its priority to the minimum interrupt priority. */
/*-------------------------------------------------------------------------------------------------*/
portENTER_CRITICAL();
{
LPC_EMAC->IntEnable = ( INT_RX_DONE | INT_TX_DONE );
NVIC_SetPriority( ENET_IRQn, configEMAC_INTERRUPT_PRIORITY );
NVIC_EnableIRQ( ENET_IRQn );
}
portEXIT_CRITICAL();
/*-------------------------------------------------------------------------------------------------*/
}
return pdPASS;
}
/-----------------------------------------------------------/
BaseType_t xNetworkInterfaceOutput( xNetworkBufferDescriptor_t * const pxSendNetworkBufferDescriptor, BaseType_t xReleaseAfterSend )
{
BaseType_t xReturn = pdFAIL;
int32_t x;
extern void EMAC_StartTransmitNextBuffer(uint32_t ulLength);
extern void EMAC_SetNextPacketToSend(uint8_t * pucBuffer);
if (KG_GetPhyLinkStatus() != 1) //PHY Link - Value 1 means Link is UP , 0 Link is Down
{
configASSERT(CAX != 0); // Just for Debugging purpose defined this artificial ConfigAssert
return pdFAIL;
}
/* Attempt to obtain access to a Tx buffer. */
for (x = 0; x < niMAX_TX_ATTEMPTS; x++)
{
if (EMAC_CheckTransmitIndex() == TRUE)
{
/* Will the data fit in the Tx buffer? */
if (pxSendNetworkBufferDescriptor-> xDataLength < ETH_MAX_FLEN) /*_RB_ The size needs to come from FreeRTOSIPConfig.h. */
{
/* Assign the buffer to the Tx descriptor that is now known to be free. */
EMAC_SetNextPacketToSend(pxSendNetworkBufferDescriptor->pucEthernetBuffer);
/* The EMAC now owns the buffer. */
pxSendNetworkBufferDescriptor->pucEthernetBuffer = NULL;
/* Initiate the Tx. */
EMAC_StartTransmitNextBuffer(pxSendNetworkBufferDescriptor->xDataLength);
iptraceNETWORK_INTERFACE_TRANSMIT();
/* The Tx has been initiated. */
xReturn = pdPASS;
}
break;
}
else
{
vTaskDelay(niTX_BUFFER_FREE_WAIT);
}
}
/* Finished with the network buffer. */
if (xReleaseAfterSend != pdFALSE) //if Finished with the network buffer then release it
{
vReleaseNetworkBufferAndDescriptor(pxSendNetworkBufferDescriptor);
}
return xReturn;
}
/-----------------------------------------------------------/
/-----------------------------------------------------------/
void ENET_IRQHandler( void )
{
uint32_t ulStatusRegister;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
ulStatusRegister = LPC_EMAC->IntStatus;
/* Clear the interrupts. */
//LPC_EMAC->IntClear = ulStatusRegister;
LPC_EMAC->IntClear = 0xFFFF; //?check
/* xHigherPriorityTaskWoken must be initialised to pdFALSE. If calling xTaskNotifyFromISR() unblocks the handling task, and the priority of
the handling task is higher than the priority of the currently running task, then xHigherPriorityTaskWoken will automatically get set to pdTRUE. */
xHigherPriorityTaskWoken = pdFALSE;
//configASSERT(CAX != 0); //This LINE OF CODE CAUSES program hang so commented out
/* Clear fatal error conditions. NOTE: The driver does not clear all errors, only those actually experienced. For future reference, range
errors are not actually errors so can be ignored. */
if( (ulStatusRegister & INT_TX_UNDERRUN ) != 0U )
{
LPC_EMAC->Command |= CR_TX_RES;
}
/* Unblock the handling task so the task can perform any processing necessitated by the interrupt. xHandlingTask is the task's handle, which was obtained
when the task was created. The handling task's notification value is bitwise ORed with the interrupt status - ensuring bits that are already
set are not overwritten. */
/* Unblock the deferred interrupt handler task if the event was an Rx. */
if( (ulStatusRegister & INT_RX_DONE ) != 0UL )
{
xTaskNotifyFromISR(xEMACTaskHandle, ulStatusRegister, eSetBits, &xHigherPriorityTaskWoken);
//configASSERT(CAX != 0); //This line Hangs program so commented out
}
//portEND_SWITCHING_ISR( ulInterruptCause );
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
//configASSERT(CAX != 0); //this line Hangs program so commented out
}
/-----------------------------------------------------------/
/-----------------------------------------------------------/
static void prvEMACHandlerTask( void *pvParameters )
{
unsigned char *pucUseBuffer;
size_t xBytesReceived;
size_t xDataLength;
const uint16_t usCRCLength = 4;
xNetworkBufferDescriptor_t *pxNextNetworkBufferDescriptor = NULL;
const TickType_t xBlockTime = pdMS_TO_TICKS(100UL);
const UBaseType_t xMinDescriptorsToLeave = 2UL;
xIPStackEvent_t xRxEvent = { eNetworkRxEvent , NULL };
uint32_t ulInterruptStatus;
int i;
/* This is not included in the header file for some reason. */
//extern uint8_t *EMAC_NextPacketToRead( void );
( void ) pvParameters;
//configASSERT(CAX != 0); // This hangs the program. Do not put as first line of code here
if (KG_GetPhyLinkStatus() != 1) //PHY Link - Value 1 means Link is UP , 0 Link is Down
{
configASSERT(CAX != 0);
//return pdFAIL;
return;
}
for (;; )
{
while ((xTaskNotifyWait(0x00, 0xffffffff, &ulInterruptStatus, xBlockTime)) == pdFALSE)
/* Check whether if At least one packet has been received. */
if (EMAC_CheckReceiveIndex() == FALSE) //Not even one packet received
goto Go_for_next_cycle;
/* Obtain the length, minus the CRC. The CRC is four bytes but the length is already minus 1. */
xBytesReceived = (size_t)EMAC_GetReceiveDataSize() - (usCRCLength - 1U);
//xBytesReceived = EMAC_ReadPacket(pucUseBuffer);
if (xBytesReceived == 0) // No data from the hardware
{
goto Go_for_next_cycle;
}
//Allocate NetworkBufferDescriptor
pxNextNetworkBufferDescriptor = pxGetNetworkBufferWithDescriptor(xBytesReceived, xBlockTime);
if (pxNextNetworkBufferDescriptor == NULL) //No free buffer available
{
iptraceETHERNET_RX_EVENT_LOST();
goto Go_for_next_cycle;
}
pxNextNetworkBufferDescriptor->pucEthernetBuffer = EMAC_NextPacketToRead();
pxNextNetworkBufferDescriptor->xDataLength = xBytesReceived;
/* See if the data contained in the received Ethernet frame needs to be processed. NOTE! It is preferable to do this in
the interrupt service routine itself, which would remove the need to unblock this task for packets that don't need processing. */
if (eConsiderFrameForProcessing(pxNextNetworkBufferDescriptor->pucEthernetBuffer) != eProcessBuffer)
goto Go_for_next_cycle;
xRxEvent.eEventType = eNetworkRxEvent; /* The event about to be sent to the TCP/IP is an Rx event. */
xRxEvent.pvData = (void *)pxNextNetworkBufferDescriptor;
/* Data was received and stored. Send a message to the IP task to let it know. */
if (xQueueSendToBack(xNetworkEventQueue, &xRxEvent, (TickType_t)0) == pdFALSE)
//if (xSendEventStructToIPTask(&xRxEvent, xBlockTime) == pdFALSE)
{
/* The buffer could not be sent to the stack so must be released again. */
vReleaseNetworkBufferAndDescriptor(pxNextNetworkBufferDescriptor);
iptraceETHERNET_RX_EVENT_LOST();
//configASSERT(CAX != 0);
}
else
{
/* The message was successfully sent to the TCP/IP stack. Call the standard trace macro to log the occurrence. */
iptraceNETWORK_INTERFACE_RECEIVE();
//configASSERT(CAX != 0); // Program comes here 23-Jun-2016
}
Go_for_next_cycle:
/* The Ethernet frame can be dropped, but the Ethernet buffer must be released. */
vReleaseNetworkBufferAndDescriptor(pxNextNetworkBufferDescriptor);
pxNextNetworkBufferDescriptor = NULL;
/* Release the frame. */
EMAC_UpdateRxConsumeIndex();
//configASSERT(CAX != 0); //Program comes here 22-Jun-2016
}
}
static int32_t KG_GetPhyLinkStatus( void)
{
static uint32_t ulPHYState;
TickType_t xStartTime = xTaskGetTickCount();
TickType_t xEndTime;
const TickType_t xShortTime = pdMS_TO_TICKS( 100UL );
const TickType_t xMaxTime = 10000UL;
// Input Parameter ulPHYState values can be
// - EMC_PHY_STAT_LINK to know MAC PHY Link Status
// - EMC_PHY_STAT_SPEED to know Speed Status
// - EMC_PHY_STAT_DUP to know Duplex Status
// - Above Definitions are in KG_lpc17xx_emac.h
ulPHYState = EMAC_PHY_STAT_LINK;
EMAC_PHYLinkStatus = 0;
for( ;; )
{
xEndTime = xTaskGetTickCount();
if( ( xEndTime - xStartTime ) > xMaxTime )
{
/* Wated for xMaxTime, return. */
configASSERT( CAX != 0 );
//return pdFAIL;
break;
}
EMAC_PHYLinkStatus = EMAC_CheckPHYStatus(ulPHYState); // Value 1 - Link is UP , 0 Link is Down
if (EMAC_PHYLinkStatus == 1) //PHY Link is UP
{
break;
}
vTaskDelay( xShortTime); //Wait for PHY Link to be UP
}
return (EMAC_PHYLinkStatus);
}
The lpc17xx_emac.c used is as follows.
/* This driver was modified by Kamlesh J Gandhi on 7-May-2016 */
#include <string.h>
#include “KG_lpc17xx_emac.h”
#include “uip-conf.h”
#include “uipopt.h”
#define 10MBIT 1
//Rx descriptor Data array - Must be 8-Byte alligned
//static volatile RX_Desc Rx_Desc[ NUM_RX_FRAG];
//static volatile attribute ((aligned (8))) RX_Stat Rx_Stat[NUM_RX_FRAG];
//static volatile RX_Stat Rx_Stat[ NUM_RX_FRAG ];
//Tx descriptor Data array
//static volatile TX_Desc Tx_Desc[ NUM_TX_FRAG ];
//static volatile TX_Stat Tx_Stat[ NUM_TX_FRAG ];
static unsigned int TxDescIndex = 0;
//Private Functions ----------------------------------------------------------
static void rx_descr_init( void );
static void tx_descr_init( void );
static void write_PHY( UNS_32 PhyReg, UNS_32 Value );
static UNS_16 read_PHY( UNS_8 PhyReg );
//#if 0
/*
//THIS CODE WAS REMOVED BY RB AS THE BUFFERS ARE MANUALLY PLACED IN THE AHB RAM
//BY THE APPLICATION CODE.
// EMAC local DMA buffers
// Rx buffer data
static uint32_t rx_buf[EMAC_NUM_RX_FRAG][ETH_MAX_FLEN>>2] = { { 0 }, { 0 } };
// Tx buffer data
static uint32_t tx_buf[EMAC_NUM_TX_FRAG][ETH_MAX_FLEN>>2] = { { 0 }, { 0 } };
uint32_t rx_buf[NUM_RX_FRAG][ETH_MAX_FLEN>>2];
uint32_t tx_buf[NUM_TX_FRAG][ETH_MAX_FLEN>>2];
#endif // 0
*/
//static void setEmacAddr(uint8_t abStationAddr[]);
//static int32_t emac_CRCCalc(uint8_t frame_no_fcs[], int32_t frame_len);
/--------------------------- write_PHY -------------------------------------/
static void write_PHY (UNS_32 PhyReg, UNS_32 Value)
{
unsigned int tout;
LPC_EMAC->MADR = DP83848C_DEF_ADR | PhyReg;
LPC_EMAC->MWTD = Value;
/* Wait utill operation completed */
tout = 0;
for( tout = 0; tout < MII_WR_TOUT; tout++ )
{
if ((LPC_EMAC->MIND & MIND_BUSY) == 0)
{
break;
}
}
}
/--------------------------- read_PHY -------------------------------------/
static UNS_16 read_PHY (UNS_8 PhyReg)
{
UNS_32 tout;
LPC_EMAC->MADR = DP83848C_DEF_ADR | PhyReg;
LPC_EMAC->MCMD = MCMD_READ;
/* Wait until operation completed */
tout = 0;
for( tout = 0; tout < MII_RD_TOUT; tout++ )
{
if ((LPC_EMAC->MIND & MIND_BUSY) == 0)
{
break;
}
}
LPC_EMAC->MCMD = 0;
return (LPC_EMAC->MRDD);
}
/--------------------------- EMAC_ReadPacket ---------------------------------/
UNS_32 EMAC_ReadPacket(void * pPacket)
{
UNS_32 Index = LPC_EMAC->RxConsumeIndex;
UNS_32 size;
if(Index == LPC_EMAC->RxProduceIndex)
{
return(0);
}
size = (RX_STAT_INFO(Index) & 0x7ff)+1;
if (size > ETH_FRAG_SIZE)
size = ETH_FRAG_SIZE;
memcpy(pPacket,(unsigned int *)RX_BUF(Index),size);
if(++Index > LPC_EMAC->RxDescriptorNumber)
{
Index = 0;
}
LPC_EMAC->RxConsumeIndex = Index;
return(size);
}
/--------------------------- EMAC_SendPacket ---------------------------------/
BOOL_32 EMAC_SendPacket(void *pPacket, UNS_32 size)
{
UNS_32 Index;
UNS_32 IndexNext = LPC_EMAC->TxProduceIndex + 1;
if(size == 0)
{
return(TRUE);
}
if(IndexNext > LPC_EMAC->TxDescriptorNumber)
{
IndexNext = 0;
}
if(IndexNext == LPC_EMAC->TxConsumeIndex)
{
return(FALSE);
}
Index = LPC_EMAC->TxProduceIndex;
if (size > ETH_FRAG_SIZE)
size = ETH_FRAG_SIZE;
memcpy((unsigned int *)TX_BUF(Index),pPacket,size);
TX_DESC_CTRL(Index) &= ~0x7ff;
TX_DESC_CTRL(Index) |= (size - 1) & 0x7ff;
LPC_EMAC->TxProduceIndex = IndexNext;
return(TRUE);
}
/--------------------------- rx_descr_init ---------------------------------/
static void rx_descr_init (void)
{
UNS_32 i;
for (i = 0; i < NUM_RX_FRAG; i++ )
{
RX_DESC_PACKET(i) = RX_BUF(i);
RX_DESC_CTRL(i) = RCTRL_INT | (ETH_FRAG_SIZE-1);
RX_STAT_INFO(i) = 0;
RX_STAT_HASHCRC(i) = 0;
}
/* Set EMAC Receive Descriptor Registers. */
LPC_EMAC->RxDescriptor = RX_DESC_BASE;
LPC_EMAC->RxStatus = RX_STAT_BASE;
LPC_EMAC->RxDescriptorNumber = NUM_RX_FRAG-1;
/* Rx Descriptors Point to 0 */
LPC_EMAC->RxConsumeIndex = 0;
}
/--------------------------- tx_descr_init ---------------------------------/
static void tx_descr_init (void)
{
UNS_32 i;
for (i = 0; i < NUM_TX_FRAG; i++)
{
TX_DESC_PACKET(i) = TX_BUF(i);
TX_DESC_CTRL(i) = (1UL<<31) | (1UL<<30) | (1UL<<29) | (1UL<<28) | (1UL<<26) | (ETH_FRAG_SIZE-1);
TX_STAT_INFO(i) = 0;
}
/* Set EMAC Transmit Descriptor Registers. */
LPC_EMAC->TxDescriptor = TX_DESC_BASE;
LPC_EMAC->TxStatus = TX_STAT_BASE;
LPC_EMAC->TxDescriptorNumber = NUM_TX_FRAG-1;
/* Tx Descriptors Point to 0 /
LPC_EMAC->TxProduceIndex = 0;
}
/ The following macro definitions may be used to select the speed
of the physical link:
10MBIT - connect at 10 MBit only
100MBIT - connect at 100 MBit only
By default an autonegotiation of the link speed is used. This may take
longer to connect, but it works for 10MBit and 100MBit physical links. */
/* Local Function Prototypes */
/--------------------------- EMAC_Init ---------------------------------/
BOOL_32 EMAC_Init(void)
{
/* Initialize the EMAC ethernet controller. */
UNS_32 regv,tout,id1,id2;
/* Power Up the EMAC controller. */
LPC_SC->PCONP |= 0x40000000;
/* Enable P1 Ethernet Pins. /
LPC_PINCON->PINSEL2 = 0x50150105;
LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~0x0000000F) | 0x00000005;
//LPC_PINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~0x0000000F);// | 0x00000005;
/ Reset all EMAC internal modules. */
LPC_EMAC->MAC1 = MAC1_RES_TX | MAC1_RES_MCS_TX | MAC1_RES_RX | MAC1_RES_MCS_RX |
MAC1_SIM_RES | MAC1_SOFT_RES;
LPC_EMAC->Command = CR_REG_RES | CR_TX_RES | CR_RX_RES; // 0011 1000
/* A short delay after reset. */
for( tout = 100; tout; tout-- );
/* Initialize MAC control registers. */
LPC_EMAC->MAC1 = MAC1_PASS_ALL;
LPC_EMAC->MAC2 = MAC2_CRC_EN | MAC2_PAD_EN;
LPC_EMAC->MAXF = ETH_MAX_FLEN;
LPC_EMAC->CLRT = CLRT_DEF;
LPC_EMAC->IPGR = IPGR_DEF;
/* PCLK=18MHz, clock select=6, MDC=18/6=3MHz /
/ Enable Reduced MII interface. */
LPC_EMAC->MCFG = MCFG_CLK_DIV20 | MCFG_RES_MII;// 1000 0000 0001 1000:::::::::::::::
//LPC_EMAC->MCFG = MCFG_CLK_DIV20;
for (tout = 100; tout; tout–);
LPC_EMAC->MCFG = MCFG_CLK_DIV20;
/* Enable Reduced MII interface. */
LPC_EMAC->Command = CR_RMII | CR_PASS_RUNT_FRM | CR_PASS_RX_FILT;// 0010 1100 0000
/* Reset Reduced MII Logic. */
LPC_EMAC->SUPP = SUPP_RES_RMII | SUPP_SPEED;
for (tout = 100; tout; tout–);
LPC_EMAC->SUPP = SUPP_SPEED;
/* Put the PHY in reset mode */
write_PHY (PHY_REG_BMCR, 0x8000);
for( tout = 1000; tout; tout-- );
/* Wait for hardware reset to end. */
for (tout = 0; tout < 0x100000; tout++)
{
regv = read_PHY (PHY_REG_BMCR);
#if defined (KEIL_BOARD_MCB17XX)
if (!(regv & 0x8000))
#else
#error “No board!”
#endif
{
/* Reset complete /
break;
}
}
if( tout >= 0x100000)
return FALSE; / reset failed */
/* Check if this is a DP83848C PHY. */
id1 = read_PHY (PHY_REG_IDR1);
id2 = read_PHY (PHY_REG_IDR2);
#if defined (KEIL_BOARD_MCB17XX)
if (((id1 << 16) | (id2 & 0xFFF0)) != DP83848C_ID)
#else
#error “No board”
#endif
return FALSE;
/* Configure the PHY device */
/* Configure the PHY device */
#if defined (10MBIT)
/* Connect at 10MBit /
write_PHY (PHY_REG_BMCR, PHY_FULLD_10M);
#elif defined (100MBIT)
/ Connect at 100MBit /
write_PHY (PHY_REG_BMCR, PHY_FULLD_100M);
#else
/ Use autonegotiation about the link speed. /
write_PHY (PHY_REG_BMCR, PHY_AUTO_NEG);
/ Wait to complete Auto_Negotiation. /
for (tout = 0; tout < 0x100000; tout++) {
regv = read_PHY (PHY_REG_BMSR);
if (regv & 0x0020) {
/ Autonegotiation Complete. */
break;
}
}
#endif
if (tout >= 0x100000)
return FALSE; // auto_neg failed
/* Check the link status. */
for (tout = 0; tout < 0x10000; tout++)
{
#if defined (KEIL_BOARD_MCB17XX)
regv = read_PHY (PHY_REG_STS);
if (regv & 0x0001)
#else
#error “No board”
#endif
{
/* Link is on. */
break;
}
}//FOR LOOP END
if( tout >= 0x10000 )
return FALSE;
/* Configure Full/Half Duplex mode. /
#if defined (KEIL_BOARD_MCB17XX)
if (regv & 0x0004)
#else
#error “No board”
#endif
{
/ Full duplex is enabled. /
LPC_EMAC->MAC2 |= MAC2_FULL_DUP;
LPC_EMAC->Command |= CR_FULL_DUP;
LPC_EMAC->IPGT = IPGT_FULL_DUP;
}
// else
{
/ Half duplex mode. */
LPC_EMAC->IPGT = IPGT_HALF_DUP;
}
/* Configure 100MBit/10MBit mode. /
#if defined (KEIL_BOARD_MCB17XX)
if (regv & 0x0002) {
#else
#error “No baord”
#endif
/ 10MBit mode. */
LPC_EMAC->SUPP = 0;
}
else{
/* 100MBit mode. */
LPC_EMAC->SUPP = SUPP_SPEED;
}
/* Set the Ethernet MAC Address registers */
// MAC_SA0 = (MYMAC_6 << 8) | MYMAC_5;
// MAC_SA1 = (MYMAC_4 << 8) | MYMAC_3;
// MAC_SA2 = (MYMAC_2 << 8) | MYMAC_1;
LPC_EMAC->SA0 = (UIP_ETHADDR1<<8) | UIP_ETHADDR0;
LPC_EMAC->SA1 = (UIP_ETHADDR3<<8) | UIP_ETHADDR2;
LPC_EMAC->SA2 = (UIP_ETHADDR5<<8) | UIP_ETHADDR4;
/* Initialize Tx and Rx DMA Descriptors */
rx_descr_init ();
tx_descr_init ();
/* Receive Broadcast and Perfect Match Packets */
LPC_EMAC->RxFilterCtrl = RFC_BCAST_EN | RFC_PERFECT_EN;
/* Enable EMAC interrupts. */
//EMAC->IntEnable = INT_RX_DONE | INT_TX_DONE;
/* Reset all interrupts */
//EMAC->IntClear = 0xFFFF;
/* Enable receive and transmit mode of MAC Ethernet core */
LPC_EMAC->Command |= (CR_RX_EN | CR_TX_EN);
LPC_EMAC->MAC1 |= MAC1_REC_EN;
/* Configure VIC for EMAC interrupt. */
//VICVectAddrxx = (UNS_32)xx;
return TRUE;
}
/*******************************************************************//
-
@brief Check specified PHY status in EMAC peripheral
-
@param[in] ulPHYState Specified PHY Status Type, should be:
-
- EMAC_PHY_STAT_LINK: Link Status
-
- EMAC_PHY_STAT_SPEED: Speed Status
-
- EMAC_PHY_STAT_DUP: Duplex Status
-
@return Status of specified PHY status (0 or 1).
-
(-1) if error.
-
Note:
-
For EMAC_PHY_STAT_LINK, return value:
-
- 0: Link Down
-
- 1: Link Up
-
For EMAC_PHY_STAT_SPEED, return value:
-
- 0: 10Mbps
-
- 1: 100Mbps
-
For EMAC_PHY_STAT_DUP, return value:
-
- 0: Half-Duplex
-
- 1: Full-Duplex
*********************************************************************/
int32_t EMAC_CheckPHYStatus (uint32_t ulPHYState)
{
int32_t regv, tmp;
//#ifdef MCB_LPC_1768
regv = read_PHY (PHY_REG_STS);
switch(ulPHYState)
{
case EMAC_PHY_STAT_LINK:
tmp = (regv & EMAC_PHY_SR_LINK) ? 1 : 0;
break;
case EMAC_PHY_STAT_SPEED:
tmp = (regv & EMAC_PHY_SR_SPEED) ? 0 : 1;
break;
case EMAC_PHY_STAT_DUP:
tmp = (regv & EMAC_PHY_SR_DUP) ? 1 : 0;
break;
/
#elif defined(IAR_LPC_1768)
//Use IAR_LPC_1768 board:
//FSZ8721BL doesn’t have Status Register
//so we read Basic Mode Status Register (0x01h) instead
//
regv = read_PHY (EMAC_PHY_REG_BMSR);
switch(ulPHYState){
case EMAC_PHY_STAT_LINK:
tmp = (regv & EMAC_PHY_BMSR_LINK_STATUS) ? 1 : 0;
break;
case EMAC_PHY_STAT_SPEED:
tmp = (regv & EMAC_PHY_SR_100_SPEED) ? 1 : 0;
break;
case EMAC_PHY_STAT_DUP:
tmp = (regv & EMAC_PHY_SR_FULL_DUP) ? 1 : 0;
break;
#endif
*/
default:
tmp = -1;
break;
}
return (tmp);
} - 1: Full-Duplex
/* Addded by Kamlesh J Gandhi on 7-May-2016----------------------------------- */
uint8_t *EMAC_NextPacketToSend( void )
{
//return ( uint8_t * ) Tx_Desc[ LPC_EMAC->TxProduceIndex ].Packet;
return ( uint8_t * ) TX_DESC_PACKET(LPC_EMAC->TxProduceIndex );
}
uint8_t *EMAC_NextPacketToRead( void )
{
//return ( uint8_t * ) Rx_Desc[ LPC_EMAC->RxConsumeIndex ].Packet;
return ( uint8_t * ) RX_DESC_PACKET (LPC_EMAC->RxConsumeIndex );
}
void EMAC_StartTransmitNextBuffer( uint32_t ulLength )
{
// Get current Tx produce index
uint32_t idx = LPC_EMAC->TxProduceIndex;
//Tx_Desc[idx].Ctrl = (ulLength - 1) | (EMAC_TCTRL_INT | EMAC_TCTRL_LAST);
//Tx_Desc[idx].Ctrl = (ulLength - 1) | (TCTRL_INT | TCTRL_LAST); //Modified by Kamlesh J Gandhi
TX_DESC_CTRL(idx) = (ulLength - 1) | (TCTRL_INT | TCTRL_LAST); //Modified by Kamlesh J Gandhi
//if (++idx == EMAC_NUM_TX_FRAG) idx = 0;
if (++idx == NUM_TX_FRAG) idx = 0; //Modified by Kamlesh J Gandhi
LPC_EMAC->TxProduceIndex = idx;
}
/*******************************************************************//
307 * @brief EMAC_SetNextPacketToSend
308 * @param[in] pucBuffer
309 * @return None
310 ***********************************************************************/
void EMAC_SetNextPacketToSend( uint8_t * pucBuffer )
{
//The old packet is now finished with and can be freed.
//vEthernetBufferRelease( ( void * ) Tx_Desc[ TxDescIndex ].Packet );
//vReleaseNetworkBuffer( ( void * ) Tx_Desc[ TxDescIndex ].Packet ); //Modified by Kamlesh J Gandhi on 11-May-2016
vReleaseNetworkBuffer( ( void * ) TX_DESC_PACKET (TxDescIndex )); //Modified by Kamlesh J Gandhi on 11-May-2016
//Assign the new packet to the descriptor.
//Tx_Desc[ TxDescIndex ].Packet = ( uint32_t ) pucBuffer;
TX_DESC_PACKET (TxDescIndex ) = ( uint32_t ) pucBuffer;
}
/*******************************************************************//
- @brief Check whether if the current RxConsumeIndex is not equal to the
-
current RxProduceIndex.
- @param[in] None
- @return TRUE if they’re not equal, otherwise return FALSE
- Note: In case the RxConsumeIndex is not equal to the RxProduceIndex,
- it means there’re available data has been received. They should be read
- out and released the Receive Data Buffer by updating the RxConsumeIndex value.
**********************************************************************/
BOOL_32 EMAC_CheckReceiveIndex(void)
{
if (LPC_EMAC->RxConsumeIndex != LPC_EMAC->RxProduceIndex)
{
return TRUE;
} else
{
return FALSE;
}
}
/*******************************************************************//
- @brief Check whether if the current TxProduceIndex is not equal to the
-
current RxProduceIndex - 1.
- @param[in] None
- @return TRUE if they’re not equal, otherwise return FALSE
- Note: In case the RxConsumeIndex is equal to the RxProduceIndex - 1,
- it means the transmit buffer is available and data can be written to transmit
- buffer to be sent.
**********************************************************************/
BOOL_32 EMAC_CheckTransmitIndex(void)
{
uint32_t tmp = LPC_EMAC->TxConsumeIndex;
if (LPC_EMAC->TxProduceIndex == ( tmp - 1 ))
{
return FALSE;
}
//else if( ( tmp == 0 ) && ( LPC_EMAC->TxProduceIndex == ( EMAC_NUM_TX_FRAG - 1 ) ) )
else if( ( tmp == 0 ) && ( LPC_EMAC->TxProduceIndex == ( NUM_TX_FRAG - 1 ) ) ) //Modified by Kamlesh J Gandhi
{
return FALSE;
}
else
{
return TRUE;
}
}
/*******************************************************************//
- @brief Get size of current Received data in received buffer (due to
-
RxConsumeIndex)
- @param[in] None
-
@return Size of received data
**********************************************************************/
uint32_t EMAC_GetReceiveDataSize(void)
{
uint32_t idx;
idx =LPC_EMAC->RxConsumeIndex;
//return ((Rx_Stat[idx].Info) & EMAC_RINFO_SIZE);
//return ((Rx_Stat[idx].Info) & RINFO_SIZE); //Kamlesh J Gandhi modified on 7-May-2016
return ((RX_STAT_INFO(idx)) & RINFO_SIZE); //Kamlesh J Gandhi modified on 15-May-2016
}
/*******************************************************************//
- @brief Increase the RxConsumeIndex (after reading the Receive buffer
-
to release the Receive buffer) and wrap-around the index if
-
it reaches the maximum Receive Number
- @param[in] None
-
@return None
**********************************************************************/
void EMAC_UpdateRxConsumeIndex(void)
{
// Get current Rx consume index
uint32_t idx = LPC_EMAC->RxConsumeIndex;
//Release frame from EMAC buffer
//if (++idx == EMAC_NUM_RX_FRAG) idx = 0;
if (++idx == NUM_RX_FRAG) idx = 0; //Modified by Kamlesh J Gandhi
LPC_EMAC->RxConsumeIndex = idx;
}
/----------------------------------Kamlesh J Gandhi --End of file ---------------------------/