19. W5100S/W5500+RP2040 Raspberry Pi Pico<MQTT and MQTTX debugging example>

1. Preface

With the rapid development of IoT technology, the MQTT (Message Queuing Telemetry Transport) protocol has become a widely used communication protocol. It is suitable for low-bandwidth, high-latency, and unreliable network communication between devices. W5500 is an embedded Ethernet controller that integrates a full hardware TCP/IP protocol stack and is also an industrial-grade Ethernet control chip.

Using W5500 + MQTT application protocol in Ethernet applications allows users to more conveniently achieve remote connection and communication between devices. This tutorial will introduce the basic principles, usage steps, application examples and precautions of W5500 Ethernet MQTT application to help readers better master this technology.

2. Introduction

2.1 What is MQTT?

MQTT (Message Queuing Telemetry Transport, Message Queuing Telemetry Transport Protocol) is a “lightweight” communication protocol based on the publish/subscribe (publish/subscribe) model. The protocol is built on the TCP/IP protocol. The biggest advantage of MQTT is that it uses very little code and limited bandwidth to provide real-time and reliable messaging services for connecting remote devices. As a low-cost, low-bandwidth instant messaging protocol, it has wide applications in the Internet of Things, small devices, mobile applications, etc.

2.2 Features

  1. Lightweight: The MQTT protocol is very lightweight, its overhead is very small, and it is suitable for low-bandwidth, low-power devices and networks.
  2. Publish/subscribe mode: MQTT adopts the publish/subscribe mode. The client can subscribe to one or more topics (Topic) and can publish messages to the topic without knowing other clients.
  3. QoS support: MQTT supports three quality of service (QoS) levels that can be specified at publish and subscribe time. These levels are 0, 1, and 2, which provide different message delivery guarantees.
  4. Will mechanism: MQTT supports the Will mechanism. When a client disconnects abnormally, it can notify other clients through the Will mechanism.
  5. Retained Message: MQTT supports retained message (Retained Message), allowing the client to publish a retained message to the topic, and then new subscribers connected to the topic can receive the message immediately.
  6. Connection control: MQTT supports a connection control mechanism, allowing clients to specify their own client ID, username and password when connecting.
  7. Security: MQTT supports TLS/SSL encrypted communication protocol to ensure secure transmission of data.
  8. TCP/IP based network connection

2.3 MQTT protocol implementation

Implementing the MQTT protocol requires communication between the client and the server. During the communication process, there are three identities in the MQTT protocol: publisher (Publish), server, and subscriber (Subscribe). Among them, the message publisher and subscriber are both clients, the message agent is the server, and the message publisher can be a subscriber at the same time.

The messages transmitted by MQTT are divided into two parts: topic and payload:

(1) Topic can be understood as the type of message. After a subscriber subscribes, he will receive the message content (payload) of the topic;

(2) Payload can be understood as the content of the message, which refers to the specific content that the subscriber wants to use.

2.4 Will message

The client’s will will only be published when unexpected disconnection. If the client disconnects from the server normally, the will mechanism will not be started, and the server will not publish it. The client’s will is published.

The will message can be regarded as a simplified version of the PUBLISH message. It also contains fields such as Topic, Payload, and QoS. The will message will be specified through the CONNECT message when the device is connected to the server, and then when the device is unexpectedly disconnected, the server will publish the will message to the will topic (Will Topic) specified at the time of connection.

It is generally recommended to set the content of the will message to client offline! When our client connects to the server, a client online message is also published to the will topic.

2.5 Application scenarios

  1. Scientific research: In scientific research, experimental data needs to be collected and transmitted. Using the MQTT protocol can effectively solve the problem of packet loss during data transmission and ensure the stability and integrity of data transmission.
  2. Financial industry: In the financial industry, transaction information needs to be monitored and transmitted in real time. Using the MQTT protocol can achieve real-time monitoring and transmission and ensure the stability and security of the data.
  3. Medical industry: In the medical industry, patients’ vital signs need to be collected and transmitted. Using the MQTT protocol can effectively solve the problem of packet loss during data transmission and ensure the stability and integrity of data transmission.
  4. Energy industry: In the energy industry, energy equipment needs to be monitored and controlled. The MQTT protocol is designed to meet this need. It has the characteristics of simplicity, reliability, and flexibility, and has been widely used in the energy field.

3 WIZnet Ethernet chip

Comparison of WIZnet mainstream hardware protocol stack Ethernet chip parameters

td>

Model Embedded Core Host I/F TX/RX Buffer HW Socket Network Performance
W5100S TCP/IPv4, MAC & PHY 8bit BUS, SPI 16KB 4 Max.25Mbps
W6100 TCP/IPv4/IPv6, MAC & PHY 8bit BUS, Fast SPI 32KB 8 Max.25Mbps
W5500 TCP/IPv4, MAC & PHY Fast SPI 32KB 8 Max 15Mbps
  1. W5100S/W6100 supports 8-bit data bus interface, and the network transmission speed will be better than W5500.
  2. W6100 supports IPv6 and is compatible with W5100S hardware. If users who already use W5100S need to support IPv6, they can be Pin to Pin compatible.
  3. W5500 has more sockets and send and receive buffers than W5100S.

4 MQTTClient network setting example overview and usage

4.1 Flowchart

The running block diagram of the program is as follows:

4.2 Core preparation work

Software

  • Visual Studio Code
  • WIZnet UartTool
  • MQTTX

Hardware

  • W5100S IO module + RP2040 Raspberry Pi Pico development board or WIZnet W5100S-EVB-Pico development board
  • Micro USB interface data cable
  • TTL to USB
  • cable

4.3 Connection method

  • Connect the USB port of the PC through the data cable (mainly used for burning programs, but can also be used as a virtual serial port)

  • Convert TTL serial port to USB and connect the default pin of UART0:

    • RP2040 GPIO0 (UART0 TX) <----> USB_TTL_RX
    • RP2040 GPIO1 (UART0 RX) <----> USB_TTL_TX
  • When wiring using module connection RP2040

    • RP2040 GPIO16 <----> W5100S MISO
    • RP2040 GPIO17 <----> W5100S CS
    • RP2040 GPIO18 <----> W5100S SCK
    • RP2040 GPIO19 <----> W5100S MOSI
    • RP2040 GPIO20 <----> W5100S RST
  • Connect the PC and device to the router LAN port through network cables

4.4 Main code overview

We are using the official ioLibrary_Driver library of WIZnet. The library supports rich protocols and is easy to operate. The chip integrates the TCP/IP protocol stack on the hardware. The library also encapsulates the protocols above the TCP/IP layer. We only need to simply call the corresponding function to complete the application of the protocol. .

Step one: Add the corresponding .h file to the mqtt_client.c file.

Step 2: Define the macros required by DHCP and the macros of the MQTT transceiver cache buff.

Step 3: Define a structure of mqtt connection parameters and define it.

Step 4: Initialize the parameters inside the library.

Step 5: Configuration of network information, initial parameters of mqtt, and flags.

Step 6: Write the timer callback processing function for DHCP and MQTT 1S tick timer processing functions.

Step 7: The main function first initializes the serial port and SPI, and then writes the network configuration parameters of W5100S. After initializing DHCP, it starts DHCP to obtain the IP. When obtained, it prints the obtained IP. When the number of acquisitions exceeds the maximum number of acquisitions, static is used. IP, then initialize MQTT, and then the main loop is a state machine polling. The state machine first enters the connection state. When the connection is successful, the state starts publishing and subscribing, then subscribes to the will message, and finally processes the heartbeat packet. Prevent disconnection.

#include "wizchip_conf.h"
#include "w5100s.h"
#include "bsp_spi.h"
#include "socket.h"
#include "loopback.h"
#include "MQTTClient.h"
#include "mqtt_interface.h"
#include "dns.h"
#include "string.h"
#include "dhcp.h"

#define SOCKET_ID 0
#define ETHERNET_BUF_MAX_SIZE (1024 * 2)

#define MQTT_SEND_BUFF_SIZE 2048 /*Send cache size*/
#define MQTT_RECV_BUFF_SIZE 2048 /*Recv cache size*/
#define DHCP_RETRY_COUNT 5 // DHCP retry times
#define ETHERNET_BUF_MAX_SIZE (1024 * 2) // Send and receive cache size

enum status
{
    CONN= 0,
    SUB,
    PUB_ONLINE,
    KEEPALIVE,
    ERROR = 255,
} run_status;


uint8_t mqtt_send_buff[MQTT_SEND_BUFF_SIZE] = {0};
uint8_t mqtt_recv_buff[MQTT_RECV_BUFF_SIZE] = {0};


typedef struct MQTTCONNECTION
{
    char mqttHostUrl[1024]; /*Server URL*/
    int port; /*Server port number*/
    char clientid[1024]; /*client ID*/
    char username[1024]; /*user name*/
    char passwd[1024]; /*user passwords*/
    uint8_t server_ip[4]; /*Server IP*/
    char pubtopic[255]; /*publication*/
    char subtopic[255]; /*subscription*/
    int pubQoS; /* publishing messages*/
    int subQoS; /* subscription messages*/
    char willtopic[255]; /*Will topic */
    int willQoS; /*Will message */
    char willmsg[255]; /*Will */
} mqttconn;

mqttconn mqtt_params = {
    .server_ip = {54,244,173,190}, /*Define the Connection Server IP*/
    .port = 1883, /*Define the connection service port number*/
    .clientid = "hxrzyBEzRJz.MQTT1|securemode=2,signmethod=hmacsha256,timestamp=1698648840189|", /*Define the client ID*/
    .username = "MQTT1 & amp;hxrzyBEzRJz", /*Define the user name*/
    .passwd = "21733721029051630f5f86efa6860403cbc68cda27223f83ec9175f69243ee93", /*Define user passwords*/
    .pubtopic = "W5100S_pubtopic", /*Define the publication message*/
    .subtopic= "W5100S_subtopic", /* vDefine subscription messages*/
    .pubQoS = 0, /*Defines the class of service for publishing messages*/
    .willtopic = "W5100S_will", /*Define the topic of the will*/
    .willQoS = 0, /*Defines the class of service for Will messages*/
    .willmsg = "W5100S offline!", /*Define a will message*/
    .subQoS = 0, /*Defines the class of service for subscription messages*/
};

MQTTMessage pubmessage = {
        .qos = 0,
        .retained = 0,
        .dup = 0,
        .id = 0,
    };
MQTTPacket_willOptions willdata = MQTTPacket_willOptions_initializer; /* Will subject struct initialization */
MQTTPacket_connectData data = MQTTPacket_connectData_initializer; /*Define the parameters of the MQTT connection*/
unsigned char *data_ptr = NULL;



/**
 * @brief Initialization of chip network information
 * @param conf_info:Static configuration information
 * @return none
 */
void network_init(wiz_NetInfo *conf_info);

wiz_NetInfo net_info = {
    .mac = {0x00, 0x08, 0xdc, 0x16, 0xed, 0x2e}, /*Define the W5100S default mac address*/
    .ip = {192, 168, 1, 123}, /*Define the W5100S default IP*/
    .sn = {255, 255, 255, 0}, /*Define the W5100S default subnet mask*/
    .gw = {192, 168, 1, 1}, /*Define the W5100S default gateway*/
    .dns = {8, 8, 8, 8}, /*Define the W5100S default DNS server*/
    .dhcp = NETINFO_DHCP}; /*Define the W5100S as statically acquiring IP mode*/
MQTTClient c = {0};
Network n = {0};
wiz_NetInfo get_info;
static uint8_t breakout_flag = 0; // Define the DHCP acquisition flag
int connOK;

static uint8_t ethernet_buf[ETHERNET_BUF_MAX_SIZE] = {
    0,
}; // Send and receive cachestatic uint8_t destip[4]={192, 168, 1, 2}; // udp destination ip


/*
    @brief Callback processing after triggering the timer.
    @param Timer struct.
    @return True.
 */
bool repeating_timer_mqtt_callback(struct repeating_timer *t);

/*
    @brief Callback processing after triggering the timer.
    @param Timer struct.
    @return True.
 */
bool repeating_timer_dhcp_callback(struct repeating_timer *t);

/*
    @brief MQTT client and connection initialization functions.
    @param None.
    @return None.
 */
void mqtt_init(void);

/*
   @brief Subscribe to the topic callback function.
   @param Message queue.
   @return None.
*/
void messageArrived(MessageData *md);

int main()
{
    int ret;
    struct repeating_timer timer_mqtt;
    struct repeating_timer timer_dhcp;
    MQTTMessage pubmessage = {0};

    /*mcu init*/
    stdio_init_all(); /*Initialize the serial port*/
    wizchip_initialize(); /*Initialize the SPI*/

   /*dhcp init*/
    DHCP_init(SOCKET_ID, ethernet_buf); // DHCP initialization
    add_repeating_timer_ms(1000, repeating_timer_mqtt_callback, NULL, & timer_mqtt); // Add DHCP 1s Tick Timer handler

    printf("wiznet chip mqtt_client example.\r\\
");
    network_init( & amp;net_info); // Configuring Network Information
    print_network_information( & amp;get_info); // Read back the configuration information and print it
    
    /*mqtt init*/
    add_repeating_timer_ms(1, repeating_timer_dhcp_callback, NULL, & timer_dhcp); /*Set a timer for one second*/ /*Initialize MQTT*/
    mqtt_init();
    while(true)
    {
       switch (run_status)
        {
         case CONN:
          {
              ret = MQTTConnect( & amp;c, & amp;data); /* Connect to the MQTT server */
            printf("Connect to the MQTT server: %d.%d.%d.%d:%d\r\\
", mqtt_params.server_ip[0], mqtt_params.server_ip[1], mqtt_params.server_ip [2], mqtt_params.server_ip[3], mqtt_params.port);
            printf("Connected:%s\r\\
\r\\
", ret == SUCCESSS ? "success" : "failed");
            if (ret != SUCCESSS)
            {
                run_status = ERROR;
            }
            else
            {
                run_status = SUB;
            }
            break;
          }

         case SUB:
          {
            ret = MQTTSubscribe( & amp;c, mqtt_params.subtopic, mqtt_params.subQoS, messageArrived); /* Subscribe to Topics */
            printf("Subscribing to %s\r\\
", mqtt_params.subtopic);
            printf("Subscribed:%s\r\\
\r\\
", ret == SUCCESSS ? "success" : "failed");
            if (ret != SUCCESSS)
            {
                run_status = ERROR;
            }
            else
            {
                run_status = PUB_ONLINE;
            }
            run_status = PUB_ONLINE;
            break;

          }
         case PUB_ONLINE:
         {
             pubmessage.qos = 0;
            pubmessage.payload = "W5100S online!";
            pubmessage.payloadlen = strlen(pubmessage.payload);
            ret = MQTTPublish( & amp;c, mqtt_params.willtopic, & amp;pubmessage); /* Publish message */
            if (ret != SUCCESSS)
            {
                run_status = ERROR;
            }
            else
            {
                printf("publish:%s,%s\r\\
\r\\
", mqtt_params.willtopic, pubmessage.payload);
                run_status = KEEPALIVE;
            }
            break;

         }
           
         case KEEPALIVE:
         {
           if (MQTTYield( & amp;c, 30) != SUCCESSS) /* keepalive MQTT */
            {
                run_status = ERROR;
            }
            sleep_ms(100);
            break;
         }
         case ERROR: /* Running error */
            printf("system ERROR!");
            sleep_ms(1000);
         break;

         default:
            break;
         }
    }
}

4.5 Result Demonstration

1. Open WIZ UartTool and fill in the parameters: select the com port corresponding to the serial port, baud rate 115200, 8 data bits, 1 stop bit, no check bit, no flow control. After filling in the parameters, click open.

2. Open the MQTTX software, create a client, connect to the same MQTT server as our device, set the subscription to publish of our device, set the publish to subscription, then publish the message, and find that the serial port will receive the message sent by mqttx , and republish the message to mqttx.

5 Notes

  • Do not reverse publishing and subscribing. Otherwise, messages will not be received.
  • The topic of publishing and messages should not be too simple, as this is likely to cause other customers using mqttx to interfere.
  • If we want to use WIZnet’s W5500 to implement the example in this chapter, we only need to modify two places:

? (1) Find the header file wizchip_conf.h under library/ioLibrary_Driver/Ethernet/, and change the _WIZCHIP_ macro definition to W5500.

? (2) Find the CMakeLists.txt file under library and set COMPILE_SEL to ON. OFF is W5100S and ON is W5500.

6 Related links

WIZnet official website

WIZnet official library link

Routine link in this chapter

If you want to know more, leave a comment!