Working with Arduino
This chapter contains the following sections. Please read as needed:
Setting Up the Development Environment
Please refer to the Install and Configure Arduino IDE Tutorial to download and install the Arduino IDE.
Example
The Arduino examples are located in the examples/Arduino directory of the example package.
| Example | Basic Program Description | Dependency Library |
|---|---|---|
| 01_MQTT | MQTT example | Adafruit_NeoPixel |

01_MQTT
Example Description
- This example uses the WS2812 LED library
Adafruit_NeoPixel; it must be installed in advance. - This example demonstrates the RP2350-POE-ETH connecting to a public MQTT Broker (default
broker.emqx.io:1883) via Ethernet, and implements:- Subscribe topic:
Sub/ed229f15 - Publish topic:
Pub/ed229f15 - Publish a device status JSON every 10 seconds (including MAC, IP, temperature, VSYS voltage, USB/POE insertion status, uptime, etc.)
- Subscribe topic:
- The program uses DHCP to obtain an IP address automatically and resolves the domain name
broker.emqx.iovia DNS to get the Broker IP before connecting. - Open-source usage notes (strongly recommended to modify on first use to avoid conflicts among multiple people/devices):
- MQTT Brokers typically require that the
Client IDbe globally unique at any given time: if two devices use the sameMQTT_CLIENT_IDto log in, the later one will kick off the earlier one, resulting in frequent disconnections. - If a fixed Topic is used, data from multiple devices will be mixed together and can easily be mis-subscribed or mis-controlled by others.
- It is recommended to modify at least:
MQTT_CLIENT_ID,MQTT_PUBLISH_TOPIC, andMQTT_SUBSCRIBE_TOPIC. If you are using your own Broker or have enabled authentication, also modifyMQTT_USERNAMEandMQTT_PASSWORD.
- MQTT Brokers typically require that the
#define MQTT_USERNAME "w6300_test"
#define MQTT_CLIENT_ID "ed229f15"
#define MQTT_PASSWORD "0123456789"
#define MQTT_PUBLISH_TOPIC "Pub/ed229f15"
#define MQTT_SUBSCRIBE_TOPIC "Sub/ed229f15"
Hardware Connection
- Connect the development board to your computer via USB (for power, flashing, and serial log viewing).
- Plug an Ethernet cable into the RJ45 port and ensure the network can reach the public internet (able to access
broker.emqx.io:1883). - Optional: Use a PoE Ethernet cable to power the board (the program will report
poe_insertedstatus in the JSON payload).
Code Analysis
-
Entry file
01-MQTT.inoextern "C" int _write(...): Redirectsprintf()output toSerial, so thatprintfprintouts from C files can also be seen in the serial monitor.setup()Serial.begin(115200): Initializes the serial port at 115200 baud rate.DEV_Module_Init(): Initializes board-level hardware (GPIO/SPI/Ethernet chip, etc., implemented internally in the BSP).bsp_adc_voltage_detection_init(...): Initializes VSYS voltage detection (later reportsvsys_voltage_vandvsys_adc_raw).usb_detect_io_init()/poe_detect_io_init(): Initializes USB/POE insertion detection IOs (later reportsusb_inserted/poe_inserted).mqtt_app_init(): Initializes Ethernet + DHCP/DNS + MQTT connection.
loop()mqtt_service_run(): The MQTT main loop (internally awhile(1)), responsible for maintaining the connection, processing subscribed messages, and publishing periodically.
-
MQTT logic file
mqtt_app.c- Key configurations (macro definitions)
- Broker
g_dns_target_domain = "broker.emqx.io": Broker domain name (default uses DNS resolution).- If DNS is disabled on your network or you want to use a fixed Broker IP: change
#if 0to#if 1inmqtt_connect()to useMQTT_BROKER_IP_0~3.
PORT_MQTT (1883): MQTT TCP port.MQTT_CLIENT_ID/MQTT_USERNAME/MQTT_PASSWORD: Credentials for connecting to the Broker (hardcoded in the example).MQTT_PUBLISH_TOPIC/MQTT_SUBSCRIBE_TOPIC: Publish/subscribe topics.MQTT_PUBLISH_PERIOD (10s): Periodic publish interval.g_dns_target_domain = "broker.emqx.io": Default Broker domain.
- Broker
- Static/Dynamic switching (it is recommended to change only this part of the source code to switch)
- Network addressing: Static IP ↔ DHCP (dynamic)
- Default (DHCP)
- Network addressing: Static IP ↔ DHCP (dynamic)
- Key configurations (macro definitions)
static eth_NetInfo g_net_info = {
.ip = {192, 168, 1, 100},
.sn = {255, 255, 255, 0},
.gw = {192, 168, 1, 1},
.dns = {8, 8, 8, 8},
.dhcp = NETINFO_DHCP,
.ipmode = NETINFO_DHCP_V4
};
- Note: In DHCP mode, the above
.ip/.sn/.gw/.dnsare only placeholders; they will be overwritten by the parameters assigned by the router afterethchip_dhcp_run()succeeds. The gateway (gw) and DNS are also provided by the router, so there is no need to manually change them to match "your own router".
int mqtt_app_init(void)
{
if (g_net_info.dhcp == NETINFO_DHCP) {
ethchip_dhcp_init(ethchip_dhcp_assign, ethchip_dhcp_assign, ethchip_dhcp_conflict);
return ethchip_dhcp_run();
}
return mqtt_connect();
}
- Switch to static IPv4 (disable DHCP and fill in fixed IP parameters)
static eth_NetInfo g_net_info = {
.ip = {192, 168, 1, 100},
.sn = {255, 255, 255, 0},
.gw = {192, 168, 1, 1},
.dns = {8, 8, 8, 8},
.dhcp = NETINFO_STATIC,
.ipmode = NETINFO_STATIC_V4
};
-
How to fill in static IP parameters (incorrect values will cause "network not working / MQTT connection failure")
.ip: The fixed IP of the development board. It must be in the same subnet as the router and must not conflict with other devices on the LAN.- Example: If your router is
192.168.1.1with subnet mask255.255.255.0, you could choose192.168.1.123.
- Example: If your router is
.sn(Subnet Mask): Must match the subnet configuration of the router.- The most common value for home routers is
255.255.255.0.
- The most common value for home routers is
.gw(Gateway): The default gateway, usually the router's LAN IP.- Example:
192.168.1.1.
- Example:
.dns: DNS server IP.- Can be the router IP (e.g.,
192.168.1.1) or a public DNS (e.g.,8.8.8.8,114.114.114.114).
- Can be the router IP (e.g.,
- Tip: If the router has DHCP enabled, try to set the static IP outside the DHCP address pool, or configure "IP/MAC binding (address reservation)" on the router to avoid conflicts.
-
Broker address: Static IP ↔ DNS (dynamic domain name resolution)
- Default (DNS resolution)
static uint8_t g_dns_target_domain[] = "broker.emqx.io";
#if 0
g_mqtt_broker_ip[0] = MQTT_BROKER_IP_0;
g_mqtt_broker_ip[1] = MQTT_BROKER_IP_1;
g_mqtt_broker_ip[2] = MQTT_BROKER_IP_2;
g_mqtt_broker_ip[3] = MQTT_BROKER_IP_3;
#else
ethchip_dns_init();
ethchip_dns_get_domain_ip(g_net_info.dns, g_dns_target_domain, g_mqtt_broker_ip);
#endif
- Switch to static Broker IP: Change
#if 0to#if 1in the code above; it will then useMQTT_BROKER_IP_0~3(currently fixed to34.243.217.54). - MQTT identity: Static client_id/username ↔ Dynamically generated (based on Unique ID)
- Default (static client_id / username)
#define MQTT_USERNAME "w6300_test"
#define MQTT_CLIENT_ID "ed229f15"
#if 1
snprintf(g_mqtt_client_id, sizeof(g_mqtt_client_id), "%s", MQTT_CLIENT_ID);
#else
snprintf(g_mqtt_client_id, sizeof(g_mqtt_client_id), "%s%02X%02X%02X%02X",
MQTT_CLIENT_ID_PREFIX, board_id.id[4], board_id.id[5], board_id.id[6], board_id.id[7]);
#endif
#if 1
snprintf(g_mqtt_username, sizeof(g_mqtt_username), "%s", MQTT_USERNAME);
#else
snprintf(g_mqtt_username, sizeof(g_mqtt_username), "%s%02X%02X%02X%02X",
MQTT_USERNAME_PREFIX, board_id.id[4], board_id.id[5], board_id.id[6], board_id.id[7]);
#endif
- Switch to dynamic generation: Change the two
#if 1above to#if 0; it will then compose a unique identity for each device usingMQTT_CLIENT_ID_PREFIX/MQTT_USERNAME_PREFIX+ Unique ID. - Note: The current publish/subscribe topics are fixed (multiple devices will have mixed data).
#define MQTT_PUBLISH_TOPIC "Pub/ed229f15"
#define MQTT_SUBSCRIBE_TOPIC "Sub/ed229f15"
generate_device_identity()- Reads the Unique ID of the RP2350 (
pico_get_unique_board_id) to generate a MAC address (first 3 bytes fixed OUI:02:08:DC, last 3 bytes taken from the chip's Unique ID). - Generates/sets MQTT
client_idandusername(the example currently uses static macros; it also supports automatic generation based on Unique ID).
- Reads the Unique ID of the RP2350 (
mqtt_app_init()- Initializes the Ethernet chip driver (SPI, reset, check, 1ms timer, etc.).
- If
g_net_info.dhcp == NETINFO_DHCP:ethchip_dhcp_init(...)+ethchip_dhcp_run(): Starts DHCP to obtain an IP address (upon success, the DHCP callback is invoked and automatically triggers MQTT connection).
- If using static IP: directly calls
mqtt_connect()to establish MQTT.
mqtt_connect()network_initialize(g_net_info): Writes the current network parameters to the Ethernet chip (IP/gateway/DNS, etc.).- DNS path (enabled by default)
ethchip_dns_get_domain_ip(...): Resolvesbroker.emqx.ioto obtaing_mqtt_broker_ip.- You can also switch to a static IP (change
#if 0to#if 1to useMQTT_BROKER_IP_0~3).
ConnectNetwork(...): Establishes a TCP connection to the Broker.MQTTClientInit(...)+MQTTConnect(...): Initializes the MQTT client and completes the CONNECT.MQTTSubscribe(..., message_arrived): Subscribes toMQTT_SUBSCRIBE_TOPIC; received messages are passed tomessage_arrived().
message_arrived(MessageData *msg_data)printf("%.*s\n", ...): Prints the received message content.mqtt_parse_and_execute_commands(...): Passes the subscribed message to the command parsing module. The current subscribe topic isSub/ed229f15. The behavior upon receiving a message is as follows:-
- Print the payload as-is to the serial port.
-
- Attempt to execute commands according to JSON fields (supports multiple fields in one payload, e.g., controlling LED and reading voltage simultaneously).
-
- The success/failure result is republished to
Pub/ed229f15(it is recommended to subscribe toPub/ed229f15to see the response).
- The success/failure result is republished to
-
// Supported control commands (payload is JSON; executes only if the field exists and value >= 0)
// {"adc":1} Read VSYS voltage and report
// {"led":2} Set WS2812 color (0-8)
// {"io_dect":1} Read USB/POE insertion status and report
static const mqtt_cmd_map_t g_cmd_map[] = {
{"adc", adc_op_handle},
{"led", led_op_handle},
{"io_dect", io_dect_op_handle},
};
{"adc":1}: Reads VSYS voltage and ADC raw value, and publishes a JSON toPub/ed229f15:
{"vsys_voltage":5.021,"vsys_adc_raw":2048}
{"led":N}: Sets the onboard WS2812 color (Nranges from0-8: OFF/WHITE/RED/ORANGE/YELLOW/GREEN/CYAN/BLUE/PURPLE), and publishes the execution result toPub/ed229f15.- Success example:
{"led_color":2,"led_name":"RED"}
- Failure example (out of range):
{"error":"invalid_led_color","value":99,"valid_range":"0-8"}
{"io_dect":1}: Reads USB/POE insertion detection IOs and publishes the status toPub/ed229f15:
{"usb_inserted":true,"poe_inserted":false}
build_mqtt_payload(...)- Reads temperature (
read_chip_temp()), flash size, system uptime, VSYS voltage, USB/POE insertion status, network parameters, etc., and composes them into a JSON string. - This JSON is used as the publish payload (
g_mqtt_message.payload).
- Reads temperature (
mqtt_service_run()MQTTYield(...): Allows the MQTT client to handle packet reception, keep‑alive, callbacks, etc.- At each
MQTT_PUBLISH_PERIODinterval: callsMQTTPublish(...)to publish device status toMQTT_PUBLISH_TOPIC. - In DHCP mode,
ethchip_dhcp_run()is called periodically to maintain the lease; when DHCP reassigns an address,ethchip_dhcp_assign()disconnects and reconnects MQTT.
Operation Result
- After flashing the example, open the serial monitor (115200 baud) and you should see logs similar to:
=== System Start ===
DHCP initialization succeed
...(after obtaining IP)...
MQTT connected
Published
Subscribed
Published
Published
...
-
Verify using any MQTT client (MQTTX recommended)
- MQTTX client settings:

RP2350-POE-ETHconnection parameters:- Host:
broker.emqx.io - Port:
1883 - Username:
w6300_test - Password:
0123456789 - Client ID:
ed229f15
- Host:
- Subscribe to topic:
Pub/ed229f15. You will receive the JSON reported by the board every 10 seconds, for example:
{
"device": { "chip": "RP2350A", "mac": "02:08:DC:xx:xx:xx", "client_id": "ed229f15" },
"system": {
"cpu_mhz": 150,
"ram_kb": 520,
"flash_mb": 16,
"temp_c": 36.2,
"vsys_voltage_v": 5.021,
"vsys_adc_raw": 2048,
"usb_inserted": true,
"poe_inserted": false,
"uptime": "0:00:01:23"
},
"network": { "mode": "DHCP", "ip": "192.168.1.100", "subnet": "255.255.255.0", "gateway": "192.168.1.1", "dns": "8.8.8.8" },
"message": "Hello, waveshare!"
}
-
Publish any string to topic
Sub/ed229f15; the board's serial port will print the received message (and pass it to the command parsing function, which is convenient for customizing control logic in secondary development).
