Since its launch in August 2024, Raspberry's RP2350 microcontroller has been adopted by various designers and manufacturers to develop their own boards. From the Raspberry Pico Version 2 to variants with specific enhancements, such as increased memory or additional peripherals, this chip has driven a new generation of devices.
Among these options, the Elecrow Pico W5 stands out, not only for incorporating 8 MB of Flash memory but also for its WiFi connectivity on both 2.4 GHz and 5.8 GHz bands.
It also includes Bluetooth 5.0, making it a great choice for Internet of Things (IoT) projects and many other applications.
In this article, I will introduce you to the main features of the Pico W5 and, most importantly, how to make the most of its connectivity capabilities. In the first part, we will explore its use with Arduino, while in an upcoming article, we will see how to do the same with MicroPython.
Let's take a quick look at the main features of this board:
CPU
The Pico W5 is powered by Raspberry's new RP2350, which uniquely includes two distinct CPU blocks—one ARM-based and the other RISC-V, both featuring dual cores. Additionally, it is faster and more powerful than its predecessor, the RP2040.
- RP2350 up to 150 MHz
- Dual-core architecture, selectable between Arm Cortex-M33 or Hazard3 RISC-V
Memory
The Pico W5 stands out for its generous Flash memory capacity:
- 8MB Flash
- 520 KB RAM (integrated into the RP2350)
GPIO
The board maintains the same size and form factor as the Raspberry Pico 2, ensuring compatibility with modules and expansions designed for it.
- 24 multifunction GPIO pins (two fewer than the Pico 2, as they are used for the WiFi module)
- Compatible with Raspberry Pico 2
- RESET button
- BOOT button
- User-controllable onboard LED
- Castellated pins for soldering the board as a module
- USB-C connector for power and programming
The following image shows the pinout of the board:
The Pico W5's connectivity is powered by a BW16 module from B&T, which integrates the Realtek RTL7820 chip.
- Supports WiFi 802.11a/b/g/n on 2.4 GHz and 5.8 GHz bands
- Bluetooth LE with Bluetooth 5.0
The BW16 module is connected to the RP2350 via a UART interface, using GPIO4 and GPIO5. It includes AiThinker firmware, which implements common functions such as WiFi network access, HTTP requests, MQTT protocol support, and Bluetooth communication. These functions are controlled using AT commands.
The Pico W5 can be programmed using various languages, with the most popular being MicroPython and C/C++, and it is also compatible with Arduino.
Below, we'll walk through how to program it using Arduino, and in an upcoming article, we'll explore how to do the same with MicroPython.
Setting Up Arduino IDE 2To program the Pico W5 with Arduino, you first need to install Arduino IDE 2, the latest and improved version of the Arduino development environment.
You can download the installer from the official Arduino website. Choose the version compatible with your operating system (Windows, macOS, or Linux) and follow the installation steps. The process is straightforward and similar to installing any other program.
Once the Arduino IDE is installed, you need to add board support using the Board Manager.
This is a simple procedure, and if you've already used another board like an ESP32 with the IDE, you're likely familiar with it.
First, open the IDE preferences by selecting File > Preferences from the menu (or pressing Control + Comma):
Look for the section labeled "Additional Board Manager URLs" and add the following URL:
https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
If you already have a URL for another board, do not delete it—simply add the new one below.
Click the "OK" button, then go to the Board Manager in the left toolbar of the Arduino IDE.
In the search box, type RP2350. You will see the installer for various boards based on the RP2040 and RP2350. Click "INSTALL" to proceed.
After a few minutes, all the necessary packages will be downloaded and installed.
Next, connect the board to your computer using a USB cable. Make sure it is recognized as a new device—keep in mind that some USB cables only provide power and do not support data transmission.
Select the board from the menu:
Tools → Board → Raspberry Pi Pico RP2040/RP2350 → Generic RP2350
Next, specify the port where the board is connected by selecting:
Tools → Port
In Windows, look for a COM port. The first time, you might see something different, like "UF2 Board", but after uploading the first code, it will appear as a COM port.
Finally, set the Flash memory size to 8 MB.
Once you have completed these steps, your Arduino IDE is fully configured to program the Pico W5. You can test it by running the "Blink" program, which you can find under:
File → Examples
ExamplesNow, let's explore some programming examples. Since the GPIO control and other basic functions are the same as in the Pico 2, we will focus on connectivity, which is the key distinguishing feature of this board.
AT CommandsThe first example is a simple "terminal" that mirrors what you type in the serial monitor to the BW16 module, and vice versa. This allows you to experiment with different AT commands.
/*
Author: Ernesto Tolocka (Profe Tolocka)
Creation Date: Feb-18-2025
Description: Sends and receives AT commands to and from the BW16.
License: MIT
*/
// Define the RX and TX pins for the second serial port
#define Serial2_RX 5 // RX
#define Serial2_TX 4 // TX
void setup() {
Serial2.setRX(Serial2_RX); // RX pin for the second port
Serial2.setTX(Serial2_TX); // TX pin for the second port
Serial2.begin(115200); // Initialize second port at 115200
Serial.begin(115200); // Initialize main port at 115200
}
void loop() {
char data;
if (Serial2.available()) { // Did something arrive from the module?
data=Serial2.read(); // Read the incoming data
Serial.write(data); // Send it to the monitor
}
if (Serial.available ()) { // Did something arrive from the monitor?
data=Serial.read(); // Read the incoming data
Serial2.write(data); // Send it to the module
}
}
All available AT commands are documented here.
Here is the response to some test commands.
To manage the connection to a WiFi network, the firmware provides several commands, including:
- AT+WMODE: Sets or queries the operating mode
- AT+WJAP: Connects to a network
- AT+WSCAN: Scans available networks
This example connects the board to a WiFi network in STA mode:
/*
Author: Ernesto Tolocka (Profe Tolocka)
Creation Date: Feb-18-2025
Description: Connects to a WiFi network
License: MIT
*/
// Define TX and RX pins for Serial2
#define Serial2_RX 5
#define Serial2_TX 4
// Define the command for STA mode
#define SET_WIFI_MODE "AT+WMODE=1,1"
// Define the command to connect
// Replace SSID and PASSW with your network name and password
#define SET_WIFI_SSID_PASSWORD "AT+WJAP=\"SSID\",\"PASSW\""
// Wait until buffers are empty
void clearSerial() {
while (Serial2.read() >= 0);
while (Serial.read() >= 0);
}
// Send an AT command with a timeout
int sendATCommand(String command, int timeout) {
clearSerial();
Serial2.println(command);
long startTime = millis();
while (millis() - startTime < timeout * 1000) {
if (Serial2.available()) {
String response = Serial2.readString();
if (response.indexOf("OK") != -1) {
return 0; // OK response received
}
}
}
return 1; // Timeout or incorrect response
}
void setup() {
// Initialize serial ports
Serial.begin(115200);
// Set TX and RX pins
Serial2.setRX(Serial2_RX);
Serial2.setTX(Serial2_TX);
Serial2.begin(115200);
delay(5000);
if (!sendATCommand (SET_WIFI_MODE,5)) { // Set mode
Serial.println ("Mode OK");
if (!sendATCommand (SET_WIFI_SSID_PASSWORD,10)) { // Connect
Serial.println ("WiFi connected");
} else {
Serial.println ("Connection error!");
}
} else {
Serial.println ("Mode error!");
}
}
void loop() {
// Main code to run repeatedly
}
The procedure and commands used are identical, whether connecting to a 2.4 GHz or 5.8 GHz network.HTTP Request
This example demonstrates how to make a GET request to an API using HTTP.
/*
Author: Ernesto Tolocka (Profe Tolocka)
Creation Date: Feb-18-2025
Description: Connects to an API using HTTP GET
License: MIT
*/
// Define TX and RX pins for Serial2
#define Serial2_RX 5
#define Serial2_TX 4
// Define the command for AP+STA mode
#define SET_WIFI_MODE "AT+WMODE=3,1"
// Define the command to connect
// Replace SSID and PASSW with your network name and password
#define SET_WIFI_SSID_PASSWORD "AT+WJAP=\"SSID\",\"PASSW\""
// Define the command to make an HTTP request with the format required by the API
#define GET_HTTP_REQ "AT+HTTPCLIENTLINE=1,2,\"application/x-www-form-urlencoded\",\"api.open-meteo.com\",80,\"/v1/forecast?latitude=-31.137&longitude=-64.296¤t=temperature_2m\""
// Sends an AT command with a timeout
int sendATCommand(String command, int timeout) {
Serial.flush();
Serial2.println(command);
long startTime = millis();
while (millis() - startTime < timeout * 1000) {
if (Serial2.available()) {
String response = Serial2.readString();
if (response.indexOf("OK") != -1) {
return 0; // OK response received
}
}
}
return 1; // Timeout or incorrect response
}
void setup() {
// Initialize serial ports
Serial.begin(9600);
// Set TX and RX pins
Serial2.setRX(Serial2_RX);
Serial2.setTX(Serial2_TX);
Serial2.begin(115200);
delay(5000);
if (!sendATCommand (SET_WIFI_MODE,5)) { // Set mode
Serial.println ("Mode OK");
if (!sendATCommand (SET_WIFI_SSID_PASSWORD,10)) { // Connect
Serial.println ("WiFi connected");
// Send HTTP request
Serial2.println (GET_HTTP_REQ);
// Wait for the response
while (!Serial2.available());
Serial.println(Serial2.readString());
} else {
Serial.println ("Connection error!");
}
} else {
Serial.println ("Mode error!");
}
}
void loop() {
// Main code to run repeatedly
}
The command used for the request is AT+HTTPCLIENTLINE, and the format is as follows:
AT+HTTPCLIENTLINE=<transport_type>,<opt>,<content-type>,<host>,<port>,<path>[,<data>]
You can find the full documentation for the command here.
For this example, I made a GET request to the open-meteo.com API, passing the latitude and longitude of my location as parameters, along with the requested data (current=temperature_2m), which represents the current temperature at a height of 2 meters above the ground.
AT+HTTPCLIENTLINE=1,2,"application/x-www-form-urlencoded","api.open-meteo.com",80,"/v1/forecast?latitude=-31.137&longitude=-64.296¤t=temperature_2m"
The response, which is in JSON format, is as follows:
{"latitude":-31.125,"longitude":-64.25,"generationtime_ms":0.014901161193847656,"utc_offset_seconds":0,"timezone":"GMT","timezone_abbreviation":"GMT","elevation":740.0,"current_units":{"time":"iso8601","interval":"seconds","temperature_2m":"°C"},"current":{"time":"2025-02-16T15:00","interval":900,"temperature_2m":26.5}}
Among all the returned information, you can see the requested temperature value (26.5 degrees) at the end.
MQTTIn this example, I will show you how to connect to an MQTT server and publish data to a topic.
/*
Author: Ernesto Tolocka (Profe Tolocka)
Creation Date: Feb-18-2025
Description: Publishes to an MQTT server
License: MIT
*/
// Define TX and RX pins for Serial2
#define Serial2_RX 5
#define Serial2_TX 4
// Define the command for AP+STA mode
#define SET_WIFI_MODE "AT+WMODE=1,1"
// Define the command to connect
// Replace SSID and PASSW with your network name and password
#define SET_WIFI_SSID_PASSWORD "AT+WJAP=\"SSID\",\"PASSW\""
// Define MQTT commands
// Broker address
#define SET_MQTT_URL "AT+MQTT=1,broker.emqx.io"
// Port number
#define SET_MQTT_PORT "AT+MQTT=2,1883"
// Connection method
#define SET_MQTT_METHOD "AT+MQTT=3,1"
// Client ID
#define SET_MQTT_CLIENT_ID "AT+MQTT=4,MyPicoW5"
// Connect command
#define SET_MQTT_CONNECT "AT+MQTT"
// Publish command
#define PUB_MQTT "AT+MQTTPUB=PicoW5,0,0,Hello"
// Sends an AT command with a timeout
int sendATCommand(String command, int timeout) {
Serial.flush();
Serial2.println(command);
long startTime = millis();
while (millis() - startTime < timeout * 1000) {
if (Serial2.available()) {
String response = Serial2.readString();
if (response.indexOf("OK") != -1) {
return 0; // OK response received
}
}
}
return 1; // Timeout or incorrect response
}
void setup() {
// Initialize serial ports
Serial.begin(9600);
// Set TX and RX pins
Serial2.setRX(Serial2_RX);
Serial2.setTX(Serial2_TX);
Serial2.begin(115200);
delay(5000);
if (!sendATCommand (SET_WIFI_MODE,5)) { // Set mode
Serial.println ("Mode OK");
if (!sendATCommand (SET_WIFI_SSID_PASSWORD,10)) { // Connect
Serial.println ("WiFi connected");
// Connect to MQTT server
sendATCommand (SET_MQTT_URL,5);
sendATCommand (SET_MQTT_PORT,5);
sendATCommand (SET_MQTT_METHOD,5);
sendATCommand (SET_MQTT_CLIENT_ID,5);
// Connect
Serial2.println (SET_MQTT_CONNECT);
// Wait for response
while (!Serial2.available());
Serial.println(Serial2.readString());
} else {
Serial.println ("Connection error!");
}
} else {
Serial.println ("Mode error!");
}
}
void loop() {
// Main code to run repeatedly
// Publish to topic
Serial2.println (PUB_MQTT);
// Wait for response
while (!Serial2.available());
Serial.println(Serial2.readString());
delay (5000);
}
After connecting to the WiFi network, the MQTT broker connection is configured by sending multiple AT+MQTT commands with different parameters: the broker address, connection port, connection method, and client ID
sendATCommand (SET_MQTT_URL,5);
sendATCommand (SET_MQTT_PORT,5);
sendATCommand (SET_MQTT_METHOD,5);
sendATCommand (SET_MQTT_CLIENT_ID,5);
.Then, the connection is established using the specified parameters with the AT+MQTT command.
// Connect
Serial2.println (SET_MQTT_CONNECT);
// Wait for response
while (!Serial2.available());
Serial.println(Serial2.readString());
And then, a simple text "Hello" is published to the PicoW5 topic every 5 seconds.
void loop() {
// Main code to run repeatedly
// Publish to topic
Serial2.println (PUB_MQTT);
// Wait for response
while (!Serial2.available());
Serial.println(Serial2.readString());
delay (5000);
}
The data received on the broker can be viewed using a client like MQTTX:
If MQTT connection errors are observed, the board should be restarted to terminate any previously open connections and then try again.Bluetooth LE
Finally, here is an example using the Bluetooth Low Energy (BLE) interface of the Pico W5.
This is a simple program that configures the BW16 module in Slave mode to receive text data via Bluetooth. If the received text is "LED=ON", the onboard LED on the Pico turns on, and if it receives "LED=OFF", the LED turns off.
/*
Author: Ernesto Tolocka (Profe Tolocka)
Creation Date: Feb-18-2025
Description: Controls the onboard LED via Bluetooth:
"LED=ON" = Turns the LED on
"LED=OFF" = Turns the LED off
License: MIT
*/
// Define TX and RX pins for Serial2
#define Serial2_RX 5
#define Serial2_TX 4
// Sends an AT command with a timeout
int sendATCommand(String command, int timeout) {
Serial2.println(command);
long startTime = millis();
while (millis() - startTime < timeout * 1000) {
if (Serial2.available()) {
String response = Serial2.readString();
Serial.println (response);
if (response.indexOf("OK") != -1) {
return 0; // OK response received
}
}
}
return 1; // Timeout or incorrect response
}
void setup() {
// LED output
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite (LED_BUILTIN, LOW);
// Initialize serial ports
Serial.begin(115200);
// Set TX and RX pins
Serial2.setRX(Serial2_RX);
Serial2.setTX(Serial2_TX);
Serial2.begin(115200);
delay(5000);
Serial.println("Configuring Bluetooth...");
// Ensure Bluetooth is off before configuring
sendATCommand ("AT+BLEMODE=9",10);
// Set device name
sendATCommand ("AT+BLENAME=ProfeTolocka",10); // Only when OFF
// UUID
sendATCommand ("AT+BLESERUUID=495353431e4d4bd9ba6123c647249616",10); // Only when OFF
// Activate Bluetooth in SLAVE mode
sendATCommand ("AT+BLEMODE=0",10);
// Advertising is enabled by default
Serial.println("Bluetooth ready! Waiting for connection...");
Serial2.flush();
}
void loop() {
// Receive data from Bluetooth and send it to the Serial Monitor
if (Serial2.available()) {
String data = Serial2.readString();
Serial.print("Received via BT: ");
Serial.println(data);
if (data.indexOf("LED=ON") != -1) {
Serial.println ("Turning LED ON");
digitalWrite (LED_BUILTIN, HIGH);
}
if (data.indexOf("LED=OFF") != -1) {
Serial.println ("Turning LED OFF");
digitalWrite (LED_BUILTIN, LOW);
}
}
}
To test the functionality, I used a simple app called Arduino Bluetooth Controller for Android, which you can download from the App Store. There are many similar apps available, so you can use any other that serves the same purpose.
In the app, I used the Switch function, which allows defining the text sent in both positions of the on-screen switch. The values must be set according to what the code expects: "LED=ON" for the on position and "LED=OFF" for the off position.
All the example programs published in this article, along with others I continue to add for the Pico W5, can be found in this repository
ConclusionsIn this article, I introduced you to the main features and some applications of the RP2350 Pico W5 from Elecrow. We explored its technical specifications, highlighting its Flash memory capacity, USB-C connector, and ability to work with 5.8 GHz WiFi networks. We also analyzed the available programming options and walked through a step-by-step guide on how to set up Arduino IDE to start working with it.
Finally, I presented several example programs demonstrating how to use the AT commands of the built-in BW16 module to perform basic connectivity functions, such as WiFi connection, HTTP requests, MQTT communication, and BLE usage.
In conclusion, the Pico W5 is a powerful and versatile board, ideal for IoT applications and home automation. Its compatibility with the Raspberry Pico 2 hardware makes it an excellent option for developers of all levels, allowing them to fully leverage its potential in projects requiring multiple connectivity options. Moreover, its ability to operate on 5.8 GHz networks sets it apart from many other boards on the market, providing a faster and more stable connection, especially in environments where the 2.4 GHz band is congested due to a high number of connected devices.
I hope this article has been useful and helps you start creating your own projects with the Pico W5. If you have questions, suggestions, or would like to share your experiences, feel free to do so in the comments section below.
For more information and projects, you can check out my blog and social media.
See you next time! 🚀
More Info- Elecrow Wiki
- Pico W5 Schematics
- AiThinker Combo Firmware
Comments
Please log in or sign up to comment.