With the basic read/write functions done,we'll look into the Initialization of the chip,and how we'll handle packets.
Before we get into that,we need to decide how to divide that 8kb buffer.Lets have,
0x0000-0x0FFF be the RX Buffer,and
0x1000-0x1FFF be the TX Buffer.
There are 6 pointers that need to be set,based on that information.
(See page 20,Figure 3-2 of the datasheet) The following diagram is indicative of how things are laid out.
|Image credits to the ENC28J60 datasheet.Edited a bit.|
The ERXSTH:ERXSTL and ERXNDH:ERXNDL define the limits of the RX buffer,and the buffer wraps around.What I mean is,if there is data being written,and we happen to come to the end of the RX buffer,then the writing continues,but the location is from ERXST onwards.In two words,its a Circular FIFO.Note that we should not modify these when the chip is in action(RX/TX is on.).If we somehow need to,then we should stop the operations by clearing the ECON1.RXEN bit,and then play with these.
Similarly with the ETXST and ETXND. The ERXWRPTH:ERXWRPTL(not shown above) registers define a location within the FIFO where the chip will write bytes that it receives. The pointer is read-only and is automatically updated by the hardware whenever a new packet is successfully received.
- Reset the chip via the designated SPI command(0xFF).
- Setup the pointers discussed above.
- Configure the ERXFCON,the receive filter control register.The ANDOR bit will be left at its initial 0.That means, Packets will be accepted unless all enabled filters reject the packet.So,if the filters dont chuck the packet out,the packet will be accepted.We will enforce Unicast,Pattern Match and the post filter CRC Check bits.See page 50 of the datasheet.
- Configure the MAC Registers.This part I've borrowed from the tuxgraphics code,So credits to them for that.
- Assign the MAC Address to the ENC chip,using the MAADR1,2,3,4,5 registers.
- Enable reception of frames by setting the RXEN bit in ECON1.
The writing of a packet(to be sent by the ENC chip) to the TX buffer is also a multi step process.Heres how it goes:
- Set the buffer pointers to the right places.ETXST and EWRPT(buffer write pointer) both to 0x1000,which is where we decided will be the start of our TX buffer space.
- Now,when transmitting packets,we need to first write a 'Per packet control byte',then our packet bytes,and set the ETXND(End of transmit buffer) pointer to the last byte of our packet.Heres what it looks like in code:
Heres where I'd like to draw attention to a point in the Errata,
ClrBitField(EIR, EIR_TXERIF | EIR_TXIF); and then set TXRTS bit in the ECON1 to command a packet transmit. Very important.
We can check the status of the transmit(done or underway) based on the TXIF bit in the EIR Register.Ofcourse,we'd need to enable interrupts on packet transmitted before hand.
We clear the TXRTS bit,when we exit the above waiting routine.Now after the packet is sent,the chip writes a bunch of bytes of status vectors after our packet data.We read those status vector bytes into a variable we declared based on a union we define in the enc28j60.h header file.This awesome organization of status vectors and more using structures is the work of Duncan Frost,and I've merely followed on with it.Credits to him.
We can then check the status vectors to see what happened to the packet we wanted to send.
For reception of packets, we must
- First check the EPKTCNT register,which contains the count of packets received.If thats non-zero,that means we have something to read.
- This packet would be written to the start of the RX buffer,so we set the Read pointers to the start of the RX buffer.
- See the diagram on page 45 of the datasheet to see how packets received are written into the buffer.Theres the next packet pointer(2 bytes) and then the receive status vectors(32 bits,or 4 bytes) after which we have our actual packet data.Note that the next packet pointer,is stored in the buffer in Little Endian way.
- We read the status vectors to see whats the status on the packet received,and read it in if the RxOk bit is set.We can get the length of the packet,by subtracting 4 from the ByteCount field in the status vectors.We subtract 4,since the CRC(that the chip appends) is of 4 bytes.
- If we are done reading the packet,we set the ERXRDPT to the Next packet's start,and decrement EPKTCNT,to indicate that we finished processing that packet.
Heres another place where I'd like to point out something in the Errata.
You may refer to the code linked here,to see how that has been implemented in the MACRead function.
Thats all for this part,and in the next blog post in this series,we'll look at ARP Requests and packet structure.