Published using Google Docs
( WIZnet.fth )
Updated automatically every 5 minutes

TACHYON

[~

{                  *** WIZnet W5100/5200 driver ***

Implements the SPI interface to the WIZnet W5100 including the primitives to talk to the chip

The aim is to make this talk to the W5200 as well but the W5100 on the Spinneret is being used for development

130218

Looking at dedicating a cog just to high-speed SPI access which will not only speed up processing but also make it easier to multi-task. I/O will be via simple hub variables.

NOTE: Refresh webpage for latest version

Please use latest kernel 2.1 130216

}

\ Module name - reports in list of modules using MODULES word.

pub WIZNET.fth                ." WIZNET 5100/5200 driver 130216.1500 " ;

\ Spinneret port definitions

#P0        |< == WDO                \ SPI data from WIZNET

#P1        |< == WDI                \ SPI data to WIZNET

#P2        |< == WCE                \ SPI slave select

#P3        |< == WCK                \ SPI clock

#P14        |< == WRST                \ Reset WIZNET - active low

#P15        |< == WSEL                \ SPI mode select - drive high then reset

pub WIZPINS ( sck.mosi.miso.cs -- )

        ' WCE 1+ !

        ' WDO 1+ !

        ' WDI 1+ !

        ' WCK 1+ !

        ;

\ Diagram: WIZnet SPI timing

\ WIZnet SPI OPCODE CONSTANTS

$F0.0000.00 == =WWR

$0F.0000.00 == =WRD

\ Write to the WIZnet register via SPI

pub WIZ! ( data address -- )

        8 SHL SWAP >B OR                                \ position address field and merge with data byte

         =WWR OR                                        \ Set write opcode

         WCE OUTCLR RUNMOD WCE OUTSET                \ chip select, write 32-bits SPI, chip deselect

        DROP

        ;

\ Read from the WIZnet register via SPI

pub WIZ@ ( address -- data )

        8 SHL =WRD OR WCE OUTCLR RUNMOD WCE OUTSET >B

        ;

\ Init the SPI for the WIZnet chip

pub !WIZIO

        BL WDO WDI WCK COGREGS  \ ( cnt miso mosi clk -- ) use 32-bit transfers

        0 4 COGREG!                        \ disable chip select mask so that we can leave with clock low (may patch later)

        WCE OUTSET                        \ Chip select is an output - active low

        WCK OUTCLR                        \ Clock is an output - leave low

        WDI OUTCLR                        \ MOSI is an output

        WSEL OUTSET                        \ Select SPI mode for W5100        

        WRST OUTCLR WRST OUTSET        \ Reset the chip (ensure pulse is >2us)

        [ESPIO]                        \ Select Enhanced SPIO module

        ;

\ write a long to 4 consecutive registers in big endian format

pri WIZ4! ( long reg -- )

        OVER #24 SHR OVER WIZ! 1+

        OVER #16 SHR OVER WIZ! 1+

pri WIZ2! ( word reg -- )

        OVER 8 SHR OVER WIZ! 1+

        WIZ!

        ;

pri WIZ2@ ( reg -- word )

        DUP WIZ@ 8 SHL SWAP 1+ WIZ@ OR

         ;

\ common registers

\ Access common registers

pub wMODE ( mask -- )                0 WIZ! ;

pub GATEWAY ( addr -- )                1 WIZ4! ;

pub SUBNET ( mask -- )                5 WIZ4! ;

pub SHAR ( high low  -- )        $0B WIZ4! 8 WIZ2! ;

pub SRCIP ( long -- )                $0F WIZ4! ;

pub INTS@ ( -- ints )                $15 WIZ@ ;

pub INTMASK ( mask -- )                $16 WIZ! ;

pub RETRYTIME ( val -- )        $17 WIZ2! ;

pub RETRYS ( cnt -- )                $19 WIZ! ;

pub RXSIZ ( mask -- )                $1A WIZ! ; \ default sets 2K for each socket (%01010101)

pub TXSIZ ( mask -- )                $1B WIZ! ;

pub UIP ( ip -- )                        $2A WIZ4! ;

pub UPORT ( port -- )                $2E WIZ2! ;

\ current socket register address offset

$400 == @SOCKET                

\ Set the socket number ( calculates address and sets as a SOCKET constant )

pub SOCKET ( socket -- )        4 + 8 SHL ' @SOCKET 1+ ! ;

\ Socket registers ( -- addr )

pub sMODE                @SOCKET ;                \ mode

pub sCMD                1 @SOCKET + ;        \ command

pub sINTS                2 @SOCKET + ;        \ interrupts

pub sSTAT                3 @SOCKET + ;        \ status

pub sPORT                4 @SOCKET + ;        \ 2 byte src port

pub sDHAR                6 @SOCKET + ;        \ 6 byte dest hardware address

pub sDIP                $0C @SOCKET + ;        \ 4 byte dest IP address

pub sDPORT                $10 @SOCKET + ;        \ 2 byte dest port

pub sSSIZE                $12 @SOCKET + ;        \ 2 byte dest max seg size

pub sPRO                $14 @SOCKET + ;        \ protocol in IP raw mode

pub TXFREE@                $20 @SOCKET + WIZ2@ ;

pub TXREAD                $22 @SOCKET + ;

pub TXWRITE                $24 @SOCKET + ;

pub RXSIZE@                $26 @SOCKET + WIZ2@ ;

pub RXREAD                $28 @SOCKET + ;

( SOCKET COMMANDS )

pub OPEN                  1 sCMD WIZ! ;

pub LISTEN                  2 sCMD WIZ! ;

pub CONNECT                  4 sCMD WIZ! ;

pub DISCON                  8 sCMD WIZ! ;

pub CLOSE                $10 sCMD WIZ! ;

pub SEND                $20 sCMD WIZ! ;

pub SENDMAC                $21 sCMD WIZ! ;

pub SENDKEEP        $22 sCMD WIZ! ;

pub RECV                $40 sCMD WIZ! ;

( SOCKET INTERRUPTS )

4        ==         =SENDOK

3        ==         =TIMEOUT

2        ==         =RECV

1        ==         =DISCON

0        ==         =CON

( SOCKET STATUS CODES )

$00        ==        SOCK_CLOSED

$13        ==        SOCK_INIT

$14        ==        SOCK_LISTEN

$17        ==        SOCK_ESTABLISHED

$1C        ==        SOCK_CLOSE_WAIT

$22        ==        SOCK_UDP

$32        ==        SOCK_IPRAW

$42        ==        SOCK_MACRAW

$5F        ==        SOCK_PPOE

( SOCKET TRANSIENT STATUS CODES )

$15        ==        SOCK_SYNSENT

$16        ==        SOCK_SYNRECV

$18        ==        SOCK_FIN_WAIT

$1A        ==        SOCK_CLOSING

$1B        ==        SOCK_TIME_WAIT

$1D        ==        SOCK_LAST_ACK

$11        ==        SOCK_ARP

$21        ==        SOCK_ARP1

$31        ==        SOCK_ARP2

pub PORT ( srcport -- )                sPORT WIZ2! ;

\ Protocol modes

pub CLOSED                                0 sMODE WIZ! ;

pub TCP                                1 sMODE WIZ! ;

pub UDP                                2 sMODE WIZ! ;

pub IPRAW                                3 sMODE WIZ! ;

pub MACRAW                                4 sMODE WIZ! ;

pub PPPoE                                5 sMODE WIZ! ;

\ Testing some basic transmit functions

pub wTX ( char -- )

        TXWRITE WIZ2@ $7FF AND $4000 + WIZ!

        TXWRITE WIZ2@ 1+ TXWRITE WIZ2!

        ;

pub wTXSTR ( str -- )

        DUP STRLEN SWAP                                                                \ ( strlen str )

        TXWRITE WIZ2@ $7FF AND $4000 +                                         \ Get transmit write pointer ( strlen str wrptr )

        OVER STRLEN ADO C@++ I WIZ! LOOP                                        \ copy string to WIZnet transmit buffer

        DROP                                                                                 \ ( strlen )

         TXWRITE WIZ2@ + TXWRITE WIZ2!                                                \ Update TXWRITE index by string length

\ (moved this to wEMIT )        SEND                                                                                \ Send the contents of the buffer

        ;

{ In this trial method simply buffer the transmit data into hub RAM and transmit it automatically

 when a LF is encountered. The buffer is then erased which also provides null terminators for the next string.

}

pub wEMIT ( ch -- )

        DUP BUFFERS C@ BUFFERS 1+ + C! 1 BUFFERS C+!

        ^J = IF

             BEGIN TXFREE@ BUFFERS 1+ STRLEN => UNTIL                        \ Is there room for this?

           BUFFERS 1+ wTXSTR SEND                                                         \ Send the buffer off as a string

           BUFFERS $80 ERASE                                                        \ clear the buffer (also null terminates all data written)

      THEN

        ;

pub (wKEY)

        BEGIN RXSIZE@ UNTIL

        RXREAD WIZ2@ $7FF AND DUP $6000 + WIZ@

        SWAP 1+ RXREAD WIZ2! RECV

        ;

pub wKEY

        BEGIN

        (wKEY) DUP $FF =                                         \ When the client connects I need to detect the "garbage" and flush

         WHILE RXSIZE@ 0 DO (wKEY) DROP LOOP                \ flush buffer

         REPEAT

         ;

{

pub wGET

        RXSIZE@

         RXREAD WIZ2@ $7FF AND SWAP OVER + SWAP $6000 +                  \ Physical start address ( size+offset readptr )

         SWAP $800 >

           IF ( overflow of socket RX memory )

           ELSE

           

           THEN

        ;

}

pub TERM

        ' wEMIT uemit W!                        \ direct output to WIZnet transmit

        ' wKEY ukey W!

        ;

\ This part works well for directing Console I/O to the TELNET port

\ still needs proper checks etc

pub TELNET

        0 SOCKET CLOSE TCP #23 PORT OPEN LISTEN        \ primitive - needs checks yet

        TERM                \ turn over the console I/O to the TELNET server

        ;

pub FTP

         1 SOCKET TCP #21 PORT OPEN LISTEN

        \ FTPSERVER

        ;

pub WEB

2 SOCKET TCP #80 PORT OPEN LISTEN

        \ WEBSERVER

        ;

\

\ Diagnostics - only needed for debugging

pub WDUMP ( addr cnt -- )

        ADO BUFFERS I $100 ADO I WIZ@ OVER C! 1+ LOOP DROP I $100 BUFFERS BDUMP $100 +LOOP

        ;

\ Dump the WIZnet common registers

pub LW        0 $100 WDUMP ;

\ list quick status

pub S                

        CR ." sSTAT = " sSTAT WIZ@ .

        CR ." sINTS = " sINTS WIZ@ .

        ;

]~

END

\ NOTE: This is the end of the software source code, what follows is normally meant to be entered interactively

 

\ Preset some initializations

( NOTE: uses new & notation for IP addresses - use Kernel 2.1 130214 onwards)

{

!WIZIO

&192.168.0.1 GATEWAY

&255.255.255.0 SUBNET

&192.168.0.80 SRCIP

$00.08 $DC.01.02.03 SHAR

Try typing TELNET and then connect to the Forth console via a TELNET session

TERM

peter@peter-XPS-L702X-Mint14 ~ $ telnet 192.168.0.80

Trying 192.168.0.80...

Connected to 192.168.0.80.

Escape character is '^]'.

.VER

.VER

  Propeller .:.:--TACHYON--:.:. Forth V21130216.1200

 ok

MY QWORDS

MY QWORDS

S LW WDUMP TELNET TERM wKEY (wKEY) wEMIT wTXSTR wTX PPPoE MACRAW IPRAW UDP TCP

CLOSED PORT SOCK_ARP2 SOCK_ARP1 SOCK_ARP SOCK_LAST_ACK SOCK_TIME_WAIT SOCK_CLOSING SOCK_FIN_WAIT

SOCK_SYNRECV SOCK_SYNSENT SOCK_PPOE SOCK_MACRAW SOCK_IPRAW SOCK_UDP SOCK_CLOSE_WAIT SOCK_ESTABLISHED

SOCK_LISTEN SOCK_INIT SOCK_CLOSED =CON =DISCON =RECV =TIMEOUT =SENDOK RECV SENDKEEP SENDMAC SEND

CLOSE DISCON CONNECT LISTEN OPEN RXREAD RXSIZE@ TXWRITE TXREAD TXFREE@ sPRO sSSIZE sDPORT

sDIP sDHAR sPORT sSTAT sINTS sCMD sMODE SOCKET @SOCKET UPORT UIP TXSIZ RXSIZ RETRYS

RETRYTIME INTMASK INTS@ SRCIP SHAR SUBNET GATEWAY wMODE WIZ2@ WIZ2! WIZ4! !WIZIO WIZ@ WIZ!

=WRD =WWR WSEL WRST WCK WCE WDI WDO

 ok

}

\ Let's try an autostart procedure for a TELNET session

pub WIZ

         !WIZIO

         &192.168.0.1 GATEWAY

         &255.255.255.0 SUBNET

         &192.168.0.80 SRCIP

         $00.08 $DC.01.02.03 SHAR

        TELNET

        ;

\ Run TELNET as a task but with simple echo while the console debugs

pri WIZECHO

         !WIZIO

         &192.168.0.1 GATEWAY

         &255.255.255.0 SUBNET

         &192.168.0.80 SRCIP

         $00.08 $DC.01.02.03 SHAR

         0 SOCKET CLOSE TCP #23 PORT OPEN LISTEN

        BEGIN wKEY wEMIT AGAIN

        ;

pub WIZTASK

        ' WIZECHO TASK? RUN

        ;

AUTORUN WIZ

\ BACKUP