---
title: "Part 12: W55RP20-EVB-MKR MicroPython Hands-on (12): MQTT Protocol Basic Communication Verification"
url: "https://maker.wiznet.io/ronpang/projects/part-12-w55rp20-evb-mkr-micropython-hands-on-12--mqtt-protocol-basic-communication-verification/"
markdown_url: "https://maker.wiznet.io/ronpang/projects/part-12-w55rp20-evb-mkr-micropython-hands-on-12--mqtt-protocol-basic-communication-verification/md"
type: "WCC: WIZnet Created Content"
author: "WIZnet HK"
editor: "WIZnet"
editor_url: "https://maker.wiznet.io/"
original_author: "WIZnet HK"
published: "2026-06-29"
language: "en"
likes: 0
views: 362
comments: 0
source: "WIZnet Makers (https://maker.wiznet.io/)"
---

# Part 12: W55RP20-EVB-MKR MicroPython Hands-on (12): MQTT Protocol Basic Communication Verification

> This article is Part 12 of the WIZnet W55RP20 chip MicroPython tutorial series. It is written based on the latest official firmware;

Original author: WIZnet HK

## Article

## **Part 12: W55RP20-EVB-MKR MicroPython Hands-on (12): MQTT Protocol Basic Communication Verification**

> This article is Part 12 of the WIZnet W55RP20 chip MicroPython tutorial series. It is written based on the latest official firmware; all code has been verified in practice and can be flashed and run directly. Copyright Notice: This article is an original technical article from WIZnet. Please indicate the source when reposting.

---

In the previous hands-on tutorial, we completed the HTTP protocol and OneNET platform data upload to the cloud using the W55RP20 chip. This article focuses on the core IoT communication protocol — MQTT. MQTT is the most mainstream lightweight communication protocol in IoT, adopting the **Publish/Subscribe (Pub/Sub)** model. It has low bandwidth usage, low power consumption, and supports reconnection after disconnection, making it very suitable for embedded Ethernet devices to connect to the cloud and communicate between devices. The W55RP20 integrates a hardware TCP/IP protocol stack, and with the **MicroPython** `umqtt` library, stable MQTT communication can be achieved in just a few lines of code without worrying about underlying Socket details.

After learning this article, you will master:

Core principles of the MQTT protocol and the publish/subscribe mechanism

Connecting W55RP20 to local/public MQTT servers

Implementing message publishing, subscribing, and callback handling

Industrial-grade stability mechanisms such as heartbeat keep-alive and disconnection reconnection

Setting up a local MQTT test environment

Three major pain points of traditional embedded MQTT development, solved by W55RP20 in one click:

Complex protocol stack debugging: Software TCP/IP protocol stacks require manual porting and debugging, occupy MCU resources, and are prone to lag and memory overflow. The W55RP20 has a built-in hardware TCP/IP protocol stack; network layer processing is entirely completed by hardware, without occupying CPU resources, and requires no protocol stack debugging.

Tedious hardware wiring: External network modules require manual soldering and debugging interface timing, making it easy for beginners to make mistakes. The W55RP20 has an onboard Ethernet interface, requiring no additional external modules, plug-and-play, greatly simplifying wiring operations.

High entry barrier: Details such as MQTT client connection and heartbeat keep-alive need to be manually written, with long debugging cycles. This article provides complete code that can be run directly, with clear comments, and with 10-minute step-by-step operations, beginners can quickly see results. Relying on MicroPython's compilation-free feature, code modifications take effect immediately, and debugging provides real-time feedback, quickly giving a sense of achievement. ![Insert image description here](https://i-blog.csdnimg.cn/direct/26fa7aae315b431d8a22a024e5710859.png#pic_center)

Core objectives of this lesson:

· Complete hardware connection of W55RP20 with PC and development environment configuration

· Understand core principles of the MQTT protocol and its minimalist workflow

· Flash MQTT client code to achieve connection with a public MQTT server

· Complete topic subscription, message publishing, and loopback communication testing

· Master quick troubleshooting methods for common faults

---

### **Tutorial Series Learning Path**

This column consists of 16 articles, progressively covering the full W55RP20-EVB-MKR module MicroPython development workflow:

Part 1: Static IP Configuration and Network Basics

Part 2: DHCP Auto-Networking and Network Diagnostics

Part 3: TCP Client Communication

Part 4: TCP Server Communication

Part 5: UDP Unicast Data Communication

Part 6: UDP Multicast/Broadcast Data Communication

Part 7: DNS Domain Name Resolution

Part 8: NTP Time Retrieval from Network

Part 9: HTTP Client Requests

Part 10: HTTP Server Setup

Part 11: HTTP Protocol and OneNET Platform Data Upload

Part 12: MQTT Protocol Basic Communication Verification (This article)

Part 13: MQTT Protocol and Alibaba Cloud Platform Integration

Part 14: MQTT Protocol and OneNET Platform Integration

Part 15: MQTT Protocol and ThingSpeak Platform Integration

Part 16: Modbus Industrial Protocol Communication

> It is recommended to bookmark this column and follow the tutorials step by step. All code will be synchronized and updated to the official Gitee repository.

---

### **Table of Contents**

1. Preparation

1.1 Software Preparation

1.2 Hardware Preparation

2. Flashing the W55RP20-EVB-MKR Exclusive MicroPython Firmware

3. Hardware Connection and Development Environment Configuration

3.1 Hardware Connection

3.1.1 Basic Connection (Power + Debug)

3.1.2 Ethernet Connection

3.1.3 Module and Development Board Wiring

3.2 Thonny Development Environment Configuration

4. MQTT Protocol Minimalist Analysis

5. Core Code Copying and Flashing

5.1 Dependency Library Description

5.2 Complete Code and Flashing Process

6. Running Results and MQTT Communication Verification

6.1 Serial Output Results

6.2 MQTT Loopback Communication Verification

7. One-Stop Troubleshooting for Common Issues

8. W55RP20 Core Advantage Comparison

9. Typical Application Scenarios

10. Summary

11. Series Preview and Resource Acquisition

11.1 Series Preview

11.2 Resource Acquisition

---

### **1. Preparation**

#### **1.1 Software Preparation**

All required software is free; download and install according to the requirements, no additional payment is needed.

| **Software Name** | **Version Requirement** | **Download Link** | **Description** |
| --- | --- | --- | --- |
| Thonny | 4.0 and above | [Thonny Official Download](https://thonny.org) | Lightweight MicroPython IDE, supporting code editing, flashing, and serial debugging, beginner-friendly |
| W55RP20-EVB-MKR Module MicroPython Firmware | Latest stable version | [WIZnet Official Firmware Download](https://www.w5500.com/chip/W55RP20) | Specially written for the W55RP20-EVB-MKR module, with WIZnet hardware driver and protocol stack integrated |

#### **1.2 Hardware Preparation**

![Insert image description here](https://i-blog.csdnimg.cn/direct/070ec962fe94486bb005e826a5965897.png)

W55RP20-EVB-MKR × 1

Micro USB data cable (must support data transmission, cannot use a charging-only cable) × 1

Standard Ethernet cable × 1

Router / switch with DHCP enabled × 1 (used to obtain network parameters and implement DNS resolution)

> The W55RP20-EVB-MKR module has integrated Ethernet-related components, requiring no additional soldering or fly-wiring. Combined with the RP2040 development board, it can quickly set up a development environment, greatly reducing the probability of wiring errors and hardware failures.

---

### **2. Flashing the W55RP20-EVB-MKR Exclusive MicroPython Firmware**

The W55RP20-EVB-MKR module is fully compatible with the Raspberry Pi MKR UF2 firmware flashing method. The operation is simple, requiring no additional programmer, and beginners can quickly get started:

Press and hold the BOOTSEL button on the RP2040 development board;

Use a Micro USB data cable to connect the development board to the PC;

After the PC recognizes a USB drive named RPI-RP2, release the BOOTSEL button;

Drag and drop the downloaded W5500_RP2040_firmware.uf2 firmware file into the USB drive;

The development board will restart automatically, and firmware flashing is complete.

> Note: If the PC does not recognize the RPI-RP2 USB drive, try replacing the USB data cable, re-plugging the development board, or changing the PC USB port (preferably use a USB 2.0 port).

---

### **3. Hardware Connection and Development Environment Configuration**

#### **3.1 Hardware Connection**

The W55RP20-EVB-MKR module connection is divided into two steps, respectively achieving power/debug and Ethernet connection. The operation is simple, requiring no complex wiring:

##### **3.1.1 Basic Connection (Power + Debug)**

Use a Micro USB data cable to connect the RP2040 development board to the PC, for development board power supply, code flashing, and serial debugging.

##### **3.1.2 Ethernet Connection**

Use an Ethernet cable to connect the W55RP20-EVB-MKR module's Ethernet interface to the router's LAN port (or directly connect to the PC's network port; in this case, the PC IP needs to be manually configured to be in the same subnet as the development board).

##### **3.1.3 Module and Development Board Wiring**

If using a separate module and development board, connect according to the following pin correspondence (SPI communication): ![Insert image description here](https://i-blog.csdnimg.cn/direct/98c95f1f4a234b49b24ecf351d9a4460.jpeg)

#### **3.2 Thonny Development Environment Configuration**

Open the Thonny software and configure the development environment according to the following steps to ensure that code can be flashed and run normally:

Click the top menu bar "Run" → "Configure Interpreter";

Switch to the "Interpreter" tab;

Select MicroPython (Generic) from the "Interpreter" dropdown list;

Select the serial port corresponding to the development board from the "Port" dropdown list (usually displayed as Board CDC @ COMx);

Check "Restart interpreter before running code" and "Synchronize device's real-time clock";

Click "OK" to complete the configuration.

> If the development board does not appear in the port list, try:
>
> Re-plugging the USB data cable;
>
> Replacing the USB data cable with one that supports data transmission;
>
> Closing other software occupying the serial port (such as serial assistants, Arduino IDE, etc.);
>
> Re-flashing the MicroPython firmware;
>
> Installing the Raspberry Pi Pico USB driver.

---

### **4. MQTT Protocol Minimalist Analysis**

MQTT is a lightweight IoT message transmission protocol based on the publish/subscribe model. It is suitable for embedded devices with limited hardware resources and network environments with limited bandwidth. It is widely used in IoT, smart hardware, industrial control, and other scenarios. Its core advantages are being lightweight, efficient, reliable, and easy to implement. The minimum control message requires only two data bytes, the message header is streamlined, and network bandwidth can be optimized.

Minimalist workflow (4 steps):

The client (W55RP20) connects to the MQTT server (this article uses a free public server, no registration required);

The client subscribes to a specified topic (such as /W55RP20/sub) to receive messages;

The client (or other devices) publishes messages to the specified topic;

All clients subscribed to this topic can receive and process the message.

This article's hands-on practice uses the free public MQTT server (broker-cn.emqx.io, port 1883), which requires no registration and can be used by connecting directly, further saving time and helping you complete the hands-on practice in 10 minutes.

---

### **5. Core Code Copying and Flashing**

#### **5.1 Dependency Library Description**

The core dependency is the `umqttsimple.py` library, used to implement basic MQTT client functions such as connection, subscription, and publishing. This library is a commonly used lightweight MQTT library in the MicroPython ecosystem, with a small size and strong adaptability, requiring no additional modifications. It can be saved directly to the W55RP20 for use. It can be downloaded from the MicroPython official repository or by directly copying the complete code provided in this article.

#### **5.2 Complete Code and Flashing Process**

Required development environment [Thonny](https://thonny.org/) If you must compile MicroPython, you must use a Linux or Unix environment. Step 1: Copy the program into Thonny, then select the environment as Raspberry Pi Pico.

Step 2: Save the `umqttsimple.py` library file to the development board.

Step 3: Run the program, and open MQTTX, connect to the same server, then subscribe to the topic as the development board's publish topic, and the publish topic as the development board's subscribe topic. See the figure below.

Step 4: Send a message in MQTTX and observe the loopback test effect.

> Note: Because MicroPython's `print` function has stdout buffering enabled, content may not be printed immediately.

![](https://maker.wiznet.io/upload/ckeditor5/205720593%5F1782743169%2Egif)

`umqttsimple.py` code:

```
# mqtt.py file
import network
import time
try:
    from machine import Pin, WIZNET_PIO_SPI
except ImportError:
    WIZNET_PIO_SPI = None
    Pin = None
​
_DEFAULTS = {
    "w5100s-evb-pico":  {},
    "w5500-evb-pico":   {},
    "w6100-evb-pico":   {},
    "w5100s-evb-pico2": {},
    "w5500-evb-pico2":  {},
    "w6100-evb-pico2":  {},
    "w55rp20-evb-pico": {"baudrate": 31250000, "sck": 21, "cs": 20, "mosi": 23, "miso": 22, "reset": 25},
    "w6300-evb-pico":  {"baudrate": 31250000, "sck": 17, "cs": 16, "io0": 18, "io1": 19, "io2": 20, "io3": 21, "reset": 22},
    "w6300-evb-pico2": {"baudrate": 31250000, "sck": 17, "cs": 16, "io0": 18, "io1": 19, "io2": 20, "io3": 21, "reset": 22},
}
_AUTO = {
    "w5100s-evb-pico", "w5500-evb-pico", "w6100-evb-pico",
    "w5100s-evb-pico2","w5500-evb-pico2","w6100-evb-pico2",
}
_SINGLE = {"w55rp20-evb-pico"}
_QSPI   = {"w6300-evb-pico", "w6300-evb-pico2"}
​
def _pin(x): return x if isinstance(x, Pin) else Pin(x)
​
def wiznet(board, *, dhcp=True, spi=None, cs=None, reset=None, **kw):
    board = board.strip().lower()
    if board not in _DEFAULTS:
        raise ValueError("Unsupported board: {}".format(board))
    cfg = _DEFAULTS[board].copy()
    cfg.update(kw)
    
    if spi is not None:
        if cs is None or reset is None:
            raise ValueError("When passing custom spi, also pass cs and reset")
        nic = network.WIZNET6K(spi, cs, reset)
    else:
        if board in _AUTO:
            nic = network.WIZNET6K()
        elif board in _SINGLE:
            if WIZNET_PIO_SPI is None or Pin is None:
                raise RuntimeError("WIZNET_PIO_SPI/Pin not available on this port")
            required = ["sck", "cs", "mosi", "miso", "reset"]
            missing = [k for k in required if k not in cfg]
            if missing:
                raise ValueError("Missing pins for W55RP20 single-SPI: " + ", ".join(missing))
            spi = WIZNET_PIO_SPI(
                baudrate=cfg.get("baudrate", 31250000),
                sck=_pin(cfg["sck"]), cs=_pin(cfg["cs"]),
                mosi=_pin(cfg["mosi"]), miso=_pin(cfg["miso"]),
            )
            nic = network.WIZNET6K(spi, _pin(cfg["cs"]), _pin(cfg["reset"]))
        elif board in _QSPI:
            if WIZNET_PIO_SPI is None or Pin is None:
                raise RuntimeError("WIZNET_PIO_SPI/Pin not available on this port")
            for k in ["sck","cs","io0","io1","io2","io3"]:
                if k not in cfg: raise ValueError("Missing pin '{}' for W6300 QSPI".format(k))
            spi = WIZNET_PIO_SPI(
                baudrate=cfg.get("baudrate", 31250000),
                sck=_pin(cfg["sck"]), cs=_pin(cfg["cs"]),
                io0=_pin(cfg["io0"]), io1=_pin(cfg["io1"]),
                io2=_pin(cfg["io2"]), io3=_pin(cfg["io3"]),
            )
            nic = network.WIZNET6K(spi, _pin(cfg["cs"]), _pin(cfg.get("reset", cfg["cs"])))
        else:
            raise ValueError("Unexpected board mapping")
​
    try: nic.active(True)
    except AttributeError: pass
​
    if dhcp:
        try: nic.ifconfig("dhcp")
        except Exception: pass
    else:
        ip = cfg.get("ip"); sn = cfg.get("sn"); gw = cfg.get("gw"); dns = cfg.get("dns", gw or "8.8.8.8")
        if not (ip and sn and gw): raise ValueError("Static mode requires ip/sn/gw")
        nic.ifconfig((ip, sn, gw, dns))
    while not nic.isconnected():
        print("Waiting for the network to connect...")
        time.sleep(1)
​
    print("MAC Address:", ":".join("%02x" % b for b in nic.config("mac")))
    print("IP Address:", nic.ifconfig()[0])
    return nic
​
from umqttsimple import MQTTClient
from machine import Timer
import machine
​
# mqtt config
mqtt_params = {}
mqtt_params['url'] = 'broker.emqx.io'
mqtt_params['port'] = 1883
mqtt_params['clientid'] = 'W55RP20'
mqtt_params['pubtopic'] = '/W55RP20/pub'
mqtt_params['subtopic'] = '/W55RP20/sub'
mqtt_params['pubqos'] = 0
mqtt_params['subqos'] = 0
​
timer_1s_count = 0
tim = Timer()
client = None
​
def w5x00_init():
    nic = wiznet("w55rp20-evb-pico", dhcp=True)
    print("IP         :",nic.ifconfig()[0])
    print("Subnet Mask:",nic.ifconfig()[1])
    print("Gateway    :",nic.ifconfig()[2])
    print("DNS        :",nic.ifconfig()[3],"\r\n")
    return nic
​
def sub_cb(topic, msg):
    topic = topic.decode('utf-8')
    msg = msg.decode('utf-8')
    if topic == mqtt_params['subtopic']:
        global client
        print("\r\ntopic:",topic,"\r\nrecv:", msg)
        client.publish(mqtt_params['pubtopic'],msg,qos=mqtt_params['pubqos'])
        print('\r\ntopic:',mqtt_params['pubtopic'],'\r\nsend:',msg)
​
def mqtt_connect():
    global client
    # Use a different ID for each reconnection to prevent server rejection
    from time import time
    new_id = "W55RP20_" + str(time())
    client = MQTTClient(new_id, mqtt_params['url'], mqtt_params['port'], keepalive=60)
    client.connect()
    print('Connected to %s MQTT Broker'%(mqtt_params['url']))
    return client
​
def reconnect():
    print('MQTT connection lost, reconnecting...')
    time.sleep(3)
​
def tick(timer):
    global timer_1s_count
    global client
    timer_1s_count += 1
    if timer_1s_count >= 30:
        timer_1s_count = 0 
        try:
            client.ping()
        except:
            pass
​
def subscribe(client):
    client.set_callback(sub_cb)
    client.subscribe(mqtt_params['subtopic'],mqtt_params['subqos'])
    print('subscribed to %s'%mqtt_params['subtopic'])
​
def main():
    global client
    print("W55RP20 chip MQTT example")
​
    # Initialize network only once
    w5x00_init()
​
    # ========== Core: Infinite loop + automatic reconnection on error ==========
    while True:
        try:
            client = mqtt_connect()
            subscribe(client)
            tim.init(freq=1, callback=tick)
​
            # Normal operation
            while True:
                client.wait_msg()
​
        except Exception as e:
            print("Error detected, reconnecting soon:", e)
            try:
                client.disconnect()
            except:
                pass
            time.sleep(2)
​
if __name__ == "__main__":
    main()
​
```

Supplementary `umqttsimple.py` library code (copy and save to the W55RP20 development board, at the same level as `mqtt.py`):

```
# umqttsimple.py file
import usocket as socket
import ustruct as struct
from ubinascii import hexlify
​
​
class MQTTException(Exception):
    pass
​
​
class MQTTClient:
    def __init__(
        self,
        client_id,
        server,
        port=0,
        user=None,
        password=None,
        keepalive=0,
        ssl=False,
        ssl_params={},
    ):
        if port == 0:
            port = 8883 if ssl else 1883
        self.client_id = client_id
        self.sock = None
        self.server = server
        self.port = port
        self.ssl = ssl
        self.ssl_params = ssl_params
        self.pid = 0
        self.cb = None
        self.user = user
        self.pswd = password
        self.keepalive = keepalive
        self.lw_topic = None
        self.lw_msg = None
        self.lw_qos = 0
        self.lw_retain = False
​
    def _send_str(self, s):
        self.sock.write(struct.pack("!H", len(s)))
        self.sock.write(s)
​
    def _recv_len(self):
        n = 0
        sh = 0
        while 1:
            b = self.sock.read(1)[0]
            n |= (b & 0x7F) << sh
            if not b & 0x80:
                return n
            sh += 7
​
    def set_callback(self, f):
        self.cb = f
​
    def set_last_will(self, topic, msg, retain=False, qos=0):
        assert 0 <= qos <= 2
        assert topic
        self.lw_topic = topic
        self.lw_msg = msg
        self.lw_qos = qos
        self.lw_retain = retain
​
    def connect(self, clean_session=True):
        self.sock = socket.socket()
        addr = socket.getaddrinfo(self.server, self.port)[0][-1]
        self.sock.connect(addr)
        if self.ssl:
            import ussl
​
            self.sock = ussl.wrap_socket(self.sock, **self.ssl_params)
        premsg = bytearray(b"\x10\0\0\0\0\0")
        msg = bytearray(b"\x04MQTT\x04\x02\0\0")
​
        sz = 10 + 2 + len(self.client_id)
        msg[6] = clean_session << 1
        if self.user is not None:
            sz += 2 + len(self.user) + 2 + len(self.pswd)
            msg[6] |= 0xC0
        if self.keepalive:
            assert self.keepalive < 65536
            msg[7] |= self.keepalive >> 8
            msg[8] |= self.keepalive & 0x00FF
        if self.lw_topic:
            sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg)
            msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3
            msg[6] |= self.lw_retain << 5
​
        i = 1
        while sz > 0x7F:
            premsg[i] = (sz & 0x7F) | 0x80
            sz >>= 7
            i += 1
        premsg[i] = sz
​
        self.sock.write(premsg, i + 2)
        self.sock.write(msg)
        # print(hex(len(msg)), hexlify(msg, ":"))
        self._send_str(self.client_id)
        if self.lw_topic:
            self._send_str(self.lw_topic)
            self._send_str(self.lw_msg)
        if self.user is not None:
            self._send_str(self.user)
            self._send_str(self.pswd)
        resp = self.sock.read(4)
        assert resp[0] == 0x20 and resp[1] == 0x02
        if resp[3] != 0:
            raise MQTTException(resp[3])
        return resp[2] & 1
​
    def disconnect(self):
        self.sock.write(b"\xe0\0")
        self.sock.close()
​
    def ping(self):
        self.sock.write(b"\xc0\0")
​
    def publish(self, topic, msg, retain=False, qos=0):
        pkt = bytearray(b"\x30\0\0\0")
        pkt[0] |= qos << 1 | retain
        sz = 2 + len(topic) + len(msg)
        if qos > 0:
            sz += 2
        assert sz < 2097152
        i = 1
        while sz > 0x7F:
            pkt[i] = (sz & 0x7F) | 0x80
            sz >>= 7
            i += 1
        pkt[i] = sz
        # print(hex(len(pkt)), hexlify(pkt, ":"))
        self.sock.write(pkt, i + 1)
        self._send_str(topic)
        if qos > 0:
            self.pid += 1
            pid = self.pid
            struct.pack_into("!H", pkt, 0, pid)
            self.sock.write(pkt, 2)
        self.sock.write(msg)
        if qos == 1:
            while 1:
                op = self.wait_msg()
                if op == 0x40:
                    sz = self.sock.read(1)
                    assert sz == b"\x02"
                    rcv_pid = self.sock.read(2)
                    rcv_pid = rcv_pid[0] << 8 | rcv_pid[1]
                    if pid == rcv_pid:
                        return
        elif qos == 2:
            assert 0
​
    def subscribe(self, topic, qos=0):
        assert self.cb is not None, "Subscribe callback is not set"
        pkt = bytearray(b"\x82\0\0\0")
        self.pid += 1
        struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid)
        # print(hex(len(pkt)), hexlify(pkt, ":"))
        self.sock.write(pkt)
        self._send_str(topic)
        self.sock.write(qos.to_bytes(1, "little"))
        while 1:
            op = self.wait_msg()
            if op == 0x90:
                resp = self.sock.read(4)
                # print(resp)
                assert resp[1] == pkt[2] and resp[2] == pkt[3]
                if resp[3] == 0x80:
                    raise MQTTException(resp[3])
                return
​
    # Wait for a single incoming MQTT message and process it.
    # Subscribed messages are delivered to a callback previously
    # set by .set_callback() method. Other (internal) MQTT
    # messages processed internally.
    def wait_msg(self):
        res = self.sock.read(1)
#         self.sock.setblocking(True)
        if res is None:
            return None
        if res == b"":
            raise OSError(-1)
        if res == b"\xd0":  # PINGRESP
            sz = self.sock.read(1)[0]
            assert sz == 0
            return None
        op = res[0]
        if op & 0xF0 != 0x30:
            return op
        sz = self._recv_len()
        topic_len = self.sock.read(2)
        topic_len = (topic_len[0] << 8) | topic_len[1]
        topic = self.sock.read(topic_len)
        sz -= topic_len + 2
        if op & 6:
            pid = self.sock.read(2)
            pid = pid[0] << 8 | pid[1]
            sz -= 2
        msg = self.sock.read(sz)
        self.cb(topic, msg)
        if op & 6 == 2:
            pkt = bytearray(b"\x40\x02\0\0")
            struct.pack_into("!H", pkt, 2, pid)
            self.sock.write(pkt)
        elif op & 6 == 4:
            assert 0
        return op
​
    # Checks whether a pending message from server is available.
    # If not, returns immediately with None. Otherwise, does
    # the same processing as wait_msg.
    def check_msg(self):
#         self.sock.setblocking(False)
        return self.wait_msg()
​
```

Supplementary `wiznet_init.py` library code (copy and save to the W55RP20 development board, at the same level as `mqtt.py`):

```
import network
import time
try:
    from machine import Pin, WIZNET_PIO_SPI
except ImportError:
    WIZNET_PIO_SPI = None
    Pin = None
​
_DEFAULTS = {
    # Auto-construct boards (no explicit PIO SPI)
    "w5100s-evb-pico":  {},
    "w5500-evb-pico":   {},
    "w6100-evb-pico":   {},
    "w5100s-evb-pico2": {},
    "w5500-evb-pico2":  {},
    "w6100-evb-pico2":  {},
​
    # W55RP20 — single SPI (PIO SPI)
    "w55rp20-evb-pico": {"baudrate": 31250000, "sck": 21, "cs": 20, "mosi": 23, "miso": 22, "reset": 25},
​
    # W6300 — QSPI QUAD(io0..io3)
    "w6300-evb-pico":  {"baudrate": 31250000, "sck": 17, "cs": 16, "io0": 18, "io1": 19, "io2": 20, "io3": 21, "reset": 22},
    "w6300-evb-pico2": {"baudrate": 31250000, "sck": 17, "cs": 16, "io0": 18, "io1": 19, "io2": 20, "io3": 21, "reset": 22},
}
_AUTO = {
    "w5100s-evb-pico", "w5500-evb-pico", "w6100-evb-pico",
    "w5100s-evb-pico2","w5500-evb-pico2","w6100-evb-pico2",
}
_SINGLE = {"w55rp20-evb-pico"}   # PIO single-SPI
_QSPI   = {"w6300-evb-pico", "w6300-evb-pico2"}
​
def _pin(x): return x if isinstance(x, Pin) else Pin(x)
​
def wiznet(board, *, dhcp=True, spi=None, cs=None, reset=None, **kw):
    board = board.strip().lower()
    if board not in _DEFAULTS:
        raise ValueError("Unsupported board: {}".format(board))
    cfg = _DEFAULTS[board].copy()
    cfg.update(kw)
    
    # Manual override path: if spi is provided, use it directly
    if spi is not None:
        if cs is None or reset is None:
            raise ValueError("When passing custom spi, also pass cs and reset")
        nic = network.WIZNET6K(spi, cs, reset)
    else:
        if board in _AUTO:
            nic = network.WIZNET6K()
​
        elif board in _SINGLE:
            if WIZNET_PIO_SPI is None or Pin is None:
                raise RuntimeError("WIZNET_PIO_SPI/Pin not available on this port")
            required = ["sck", "cs", "mosi", "miso", "reset"]
            missing = [k for k in required if k not in cfg]
            if missing:
                raise ValueError("Missing pins for W55RP20 single-SPI: " + ", ".join(missing))
            spi = WIZNET_PIO_SPI(
                baudrate=cfg.get("baudrate", 31250000),
                sck=_pin(cfg["sck"]), cs=_pin(cfg["cs"]),
                mosi=_pin(cfg["mosi"]), miso=_pin(cfg["miso"]),
            )
            nic = network.WIZNET6K(spi, _pin(cfg["cs"]), _pin(cfg["reset"]))
​
        elif board in _QSPI:
            if WIZNET_PIO_SPI is None or Pin is None:
                raise RuntimeError("WIZNET_PIO_SPI/Pin not available on this port")
            for k in ["sck","cs","io0","io1","io2","io3"]:
                if k not in cfg: raise ValueError("Missing pin '{}' for W6300 QSPI".format(k))
            spi = WIZNET_PIO_SPI(
                baudrate=cfg.get("baudrate", 31250000),
                sck=_pin(cfg["sck"]), cs=_pin(cfg["cs"]),
                io0=_pin(cfg["io0"]), io1=_pin(cfg["io1"]),
                io2=_pin(cfg["io2"]), io3=_pin(cfg["io3"]),
            )
            nic = network.WIZNET6K(spi, _pin(cfg["cs"]), _pin(cfg.get("reset", cfg["cs"])))
​
        else:
            raise ValueError("Unexpected board mapping")
​
    # Bring up (if supported)
    try: nic.active(True)
    except AttributeError: pass
​
    if dhcp:
        try: nic.ifconfig("dhcp")
        except Exception: pass
    else:
        ip = cfg.get("ip"); sn = cfg.get("sn"); gw = cfg.get("gw"); dns = cfg.get("dns", gw or "8.8.8.8")
        if not (ip and sn and gw): raise ValueError("Static mode requires ip/sn/gw")
        nic.ifconfig((ip, sn, gw, dns))
    while not nic.isconnected():
        print("Waiting for the network to connect...")
        time.sleep(1)
​
    print("MAC Address:", ":".join("%02x" % b for b in nic.config("mac")))
    print("IP Address:", nic.ifconfig())
    return nic
​
​
```

---

### **6. Running Results and MQTT Communication Verification**

#### **6.1 Serial Output Results**

Click the Run button in Thonny (or press F5), and the Shell window will output the following content, indicating successful network initialization and MQTT connection:

Note: If "Waiting for the network to connect....." is printed, this is normal; wait 1-3 seconds to obtain the IP. If the IP cannot be obtained for a long time, refer to the "Common Issue Troubleshooting" section.

```
MPY: soft reboot
W55RP20 chip MQTT example
Waiting for the network to connect...
Waiting for the network to connect...
Waiting for the network to connect...
Waiting for the network to connect...
MAC Address: 02:90:86:88:4d:56
IP Address: 192.168.1.118
IP         : 192.168.1.118
Subnet Mask: 255.255.255.0
Gateway    : 192.168.1.1
DNS        : 202.96.134.33
​
Connected to broker.emqx.io MQTT Broker
subscribed to /W55RP20/sub
```

#### **6.2 MQTT Loopback Communication Verification**

Use the [MQTTX](https://mqttx.app/zh) tool for testing. The steps are as follows (if you don't know how, follow the figures below):

Open MQTTX, click the "+" button to create a new connection:

Name: Custom (e.g., W55RP20 Test)

Server: broker-cn.emqx.io

Port: 1883

Other parameters are default; click "Connect";

Subscribe to W55RP20's publish topic: /W55RP20/pub; you can customize it

Send a message to W55RP20's subscribe topic: /W55RP20/sub (e.g., "W55RP20 MQTT Test"); you can customize it

Observe the feedback in two places:

Thonny Shell window: Prints the received message and the "Message loopback successful" prompt;

MQTTX tool: Receives the message loopback-published by W55RP20 (consistent with the sent message).![](https://maker.wiznet.io/upload/ckeditor5/205720593%5F1782743332%2Egif)

At this point, the W55RP20 MQTT communication hands-on practice is complete

> MQTTX URL: [MQTTX: Full-Featured MQTT Client Tool](https://mqttx.app/zh)
>
> ![](https://maker.wiznet.io/upload/ckeditor5/205720593%5F1782743616%2Epng)
>
> ![](https://maker.wiznet.io/upload/ckeditor5/205720593%5F1782743616%5F0%2Epng)

---

### **7. One-Stop Troubleshooting for Common Issues**

| **Issue Symptom** | **Troubleshooting Steps** |
| --- | --- |
| 1. Thonny cannot recognize the W55RP20 port | 1. Replace with a USB data cable that supports data transmission 2. Re-plug the development board and close other software occupying the serial port (such as serial assistants) |
| 2. Cannot obtain IP address, keeps printing "Waiting for network to connect..." | 1. Check if the Ethernet cable is firmly plugged in 2. Check if the router has DHCP enabled 3. Check if the Ethernet cable is connected to the router's LAN port (not the WAN port), and restart the router and development board |
| 3. MQTT connection fails, triggering reconnection | Confirm the network is connected, the MQTT server address and port are correct (the public server used in this article requires no registration), and the `umqttsimple.py` library is saved correctly. |
| 4. Message received but cannot loopback-publish | 1. Confirm that the publish topic and subscribe topic in the code are configured correctly 2. The MQTT connection is not disconnected 3. Restart the development board and re-run the code |
| 5. No serial output or garbled output | 1. Confirm that the Thonny interpreter and port configuration are correct 2. The firmware is the exclusive firmware for W55RP20 3. Re-flash the firmware |

---

### **8. W55RP20 Core Advantage Comparison**

To give you a more intuitive understanding of the value of W55RP20, we compare the three mainstream embedded Ethernet solutions currently available:

| **Comparison Dimension** | **W55RP20 Integrated Solution** | **External PHY Chip Solution** | **External Serial-to-Ethernet Module Solution** |
| --- | --- | --- | --- |
| BOM Cost | Low (single chip) | Medium-High (MCU + module + peripheral components) | High |
| PCB Area | Small (only network port circuit required) | Large (space needed for chip and routing) | High |
| Development Difficulty | Low (connect to network with one line of code) | Medium-High (debug protocol stack, write drivers) | Low |
| Network Stability | Extremely High (WIZnet has focused on hardware TCP/IP protocol stack for 25 years) | Variable (high requirements for R&D personnel, familiarity with protocol stack and network development needed for stable debugging) | Variable (depends on R&D company capability level) |
| CPU Resource Usage | 0% (protocol stack network processing completely completed by hardware) | 50% and above (protocol stack fully runs on MCU, occupying related resources) | 0% |
| Hardware Socket Count | 8 independent hardware Sockets | Depends on MCU capability, theoretically supports multi-channel expansion | Generally single-channel transparent transmission |
| Network Throughput | Up to 15Mbps | Depends on MCU capability | Approx. 3-5Mbps |
| Interface Usability | Single-chip integration | Requires MCU with MII/RMII and other interfaces | TTL interface |
| Deployment Difficulty | Low (mature MicroPython firmware, most application layer protocols have library files, can be flexibly added and deployed) | High (application layer protocols require manual porting of open-source library adaptation) | Depends on module integration; functions without integration require self-packaging and unpacking |

---

### **9. Typical Application Scenarios**

The W55RP20 chip integrates Ethernet functionality, and combined with its industrial-grade stability, it is very suitable for the following application scenarios:

Industrial Data Acquisition Gateway: Simplifies on-site deployment and achieves stable upload of sensor data

Remote Monitoring Terminal: Used for remote monitoring of equipment status in factories, machine rooms, substations, and other environments

Serial-to-Ethernet Device: Quickly upgrades traditional RS232/RS485 serial devices to Ethernet devices

Smart Building Node: Used for network control of lighting, air conditioning, access control, and other building devices

Industrial PLC Expansion Module: Adds Ethernet communication capability to PLCs, enabling remote programming and data acquisition

---

### **10. Summary**

This article detailed the complete process of implementing MQTT protocol communication using MicroPython on the W55RP20-EVB-MKR development board. From firmware flashing, hardware connection, and development environment configuration, to the implementation and flashing of core code, and then to running result verification and common issue troubleshooting, we completed the setup of MQTT basic communication step by step.

Through the study of this article, you should have mastered:

How to flash the exclusive MicroPython firmware for W55RP20-EVB-MKR

The basic working principles of the MQTT protocol (publish/subscribe model, QoS levels, etc.)

The core code logic for implementing an MQTT client using the `umqtt.simple` library

Verifying communication success through serial output and MQTT loopback testing

Troubleshooting ideas for common connection issues

With its built-in Ethernet MAC+PHY high-integration design, the W55RP20 chip demonstrates significant advantages in the industrial IoT field. Whether as a data acquisition gateway, remote monitoring terminal, or serial-to-Ethernet device, it can achieve stable and reliable Ethernet communication at a very low cost.

---

Source: https://maker.wiznet.io/ronpang/projects/part-12-w55rp20-evb-mkr-micropython-hands-on-12--mqtt-protocol-basic-communication-verification/
