For starters: Yes I know I'm about to reinvent the wheel with the following task ahead.
I want to create my own library for the ENC28J60 for an AVR (ATMEGA1284P).
So I've been browsing the net for months now made fairly good progress, but now I'm hitting walls to often.
This is my network layout. For the first step I'm only atempting to communicate uC1 with PC1 over Router1.
The final step would be to have communication between PC1 and uC2.
Tobby Jaffey in his answer here has broken down the steps to how to get the chip to work.
Now with the help of his list I'll show you all where I'm at right now.
If I were undertaking this project, I'd break it down like this:
- Write a program to blink an LED
- Extend it to send and receive bytes on the UART (this will be invaluable for debugging)
- Extend it to use the SPI interface, verifying the waveforms with a scope/logic analyser
- Wire up the ENC28J60 to the SPI interface, not forgetting chip select (I'd leave the interrupt line unconnected for now)
- Extend the software to read from the chip id/version register and verify the result
- Extend the software to write to a register and read it back
- Plug in an ethernet cable, verify that the ethernet link status is changing in the ENC28J60s registers
- Wire up the ENC28J60 interrupt line to an input on my microcontroller and test (enabling interrupts on link state changes would seem a good test)
Now, I'm confident that my hardware works.
- Bring the ethernet driver functions (accesses to 16 bit registers, fifo access, etc) into my project and verify them by accessing registers
- Configure the ENC28J60 for promiscuous mode and dump incoming packets to the UART, verify by comparing with Wireshark/tcpdump
- Look at how the original author managed time, in particular how regularly they poll the IP stack and the ethernet driver. Implement a main loop to service these routines
- Pull the rest of the IP stack on top of my driver layer
- Configure the IP stack for my network (starting with a static IP)
- Ping it
- Pull the rest of the application code (web server/etc.) into my project.
Blinking a LED is no problem. I'm using logic XOR for it. Works for me.
Communication over UART is only one way from uC to PC. I'm displaing data in HyperTerminal. For every new untested code fragment/part I'm sending a UART text line like to PC.
void ENC28J60_SRC(void) // System Reset Command (Soft Reset)
{
ENC28J60_CS(); // Enable
SPIWR(0xFF);
ENC28J60_DS(); // Disable
_delay_ms(50);
while(!(ENC28J60_RD(ESTAT) & CLKRDY))
{
USART0_TX_String("waiting for CLKRDY");
}
USART0_TX_String("CLKRDY is Ready");
}
SPI communication works, but wasn't tested with scope or logis analyser. I've been sending and receiving data form the ENC28J60 without a problem. So we can check the reading and writing registers part as well as the reading chip/id that has the value of 6 so the chip is Rev.:B7
After setting up the PHY registers and pluging the cable in, LEDs are blinking, but still no data is accepted. I've been also checking the packet counter. It's always 0.
Interrupt is enabled only for packet receive. Never goes to logic LOW level.
Hardware, as in the ENC28J60, is from shop, so it's not self built, connection errors are less likely. The ATMEGA1284P test panel is self made, connections tested.
My ENC28J60 Initialization looks like this:
void ENC28J60_Init(void)
{
USART0_TX_String("ENC28J60 Reset");
USART0_TXD(13);
USART0_TXD(10);
ENC28J60_SRC();
USART0_TX_String("RX Buffer Init");
USART0_TXD(13);
USART0_TXD(10);
/*
#define RXSTART 0x0000 0x0000 0 0 0
#define RXEND 4095 0x0FFF 15 255 4095
#define TXSTART (RXEND+1) 0x1000 16 0 4096
#define TXEND 0x1FFF 0x1FFF 31 255 8191
*/
// Init TX/RX Buffer Datasheet Section 6.1
ENC28J60_BANK_SEL(BANK0);
ENC28J60_CS();
SPIWR(WCR|ERDPTL); //
SPIWR(RXSTART&0xFF); // ERDPTL Buffer Read Pointer Low
SPIWR(RXSTART>>8); // ERDPTH Buffer Read Pointer High
SPIWR(TXSTART&0xFF); // EWRPTL Buffer Write Pointer Low
SPIWR(TXSTART>>8); // EWRPTH Buffer Write Pointer High
SPIWR(TXSTART&0xFF); // ETXSTL Transmit Buffer Start Low
SPIWR(TXSTART>>8); // ETXSTH Transmit Buffer Start High
SPIWR(TXEND&0xFF); // ETXNDL Transmit Buffer End Low
SPIWR(TXEND>>8); // ETXNDH Transmit Buffer High
SPIWR(RXSTART&0xFF); // ERXSTL Recive Buffer Start Low
SPIWR(RXSTART>>8); // ERXSTH Recive Buffer Start High
SPIWR(RXEND&0xFF); // ERXNDL Recive Buffer End Low
SPIWR(RXEND>>8); // ERXNDH Recive Buffer End High
SPIWR(RXSTART&0xFF); // ERXRDPTL Recive Buffer Read Pointer Low
SPIWR(RXSTART>>8); // ERXRDPTH Recive Buffer Read Pointer High
SPIWR(RXSTART&0xFF); // ERXWRPTL Recive Buffer Write Pointer Low
SPIWR(RXSTART>>8); // ERXWRPTH Recive Buffer Write Pointer High
SPIWR(0x00); // EDMASTL DMA Start Low
SPIWR(0x00); // EDMASTH DMA Start High
SPIWR(0x00); // EDMANDL DMA End Low
SPIWR(0x00); // EDMANDH DMA End High
SPIWR(0x00); // EDMADSTL DMA Destination Low
SPIWR(0x00); // EDMADSTH DMA Destination High
SPIWR(0x00); // EDMACSL DMA Checksum Low
SPIWR(0x00); // EDMACSH DMA Checksum High
ENC28J60_DS();
USART0_TX_String("BANK1");
USART0_TXD(13);
USART0_TXD(10);
/*
USART0_TX_String("BANK1 EPMM Init");
USART0_TXD(13);
USART0_TXD(10);
ENC28J60_BANK_SEL(BANK1);
ENC28J60_CS();
SPIWR(WCR|EPMM0);
SPIWR(0x00); // EPMM0
SPIWR(0x00); //
SPIWR(0x00); //
SPIWR(0x00); //
SPIWR(0x00); //
SPIWR(0x00); //
SPIWR(0x00); //
SPIWR(0x00); // EPMM7
SPIWR(0x00); // EPMCSL
SPIWR(0x00); // EPMCSH
SPIWR(DUMMY);
SPIWR(DUMMY);
SPIWR(0x00); // EPMOL
SPIWR(0x00); // EPMOH
ENC28J60_DS();
ENC28J60_BANK_SEL(BANK1);
ENC28J60_CS();
SPIWR(WCR|ERXFCON);
SPIWR(0xA3); // ERXFCON
ENC28J60_DS();
*/
USART0_TX_String("MAC Init");
USART0_TXD(13);
USART0_TXD(10);
ENC28J60_BANK_SEL(BANK2);
ENC28J60_CS();
SPIWR(WCR|MACON1);
SPIWR(MARXEN|TXPAUS|RXPAUS); // MACON1
SPIWR(DUMMY); // MACON2?
SPIWR(PADCFG0|FRMLNEN|TXCRCEN|FULDPX); // MACON3
SPIWR(DEFER); // MACON4
SPIWR(0x15); // MABBIPG
SPIWR(DUMMY); //
SPIWR(0x12); // MAIPGL
SPIWR(0x00); // MAIPGH
SPIWR(0x00); // MACLCON1
SPIWR(0x00); // MACLCON2
SPIWR(0xEE); // MAMXFLL MAC MaXimum Frame Length is set to 0x0500 or 1280byte (0x05EE 1518byte)
SPIWR(0x05); // MAMXFLH
ENC28J60_DS();
USART0_TX_String("BANK3");
USART0_TXD(13);
USART0_TXD(10);
// MAC Init Datasheet Section 6.5
ENC28J60_BANK_SEL(BANK3);
ENC28J60_CS();
SPIWR(WCR|MAADR5);
SPIWR(myMAC[4]); // MAC address 5
SPIWR(myMAC[5]); // MAC address 6
SPIWR(myMAC[2]); // MAC address 3
SPIWR(myMAC[3]); // MAC address 4
SPIWR(myMAC[0]); // MAC address 1
SPIWR(myMAC[1]); // MAC address 2
ENC28J60_DS();
USART0_TX_String("PHY Init");
USART0_TXD(13);
USART0_TXD(10);
// PHY Init Datasheet Section 6.6
ENC28J60_PHYWR(PHCON1,PDPXMD,0); // PHY in Full-Duplex Mode
ENC28J60_PHYWR(PHLCON,0b00000010,0b00010010); // LED Init
USART0_TX_String("Int Init");
USART0_TXD(13);
USART0_TXD(10);
ENC28J60_BANK_SEL(BANK0);
ENC28J60_CS();
SPIWR(BFS|EIE); //
SPIWR(INTIE|PKTIE); // EIE
ENC28J60_DS();
USART0_TX_String("ECON1.RXEN Enabled");
ENC28J60_CS();
SPIWR(BFS|ECON1);
SPIWR(RXEN); // ECON1
ENC28J60_DS();
}
Problems sofar:
Could not get the ECON1.RXEN bit to set. Somehow it fixed it self, don't know what did. Not getting any data in the recive buffer. LED blinks on RX activity.
Maybe dropping the CRC check in the filter will help?
Update: 2014.08.16 23:25
Yes! Dropping the CRC check helped. Now I'm able to receive packets.