[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