[Oberon] Wiznet W5500 code for Oberon System[?]

Jörg joerg.straube at iaeth.ch
Sat Mar 12 16:10:49 CET 2022


I‘m a little bit further than Paul :-)
I have
- Timers.Mod
- W5500.Mod
- IP.Mod
- UDP.Mod
- TCP.Mod
- DNS.Mod
- DHCP.Mod

But the code is not polished / documented.

Br, Jörg

> Am 12.03.2022 um 14:57 schrieb Paul Reed <paulreed at paddedcell.com>:
> 
> Hi Wojtek,
> 
>> I remember some remarks concerning the Wiznet W5500 support for Oberon
>> System... if we could use the existing code...
> 
> I remember some discussions, and some wishful thinking, but I don't remember anyone producing any code.
> 
> So given there was no answer, I grabbed a WIZ850io module (a W5500 breakout) and wired it to the GPIO port on an Oberon system (Spartan-3 Starter Kit, as it happens). My working test code is below in case it helps.
> 
>> ...SPI-to-Ethernet translator. It helps to avoid the burden of
>> maintaining the TCP/IP stack within the Oberon System.
> 
> So it's intended as an SPI-to-TCP/IP translator, more accurately. You open a socket and go. However as you'll see from my code I wasn't really interested in that and preferred to put it in MACRAW mode (socket 0 only, see datasheet) so I could look at the Ethernet frames on my test network.
> 
> *******
> Obviously, only use this code on a network that you control, or where you have permission to look at raw frames: if they haven't heard of Oberon, say "WireShark". ;-)
> *******
> 
> Status0 reads (peeks, not removes) the frames captured in the RX buffer of socket 0 as it fills up.
> 
> Interestingly, Init doesn't reset the chip, it just re-opens the socket without closing it, but doing this you'll then get a new buffer to peek at.
> 
> Even if someone had produced more elaborate code in Oberon, it may not even have been helpful, because this is an application-level protocol, it doesn't work at the driver level in any normal sense.
> 
> So how someone else had used it may prejudice how you might want to use it. Searching I found sample code in BASIC and in Python, but it wasn't very useful except to confirm some of the concepts in the datasheet.
> 
> You probably want to dedicate an SPI port to it, that seems to be the consensus (especially since it may be able to run at 33-80MHz). Of course, with an FPGA that's relatively easy. I bit-banged the SPI over GPIO because that was the easiest way to connect the module just as a test without too much investment.
> 
> Cheers,
> Paul
> 
> 
> MODULE W5500;  (* PDR 11.3.22      W5500.Init     W5500.Status0*)
>  IMPORT SYSTEM, Texts, Oberon;
> 
> CONST gpio= -32; gpoc = -28;  (* general-purpose I/O data and output control *)
>  MISObit = 0; MOSI = 2; SCK = 4; CS = 8;  (* W5500 module pin assignments *)
>  COMMON = 0; SOCKREG0 = 8; SOCKRX0 = 24; WRITE = 4;  (* W5500 control byte *)
> 
> VAR W: Texts.Writer;
>  init: BOOLEAN; rcvd: INTEGER;
> 
> (* bit-bang the W5500 SPI interface using GPIO *)
> 
> PROCEDURE bits(x, n: INTEGER); (*adapted from NW PICL.Mod*)
>  VAR b: INTEGER;
> BEGIN (*send n bits of x, MSB first*)
>  REPEAT DEC(n); b := ROR(x, n) MOD 2 * MOSI;
>    SYSTEM.PUT(gpio, b); rcvd := rcvd * 2 + ORD(SYSTEM.BIT(gpio, MISObit));
>    SYSTEM.PUT(gpio, b + SCK)
>  UNTIL n = 0
> END bits;
> 
> PROCEDURE begin;
> BEGIN SYSTEM.PUT(gpio, CS); SYSTEM.PUT(gpoc, MOSI+SCK+CS); SYSTEM.PUT(gpio, 0)
> END begin;
> 
> PROCEDURE end;
> BEGIN SYSTEM.PUT(gpio, CS); SYSTEM.PUT(gpoc, 0); SYSTEM.PUT(gpio, 0)
> END end;
> 
> PROCEDURE get(adr, ctrl, n: INTEGER);
> BEGIN begin; bits(adr, 16); bits(ctrl, 8); rcvd := 0; bits(0, n); end
> END get;
> 
> PROCEDURE set(adr, ctrl, x, n: INTEGER);
> BEGIN begin; bits(adr, 16); bits(ctrl + WRITE, 8); bits(x, n); end
> END set;
> 
> PROCEDURE Init*;
> BEGIN get(39H, COMMON, 8);
>  Texts.WriteString(W, "W5500 version byte (reg 39H) = "); Texts.WriteHex(W, rcvd);
>  Texts.WriteLn(W);
>  IF rcvd = 4 THEN get(2EH, COMMON, 8);
>    Texts.WriteString(W, "  PHYCFGR"); Texts.WriteHex(W, rcvd);
>    IF ODD(rcvd DIV 4) THEN Texts.WriteString(W, ": full") ELSE Texts.WriteString(W, ": half") END;
>    Texts.WriteString(W, " duplex, 10");
>    IF ODD(rcvd DIV 2) THEN Texts.Write(W, "0") END;
>    Texts.WriteString(W, "Mb, link ");
>    IF ODD(rcvd) THEN Texts.WriteString(W, "up") ELSE Texts.WriteString(W, "down") END;
>    Texts.WriteLn(W);
>    IF rcvd DIV 8 # 17H THEN
>      Texts.WriteString(W,  "  Unexpected config, not HW auto");
>      Texts.WriteLn(W);
>    END;
>    set(0, SOCKREG0, 4, 8); (*raw*)
>    set(1, SOCKREG0, 1, 8); (*open*)
>    init := TRUE
>  ELSE Texts.WriteString(W, "04 expected, initialisation failed")
>  END;
>  Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf)
> END Init;
> 
> PROCEDURE Hex(VAR W: Texts.Writer; x, n: INTEGER);
>  VAR c: INTEGER;
> BEGIN (*n MOD 4 = 0, n >= 4*)
>  REPEAT DEC(n, 4);
>    c := ROR(x, n) MOD 10H;
>    IF c > 9 THEN c := c - 10 + ORD("A") ELSE c := c + ORD("0") END;
>    Texts.Write(W, CHR(c))
>  UNTIL n <= 0
> END Hex;
> 
> PROCEDURE Status0*;
>  VAR rx, len, i: INTEGER;
> BEGIN IF ~init THEN Init END;
>  get(3, SOCKREG0, 8);
>  Texts.WriteString(W, "Socket 0 status"); Texts.WriteHex(W, rcvd);
>  get(26H, SOCKREG0, 16); rx := rcvd;
>  Texts.WriteString(W, ", rx size "); Texts.WriteInt(W, rx, 1);
>  Texts.WriteLn(W); i := 0;
>  WHILE i < rx DO
>    get(i+0, SOCKRX0, 16); len := rcvd; Texts.WriteInt(W, len, 1); Texts.Write(W, " ");
>    get(i+2, SOCKRX0, 32); Texts.WriteHex(W, rcvd);
>    get(i+6, SOCKRX0, 16); Hex(W, rcvd, 16); (*dst MAC*)
>    get(i+8, SOCKRX0, 32); Texts.WriteHex(W, rcvd);
>    get(i+12, SOCKRX0, 16); Hex(W, rcvd, 16); (*src MAC*)
>    get(i+14, SOCKRX0, 16); Texts.WriteHex(W, rcvd); (*ether type*)
>    Texts.WriteLn(W);
>    i := i + len
>  END; Texts.Append(Oberon.Log, W.buf)
> END Status0;
> 
> BEGIN end; Texts.OpenWriter(W); init := FALSE
> END W5500.
> --
> Oberon at lists.inf.ethz.ch mailing list for ETH Oberon and related systems
> https://lists.inf.ethz.ch/mailman/listinfo/oberon


More information about the Oberon mailing list