📄 xllp_ethernet.c
字号:
None
Input Arguments:
P_XLLP_UCHAR_T frame - a pointer to the frame.
XLLP_UINT16_T length - length of the frame.
Output Arguments:
None
Return Value:
None
*******************************************************************************/
void XllpEthernetDumpFrame(P_XLLP_UINT8_T frame, XLLP_UINT16_T length)
{
XLLP_UINT32_T x;
printf(" To: %02x:%02x:%02x:%02x:%02x:%02x\r\n",
frame[0], frame[1], frame[2],
frame[3], frame[4], frame[5]);
printf(" From: %02x:%02x:%02x:%02x:%02x:%02x\r\n",
frame[6], frame[7], frame[8],
frame[9], frame[10], frame[11]);
printf(" Type: 0x%x, Length: %u\r\n",
ntohs(*((P_XLLP_UINT16_T)(frame + 12))), length);
for (x = 14; x < length; x += 8)
{
printf(" %02x %02x %02x %02x %02x %02x %02x %02x\r\n",
frame[x],
frame[x + 1],
frame[x + 2],
frame[x + 3],
frame[x + 4],
frame[x + 5],
frame[x + 6],
frame[x + 7]);
}
}
/******************************************************************************
Function Name:
XllpEthernetVerifyRAMBuffer
Description:
This routine used for debugging to verify the data placed into the RAM.
Global Register Modified:
None
Input Arguments:
XLLP_UINT32_T bufferSize - a length of the frame stored in the RAM
Output Arguments:
None
Return Value:
None
*******************************************************************************/
void XllpEthernetVerifyRAMBuffer (XLLP_UINT32_T bufferSize)
{
XLLP_UINT16_T j;
XLLP_UINT32_T testValue;
XllpEthernetSelectRegisterBank (BANK2);
for (j = 0; j < (XLLP_UINT16_T)bufferSize; j+=4)
{
// Read data
XllpEthernetWriteWord((XLLP_UINT16_T)(XLLP_LAN91C111_PTR_AUTO_INCR | XLLP_LAN91C111_PTR_READ | j), XLLP_LAN91C111_POINTER);
testValue = XllpEthernetReadDoubleWord(XLLP_LAN91C111_DATA_HIGH);
printf("%d: %08X\r\n", (int)j, (int)testValue);
}
}
/******************************************************************************
Function Name:
XllpEthernetTransmitPacket
Description:
This routine transmits a frame. It polls the Interrupt Status Register for the
completion of the TX
- It allocates a packet for transmit frame.
- Set the Auto Increment bit in the Pointer Register to increment the internal address
on access to the data register.
- Writes the frame into Tx FIFO
- Enqueue the frame number into the TX FIFO.
- Checks the Interrupt Status Register for Transmit Empty and Tx Error.
- Acknowledges the Transmit interrupt or errors
Global Register Modified:
None
Input Arguments:
P_XLLP_UINT16_T buffer - a data buffer where the frame data will be taken from
XLLP_UINT32_T length - a length of the frame
Output Arguments:
None
Return Value:
XLLP_UINT_T - error code if failed, zero if success
*******************************************************************************/
XLLP_UINT32_T XllpEthernetTransmitPacket(P_XLLP_UINT16_T buffer,
XLLP_UINT32_T length)
{
XLLP_UINT32_T start, timebase = getTimebase();
XLLP_UINT32_T timeout = XLLP_LAN91C111_TO_TRANSMIT * timebase;
XLLP_UINT8_T intStatus;
XLLP_UINT16_T bufferSize, x;
XLLP_UINT16_T resultCode;
XLLP_UINT16_T frameHandle = 0;
P_XLLP_UINT16_T dataP = buffer;
XLLP_BOOL_T oddFlag = XLLP_FALSE;
XLLP_UINT16_T revision;
P_XLLP_VUINT8_T ioRegsP = (P_XLLP_VUINT8_T)XllpEthernetGetPointerToIORegistersBase (); // Get pointer to I/O space
//////////////////////////////////
// Evil hack to work around the memory leak we are currently experiencing with autorelease mode.
// Expect that future rework to the transmit routine that checks the EPH status register will fix this problem.
// Until then, check the available memory, and if it has decreased, reset the MMU to release these packets.
XllpEthernetSelectRegisterBank (BANK0);
// Upper half word
bufferSize = (*(ioRegsP + 9));
// read available memory
// if too low, reset device.
if (bufferSize < 3)
{
XllpEthernetSelectRegisterBank (BANK2);
XllpEthernetWriteWord16(XLLP_LAN91C111_MMUCR_RESET_MMU, XLLP_LAN91C111_MMU);
}
//////////////////////////////////
// Read the LAN91C111 revision. This assumes Bank 3 is selected.
XllpEthernetSelectRegisterBank (BANK3);
revision = XllpEthernetReadWord(XLLP_LAN91C111_REVISION);
DM_CwDbgPrintf(DM_CW_LAN91C111_0, " LAN91C111 Revision: %d, Chip: %d",
(revision & 0x0F),
(revision & 0xF0) >> 4);
// Clear the error log.
loggedError = 0;
// Allocate a transmit frame from the LAN91C111.
if (XllpEthernetAllocateTxPacket(&frameHandle))
{
return loggedError;
}
// Write the allocated packet number into the Packet Number Register.
XllpEthernetSelectRegisterBank (BANK2);
XllpEthernetWriteByte((XLLP_UINT8_T)frameHandle, XLLP_LAN91C111_PNR);
// Set the Auto Increment bit in the Pointer Register to increment the
// internal address on access to the data register.
XllpEthernetWriteWord(XLLP_LAN91C111_PTR_AUTO_INCR, XLLP_LAN91C111_POINTER);
// Calculate the memory needed. This includes the status word, byte count
// data and control rounded up.
bufferSize = sizeof(XLLP_UINT16_T) + sizeof(XLLP_UINT16_T) + length + 1;
if (bufferSize & 1)
{
// Round the size up.
bufferSize++;
}
else
{
// Check for Revision A for odd byte workaround.
if ((revision & 0x0F) <= 1)
{
// Add an extra 2 bytes to the internal buffer length to workaround
// the odd byte problem.
bufferSize += 3;
oddFlag = XLLP_TRUE;
DM_CwDbgPrintf(DM_CW_LAN91C111_0, " Odd byte workaround");
}
}
// Write the status word.
XllpEthernetWriteWord16(0, XLLP_LAN91C111_DATA_HIGH);
// Write the byte count.
XllpEthernetWriteWord16(bufferSize, XLLP_LAN91C111_DATA_HIGH);
// Write to the packet buffer:
for (x = 0; x < length; x+=2)
{
// Write the data.
XllpEthernetWriteWord16(*dataP++, XLLP_LAN91C111_DATA_HIGH);
}
// Check for Revision A for odd byte workaround.
if ((revision & 0x0F) <= 1)
{
// Check for odd byte packets.
if (oddFlag)
{
// Write the last byte of the packet with padding.
XllpEthernetWriteWord16((*dataP & 0xFF), XLLP_LAN91C111_DATA_HIGH);
}
// Write just the control byte. Packet will alway be even.
XllpEthernetWriteWord16((XLLP_LAN91C111_CONTROL_CRC << 8), XLLP_LAN91C111_DATA_HIGH);
}
else
{
if (length & 1)
{
// Write the control byte and last data byte.
XllpEthernetWriteWord16((((XLLP_LAN91C111_CONTROL_CRC | XLLP_LAN91C111_CONTROL_ODD) << 8) |
(*(dataP) & 0xFF)), XLLP_LAN91C111_DATA_HIGH);
}
else
{
// Write just the control byte.
XllpEthernetWriteWord16((XLLP_LAN91C111_CONTROL_CRC << 8), XLLP_LAN91C111_DATA_HIGH);
}
}
// XllpEthernetVerifyRAMBuffer (bufferSize);
// Enqueue the frame number into the TX FIFO.
XllpEthernetSelectRegisterBank (BANK2);
XllpEthernetWriteWord16(XLLP_LAN91C111_MMUCR_ENQUEUE, XLLP_LAN91C111_MMU);
// Prepare for timeout by getting the initial time interval.
start = TimerRegBaseP->oscr0;
// Check the Interrupt Status Register for Transmit Empty.
while (!((intStatus = XllpEthernetReadByte(XLLP_LAN91C111_INT_STATS)) &
XLLP_LAN91C111_IST_TX_EMPTY_INT))
{
if (getDelta(TimerRegBaseP, start) > timeout)
{
// Parse the transmit error bits.
XllpEthernetDisplayTxStatus();
// Cleanup after the transmit error.
if (XllpEthernetDeallocateTxPacket())
{
return (loggedError);
}
DM_CwDbgPrintf(DM_CW_LAN91C111_1, " Timeout Tx frame");
LOGERROR(&loggedError,
ERR_L_LAN91C111, ERR_S_ALLOC, ERR_T_TIMEOUT,
intStatus, 0, 0);
return (loggedError);
}
}
// Now check for transmit complete.
if (intStatus & XLLP_LAN91C111_IST_TX_EMPTY_INT)
{
// Acknowledge Transmit Empty Interrupt.
XllpEthernetWriteByte((XLLP_UINT8_T)(intStatus | XLLP_LAN91C111_IST_TX_EMPTY_INT), XLLP_LAN91C111_INT_STATS);
}
// Now check for transmit complete with no errors.
if (intStatus & XLLP_LAN91C111_IST_TX_INT)
{
// Acknowledge the Transmit interrupt.
XllpEthernetWriteByte((XLLP_UINT8_T)(intStatus | XLLP_LAN91C111_IST_TX_INT), XLLP_LAN91C111_INT_STATS);
resultCode = XllpEthernetReadWord(XLLP_LAN91C111_FIFO);
if (!(resultCode & XLLP_LAN91C111_FIFO_TEMPTY))
{
DM_CwDbgPrintf(DM_CW_LAN91C111_1, " Tx FIFO not empty");
XllpEthernetWriteByte((XLLP_UINT8_T)resultCode, XLLP_LAN91C111_PNR);
LOGERROR(&loggedError,
ERR_L_LAN91C111, ERR_S_TRANSMIT, ERR_T_TIMEOUT,
intStatus, 1, 0);
return (loggedError);
}
}
// Clear the collision count.
XllpEthernetSelectRegisterBank (BANK0);
XllpEthernetReadWord(XLLP_LAN91C111_COUNTER);
return (loggedError);
}
/******************************************************************************
Function Name:
XllpEthernetDeallocateRxPacket
Description:
This routine will deallocate a receive buffer and clear any errors.
Global Register Modified:
None
Input Arguments:
None
Output Arguments:
None
Return Value:
XLLP_UINT32_T - error code if failed, zero if success
*******************************************************************************/
static
XLLP_UINT32_T XllpEthernetDeallocateRxPacket(void)
{
XLLP_UINT32_T start, timebase = getTimebase();
XLLP_UINT32_T timeout = XLLP_LAN91C111_TO_ALLOC * timebase;
loggedError = 0;
// Release the memory from the received Frame.
XllpEthernetSelectRegisterBank (BANK2);
XllpEthernetWriteWord16(XLLP_LAN91C111_MMUCR_REM_REL_RX, XLLP_LAN91C111_MMU);
// Prepare for timeout by getting the initial time interval.
start = TimerRegBaseP->oscr0;
while (XllpEthernetReadWord(XLLP_LAN91C111_MMU) & XLLP_LAN91C111_MMUCR_NO_BUSY)
{
// Get the current time interval.
if ((getDelta(TimerRegBaseP, start)) > timeout)
{
DM_CwDbgPrintf(DM_CW_LAN91C111_1, " Error deallocating Rx frame");
// Report timeout error.
LOGERROR(&loggedError,
ERR_L_LAN91C111, ERR_S_RECEIVE, ERR_T_TIMEOUT,
0, 0, 0);
return (loggedError);
}
}
return (loggedError);
}
/******************************************************************************
Function Name:
XllpEthernetReceiveStatus
Description:
This routine returns the status of the Interrupt Status Register for
Receive Interrupt of the Ethernet Controller
Global Register Modified:
None
Input Arguments:
None
Output Arguments:
P_XLLP_UINT16_T rxIntStatusP - returns TRUE if the Receive Interrupt took place,
FALSE otherwise
Return Value:
XLLP_UINT32_T - error code if failed, zero if success
*******************************************************************************/
XLLP_UINT32_T XllpEthernetReceiveStatus(P_XLLP_UINT16_T rxIntStatusP)
{
XLLP_UINT8_T intStatus;
XLLP_UINT32_T start, timebase = getTimebase();
XLLP_UINT32_T timeout = XLLP_LAN91C111_TO_TRANSMIT * timebase;
loggedError = 0;
// Assume the failure
*rxIntStatusP = XLLP_FALSE;
// Prepare for timeout by getting the initial time interval.
// start = ostCtxP->getTimer_fnp(ostCtxP);
start = TimerRegBaseP->oscr0;
// Check the Interrupt Status Register for Receive Interrupt.
XllpEthernetSelectRegisterBank (BANK2);
while (!((intStatus = XllpEthernetReadByte(XLLP_LAN91C111_INT_STATS)) &
XLLP_LAN91C111_IST_RCV_INT))
{
if (getDelta(TimerRegBaseP, start) > timeout)
{
DM_CwDbgPrintf(DM_CW_LAN91C111_1, " Timeout Rx Status");
LOGERROR(&loggedError,
ERR_L_LAN91C111, ERR_S_RECEIVE, ERR_T_TIMEOUT,
intStatus, 0, 0);
break;
}
}
// Check for receive overrun errors
if (intStatus & XLLP_LAN91C111_IST_RX_OVRN_INT)
{
// Acknowledge the Receive Overrun interrupt.
XllpEthernetWriteByte(XLLP_LAN91C111_ACK_RX_OVRN_INT, XLLP_LAN91C111_INT_ACK);
}
// Check the Receive Interrupt.
else if (intStatus & XLLP_LAN91C111_IST_RCV_INT)
{
// Indicate receive packet pending.
*rxIntStatusP = XLLP_TRUE;
}
return (loggedError);
}
/******************************************************************************
Function Name:
XllpEthernetInterruptHandler
Description:
This routine handles the operations normally performed by an Interrupt
Service Routine. Since we aren't using interrupts to drive transmit and
receive, this routine is used in place of the ISR routine.
Global Register Modified:
None
Input Arguments:
None
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -