We have FreeRTOSPlusTCP Server application (developed using FreeRTOS Socket API) is running on NXP LPC1768 and modified FreeRTOSPlusTCPMinimalWindowsSimulator 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. FreeRTOSPlusTCPMinimalWindowsSimulator 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 FreeRTOSaccept start executing (if fact FreeRTOSaccept 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. */
uint8t ucMACAddress[ 6 ] = { 0x00,0x07,0x27,0x07,0x19,0x54 };
static const uint8t ucIPAddress[4] = { 192,168,1,211 };
static const uint8t ucNetMask[ 4 ] = { 255, 255, 255, 0 };
static const uint8t 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( vuKGTCPTask, "uIP WEBSERVER", mainBASICUIPWEBSTACKSIZE, NULL, mainUIPTASK_PRIORITY, &xUIPTaskHandle );
/* Start the scheduler so our tasks start executing. */
vTaskStartScheduler();
for( ;; )
{
}
return 0;
}
void vApplicationIPNetworkEventHook( eIPCallbackEventt eNetworkEvent )
{
static BaseTypet 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 vuKGTCPSendReceiveTask(void)
static struct freertossockaddr xClient, xBindAdress;
Sockett xListeningSocket, xConnectedSocket;
socklent xSize = sizeof(xClient);
xWinProperties_t xWinProps;
const BaseType_t xBacklog = 20;
//static const TickTypet xReceiveTimeOut = portMAXDELAY;
//static const TickTypet xSendTimeOut = portMAXDELAY;
static const TickTypet xReceiveTimeOut = pdMSTOTICKS( 20 );
static const TickTypet xSendTimeOut = pdMSTOTICKS(100);
BaseType_t xBytesRecceived = 0;
define Buffer_Size 30
static char RcvBuffer[BufferSize];
xListeningSocket = FreeRTOSsocket(FREERTOSAFINET, FREERTOSSOCKSTREAM, FREERTOSIPPROTOTCP);
configASSERT(xListeningSocket != FREERTOSINVALIDSOCKET);
if (xListeningSocket != FREERTOSINVALIDSOCKET)
{
sprintf(pBuff, "%sn", "Server Socket Created Successfully...n"); kgprint(pBuff);
}
else
{
sprintf(pBuff, "%sn", "Failed to Create Server Socket ...n"); kgprint(pBuff);
//goto ReviveUIPWEBSERVER;
}
FreeRTOSsetsockopt(xListeningSocket, 0, FREERTOSSORCVTIMEO, &xReceiveTimeOut, sizeof(xReceiveTimeOut));
FreeRTOSsetsockopt(xListeningSocket, 0, FREERTOSSOSNDTIMEO, &xSendTimeOut, sizeof(xSendTimeOut));
if( ipconfigUSETCPWIN == 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. */
FreeRTOSsetsockopt( xListeningSocket,0,FREERTOSSOWINPROPERTIES,&xWinProps, sizeof( xWinProps ) );
endif /* ipconfigUSETCPWIN */
xBindAdress.sinaddr = FreeRTOSinetaddrquick( 192,168,1,211);
xBindAdress.sinport = FreeRTOShtons( 27754);
if (FreeRTOS_bind( xListeningSocket, &xBindAdress, sizeof(xBindAdress) ) == 0)
{
sprintf(pBuff,"%sn","Server Bind AT PORT 27754 Successful....n");kgprint(pBuff); }
else
{
sprintf(pBuff,"%sn","Server Bind Failed....n");kgprint(pBuff);
}
if (FreeRTOS_listen(xListeningSocket, xBacklog) == 0)
{
sprintf(pBuff,"%sn","Listening for Client...n"); kgprint(pBuff
}
sprintf(pBuff, "%sn", "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
}
SocShutdown:
/* Initiate graceful shutdown. */
FreeRTOSshutdown( xListeningSocket, FREERTOSSHUTRDWR );
FreeRTOSshutdown( xConnectedSocket, FREERTOSSHUT_RDWR );
vTaskDelay(500 ); //wait for graceful disconnect
/* The socket has shut down and is safe to close. */
sprintf(pBuff,"%sn","Closing Sockets.....n"); kgprint(pBuff);
FreeRTOSclosesocket( xListeningSocket );
FreeRTOSclosesocket( 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
include
include
/* FreeRTOS includes. */
include "FreeRTOS.h"
include "task.h"
include "queue.h"
include "semphr.h"
include "KGlpc17xxemac.h"
//#include "lpc17xx.h"
/* FreeRTOS+TCP includes. */
include "FreeRTOS_IP.h"
include "FreeRTOS_Sockets.h"
include "FreeRTOSIPPrivate.h"
include "NetworkBufferManagement.h"
include "KG_NetworkInterface.h"
//#include "uart.h"
if ipconfigETHERNETDRIVERFILTERSFRAMETYPES != 1
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer
else
#define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )
endif
/-------------------------------------------------------------------------------------/
static int32t EMACPHYLinkStatus;
ifndef EMACMAXBLOCKTIMEMS
#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 niTXBUFFERFREEWAIT
milliseconds. It will do this a maximum of niMAXTX_ATTEMPTS before giving up. */
define niTXBUFFERFREEWAIT ( ( TickTypet ) 2UL / portTICKRATEMS )
define niMAXTXATTEMPTS ( 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 configMINIMALSTACKSIZE is a user definable constant. */
ifndef configEMACTASKSTACK_SIZE
#define configEMAC_TASK_STACK_SIZE ( 4 * configMINIMAL_STACK_SIZE )
endif
define configMACINTERRUPTPRIORITY 6
/-----------------------------------------------------------/
/*
* A deferred interrupt handler task that processes LPC1768 EMAC interrupts.*/
static void prvEMACHandlerTask( void *pvParameters );
static int32t KGGetPhyLinkStatus( void);
/* LLMNR multicast address. */
//static const uint8t llmnrmacaddress[] = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0xFC };
static int CAX = 0;
static int InitCnt = 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;
BaseTypet xNetworkInterfaceInitialise( void )
{
//const TickTypet 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;
}
/-----------------------------------------------------------/
BaseTypet xNetworkInterfaceOutput( xNetworkBufferDescriptort * const pxSendNetworkBufferDescriptor, BaseTypet xReleaseAfterSend )
{
BaseTypet xReturn = pdFAIL;
int32t x;
extern void EMACStartTransmitNextBuffer(uint32t ulLength);
extern void EMACSetNextPacketToSend(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 ENETIRQHandler( void )
{
uint32t 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;
sizet xBytesReceived;
sizet xDataLength;
const uint16_t usCRCLength = 4;
xNetworkBufferDescriptort *pxNextNetworkBufferDescriptor = NULL;
const TickTypet xBlockTime = pdMSTOTICKS(100UL);
const UBaseTypet xMinDescriptorsToLeave = 2UL;
xIPStackEventt xRxEvent = { eNetworkRxEvent , NULL };
uint32_t ulInterruptStatus;
int i;
/* This is not included in the header file for some reason. */
//extern uint8t *EMACNextPacketToRead( 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 int32t KGGetPhyLinkStatus( void)
{
static uint32t ulPHYState;
TickTypet xStartTime = xTaskGetTickCount();
TickTypet xEndTime;
const TickTypet xShortTime = pdMSTOTICKS( 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
include "KGlpc17xxemac.h"
include "uip-conf.h"
include "uipopt.h"
define 10MBIT 1
//Rx descriptor Data array - Must be 8-Byte alligned
//static volatile RXDesc RxDesc[ NUMRXFRAG];
//static volatile attribute ((aligned (8))) RXStat RxStat[NUMRXFRAG];
//static volatile RXStat RxStat[ NUMRXFRAG ];
//Tx descriptor Data array
//static volatile TXDesc TxDesc[ NUMTXFRAG ];
//static volatile TXStat TxStat[ NUMTXFRAG ];
static unsigned int TxDescIndex = 0;
//Private Functions ----------------------------------------------------------
static void rxdescrinit( void );
static void txdescrinit( void );
static void writePHY( UNS32 PhyReg, UNS32 Value );
static UNS16 readPHY( UNS8 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 uint32t rxbuf[EMACNUMRXFRAG][ETHMAXFLEN>>2] = { { 0 }, { 0 } };
// Tx buffer data
static uint32t txbuf[EMACNUMTXFRAG][ETHMAXFLEN>>2] = { { 0 }, { 0 } };
uint32t rxbuf[NUMRXFRAG][ETHMAXFLEN>>2];
uint32t txbuf[NUMTXFRAG][ETHMAXFLEN>>2];
endif // 0
*/
//static void setEmacAddr(uint8t abStationAddr[]);
//static int32t emacCRCCalc(uint8t framenofcs[], int32t framelen);
/--------------------------- write_PHY -------------------------------------/
static void writePHY (UNS32 PhyReg, UNS_32 Value)
{
unsigned int tout;
LPCEMAC->MADR = DP83848CDEFADR | PhyReg;
LPCEMAC->MWTD = Value;
/* Wait utill operation completed */
tout = 0;
for( tout = 0; tout < MIIWRTOUT; tout++ )
{
if ((LPCEMAC->MIND & MINDBUSY) == 0)
{
break;
}
}
}
/--------------------------- read_PHY -------------------------------------/
static UNS16 readPHY (UNS8 PhyReg)
{
UNS32 tout;
LPCEMAC->MADR = DP83848CDEFADR | PhyReg;
LPCEMAC->MCMD = MCMD_READ;
/* Wait until operation completed */
tout = 0;
for( tout = 0; tout < MIIRDTOUT; tout++ )
{
if ((LPCEMAC->MIND & MINDBUSY) == 0)
{
break;
}
}
LPCEMAC->MCMD = 0;
return (LPCEMAC->MRDD);
}
/--------------------------- EMAC_ReadPacket ---------------------------------/
UNS32 EMACReadPacket(void * pPacket)
{
UNS32 Index = LPCEMAC->RxConsumeIndex;
UNS_32 size;
if(Index == LPC_EMAC->RxProduceIndex)
{
return(0);
}
size = (RXSTATINFO(Index) & 0x7ff)+1;
if (size > ETHFRAGSIZE)
size = ETHFRAGSIZE;
memcpy(pPacket,(unsigned int *)RX_BUF(Index),size);
if(++Index > LPCEMAC->RxDescriptorNumber)
{
Index = 0;
}
LPCEMAC->RxConsumeIndex = Index;
return(size);
}
/--------------------------- EMAC_SendPacket ---------------------------------/
BOOL32 EMACSendPacket(void *pPacket, UNS32 size)
{
UNS32 Index;
UNS32 IndexNext = LPCEMAC->TxProduceIndex + 1;
if(size == 0)
{
return(TRUE);
}
if(IndexNext > LPC_EMAC->TxDescriptorNumber)
{
IndexNext = 0;
}
if(IndexNext == LPCEMAC->TxConsumeIndex)
{
return(FALSE);
}
Index = LPCEMAC->TxProduceIndex;
if (size > ETHFRAGSIZE)
size = ETHFRAGSIZE;
memcpy((unsigned int *)TXBUF(Index),pPacket,size);
TXDESCCTRL(Index) &= ~0x7ff;
TXDESC_CTRL(Index) |= (size - 1) & 0x7ff;
LPC_EMAC->TxProduceIndex = IndexNext;
return(TRUE);
}
/--------------------------- rxdescrinit ---------------------------------/
static void rxdescrinit (void)
{
UNS_32 i;
for (i = 0; i < NUMRXFRAG; i++ )
{
RXDESCPACKET(i) = RXBUF(i);
RXDESCCTRL(i) = RCTRLINT | (ETHFRAGSIZE-1);
RXSTATINFO(i) = 0;
RXSTATHASHCRC(i) = 0;
}
/* Set EMAC Receive Descriptor Registers. */
LPCEMAC->RxDescriptor = RXDESCBASE;
LPCEMAC->RxStatus = RXSTATBASE;
LPCEMAC->RxDescriptorNumber = NUMRX_FRAG-1;
/* Rx Descriptors Point to 0 */
LPC_EMAC->RxConsumeIndex = 0;
}
/--------------------------- txdescrinit ---------------------------------/
static void txdescrinit (void)
{
UNS_32 i;
for (i = 0; i < NUMTXFRAG; i++)
{
TXDESCPACKET(i) = TXBUF(i);
TXDESCCTRL(i) = (1UL<<31) | (1UL<<30) | (1UL<<29) | (1UL<<28) | (1UL<<26) | (ETHFRAGSIZE-1);
TXSTAT_INFO(i) = 0;
}
/* Set EMAC Transmit Descriptor Registers. */
LPCEMAC->TxDescriptor = TXDESCBASE;
LPCEMAC->TxStatus = TXSTATBASE;
LPCEMAC->TxDescriptorNumber = NUMTX_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 ---------------------------------/
BOOL32 EMACInit(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. /
LPCPINCON->PINSEL2 = 0x50150105;
LPCPINCON->PINSEL3 = (LPCPINCON->PINSEL3 & ~0x0000000F) | 0x00000005;
//LPCPINCON->PINSEL3 = (LPC_PINCON->PINSEL3 & ~0x0000000F);// | 0x00000005;
/ Reset all EMAC internal modules. */
LPCEMAC->MAC1 = MAC1RESTX | MAC1RESMCSTX | MAC1RESRX | MAC1RESMCSRX |
MAC1SIMRES | MAC1SOFT_RES;
LPCEMAC->Command = CRREGRES | CRTXRES | CRRX_RES; // 0011 1000
/* A short delay after reset. */
for( tout = 100; tout; tout-- );
/* Initialize MAC control registers. */
LPCEMAC->MAC1 = MAC1PASSALL;
LPCEMAC->MAC2 = MAC2CRCEN | MAC2PADEN;
LPCEMAC->MAXF = ETHMAXFLEN;
LPCEMAC->CLRT = CLRTDEF;
LPCEMAC->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:::::::::::::::
//LPCEMAC->MCFG = MCFGCLK_DIV20;
for (tout = 100; tout; tout--);
LPCEMAC->MCFG = MCFGCLK_DIV20;
/* Enable Reduced MII interface. */
LPCEMAC->Command = CRRMII | CRPASSRUNTFRM | CRPASSRXFILT;// 0010 1100 0000
/* Reset Reduced MII Logic. */
LPCEMAC->SUPP = SUPPRESRMII | SUPPSPEED;
for (tout = 100; tout; tout--);
LPCEMAC->SUPP = SUPPSPEED;
/* Put the PHY in reset mode */
writePHY (PHYREG_BMCR, 0x8000);
for( tout = 1000; tout; tout-- );
/* Wait for hardware reset to end. */
for (tout = 0; tout < 0x100000; tout++)
{
regv = readPHY (PHYREG_BMCR);
if defined (KEILBOARDMCB17XX)
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 = readPHY (PHYREGIDR1);
id2 = readPHY (PHYREGIDR2);
if defined (KEILBOARDMCB17XX)
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 (KEILBOARDMCB17XX)
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 (KEILBOARDMCB17XX)
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. */
LPCEMAC->IPGT = IPGTHALF_DUP;
}
/* Configure 100MBit/10MBit mode. */
if defined (KEILBOARDMCB17XX)
if (regv & 0x0002) {
else
#error "No baord"
endif
/* 10MBit mode. */
LPC_EMAC->SUPP = 0;
}
else{
/* 100MBit mode. */
LPCEMAC->SUPP = SUPPSPEED;
}
/* Set the Ethernet MAC Address registers */
// MACSA0 = (MYMAC6 << 8) | MYMAC5;
// MACSA1 = (MYMAC4 << 8) | MYMAC3;
// MACSA2 = (MYMAC2 << 8) | MYMAC1;
LPCEMAC->SA0 = (UIPETHADDR1<<8) | UIPETHADDR0;
LPCEMAC->SA1 = (UIPETHADDR3<<8) | UIPETHADDR2;
LPCEMAC->SA2 = (UIPETHADDR5<<8) | UIPETHADDR4;
/* Initialize Tx and Rx DMA Descriptors */
rxdescrinit ();
txdescrinit ();
/* Receive Broadcast and Perfect Match Packets */
LPCEMAC->RxFilterCtrl = RFCBCASTEN | RFCPERFECT_EN;
/* Enable EMAC interrupts. */
//EMAC->IntEnable = INTRXDONE | INTTXDONE;
/* Reset all interrupts */
//EMAC->IntClear = 0xFFFF;
/* Enable receive and transmit mode of MAC Ethernet core */
LPCEMAC->Command |= (CRRXEN | CRTXEN);
LPCEMAC->MAC1 |= MAC1RECEN;
/* 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:
* - EMACPHYSTATLINK: Link Status
* - EMACPHYSTATSPEED: Speed Status
* - EMACPHYSTATDUP: Duplex Status
* @return Status of specified PHY status (0 or 1).
* (-1) if error.
*
* Note:
* For EMACPHYSTATLINK, return value:
* - 0: Link Down
* - 1: Link Up
* For EMACPHYSTATSPEED, return value:
* - 0: 10Mbps
* - 1: 100Mbps
* For EMACPHYSTATDUP, return value:
* - 0: Half-Duplex
* - 1: Full-Duplex
**********************************************************************/
int32t EMACCheckPHYStatus (uint32t ulPHYState)
{
int32t regv, tmp;
//#ifdef MCBLPC1768
regv = readPHY (PHYREGSTS);
switch(ulPHYState)
{
case EMACPHYSTATLINK:
tmp = (regv & EMACPHYSRLINK) ? 1 : 0;
break;
case EMACPHYSTATSPEED:
tmp = (regv & EMACPHYSRSPEED) ? 0 : 1;
break;
case EMACPHYSTATDUP:
tmp = (regv & EMACPHYSR_DUP) ? 1 : 0;
break;
/
elif defined(IARLPC1768)
//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);
}
/* Addded by Kamlesh J Gandhi on 7-May-2016----------------------------------- */
uint8t *EMACNextPacketToSend( void )
{
//return ( uint8t * ) TxDesc[ LPCEMAC->TxProduceIndex ].Packet;
return ( uint8t * ) TXDESCPACKET(LPC_EMAC->TxProduceIndex );
}
uint8t *EMACNextPacketToRead( void )
{
//return ( uint8t * ) RxDesc[ LPCEMAC->RxConsumeIndex ].Packet;
return ( uint8t * ) RXDESCPACKET (LPC_EMAC->RxConsumeIndex );
}
void EMACStartTransmitNextBuffer( uint32t ulLength )
{
// Get current Tx produce index
uint32t idx = LPCEMAC->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 EMACSetNextPacketToSend( uint8t * pucBuffer )
{
//The old packet is now finished with and can be freed.
//vEthernetBufferRelease( ( void * ) TxDesc[ TxDescIndex ].Packet );
//vReleaseNetworkBuffer( ( void * ) TxDesc[ TxDescIndex ].Packet ); //Modified by Kamlesh J Gandhi on 11-May-2016
vReleaseNetworkBuffer( ( void * ) TXDESCPACKET (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.
**********************************************************************/
BOOL32 EMACCheckReceiveIndex(void)
{
if (LPCEMAC->RxConsumeIndex != LPCEMAC->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.
**********************************************************************/
BOOL32 EMACCheckTransmitIndex(void)
{
uint32t tmp = LPCEMAC->TxConsumeIndex;
if (LPCEMAC->TxProduceIndex == ( tmp - 1 ))
{
return FALSE;
}
//else if( ( tmp == 0 ) && ( LPCEMAC->TxProduceIndex == ( EMACNUMTXFRAG - 1 ) ) )
else if( ( tmp == 0 ) && ( LPCEMAC->TxProduceIndex == ( NUMTXFRAG - 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
**********************************************************************/
uint32t EMACGetReceiveDataSize(void)
{
uint32t idx;
idx =LPCEMAC->RxConsumeIndex;
//return ((RxStat[idx].Info) & EMACRINFOSIZE);
//return ((RxStat[idx].Info) & RINFOSIZE); //Kamlesh J Gandhi modified on 7-May-2016
return ((RXSTATINFO(idx)) & RINFOSIZE); //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 EMACUpdateRxConsumeIndex(void)
{
// Get current Rx consume index
uint32t 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 ---------------------------/