ENC28J60 Ethernet Driver
localroger            
            
                Posts: 3,452            
            
                    Awhile back I asked if anyone was working on this, and realized that apparently nobody was.  So here's my take.  The demo program just supports ARP and PING, which demonstrates the full functionality of the ENC28J60.  I will soon add UDP for my own purposes but that requires nonstandard software to test, and if I ever do TCP/IP I will probably take a different approach than Harrison since we have much more memory to work with.
I would appreciate it if the P2 experts could look over the way I implemented the SPI interface and make sure I didn't miss a better way to do things. I wanted to use inline asm for outh/outl etc. to avoid the outa/outb goat rodeo, but I also wanted to make pin assignments dynamic. The solution I came up with lets the four pin assignments to be moved to local variables with a minimum of overhead. I wanted to try using setd to modify the actual inline asm code just once but I couldn't figure out a way to get an asm label address into a local variable.
UPDATE: The new demo adds ARP-query, ARP-reply handling, and UDP as both server and client. This is a fully usable lightweight framework for communicating over a network or even the Internet.
                
            I would appreciate it if the P2 experts could look over the way I implemented the SPI interface and make sure I didn't miss a better way to do things. I wanted to use inline asm for outh/outl etc. to avoid the outa/outb goat rodeo, but I also wanted to make pin assignments dynamic. The solution I came up with lets the four pin assignments to be moved to local variables with a minimum of overhead. I wanted to try using setd to modify the actual inline asm code just once but I couldn't figure out a way to get an asm label address into a local variable.
UPDATE: The new demo adds ARP-query, ARP-reply handling, and UDP as both server and client. This is a fully usable lightweight framework for communicating over a network or even the Internet.

                            
Comments
Cool, great to see an Ethernet pulse on P2
Why not use smart pin SPI modes here ? ( mode %11100 = synchronous serial transmit)
I see ENC28J60 specs 20MHz SPI which is modest, ENC624J600 is 10/100, with similar SPI but 3x memory, or I see KSZ8851 looks also 10/100
Is the aim to connect many Ethernet controllers to P2 as you can ?
Other chips -- the enc28j60 is the one I have code for. I know almost nothing about how it really works and basically got Harrison's code to run on top of my new SPI interface, which doesn't require launching a cog like the P1 version. I also have a lot of production code which is geared toward this hardware and doesn't need better performance, although it would benefit a lot from the P2's extra pins and RAM for business logic.
The point with the pin assignments is that for inline asm they must either be coded as constants or placed in LOCAL variables. I wanted to have a special call syntax that would set up the variables once via self-modifying code, but I couldn't figure out how to get the absolute address of a PASM label into a local Spin variable. The way I did it minimizes overhead by passing only one argument and then only shifting out the pins that are used by that function, instead of passing four variables every time.
This would get you twice as many ethernet ports as the P1 if you want them; on P1 the driver needs its own cog for packet service and another for the SPI interface; presumably you would need yet another for any complex business logic. So maybe three ports if your business logic is shared. On P2 you could serve seven since each ethernet port just needs one cog for both packet service and SPI. In a low-throughput application it might be possible for one cog to service two or more enc28j60 chips, since they buffer packets until read so you could maybe do a round-robin like the 4-port serial object, and that would allow you to build a pretty monster custom switch but it wouldn't be able to handle much traffic per port. I could see applications for such a beast though...
Also, if someone would like to expand on what I did here to add smart pin support, I would welcome the improvement on general principles. (That is one reason I broke the SPI functions out to a separate object, even though it doesn't start a cog.) There is a lot about P2 I am just beginning to learn and I know this isn't going to be the best or ultimate solution.
Search finds this
https://forums.parallax.com/discussion/comment/1466053/#Comment_1466053
and there is this example
https://forums.parallax.com/discussion/169582/i2s-interfacing-with-the-prop2
but I thought there was more ?
Ah, here - examples and scope images too
https://forums.parallax.com/discussion/169776/smartpin-synchronous-serial-transmit/p1
Sounds cool. The enc28j60 is a mature part, so what you have working, is fine for that.
'********************** SPI READ/WRITE ********************* ' Read bytes in from SPI to memory ' SPI>BUF ( dst cnt -- sum ) 461.7us/512 SPIRX wrfast #0,tos1 mov tos1,#0 .L0 rep @.end,#8 ' 8 bits outnot sck ' clock (low high or low high) rcl r1,#1 ' shift in msb first outnot sck nop testp miso wc ' read data from card .end rcl r1,#1 ' shift in msb first wfbyte r1 djnz tos,#.L0 jmp #DROP ' Read 32-bits from SPI' SPIRDL rep @sre1,#32 skip #1 ' SPIRD ( dat -- dat+rd ) SPIRD rep @sre1,#8 ' 8 bits outnot sck ' clock (low high) RWAIT nop outnot sck nop testp miso wc ' read data from card rcl tos,#1 ' shift in msb first sre1 ret ' Write bytes from memory to SPI ' ' SPITX ( src bytes -- ) ' 474.6us/512 SPITXE drvl ss drvl sck SPITX rdfast #0,tos1 .L0 rfbyte fx shl fx,#24 mov r1,#8 call #SPITX8 djnz tos,#.L0 jmp #DROP2 ' Write SD Command SPIWRC and tos,#$3F or tos,#$40 ' SPIWR8 ( byte -- ) ' Shift 8 bits from data[0..7] out and leave data on stack (restored with other bytes zeroed) ' SPIWR8 shl tos , #24 ' left justify 8-bit data s mov r1,#8 SPIWR drvl ss drvl sck call #POPX ' POP VALUE ' SPITX8 rep @.L1,r1 rol fx,#1 wc ' output next msb outc mosi outnot sck ' clock WWAIT nop outnot sck ' clock .L1 ret SPIWRL mov r1,#32 jmp #SPIWR SPIWM shl tos,#8 mov r1,#24 jmp #SPIWR SPIWR16 shl tos,#16 mov r1,#16 jmp #SPIWR SPICE drvh ss _ret_ drvh sck ' P2 shares clock as ce with other boot devices'