📄 enc28j60.c
字号:
TXSTATUS TXStatus;
BYTE i;
// Cancel the previous transmission if it has become stuck set
BFCReg(ECON1, ECON1_TXRTS);
// Save the current read pointer (controlled by application)
BankSel(ERDPTL);
ReadPtrSave.v[0] = ReadETHReg(ERDPTL).Val;
ReadPtrSave.v[1] = ReadETHReg(ERDPTH).Val;
// Get the location of the transmit status vector
TXEnd.v[0] = ReadETHReg(ETXNDL).Val;
TXEnd.v[1] = ReadETHReg(ETXNDH).Val;
TXEnd.Val++;
// Read the transmit status vector
WriteReg(ERDPTL, TXEnd.v[0]);
WriteReg(ERDPTH, TXEnd.v[1]);
MACGetArray((BYTE*)&TXStatus, sizeof(TXStatus));
// Implement retransmission if a late collision occured (this can
// happen on B5 when certain link pulses arrive at the same time
// as the transmission)
for(i = 0; i < 16; i++)
{
if(ReadETHReg(EIR).EIRbits.TXERIF && TXStatus.bits.LateCollision)
{
// Reset the TX logic
BFSReg(ECON1, ECON1_TXRST);
BFCReg(ECON1, ECON1_TXRST);
BFCReg(EIR, EIR_TXERIF | EIR_TXIF);
// Transmit the packet again
BFSReg(ECON1, ECON1_TXRTS);
while(!(ReadETHReg(EIR).Val & (EIR_TXERIF | EIR_TXIF)));
// Cancel the previous transmission if it has become stuck set
BFCReg(ECON1, ECON1_TXRTS);
// Read transmit status vector
WriteReg(ERDPTL, TXEnd.v[0]);
WriteReg(ERDPTH, TXEnd.v[1]);
MACGetArray((BYTE*)&TXStatus, sizeof(TXStatus));
}
else
{
break;
}
}
// Restore the current read pointer
WriteReg(ERDPTL, ReadPtrSave.v[0]);
WriteReg(ERDPTH, ReadPtrSave.v[1]);
}
}
}
/******************************************************************************
* Function: void MACSetRxBuffer(WORD offset)
*
* PreCondition: A packet has been obtained by calling MACGetHeader() and
* getting a TRUE result.
*
* Input: offset: WORD specifying how many bytes beyond the Ethernet
* header's type field to relocate the SPI read and
* write pointers.
*
* Output: None
*
* Side Effects: None
*
* Overview: SPI read and write pointers are updated. All calls to
* MACGet(), MACPut(), MACGetArray(), and MACPutArray(),
* and various other functions will use these new values.
*
* Note: RXSTOP must be statically defined as being > RXSTART for
* this function to work correctly. In other words, do not
* define an RX buffer which spans the 0x1FFF->0x0000 memory
* boundary.
*****************************************************************************/
void MACSetRxBuffer(WORD offset)
{
WORD_VAL ReadPT;
// Determine the address of the beginning of the entire packet
// and adjust the address to the desired location
ReadPT.Val = CurrentPacketLocation.Val + sizeof(ENC_PREAMBLE) + offset;
// Since the receive buffer is circular, adjust if a wraparound is needed
if ( ReadPT.Val > RXSTOP )
ReadPT.Val -= RXSIZE;
// Set the SPI read and write pointers to the new calculated value
BankSel(ERDPTL);
WriteReg(ERDPTL, ReadPT.v[0]);
WriteReg(ERDPTH, ReadPT.v[1]);
WriteReg(EWRPTL, ReadPT.v[0]);
WriteReg(EWRPTH, ReadPT.v[1]);
}
/******************************************************************************
* Function: void MACSetTxBuffer(BUFFER buffer, WORD offset)
*
* PreCondition: None
*
* Input: buffer: BYTE specifying which transmit buffer to seek
* within. If MAC_TX_BUFFER_COUNT <= 1, this
* parameter is not used.
* offset: WORD specifying how many bytes beyond the Ethernet
* header's type field to relocate the SPI read and
* write pointers.
*
* Output: None
*
* Side Effects: None
*
* Overview: SPI read and write pointers are updated. All calls to
* MACGet(), MACPut(), MACGetArray(), and MACPutArray(),
* and various other functions will use these new values.
*
* Note: None
*****************************************************************************/
void MACSetTxBuffer(BUFFER buffer, WORD offset)
{
CurrentTxBuffer = buffer;
// Calculate the proper address. Since the TX memory area is not circular,
// no wrapparound checks are necessary. +1 adjustment is needed because of
// the per packet control byte which preceeds the packet in the TX memory
// area.
#if MAC_TX_BUFFER_COUNT > 1
offset += TxBuffers[buffer].StartAddress.Val + 1 + sizeof(ETHER_HEADER);
#else
offset += TXSTART + 1 + sizeof(ETHER_HEADER);
#endif
// Set the SPI read and write pointers to the new calculated value
BankSel(EWRPTL);
WriteReg(ERDPTL, ((WORD_VAL*)&offset)->v[0]);
WriteReg(ERDPTH, ((WORD_VAL*)&offset)->v[1]);
WriteReg(EWRPTL, ((WORD_VAL*)&offset)->v[0]);
WriteReg(EWRPTH, ((WORD_VAL*)&offset)->v[1]);
}
// MACCalcRxChecksum() and MACCalcTxChecksum() use the DMA module to calculate
// checksums. These two functions have been tested.
/******************************************************************************
* Function: WORD MACCalcRxChecksum(WORD offset, WORD len)
*
* PreCondition: None
*
* Input: offset - Number of bytes beyond the beginning of the
* Ethernet data (first byte after the type field)
* where the checksum should begin
* len - Total number of bytes to include in the checksum
*
* Output: 16-bit checksum as defined by rfc 793.
*
* Side Effects: None
*
* Overview: This function performs a checksum calculation in the MAC
* buffer itself using the hardware DMA module
*
* Note: None
*****************************************************************************/
WORD MACCalcRxChecksum(WORD offset, WORD len)
{
WORD_VAL temp;
// Add the offset requested by firmware plus the Ethernet header
temp.Val = CurrentPacketLocation.Val + sizeof(ENC_PREAMBLE) + offset;
if ( temp.Val > RXSTOP ) // Adjust value if a wrap is needed
{
temp.Val -= RXSIZE;
}
// Program the start address of the DMA
BankSel(EDMASTL);
WriteReg(EDMASTL, temp.v[0]);
WriteReg(EDMASTH, temp.v[1]);
// Calculate the end address, given the start address and len
temp.Val += len-1;
if ( temp.Val > RXSTOP ) // Adjust value if a wrap is needed
{
temp.Val -= RXSIZE;
}
// Program the end address of the DMA
WriteReg(EDMANDL, temp.v[0]);
WriteReg(EDMANDH, temp.v[1]);
// Calculate the checksum using the DMA device
BFSReg(ECON1, ECON1_DMAST | ECON1_CSUMEN);
while(ReadETHReg(ECON1).ECON1bits.DMAST);
// Swap endianness and return
temp.v[1] = ReadETHReg(EDMACSL).Val;
temp.v[0] = ReadETHReg(EDMACSH).Val;
return temp.Val;
}
/******************************************************************************
* Function: WORD MACCalcTxChecksum(WORD offset, WORD len)
*
* PreCondition: None
*
* Input: offset - Number of bytes beyond the beginning of the
* Ethernet data (first byte after the type field)
* where the checksum should begin
* len - Total number of bytes to include in the checksum
*
* Output: 16-bit checksum as defined by rfc 793.
*
* Side Effects: None
*
* Overview: This function performs a checksum calculation in the MAC
* buffer itself using the hardware DMA module
*
* Note: None
*****************************************************************************/
WORD MACCalcTxChecksum(WORD offset, WORD len)
{
WORD_VAL temp;
// Program the start address of the DMA, after adjusting for the Ethernet
// header
#if MAC_TX_BUFFER_COUNT > 1
temp.Val = TxBuffers[CurrentTxBuffer].StartAddress.Val + sizeof(ETHER_HEADER)
+ offset + 1; // +1 needed to account for per packet control byte
#else
temp.Val = TXSTART + sizeof(ETHER_HEADER)
+ offset + 1; // +1 needed to account for per packet control byte
#endif
BankSel(EDMASTL);
WriteReg(EDMASTL, temp.v[0]);
WriteReg(EDMASTH, temp.v[1]);
// Program the end address of the DMA.
temp.Val += len-1;
WriteReg(EDMANDL, temp.v[0]);
WriteReg(EDMANDH, temp.v[1]);
// Calcualte the checksum using the DMA device
BFSReg(ECON1, ECON1_DMAST | ECON1_CSUMEN);
while(ReadETHReg(ECON1).ECON1bits.DMAST);
// Swap endianness and return
temp.v[1] = ReadETHReg(EDMACSL).Val;
temp.v[0] = ReadETHReg(EDMACSH).Val;
return temp.Val;
}
/******************************************************************************
* Function: WORD CalcIPBufferChecksum(WORD len)
*
* PreCondition: Read buffer pointer set to starting of checksum data
*
* Input: len: Total number of bytes to calculate the checksum over.
* The first byte included in the checksum is the byte
* pointed to by ERDPT, which is updated by calls to
* MACGet(), MACSetRxBuffer(), MACSetTxBuffer(), etc.
*
* Output: 16-bit checksum as defined by rfc 793.
*
* Side Effects: None
*
* Overview: This function performs a checksum calculation in the MAC
* buffer itself. The ENC28J60 has a hardware DMA module
* which can calculate the checksum faster than software, so
* this function replaces the CaclIPBufferChecksum() function
* defined in the helpers.c file. Through the use of
* preprocessor defines, this replacement is automatic.
*
* Note: This function works either in the RX buffer area or the TX
* buffer area. No validation is done on the len parameter.
*****************************************************************************/
WORD CalcIPBufferChecksum(WORD len)
{
WORD_VAL temp;
// Take care of special cases which the DMA cannot be used for
if(len == 0u)
{
return 0xFFFF;
}
else if(len == 1u)
{
return ~(((WORD)MACGet())<<8);
}
// Set the DMA starting address to the SPI read pointer value
BankSel(ERDPTL);
temp.v[0] = ReadETHReg(ERDPTL).Val;
temp.v[1] = ReadETHReg(ERDPTH).Val;
WriteReg(EDMASTL, temp.v[0]);
WriteReg(EDMASTH, temp.v[1]);
// See if we are calculating a checksum within the RX buffer (where
// wrapping rules apply) or TX/unused area (where wrapping rules are
// not applied)
#if RXSTART == 0
if(temp.Val <= RXSTOP)
#else
if(temp.Val >= RXSTART && temp.Val <= RXSTOP)
#endif
{
// Calculate the DMA ending address given the starting address and len
// parameter. The DMA will follow the receive buffer wrapping boundary.
temp.Val += len-1;
if(temp.Val > RXSTOP)
{
temp.Val -= RXSIZE;
}
}
else
{
temp.Val += len-1;
}
// Write the DMA end address
WriteReg(EDMANDL, temp.v[0]);
WriteReg(EDMANDH, temp.v[1]);
// Begin the DMA checksum calculation and wait until it is finished
BFSReg(ECON1, ECON1_DMAST | ECON1_CSUMEN);
while(ReadETHReg(ECON1).ECON1bits.DMAST);
// Return the resulting good stuff
temp.v[0] = ReadETHReg(EDMACSL).Val;
temp.v[1] = ReadETHReg(EDMACSH).Val;
return temp.Val;
}
/******************************************************************************
* Function: void MACCopyRxToTx(WORD RxOffset, WORD TxOffset, WORD len)
*
* PreCondition: None
*
* Input: RxOffset: Offset in the RX buffer (0=first byte of
* destination MAC address) to copy from.
* TxOffset: Offset in the TX buffer (0=first byte of
* destination MAC address) to copy to.
* len: Number of bytes to copy
*
* Output: None
*
* Side Effects: None
*
* Overview: If the TX logic is transmitting a packet (ECON1.TXRTS is
* set), the hardware will wait until it is finished. Then,
* the DMA module will copy the data from the receive buffer
* to the transmit buffer.
*
* Note: None
*****************************************************************************/
// Remove this line if your application needs to use this
// function. This code has NOT been tested.
#if 0
void MACCopyRxToTx(WORD RxOffset, WORD TxOffset, WORD len)
{
WORD_VAL temp;
temp.Val = CurrentPacketLocation.Val + RxOffset + sizeof(ENC_PREAMBLE);
if ( temp.Val > RXSTOP ) // Adjust value if a wrap is needed
temp.Val -= RXSIZE;
BankSel(EDMASTL);
WriteReg(EDMASTL, temp.v[0]);
WriteReg(EDMASTH, temp.v[1]);
temp.Val += len-1;
if ( temp.Val > RXSTOP ) // Adjust value if a wrap is needed
temp.Val -= RXSIZE;
WriteReg(EDMANDL, temp.v[0]);
WriteReg(EDMANDH, temp.v[1]);
TxOffset += TXSTART+1;
WriteReg(EDMADSTL, ((WORD_VAL*)&TxOffset)->v[0]);
WriteReg(EDMADSTH, ((WORD_VAL*)&TxOffset)->v[1]);
// Do the DMA Copy. The DMA module will wait for TXRTS to become clear
// before starting the copy.
BFCReg(ECON1, ECON1_CSUMEN);
BFSReg(ECON1, ECON1_DMAST);
while(ReadETHReg(ECON1).ECON1bits.DMAST);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -