Wiznet makers

louis_m

Published April 16, 2025 ©

89 UCC

16 WCC

38 VAR

0 Contests

0 Followers

0 Following

W5500 Decoder in Logic Analyzer

A custom protocol plug-in that allows Saleae Logic Analyzer software to decode SPI communication from the WIZnet W5500 Ethernet chip.

COMPONENTS Hardware components

WIZnet - W5500

x 1


PROJECT DESCRIPTION

Getting Started with the Python Extension Decoder in Logic 2
 

1. Launch Logic 2

2. click the Extensions tab 

3. In the “Create Extension” window that opens, select “High-Level Analyzer”.

 

4. Enter a name of your choice, specify a save location

High Level Analyzer Files

In your new High Level Analyzer (HLA) extension folder you will find 3 files:

README.md

  • Documentation for your extension, shown within Logic 2 when you select an extension, and what users will see if you put your extension on the Marketplace.

extension.json

  • Every extension must have this file in its root directory.
  • Contains metadata about the extension, and the HLAs and Measurement scripts that are included with the extension.

HighLevelAnalyzer.py

  • Python source code for your HLA.
  • For the purposes of this document, we will be focusing on HighLevelAnalyzer.py

 

5. You can do this by modifying HighLevelAnalyzer.py as shown below.

HighLevelAnalyzer.py

from typing import Optional, Union
from saleae.analyzers import HighLevelAnalyzer, AnalyzerFrame

regs = {
    0x0000: "MR",
    0x0001: "GAR0", 0x0002: "GAR1", 0x0003: "GAR2", 0x0004: "GAR3",
    0x0005: "SUBR0", 0x0006: "SUBR1", 0x0007: "SUBR2", 0x0008: "SUBR3",
    0x0009: "SHAR0", 0x000A: "SHAR1", 0x000B: "SHAR2",
    0x000C: "SHAR3", 0x000D: "SHAR4", 0x000E: "SHAR5",
    0x000F: "SIPR0", 0x0010: "SIPR1", 0x0011: "SIPR2", 0x0012: "SIPR3",
    0x0013: "INTLEVEL0", 0x0014: "INTLEVEL1",
    0x0015: "IR", 0x0016: "IMR", 0x0017: "SIR", 0x0018: "SIMR",
    0x0019: "RTR0", 0x001A: "RTR1", 0x001B: "RCR",
    0x001C: "PTIMER", 0x001D: "PMAGIC",
    0x001E: "PHAR0", 0x001F: "PHAR1", 0x0020: "PHAR2",
    0x0021: "PHAR3", 0x0022: "PHAR4", 0x0023: "PHAR5",
    0x0024: "PSID0", 0x0025: "PSID1", 0x0026: "PMRU0", 0x0027: "PMRU1",
    0x0028: "UIPR0", 0x0029: "UIPR1", 0x002A: "UIPR2", 0x002B: "UIPR3",
    0x002C: "UPORTR0", 0x002D: "UPORTR1", 0x002E: "PHYCFGR",
    0x0039: "VERSIONR"
}

sn_regs = {
    0x0000: "MR", 0x0001: "CR", 0x0002: "IR", 0x0003: "SR",
    0x0004: "PORT0", 0x0005: "PORT1",
    0x0006: "DHAR0", 0x0007: "DHAR1", 0x0008: "DHAR2",
    0x0009: "DHAR3", 0x000A: "DHAR4", 0x000B: "DHAR5",
    0x000C: "DIPR0", 0x000D: "DIPR1", 0x000E: "DIPR2", 0x000F: "DIPR3",
    0x0010: "DPORT0", 0x0011: "DPORT1",
    0x0012: "MSSR0", 0x0013: "MSSR1",
    0x0015: "TOS", 0x0016: "TTL",
    0x001E: "RXBUF_SIZE", 0x001F: "TXBUF_SIZE",
    0x0020: "TX_FSR0", 0x0021: "TX_FSR1",
    0x0022: "TX_RD0", 0x0023: "TX_RD1",
    0x0024: "TX_WR0", 0x0025: "TX_WR1",
    0x0026: "RX_RSR0", 0x0027: "RX_RSR1",
    0x0028: "RX_RD0", 0x0029: "RX_RD1",
    0x002A: "RX_WR0", 0x002B: "RX_WR1",
    0x002C: "IMR", 0x002D: "FRAG0", 0x002E: "FRAG1",
    0x002F: "KPALVTR"
}


def get_reg_name(address: int) -> str:
    return regs.get(address, "INVALID")

def get_sn_reg_name(address: int) -> str:
    return sn_regs.get(address, "INVALID")

class Hla(HighLevelAnalyzer):
    result_types = {
        "address": {"format": "Address {{data.address}}"},
        "control": {"format": "{{data.block}} block {{data.rw}}"},
        "read": {"format": "{{data.rw}} {{data.reg}} {{data.value}}"},
        "write": {"format": "{{data.rw}} {{data.reg}} {{data.value}}"},
    }

    def __init__(self):
        self._previous_type = ""
        self._address = None
        self._block = ""
        self._rw = ""
        self._byte_pos = 0
        self._sn = None
        self._start_of_address_frame = None

    def decode(self, frame: AnalyzerFrame) -> Optional[AnalyzerFrame]:
        is_first_byte = self._previous_type == "enable"
        self._previous_type = frame.type

        if is_first_byte:
            self._byte_pos = 0
        else:
            self._byte_pos += 1

        if frame.type != "result":
            return None

        mosi = frame.data["mosi"]
        miso = frame.data["miso"]

        if self._byte_pos == 0:
            self._address = mosi[0] << 8
            self._start_of_address_frame = frame.start_time
        elif self._byte_pos == 1:
            self._address |= mosi[0]
            return AnalyzerFrame("address", self._start_of_address_frame, frame.end_time, {
                "address": f"0x{self._address:04X}"
            })
        elif self._byte_pos == 2:
            control = mosi[0]
            self._rw = "write" if ((control >> 2) & 0b1) else "read"
            bsb = control >> 3
            self._sn = None
            if bsb == 0:
                self._block = "common"
            else:
                sn = int(bsb / 4)
                if sn <= 7:
                    self._sn = sn
                    snblock = bsb - sn * 4 - 1
                    if snblock == 0:
                        self._block = f"Sn{sn} Socket"
                    elif snblock == 1:
                        self._block = f"Sn{sn} TX"
                    elif snblock == 2:
                        self._block = f"Sn{sn} RX"
                    else:
                        self._block = "INVALID"
                else:
                    self._block = "INVALID"

            return AnalyzerFrame("control", frame.start_time, frame.end_time, {
                "block": self._block,
                "rw": self._rw
            })
        elif self._byte_pos > 2:
            byte = mosi[0] if self._rw == "write" else miso[0]
            if self._sn is not None:
                if self._block.endswith("TX"):
                    name = "TX"
                elif self._block.endswith("RX"):
                    name = "RX"
                else:
                    name = get_sn_reg_name(self._address)
            else:
                name = get_reg_name(self._address)

            result = AnalyzerFrame(self._rw.lower(), frame.start_time, frame.end_time, {
                "reg": name,
                "rw": self._rw,
                "value": f"0x{byte:02X}"
            })

            self._address = (self._address + 1) & 0xFFFF
            return result

6. On the Analyzers tab, add the W5500, connect the SPI, and you're ready to decode.

 

1. read the chip version of the W5500

 

2. Get the MAC Address of the W5500

 

3. read the socket's status register

 

Documents
Comments Write