La Pico W5 de Elecrow es una placa basada en el RP2350 de Raspberry con características que la hacen única. En este artículo te cuento cuáles son sus especificaciones y particularidades y cómo puedes aprovechar su potencial programandola usando Arduino.
Introducción
Desde su lanzamiento en agosto de 2024, el microcontrolador RP2350 de Raspberry ha sido adoptado por diversos diseñadores y fabricantes para desarrollar sus propias placas. Desde la Raspberry Pico versión 2 hasta variantes con mejoras específicas, como mayor memoria o la incorporación de periféricos adicionales, este chip ha impulsado una nueva generación de dispositivos.
Entre estas opciones, destaca la Pico W5 de Elecrow, que además de incorporar 8 MB de memoria Flash, también se distingue por su capacidad de conectividad Wifi en las bandas de 2.4 GHz y 5.8 GHz.
También incluye Bluetooth, lo que la convierte en una opción a tener en cuenta para proyectos de Internet de las cosas (IoT) y muchas otras aplicaciones.
En este artículo, te presentaré las principales características de la Pico W5 y, sobre todo, cómo aprovechar sus capacidades de conectividad. En la primera parte, exploraremos su uso con Arduino, mientras que en la segunda veremos cómo hacer lo mismo con MicroPython.
Características
Veamos rápidamente las principales características de esta placa:
CPU
La Pico W5 incorpora el nuevo RP2350 de Raspberry que tiene la particularidad de incluir dos bloques distintos de CPU, uno tipo ARM y el otro RISC-V, ambos con dos cores. Además es mas rápido y mas potente que su antecesor el RP2040.
- RP2350 hasta 150 MHz
- Dual core seleccionable entre Arm Cortex-M33 o Hazard3 RISC-V.
Memoria
La Pico W5 se destaca por tener una buena cantidad de memoria Flash.
- 8MB de Flash
- 520 KB de RAM (incorporada en el RP2350)
GPIO
La placa tiene el mismo tamaño y formato que la Pico 2, así que es compatible con módulos o ampliaciones diseñados para ella.
- 24 pines GPIO multifunción (dos menos que la Pico 2, que se conectan al módulo Wifi).
- Compatible con Raspberry Pico 2.
- Botón de RESET.
- Botón de BOOT.
- LED incorporado controlado por usuario.
- Pines en formato «castellated» para soldar la placa como un módulo.
- Conector USB-C de alimentación y programación.
En la siguiente imagen puedes ver el pinout de la placa:
Conectividad
La conectividad de la Pico W5 corre por cuenta de un módulo BW16 de la marca B&T que incluye en su interior el chip RTL7820 de Realtek.
- Soporta Wifi 802.11a/b/g/n en las bandas de 2.4 GHz y 5.8 GHz.
- Bluetooth LE con Bluetooth 5.0
El módulo BW16 está conectado en la placa al RP2350 a través de una interfaz UART empleando los pines GPIO4 y GPIO5. Incluye en su interior un firmware de AiThinker que implementa las funciones mas comunes, como acceder a una red Wifi, realizar peticiones HTTP, implementar el protocolo MQTT así como controlar la comunicación Bluetooth. El control de estas funciones se hace a través de comandos AT.
Para aclarar un poco mas el punto anterior tal vez sirva una comparación con la Pico 2W.
La placa de Raspberry incluye un módulo parecido al BW16, el CYW43439 de Infineon. También se conecta al RP2350 a través de una puerto de comunicaciones. En el caso de Raspberry la programación es sencilla porque disponemos de la librería libcyw43 que se encarga de todos los detalles del funcionamiento del CYW43439, pero con el BW16 no tenemos esa suerte y debemos enviar los comandos AT necesarios desde nuestro código.
Otra aclaración: el BW16 incluye en su interior un procesador comparable a un Cortex M0 que puede ser programado en Arduino e incluso en Micropython. Para ello existen tanto un Core de Arduino como un port de Micropython que corren en este procesador interno del BW16 y no en el RP2350 de la Pico W5. Al correr dentro del BW16 pueden acceder de otra forma a las funciones internas y tampoco en ese caso se requiere del uso de los comandos AT empleados para comunicarse con el RP2350.
Programación
La Pico W5 puede ser programada usando varios lenguajes, siendo los mas populares Micropython y C/C++, siendo compatible con Arduino.
Veamos a continuación como se programa usando Arduino y en la segunda parte de esta serie de artículos haremos lo mismo con Micropython.
Configuración de Arduino IDE 2
Para programar la Pico W5 con Arduino, primero necesitas instalar el Arduino IDE 2, que es la versión más reciente y mejorada del entorno de desarrollo de Arduino.
Puedes descargar el instalador desde la página oficial de Arduino aquí. Elige la versión compatible con tu sistema operativo (Windows, macOS o Linux) y sigue los pasos de instalación. La instalación es bastante sencilla y similar a la de cualquier otro programa.
Una vez instalado el Arduino IDE debes agregar el soporte para la placa a través del Gestor de Placas.
Este es un procedimiento sencillo y si ya estás usando otra placa como un ESP32 con el IDE, seguro que ya estarás familiarizado con él.
Primero, abre las preferencias del IDE seleccionando del menú las opciones Archivo y luego Preferencias (o pulsando las teclas «Control» y la coma):
Busca donde dice URLS adicionales del gestor de placas y agrega la siguiente dirección:
https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
Si ya tienes cargada una dirección para otra placa, no la borres, agrega la nueva mas abajo.
Dale click al botón ACEPTAR y en la barra de herramientas de la izquierda del IDE selecciona el Gestor de Placas. En el cuadro de búsquedas tipea RP2350. Te aparecerá el instalador del paquete para distintas placas basadas en el RP2040 y RP2350. Dale click a INSTALAR.
Luego de unos minutos se descargarán e instalarán todos los paquetes necesarios.
Conecta la placa a la computadora con un cable USB, asegurate que sea detectada como un nuevo dispositivo (algunos cables USB sirven sólo de alimentación y no sirven para transmitir datos).
Selecciona la placa en el menú Herramientas – Placa – Raspberry Pi Pico RP2040/RP2350 – Generic RP2350.
A continuación indica el puerto donde está conectada la placa seleccionando en el menú Herramientas – Puerto. Busca un puerto COM. La primera vez puede que veas algo diferente, como «UF2 Board», pero luego de descargar el primer código se verá como un puerto COM.
Para finalizar, configura el tamaño de la memoria Flash a 8 MB:
Una vez completados estos pasos ya tienes el IDE configurado para programar la Pico W5. Prueba con el programa «Blink» que está en Archivo – Ejemplos.
Ejemplos
Veamos a continuación algunos ejemplos de programación. Como el control de los pines GPIO y el resto de las funciones es igual que en la Pico 2, nos vamos a concentrar en la parte de conectividad, que es la característica distintiva de esta placa.
Comandos AT
El primer programa de ejemplo consiste en una especie de «terminal» que copia lo que escribamos en el monitor serie al módulo BW16 y viceversa, lo que permite que experimentemos con los distintos comandos AT.
// Define los pines RX y TX del segundo puerto serie #define Serial2_RX 5 // RX #define Serial2_TX 4 // TX void setup() { Serial2.setRX(Serial2_RX); // Pin RX del segundo puerto Serial2.setTX(Serial2_TX); // Pin TX del segundo puerto Serial2.begin(115200); // Inicializar segundo puerto a 115200 Serial.begin(115200); // Inicializa puerto principal a 115200 } void loop() { char dato; if (Serial2.available()) { //Llega algo del módulo? dato=Serial2.read(); //Leer lo que llegó Serial.write(dato); //Sacarlo al monitor } if (Serial.available ()) { //Llega algo del monitor? dato=Serial.read(); //Leer lo que llegó Serial2.write(dato); //Sacarlo al módulo } }
Todos los comandos AT disponibles están documentados aquí.
Esta es la respuesta a algunos comandos de prueba.
Conexión a un red Wifi
Para controlar la conexión a una red Wifi el firmware nos provee de varios comandos, entre ellos:
- AT+WMODE: Establece o consulta el modo de trabajo
- AT+WJAP: Conecta a una red
- AT+WSCAN: Escanea las redes disponibles
Este ejemplo conecta la placa en modo STA con una red Wifi.
// Define pines de TX y RX para Serial2 #define Serial2_RX 5 #define Serial2_TX 4 // Define el comando para el modo de trabajo STA #define SET_WIFI_MODE "AT+WMODE=1,1" // Define el comando para conectar // Reemplaza SSID y PASSW por el nombre de tu red y tu contraseña #define SET_WIFI_SSID_PASSWORD "AT+WJAP=\"SSID\",\"PASSW\"" // Espera a que no haya nada en los buffers void clearSerial() { while (Serial2.read() >= 0); while (Serial.read() >= 0); } // Envía un comando AT con 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; // Respuesta OK recibida } } } return 1; // Timeout o respuesta incorrecta } void setup() { // Inicializa los puertos serie Serial.begin(115200); // Establece pines TX y RX Serial2.setRX(Serial2_RX); Serial2.setTX(Serial2_TX); Serial2.begin(115200); delay(5000); if (!sendATCommand (SET_WIFI_MODE,5)) { // Fija modo Serial.println ("Modo OK"); if (!sendATCommand (SET_WIFI_SSID_PASSWORD,10)) { // Conecta Serial.println ("Wifi conectado"); } else { Serial.println ("Error al conectar!"); } } else { Serial.println ("Modo Error!"); } } void loop() { // Main code to run repeatedly }
El procedimiento y los comandos a utilizar son idénticos ya sea que vayamos a usar una red de 2.4 GHz o una de 5.8 GHz.
Solicitud HTTP
Este ejemplo muestra como hacer una solicitud tipo GET a una API empleando HTTP.
// Define pines de TX y RX para Serial2 #define Serial2_RX 5 #define Serial2_TX 4 // Define el comando para el modo de trabajo AP+STA #define SET_WIFI_MODE "AT+WMODE=3,1" // Define el comando para conectar // Reemplaza SSID y PASSW por el nombre de tu red y tu contraseña #define SET_WIFI_SSID_PASSWORD "AT+WJAP=\"SSID\",\"PASSW\"" // Define el comando para hacer la solicitud HTTP con el formato requerido por la 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\"" // Envía un comando AT con 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; // Respuesta OK recibida } } } return 1; // Timeout o respuesta incorrecta } void setup() { // Inicializa los puertos serie Serial.begin(9600); // Establece pines TX y RX Serial2.setRX(Serial2_RX); Serial2.setTX(Serial2_TX); Serial2.begin(115200); delay(5000); if (!sendATCommand (SET_WIFI_MODE,5)) { // Fija modo Serial.println ("Modo OK"); if (!sendATCommand (SET_WIFI_SSID_PASSWORD,10)) { // Conecta Serial.println ("Wifi conectado"); // Enviar solicitud HTTP Serial2.println (GET_HTTP_REQ); // Esperar la respuesta while (!Serial2.available()); Serial.println(Serial2.readString()); } else { Serial.println ("Error al conectar!"); } } else { Serial.println ("Modo Error!"); } } void loop() { // Main code to run repeatedly }
El comando a utilizar para la solicitud es AT+HTTPCLIENTLINE y el formato es el siguiente:
AT+HTTPCLIENTLINE=<transport_type>,<opt>,<content-type>,<host>,<port>,<path>[,<data>]
Puedes ver la documentación completa del comando aquí. Para este ejemplo hice una solicitud a la API de open-meteo.com usando el método GET y pasando como parámetros la latitud y longitud del lugar donde vivo y el dato solicitado (current=temperature_2m) que es el valor actual de temperatura a una altura de 2 metros del suelo.
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"
La respuesta, que está en formato JSON es la siguiente:
{"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}}
Entre toda la información devuelta puedes ver al final el valor de temperatura solicitado (26.5 grados).
MQTT
En este ejemplo te muestro como conectar a un servidor MQTT y publicar datos en un topic.
// Define pines de TX y RX para Serial2 #define Serial2_RX 5 #define Serial2_TX 4 // Define el comando para el modo de trabajo AP+STA #define SET_WIFI_MODE "AT+WMODE=3,1" // Define el comando para conectar // Reemplaza SSID y PASSW por el nombre de tu red y tu contraseña #define SET_WIFI_SSID_PASSWORD "AT+WJAP=\"SSID\",\"PASSW\"" // Define comandos para MQTT // Dirección del brokrer #define SET_MQTT_URL "AT+MQTT=1,broker.emqx.io" // Número de puerto #define SET_MQTT_PORT "AT+MQTT=2,1883" // Método de conexión #define SET_MQTT_METHOD "AT+MQTT=3,1" // Identificador del cliente (Client ID) #define SET_MQTT_CLIENT_ID "AT+MQTT=4,MiPicoW5" // Conexión #define SET_MQTT_CONNECT "AT+MQTT" // Publicación #define PUB_MQTT "AT+MQTTPUB=PicoW5,0,0,Hola" // Envía un comando AT con 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; // Respuesta OK recibida } } } return 1; // Timeout o respuesta incorrecta } void setup() { // Inicializa los puertos serie Serial.begin(9600); // Establece pines TX y RX Serial2.setRX(Serial2_RX); Serial2.setTX(Serial2_TX); Serial2.begin(115200); delay(5000); if (!sendATCommand (SET_WIFI_MODE,5)) { // Fija modo Serial.println ("Modo OK"); if (!sendATCommand (SET_WIFI_SSID_PASSWORD,10)) { // Conecta Serial.println ("Wifi conectado"); // Conectar al servidor MQTT sendATCommand (SET_MQTT_URL,5); sendATCommand (SET_MQTT_PORT,5); sendATCommand (SET_MQTT_METHOD,5); sendATCommand (SET_MQTT_CLIENT_ID,5); // Conectar Serial2.println (SET_MQTT_CONNECT); // Esperar la respuesta while (!Serial2.available()); Serial.println(Serial2.readString()); } else { Serial.println ("Error al conectar!"); } } else { Serial.println ("Modo Error!"); } } void loop() { // Main code to run repeatedly //Publicar en topico Serial2.println (PUB_MQTT); // Esperar la respuesta while (!Serial2.available()); Serial.println(Serial2.readString()); delay (5000); }
Luego de conectar con la red Wifi se configuraa la conexión con el broker MQTT, lo que se hace enviando varias instrucciones AT+MQTT, con distintos parámetros: la dirección del broker, el puerto de conexión, el método de conexión y el ID de cliente.
sendATCommand (SET_MQTT_URL,5); sendATCommand (SET_MQTT_PORT,5); sendATCommand (SET_MQTT_METHOD,5); sendATCommand (SET_MQTT_CLIENT_ID,5);
Luego se establece la conexión con los parámetros especificados usando el comando AT+MQTT:
// Conectar Serial2.println (SET_MQTT_CONNECT); // Esperar la respuesta while (!Serial2.available()); Serial.println(Serial2.readString());
y a continuación se publica un simple texto «Hola» en el tópico PicoW5 cada 5 segundos:
void loop() { // Main code to run repeatedly //Publicar en topico Serial2.println (PUB_MQTT); // Esperar la respuesta while (!Serial2.available()); Serial.println(Serial2.readString()); delay (5000); }
Los datos recibidos en el broker se pueden ver usando un cliente como MQTTX:
Si se observan errores de conexión MQTT se debe reiniciar la placa para terminar cualquier conexión anterior que haya quedado abierta y probar nuevamente.
Bluetooth LE
Para finalizar, te comparto un ejemplo haciendo uso de la interfaz BLE (Bluetooth Low Energy) de la Pico W5.
Se trata de un sencillo programa que configura el modulo BW16 en modo Slave para recibir datos en formato de texto a través del Bluetooth. Si el texto es «LED=ON», prende el led incorporado en la Pico y si recibe «LED=OFF», lo apaga.
// Controla el led incorporado a través de BT. Datos válidos: // "LED=ON" = Prende el led // "LED=OFF" = Apaga el led // Define pines de TX y RX para Serial2 #define Serial2_RX 5 #define Serial2_TX 4 // Envía un comando AT con 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(); Serial.println (response); if (response.indexOf("OK") != -1) { return 0; // Respuesta OK recibida } } } return 1; // Timeout o respuesta incorrecta } void setup() { //Salida del LED pinMode(LED_BUILTIN, OUTPUT); digitalWrite (LED_BUILTIN, LOW); // Inicializa los puertos serie Serial.begin(115200); // Establece pines TX y RX Serial2.setRX(Serial2_RX); Serial2.setTX(Serial2_TX); Serial2.begin(115200); delay(5000); Serial.println("Configurando Bluetooth..."); // Asegurar el BT apagado para configurarlo sendATCommand ("AT+BLEMODE=9",10); // Configurar nombre del dispositivo sendATCommand ("AT+BLENAME=ProfeTolocka",10); //Sólo en OFF // UUID sendATCommand ("AT+BLESERUUID=495353431e4d4bd9ba6123c647249616",10); //Sólo en OFF // Activar BT en modo SLAVE sendATCommand ("AT+BLEMODE=0",10); //La publicidad está activada por defecto Serial.println("Bluetooth listo! Esperando conexión..."); Serial2.flush(); } void loop() { // Recibir datos desde Bluetooth y enviarlos al Monitor Serie if (Serial2.available()) { String data = Serial2.readString(); Serial.print("Recibido via BT: "); Serial.println(data); //Serial.println (strlen(data)); if (data.indexOf("LED=ON") != -1) { Serial.println ("Prende LED"); digitalWrite (LED_BUILTIN, HIGH); } if (data.indexOf("LED=OFF") != -1) { Serial.println ("Apaga LED"); digitalWrite (LED_BUILTIN, LOW); } } }
Para comprobar el funcionamiento utilicé una sencilla App llamada Arduino Bluetooth Controller para Android que puedes descargar desde la App Store. Hay muchas que tienen la misma función, así que también puedes usar otra.
En la App uso la función Conmutador que permite definir el texto que se envía en las dos posiciones del switch que se muestra en pantalla, debiendo configurarse los valores que espera el código, es decir «LED=ON» para la posición de encendido y «LED=OFF» para el apagado.
Repositorios
Todos los programas de ejemplo publicados en este artículos y otros que voy agregando para la Pico W5 se pueden encontrar en este repositorio:
Información y ejemplos de la placa Pico W5 de Elecrow
Conclusiones
En este artículo te presenté las principales características y algunas aplicaciones de la RP2350 Pico W5 de Elecrow. Vimos sus especificaciones técnicas, destacando la cantidad de memoria Flash, el uso de conector USB-C y su capacidad de trabajar con redes Wifi de 5.8 GHz. Tambien analizamos las opciones disponibles para programarla y te expliqué paso a paso como configurar el Arduino IDE para empezar a trabajar con ella. Finalmente te presenté varios programas de ejemplo que demuestran como emplear los distintos comandos AT del módulo BW16 incorporado para realizar algunas funciones básicas de conectividad como conexión Wifi, solicitudes HTPP, uso de MQTT y BLE.
En conclusión, la Pico W5 es una placa potente y versátil, ideal para aplicaciones IoT y automatización del hogar. Su compatibilidad con el hardware de la Raspberry Pico 2 la convierte en una excelente opción para desarrolladores de todos los niveles, permitiendo maximizar su potencial en proyectos que requieran múltiples opciones de conectividad. Además, su capacidad de operar en redes de 5.8 GHz la diferencia de muchas otras placas disponibles en el mercado, proporcionando una conexión más rápida y estable, especialmente en entornos donde la banda de 2.4 GHz suele estar congestionada debido a la alta cantidad de dispositivos que la utilizan.
Espero que el artículo te haya sido de utilidad y que te sirva para comenzar a crear tus propios proyectos con la Pico W5. Si tienes dudas, sugerencias o quieres compartir tus experiencias, puedes hacerlo mas abajo en la sección de comentarios o en el canal de Discord. Hasta la próxima!