Pico 2 W vs Pico 1 W: Hardware and Wireless Specs
Before wiring your breadboard, it is critical to understand how the RP2350 changes your power and memory budget. The original Pico W (RP2040) frequently hit memory walls when combining Wi-Fi buffers with sensor arrays. The Pico 2 W solves this, but introduces a new power management IC that behaves differently under load.
| Specification | Raspberry Pi Pico W (Original) | Raspberry Pi Pico 2 W (2024+) |
|---|---|---|
| Microcontroller | RP2040 (Dual-core Cortex-M0+ @ 133MHz) | RP2350 (Dual-core Cortex-M33 / Hazard3 @ 150MHz) |
| SRAM | 264 KB | 520 KB (Banked) |
| Flash Storage | 2 MB | 4 MB |
| Wireless Chip | Infineon CYW43439 (Wi-Fi 4 / BLE 5.0) | Infineon CYW43439 (Wi-Fi 4 / BLE 5.2) |
| Power Regulation | RT6185 Buck-Boost | RT6185 Buck-Boost (Updated quiescent tuning) |
| Typical Pricing | $6.00 USD | $7.00 USD |
Source: Raspberry Pi Pico Series Documentation
3V3 OUT pin to power external sensors and displays, you will trigger a brownout reset. Keep external 3.3V loads under 100mA, or use a dedicated external LDO.
Parts List and Pin Mapping
This build targets the Raspberry Pi Pico 2 W (SC0919) with pre-soldered headers. We are using the BME280 for environmental data, but the code includes a fallback to the RP2350's internal temperature sensor if the I2C bus fails to initialize.
Required Components
- MCU: Raspberry Pi Pico 2 W (Ensure it says 'Pico 2 W' on the silkscreen, not just 'Pico 2')
- Sensor: Adafruit BME280 I2C Breakout (PID 2652) or SparkFun (SEN-13676)
- Wiring: 4x M-to-M jumper wires (22 AWG stranded)
- Power: 5V 2A USB-C power supply (MicroPython Wi-Fi init requires clean 5V)
Pin Mapping Table (I2C0)
| Pico 2 W Pin | GPIO Number | Function | BME280 Breakout Pin |
|---|---|---|---|
| Pin 1 | GP0 | I2C0 SDA | SDI / SDA |
| Pin 2 | GP1 | I2C0 SCL | SCK / SCL |
| Pin 36 | N/A | 3V3 OUT | VIN / VCC |
| Pin 38 | N/A | GND | GND |
Complete MicroPython Firmware and MQTT Code
The following code targets MicroPython v1.24.0+ (RP2350 Pico 2 W build). It connects to Wi-Fi, attempts to read the BME280, and publishes to an MQTT broker. If the BME280 is missing or the I2C bus locks up, it gracefully falls back to the RP2350's internal core temperature sensor to keep the node online.
import network
import time
import gc
from machine import Pin, I2C, ADC
from umqtt.simple import MQTTClient
# --- PIN & CONFIG DEFINITIONS ---
WIFI_SSID = 'YourNetworkSSID'
WIFI_PASS = 'YourNetworkPassword'
MQTT_BROKER = '192.168.1.50'
MQTT_TOPIC = b'pico2w/env/data'
I2C_SDA = Pin(0)
I2C_SCL = Pin(1)
# On Pico W / Pico 2 W, the onboard LED is routed through the CYW43439 chip
LED = Pin('LED', Pin.OUT)
# --- HARDWARE INITIALIZATION ---
i2c = I2C(0, sda=I2C_SDA, scl=I2C_SCL, freq=400000)
adc_temp = ADC(ADC.CORE_TEMP) # RP2350 internal temp sensor
bme_sensor = None
try:
import bme280
# Scan I2C bus to verify BME280 presence (default addr 0x76 or 0x77)
devices = i2c.scan()
if 0x76 in devices or 0x77 in devices:
bme_sensor = bme280.BME280(i2c=i2c)
print('[INFO] BME280 initialized successfully.')
else:
print('[WARN] BME280 not found on I2C bus. Using internal fallback.')
except Exception as e:
print(f'[ERROR] BME280 init failed: {e}. Using internal fallback.')
# --- NETWORK CONNECTION ---
def connect_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
# Prevent Wi-Fi sleep to avoid CYW43439 bus timeouts during MQTT
wlan.config(pm = 0xa11140)
if not wlan.isconnected():
print(f'[INFO] Connecting to {WIFI_SSID}...')
wlan.connect(WIFI_SSID, WIFI_PASS)
timeout = 20
while not wlan.isconnected() and timeout > 0:
LED.value(1)
time.sleep(0.25)
LED.value(0)
time.sleep(0.25)
timeout -= 1
if wlan.isconnected():
print(f'[SUCCESS] Wi-Fi connected: {wlan.ifconfig()[0]}')
return True
else:
print('[FAIL] Wi-Fi connection timed out.')
return False
# --- SENSOR READING ---
def get_telemetry():
gc.collect() # Prevent ENOMEM errors before MQTT payload allocation
if bme_sensor:
try:
t, p, h = bme_sensor.values
return f'{{"temp": {t}, "humidity": {h}, "pressure": {p}, "src": "bme"}}'
except OSError:
print('[WARN] I2C read error, falling back to internal.')
# Fallback: RP2350 Internal Core Temp
raw = adc_temp.read_u16()
# Datasheet formula: T = 27 - (ADC_voltage - 0.706) / 0.001721
core_temp_c = 27 - (raw * 3.3 / 65535 - 0.706) / 0.001721
return f'{{"temp": {round(core_temp_c, 2)}, "src": "internal_core"}}'
# --- MAIN LOOP ---
def main():
if not connect_wifi():
machine.reset()
client = MQTTClient('pico2w_node', MQTT_BROKER, keepalive=60)
try:
client.connect()
print('[INFO] MQTT Broker connected.')
except Exception as e:
print(f'[FATAL] MQTT Connect failed: {e}')
machine.reset()
while True:
try:
payload = get_telemetry()
client.publish(MQTT_TOPIC, payload)
print(f'[TX] {payload}')
LED.value(1)
time.sleep(0.1)
LED.value(0)
client.check_msg() # Non-blocking check for incoming
time.sleep(10)
except Exception as e:
print(f'[ERROR] Loop exception: {e}. Rebooting...')
time.sleep(2)
machine.reset()
if __name__ == '__main__':
main()
Debugging the CYW43439 Wireless Stack
The transition from the RP2040 to the RP2350 changed the bootrom and the way the SPI bus is shared with the Infineon CYW43439 wireless chip. If your node fails to connect, do not blindly rewrite your code. Check these specific failure modes.
The First Three Things to Check When It Fails
- Firmware Variant Mismatch: The RP2350 has a different UF2 firmware file than the RP2040. If you flash the standard
PICO2firmware instead of thePICO2_Wfirmware, thenetworkmodule will not exist, and the CYW43439 will never initialize. Always verify your UF2 filename includesPICO2_W. - 3.3V Rail Sag Under TX Load: Use a multimeter with min/max hold (or an oscilloscope) on the
3V3 OUTpin. When the Wi-Fi radio transmits a beacon, it spikes current draw. If your USB cable has high resistance or your power supply is marginal, the voltage will dip below 3.0V, causing the wireless chip to silently reset. - I2C Pull-Up Equivalent Resistance: The CYW43439 shares the SPI bus internally, but external I2C buses are sensitive to noise. If you have multiple sensors on I2C0, the parallel pull-up resistors might drop the equivalent resistance below 1kΩ, corrupting the I2C clock stretching and causing the MicroPython I2C driver to hang the entire thread.
Common Error Strings and Ranked Causes
RuntimeError: CYW43439 init failedMeaning: The RP2350 cannot communicate with the wireless chip over the internal SPI bus.
Causes:
1. Flashed the non-W Pico 2 firmware (Missing Wi-Fi drivers in the build).
2. Severe 3.3V brownout during the chip's power-on self-test (POST).
3. Hardware defect on the Pico 2 W module (rare, but happens with cold solder joints on the CYW43 chip).
OSError: [Errno 12] ENOMEMMeaning: MicroPython ran out of heap memory to allocate the TLS/MQTT buffer.
Causes:
1. Heap fragmentation. (Fix: Call
gc.collect() right before creating the MQTT payload string, as shown in the code above).2. Using standard MQTT over TLS (port 8883) without increasing the MicroPython heap size. The Pico 2 W has 520KB SRAM, but MicroPython partitions this. If using TLS, you may need to compile a custom MicroPython build with an increased
MICROPY_HEAP_SIZE.
Extending and Simplifying the Build
Depending on your deployment environment, you may need to strip this project down to its bare essentials or scale it up for industrial prototyping.
How to Simplify (No MQTT Broker Required)
If you do not want to maintain a local Mosquitto MQTT broker or a Home Assistant instance, strip the umqtt library out entirely. Replace the MQTT publish block with a standard HTTP GET request using the urequests library. Point it at a simple PHP script or a free service like ThingSpeak. This reduces SRAM usage by roughly 15KB and eliminates the need for keep-alive ping management, allowing the RP2350 to sleep longer between transmissions.
How to Extend (Deep Sleep and BLE Fallback)
The RP2350 features a dedicated always-on RTC (Real Time Clock) domain that consumes only a few microamps. To extend this build for battery operation:
- Replace the
time.sleep()loop withmachine.deepsleep(60000). - Wire a PIR motion sensor to a GPIO pin configured as a wake source using
machine.Pin_WAKE. - Add a Bluetooth Low Energy (BLE) fallback. If the Wi-Fi router is down, use the
bluetoothmodule to broadcast the BME280 data as a BLE GATT characteristic, allowing a passing smartphone to scrape the environmental data without needing local network infrastructure.
For deeper details on the RP2350 power domains, refer to the RP2350 Datasheet (Section 2.4: Power Management) and the MicroPython Machine Module Documentation.






