diff --git a/exi_bba/w5100_parallel_master.py b/exi_bba/w5100_parallel_master.py index f47cd87..567708b 100644 --- a/exi_bba/w5100_parallel_master.py +++ b/exi_bba/w5100_parallel_master.py @@ -50,6 +50,10 @@ _SUBR0 = 0x0005 # Subnet mask, 4 bytes _SHAR0 = 0x0009 # Source MAC, 6 bytes _SIPR0 = 0x000F # Source IP, 4 bytes _NETLCKR = 0x0071 # W5100S Network Lock Register (WO) — GWR/SUBR/SHAR/SIPR are + +# Default RSTn low time before release (sync cycles). 24_000 @ 24 MHz = 1 ms; +# the W5100S datasheet minimum is ~2 us, so this is generous on purpose. +_RST_LOW_DEFAULT = 24_000 _NETLCK_UNLOCK = 0x3A # writable ONLY while NETLCKR==0x3A (default 0x00 = locked) _IR = 0x0015 # Interrupt register _IMR = 0x0016 # Interrupt mask @@ -150,6 +154,10 @@ class W5100ParallelMaster(Elaboratable): self._strobe = strobe_cycles # MR-reset settle wait; testbench overrides with a small value. self._reset_cycles = reset_cycles + # RSTn low time. Clamped to reset_cycles so the testbenches (which + # pass a tiny reset_cycles to stay fast) keep wait_ctr wide enough to + # actually reach it -- an unreachable target would hang the FSM. + self._rst_low = min(_RST_LOW_DEFAULT, reset_cycles) # ── Optional socket-1 UDP bring-up test ─────────────────────────────── # When enabled, init also configures the W5100's IP stack (GAR/SUBR/ @@ -556,7 +564,8 @@ class W5100ParallelMaster(Elaboratable): with m.If(self.init_req): for i in range(6): m.d.sync += mac_shadow[i].eq(self.par[i*8:(i+1)*8]) - m.next = "MR_RST" + m.d.sync += [self.w5100_rst_n.eq(0), wait_ctr.eq(0)] + m.next = "HW_RST" with m.Elif(~self.w5100_int_n): m.next = "RX_CHECK" with m.Elif(self.tx_valid & self.tx_sof): @@ -582,6 +591,32 @@ class W5100ParallelMaster(Elaboratable): self.dbg_rd_done.eq(1)] m.next = "IDLE" + # Pulse the W5100's RSTn pin, then let it boot, BEFORE touching the + # bus. This used to be missing entirely: w5100_rst_n was declared + # and never driven, so the only reset the chip ever got was the MR + # software reset -- which a wedged chip does not answer, because it + # arrives over the very bus that is stuck. The result was a W5100 + # that could only be recovered by a 12 V power cycle; even + # reconfiguring the FPGA did not help, since RSTn just floats to its + # pull-up (R36) while the FPGA is unconfigured. Driving it here + # makes an NCRA reset able to recover the chip on its own. + # RSTn low: datasheet minimum is ~2 us; _RST_LOW is far longer and + # costs nothing on a path that runs once per init. + with m.State("HW_RST"): + with m.If(wait_ctr == self._rst_low): + m.d.sync += [self.w5100_rst_n.eq(1), wait_ctr.eq(0)] + m.next = "HW_RST_WAIT" + with m.Else(): + m.d.sync += wait_ctr.eq(wait_ctr + 1) + + # RSTn released: the W5100S needs 60.3 ms before it answers at all. + with m.State("HW_RST_WAIT"): + with m.If(wait_ctr == self._reset_cycles): + m.d.sync += wait_ctr.eq(0) + m.next = "MR_RST" + with m.Else(): + m.d.sync += wait_ctr.eq(wait_ctr + 1) + # MR = 0x80 software reset (direct A=00), then settle. # # reset_cycles MUST cover the W5100S's post-reset dead time (the