📄 enc28j60.c
字号:
* Side Effects: None
*
* Overview: ReadMACReg sends the 8 bit RCR opcode/Address byte as well
* as a dummy byte over the SPI and then retrives the
* register contents in the last 8 SPI clocks.
*
* Note: This routine cannot be used to access ETH or PHY
* registers. Use ReadETHReg() or ReadPHYReg() for that
* purpose.
*****************************************************************************/
static REG ReadMACReg(BYTE Address)
{
REG r;
ENC_CS_IO = 0;
ENC_SPI_IF = 0;
ENC_SSPBUF = RCR | Address; // Send the Read Control Register opcode and
// address.
while(!ENC_SPI_IF); // Wait until opcode/address is transmitted.
r.Val = ENC_SSPBUF;
ENC_SPI_IF = 0;
ENC_SSPBUF = 0; // Send a dummy byte
while(!ENC_SPI_IF); // Wait for the dummy byte to be transmitted
r.Val = ENC_SSPBUF;
ENC_SPI_IF = 0;
ENC_SSPBUF = 0; // Send another dummy byte to receive the register
// contents.
while(!ENC_SPI_IF); // Wait until register is received.
r.Val = ENC_SSPBUF;
ENC_SPI_IF = 0;
ENC_CS_IO = 1;
return r;
}//end ReadMACReg
/******************************************************************************
* Function: ReadPHYReg
*
* PreCondition: SPI bus must be initialized (done in MACInit()).
*
* Input: Address of the PHY register to read from.
*
* Output: 16 bits of data read from the PHY register.
*
* Side Effects: Alters bank bits to point to Bank 2
*
* Overview: ReadPHYReg performs an MII read operation. While in
* progress, it simply polls the MII BUSY bit wasting time
* (10.24us).
*
* Note: None
*****************************************************************************/
PHYREG ReadPHYReg(BYTE Register)
{
PHYREG Result;
// Set the right address and start the register read operation
BankSel(MIREGADR);
WriteReg((BYTE)MIREGADR, Register);
WriteReg((BYTE)MICMD, MICMD_MIIRD);
// Loop to wait until the PHY register has been read through the MII
// This requires 10.24us
BankSel(MISTAT);
while(ReadMACReg((BYTE)MISTAT).MISTATbits.BUSY);
// Stop reading
BankSel(MIREGADR);
WriteReg((BYTE)MICMD, 0x00);
// Obtain results and return
Result.VAL.v[0] = ReadMACReg((BYTE)MIRDL).Val;
Result.VAL.v[1] = ReadMACReg((BYTE)MIRDH).Val;
return Result;
}//end ReadPHYReg
/******************************************************************************
* Function: void WriteReg(BYTE Address, BYTE Data)
*
* PreCondition: SPI bus must be initialized (done in MACInit()).
* Bank select bits must be set corresponding to the register
* to modify.
*
* Input: 5 bit address of the ETH, MAC, or MII register to modify.
* The top 3 bits must be 0.
* Byte to be written into the register.
*
* Output: None
*
* Side Effects: None
*
* Overview: WriteReg sends the 8 bit WCR opcode/Address byte over the
* SPI and then sends the data to write in the next 8 SPI
* clocks.
*
* Note: This routine is almost identical to the BFCReg() and
* BFSReg() functions. It is seperate to maximize speed.
* Unlike the ReadETHReg/ReadMACReg functions, WriteReg()
* can write to any ETH or MAC register. Writing to PHY
* registers must be accomplished with WritePHYReg().
*****************************************************************************/
static void WriteReg(BYTE Address, BYTE Data)
{
BYTE Dummy;
ENC_CS_IO = 0;
ENC_SPI_IF = 0;
ENC_SSPBUF = WCR | Address; // Send the opcode and address.
while(!ENC_SPI_IF); // Wait until opcode/address is transmitted.
Dummy = ENC_SSPBUF;
ENC_SPI_IF = 0;
ENC_SSPBUF = Data; // Send the byte to be writen.
while(!ENC_SPI_IF); // Wait until register is written.
Dummy = ENC_SSPBUF;
ENC_SPI_IF = 0;
ENC_CS_IO = 1;
}//end WriteReg
/******************************************************************************
* Function: void BFCReg(BYTE Address, BYTE Data)
*
* PreCondition: SPI bus must be initialized (done in MACInit()).
* Bank select bits must be set corresponding to the register
* to modify.
*
* Input: 5 bit address of the register to modify. The top 3 bits
* must be 0.
* Byte to be used with the Bit Field Clear operation.
*
* Output: None
*
* Side Effects: None
*
* Overview: BFCReg sends the 8 bit BFC opcode/Address byte over the
* SPI and then sends the data in the next 8 SPI clocks.
*
* Note: This routine is almost identical to the WriteReg() and
* BFSReg() functions. It is separate to maximize speed.
* BFCReg() must only be used on ETH registers.
*****************************************************************************/
static void BFCReg(BYTE Address, BYTE Data)
{
BYTE Dummy;
ENC_CS_IO = 0;
ENC_SPI_IF = 0;
ENC_SSPBUF = BFC | Address; // Send the opcode and address.
while(!ENC_SPI_IF); // Wait until opcode/address is transmitted.
Dummy = ENC_SSPBUF;
ENC_SPI_IF = 0;
ENC_SSPBUF = Data; // Send the byte to be writen.
while(!ENC_SPI_IF); // Wait until register is written.
Dummy = ENC_SSPBUF;
ENC_SPI_IF = 0;
ENC_CS_IO = 1;
}//end BFCReg
/******************************************************************************
* Function: void BFSReg(BYTE Address, BYTE Data)
*
* PreCondition: SPI bus must be initialized (done in MACInit()).
* Bank select bits must be set corresponding to the register
* to modify.
*
* Input: 5 bit address of the register to modify. The top 3 bits
* must be 0.
* Byte to be used with the Bit Field Set operation.
*
* Output: None
*
* Side Effects: None
*
* Overview: BFSReg sends the 8 bit BFC opcode/Address byte over the
* SPI and then sends the data in the next 8 SPI clocks.
*
* Note: This routine is almost identical to the WriteReg() and
* BFCReg() functions. It is separate to maximize speed.
* BFSReg() must only be used on ETH registers.
*****************************************************************************/
static void BFSReg(BYTE Address, BYTE Data)
{
BYTE Dummy;
ENC_CS_IO = 0;
ENC_SPI_IF = 0;
ENC_SSPBUF = BFS | Address; // Send the opcode and address.
while(!ENC_SPI_IF); // Wait until opcode/address is transmitted.
Dummy = ENC_SSPBUF;
ENC_SPI_IF = 0;
ENC_SSPBUF = Data; // Send the byte to be writen.
while(!ENC_SPI_IF); // Wait until register is written.
Dummy = ENC_SSPBUF;
ENC_SPI_IF = 0;
ENC_CS_IO = 1;
}//end BFSReg
/******************************************************************************
* Function: WritePHYReg
*
* PreCondition: SPI bus must be initialized (done in MACInit()).
*
* Input: Address of the PHY register to write to.
* 16 bits of data to write to PHY register.
*
* Output: None
*
* Side Effects: Alters bank bits to point to Bank 3
*
* Overview: WritePHYReg performs an MII write operation. While in
* progress, it simply polls the MII BUSY bit wasting time.
*
* Note: None
*****************************************************************************/
void WritePHYReg(BYTE Register, WORD Data)
{
// Write the register address
BankSel(MIREGADR);
WriteReg((BYTE)MIREGADR, Register);
// Write the data
// Order is important: write low byte first, high byte last
WriteReg((BYTE)MIWRL, ((WORD_VAL*)&Data)->v[0]);
WriteReg((BYTE)MIWRH, ((WORD_VAL*)&Data)->v[1]);
// Wait until the PHY register has been written
BankSel(MISTAT);
while(ReadMACReg((BYTE)MISTAT).MISTATbits.BUSY);
}//end WritePHYReg
/******************************************************************************
* Function: BankSel
*
* PreCondition: SPI bus must be initialized (done in MACInit()).
*
* Input: Register address with the high byte containing the 2 bank
* select 2 bits.
*
* Output: None
*
* Side Effects: None
*
* Overview: BankSel takes the high byte of a register address and
* changes the bank select bits in ETHCON1 to match.
*
* Note: None
*****************************************************************************/
static void BankSel(WORD Register)
{
BFCReg(ECON1, ECON1_BSEL1 | ECON1_BSEL0);
BFSReg(ECON1, ((WORD_VAL*)&Register)->v[1]);
}//end BankSel
/******************************************************************************
* Function: static BOOL TestMemory(void)
*
* PreCondition: SPI bus must be initialized (done in MACInit()).
*
* Input: None
*
* Output: TRUE if the memory tests have passed
* FALSE if the BIST has detected a hardware fault
*
* Side Effects: Alters the state of numerous control registers and all
* RAM bytes.
*
* Overview: The internal BIST and DMA modules are used to fill the
* entire dual port memory and calculate a checksum of the
* data stored within. Address and Random fill modes are
* used.
*
* Note: For the Random Fill mode, the random number generator is
* seeded by the contents of the TMR0L PIC SFR. If the timer
* is running, additional confidence that the memory is
* working can be obtained by calling TestMemory multiple
* times.
*****************************************************************************/
#if defined(MAC_POWER_ON_TEST)
static BOOL TestMemory(void)
{
#define RANDOM_FILL 0b0000
#define ADDRESS_FILL 0b0100
#define PATTERN_SHIFT 0b1000
WORD_VAL DMAChecksum, BISTChecksum;
// Select Bank 0 and disable anything that could have been in progress
WriteReg(ECON1, 0x00);
// Set up necessary pointers for the DMA to calculate over the entire
// memory
WriteReg(EDMASTL, 0x00);
WriteReg(EDMASTH, 0x00);
WriteReg(EDMANDL, LOW(RAMSIZE-1u));
WriteReg(EDMANDH, HIGH(RAMSIZE-1u));
WriteReg(ERXNDL, LOW(RAMSIZE-1u));
WriteReg(ERXNDH, HIGH(RAMSIZE-1u));
// Enable Test Mode and do an Address Fill
BankSel(EBSTCON);
WriteReg((BYTE)EBSTCON, EBSTCON_TME |
EBSTCON_BISTST |
ADDRESS_FILL);
// Wait for the BIST to complete and disable test mode before
// starting any DMA operations.
while(ReadETHReg((BYTE)EBSTCON).EBSTCONbits.BISTST);
BFCReg((BYTE)EBSTCON, EBSTCON_TME);
// Begin reading the memory and calculating a checksum over it
// Block until the checksum is generated
BFSReg(ECON1, ECON1_DMAST | ECON1_CSUMEN);
BankSel(EDMACSL);
while(ReadETHReg(ECON1).ECON1bits.DMAST);
// Obtain the resulting DMA checksum and the expected BIST checksum
DMAChecksum.v[0] = ReadETHReg(EDMACSL).Val;
DMAChecksum.v[1] = ReadETHReg(EDMACSH).Val;
BankSel(EBSTCSL);
BISTChecksum.v[0] = ReadETHReg((BYTE)EBSTCSL).Val;
BISTChecksum.v[1] = ReadETHReg((BYTE)EBSTCSH).Val;
BFCReg((BYTE)EBSTCON, EBSTCON_TME);
// Compare the results
// 0xF807 should always be generated in Address fill mode
if( (DMAChecksum.Val != BISTChecksum.Val) || (DMAChecksum.Val != 0xF807) )
return FALSE;
// Seed the random number generator and begin another Random Fill test
// with the DMA and BIST memory access ports swapped.
#ifdef __C30__
WriteReg((BYTE)EBSTSD, TMR1);
#else
WriteReg((BYTE)EBSTSD, TMR0L);
#endif
WriteReg((BYTE)EBSTCON, EBSTCON_TME |
EBSTCON_PSEL |
EBSTCON_BISTST |
RANDOM_FILL);
// Wait for the BIST to complete and disable test mode since
// we won't be needing it anymore
while(ReadETHReg((BYTE)EBSTCON).EBSTCONbits.BISTST);
BFCReg((BYTE)EBSTCON, EBSTCON_TME);
// Begin reading the memory and calculating a checksum over it
// Block until the checksum is generated
BFSReg(ECON1, ECON1_DMAST | ECON1_CSUMEN);
BankSel(EDMACSL);
while(ReadETHReg(ECON1).ECON1bits.DMAST);
// Obtain the resulting DMA checksum and the expected BIST checksum
DMAChecksum.v[0] = ReadETHReg(EDMACSL).Val;
DMAChecksum.v[1] = ReadETHReg(EDMACSH).Val;
BankSel(EBSTCSL);
BISTChecksum.v[0] = ReadETHReg((BYTE)EBSTCSL).Val;
BISTChecksum.v[1] = ReadETHReg((BYTE)EBSTCSH).Val;
return (DMAChecksum.Val == BISTChecksum.Val);
}//end TestMemory
#endif
/******************************************************************************
* Function: void MACSetDuplex(DUPLEX DuplexState)
*
* PreCondition: SPI bus must be initialized (done in MACInit()).
*
* Input: Member of DUPLEX enum:
* FULL: Set full duplex mode
* HALF: Set half duplex mode
* USE_PHY: Set the MAC to match the PHYDPLXMODE bit in
* PHYCON. This is controlled by LEDB on RESET.
*
* Output: None
*
* Side Effects: Changes bank bits to Bank 2.
*
* Overview: Disables RX, TX logic, sets MAC up for full duplex
* operation, sets PHY up for full duplex operation, and
* reenables RX logic. The back-to-back inter-packet gap
* register (MACBBI
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -