ENC28J60 Ethernet Driver

localrogerlocalroger Posts: 3,273
edited 2019-04-29 - 16:38:07 in Propeller 2
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.

Comments

  • jmgjmg Posts: 14,027
    localroger wrote: »
    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.

    Cool, great to see an Ethernet pulse on P2 :)
    localroger wrote: »
    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.
    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

    localroger wrote: »
    The solution I came up with lets the four pin assignments to be moved to local variables with a minimum of overhead.
    Is the aim to connect many Ethernet controllers to P2 as you can ?

  • Smart pins -- because I don't know how to make them work, and the P2 is already almost too fast for the enc28j60 when bit-banging the interface. I doubt you could get it more than about twice as fast as this version with perfect execution to the enc28j60 specs.

    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.
  • jmgjmg Posts: 14,027
    localroger wrote: »
    ..
    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...
    I think SPI has been exampled somewhere, but the smart pin DOCs are example sparse right now.

    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

  • Well I'm not going to break my neck to do smartpin SPI; I've got what I need. There are other speed demons here though who aren't happy with anything less than 450,000 baud, and I'm sure one of them will eventually come around to improving this if they want to. There is a bit of a dance between transmit and receive, and just sending the bits is only a bit less than half of it. If somebody wants to do the Indy 500 thing on the SPI interface then I've done the rest; that's working. Speed it up and just keep it working is a bit less work than implementing it from scratch with the better/faster SPI and making it work for the first time.
  • jmgjmg Posts: 14,027
    localroger wrote: »
    Well I'm not going to break my neck to do smartpin SPI; I've got what I need. There are other speed demons here though who aren't happy with anything less than 450,000 baud, and I'm sure one of them will eventually come around to improving this if they want to. There is a bit of a dance between transmit and receive, and just sending the bits is only a bit less than half of it. If somebody wants to do the Indy 500 thing on the SPI interface then I've done the rest; that's working. Speed it up and just keep it working is a bit less work than implementing it from scratch with the better/faster SPI and making it work for the first time.

    Sounds cool. The enc28j60 is a mature part, so what you have working, is fine for that.
  • I have had my W5500 Ethernet working on the P2 years ago and recently too. The SPI is bit-bashed but runs up to 30MHz. Here are the SPI routines that also work for the SD card too. I may use smartpins eventually but they do seem to need some setting up.
    '********************** 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'
    
    

    Tachyon Forth - compact, fast, forthwright and interactive
    useforthlogo-s.png
    P2 --- The LOT --- TAQOZ INTRO & LINKS --- P2 SHORTFORM DATASHEET --- TAQOZ RELOADED - 64kB binary with room to spare
    P1 --- Latest Tachyon with EASYFILE --- Tachyon Forth News Blog --- More
    paypal.png PayPal me
    Brisbane, Australia
  • New example added to first post adds full UDP client and server support.
Sign In or Register to comment.