05 The SPI interface
The SPI interface
The communication between ENC28J60 and PIC it happens through the interface SPI; this only supports the 0,0 modality and the controller is a slave, so the PIC provides the clock and manages the transmission.
The maximum admitted frequency is of 10Mhz for the Rev. B1-B4, while is double for the B5. Also,
because of a problem in the interface (described in Errata), for the Rev. B1-B4 the clock must necessarily be between 8 and 10Mhz, or the PIC clock must be draw from the pin CLKOUT of the controller (max 25Mhz). So, in the first case the PIC must work at a frequency between 32 and 40Mhz.
SPI Commands
Through the interface is possible to send to the chip 7 various commands (of 8bit), eventuality followed from a dates byte; there are:
| Nome | 1° byte | 2° byte | Description |
| Read Control Register (RCR) | 000 AAAAA | is useful to read the control register A | |
| Write Control Register (WCR) | 010 AAAAA | DDDDDDDD | to write the byte D inside the registry A (in the selected bank) |
| Read Buffer Memory (RBM) | 00111010 | is useful to read the controller RAM memory to the current address. | |
| Write Buffer Memory (WBM) | 01111010 | DDDDDDDD | writes the byte D to the current address of the RAM memory. |
| Bit Field Set (BFS) | 100 AAAAA | DDDDDDDD | sets in the registry A (just ETH), the bit which in D are at 1 (OR). |
| Bit Field Set (BFS) | 101 AAAAA | DDDDDDDD | resets in the registry A (just ETH), the bit which in D are at 1 (NOT AND). |
| System Reset Command (SRC) | 11111111 | reset the controller. |
SPI Commands: implementation
The SPI initialization module is illustrated, let's see some base methods.
#define spiWrite(x) spiRW(x)
#define spiRead() spiRW(0)
....
u8 spiRW(u8 data){
SSPBUF = data;
while(!PIR1bits.SSPIF);
PIR1bits.SSPIF = 0;
return SSPBUF;
}This is a method which permits to read/write in the bus SPI. As far as the writing, the byte for the sending (data) is put in the SSPBUF registry (is part of SPI module), then attend that the transmission is finished observing the SSPIF bit; to read a byte, is necessary to write a zero in the registry SSPBUF (like this are generated 8 impulses of clock), attend the operation end and the read byte it will be in the same SSPBUF registry .
In this case I I have condensed in an only method the reading operations and writing, then, for mental clarity, I have defined spiWrite and spiRead.
#define CS PORTCbits.RC2 // Chip Select dell'ENC28J60
#define WCR (0b01000000) // Write Control Register command
#define BFS (0b10000000) // Bit Field Set command
#define BFC (0b10100000) // Bit Field Clear command
#define RCR (0b00000000) // Read Control Register command
#define RBM (0b00111010) // Read Buffer Memory command
#define WBM (0b01111010) // Write Buffer Memory command
#define SRC (0b11111111) // System Reset command
....
void writeReg(u8 reg, u8 data){
CS = 0;
spiWrite(WCR | reg);
spiWrite(data);
CS = 1;
}
u8 readMAC(u8 reg){
u8 b;
CS = 0;
spiWrite(RCR | reg);
spiRead();
b = spiRead();
CS = 1;
return b;
}
u8 readETH(u8 reg){
u8 b;
CS = 0;
spiWrite(RCR | reg);
b = spiRead();
CS = 1;
return b;
}With these three methods we can read and write the control registries ( to read registries MII is used readMAC).
Like you can notice the reading procedure of a MAC and ETH registry is slightly diverse, for the first type must send a bite zero before make the reading.
void BFCReg(u8 reg, u8 data){
CS = 0;
spiWrite(BFC | reg);
spiWrite(data);
CS = 1;
}
void BFSReg(u8 reg, u8 data){
CS = 0;
spiWrite(BFS | reg);
spiWrite(data);
CS = 1;
}
void setBank(u8 bank){
BFCReg(ECON1, 0b11);
BFSReg(ECON1, bank);
}Here we see the Bit Set and Bit Clear commands implementation; then the setBank method, with which we can select the memory bank of the control registries, acting on the ECON1 registry (commune at all the baks).
u16 bufSize;
....
void encPut(u8 b){
CS = 0;
spiWrite(WBM);
spiWrite(b);
CS = 1;
bufSize++;
}
u8 encGet(){
u8 b;
CS = 0;
spiWrite(RBM);
b = spiRead();
CS = 1;
return b;
}
void sendReset(){
CS = 0;
spiWrite(SRC);
CS = 1;
}The remaining three commands are performed by these three methods: the reading and the writing of the RAM, and reset. The variable static bufSize is useful to keep track of the RAM byte number (it will be useful then).


