Raspberry Pi Pico with Waveshare LoRa HAT

The Raspberry Pi Pico paired with a Waveshare LoRa module is a low-cost platform for LoRa radio projects. The original Pico and Pico W provide the RP2040 microcontroller, while Pico 2 and Pico 2 W use the newer RP2350; the Waveshare HAT or breakout adds the Semtech SX126x radio. Together they make a capable LoRa node that can run on battery for extended periods. This covers the hardware, wiring, and getting MicroPython talking to the radio.

The Hardware

ComponentNotes
Raspberry Pi PicoOriginal RP2040 board; 264KB SRAM and typically 2MB flash; no WiFi or Bluetooth. A good simple USB-connected LoRa controller.
Raspberry Pi Pico WRP2040 board with CYW43439 wireless connectivity; typically 2MB flash. WiFi/Bluetooth can support network features when the firmware and project use them.
Raspberry Pi Pico 2Newer RP2350 board; 520KB SRAM and typically 4MB flash; no WiFi or Bluetooth. It is not an RP2040 board, so firmware targets must match.
Raspberry Pi Pico 2 WRP2350 board with CYW43439 wireless connectivity; typically 4MB flash. It combines the newer MCU with the W-series wireless hardware.
Waveshare Pico-LoRa-SX1262Most common variant. SX1262 radio chip; 915MHz or 868MHz version. Plugs directly onto the Pico 40-pin header.
Waveshare SX1268 variant433/470MHz version. Different chip, same interface. Check your regional frequency before ordering.
AntennaRequired — never transmit without an antenna. The Waveshare modules include a small antenna; an external omnidirectional 915MHz antenna improves range significantly.

What the Names Mean

The four names describe two separate choices:

ChoiceOriginal generationSecond generation
MicrocontrollerPico / Pico W use RP2040Pico 2 / Pico 2 W use RP2350
WirelessPico and Pico 2 have no built-in WiFi/BluetoothThe W versions add WiFi/Bluetooth; the LoRa radio is still a separate SX126x device

Pico 2 boards keep the familiar Pico form factor and header layout, so a HAT may physically fit, but physical compatibility is not the same as firmware compatibility. Check the Waveshare documentation and the Meshtastic release assets for the exact board and radio combination.

For a simple USB-connected Meshtastic node, the non-W version is enough. Choose a W version only when the project needs WiFi or Bluetooth and the selected firmware supports it. The W does not change the LoRa frequency or make a 915 MHz board work on another band.

For the RP2040 Cortex-M0+ and Thumb assembly boundary behind Pico/Pico W projects, see Raspberry Pi Pico W Assembly: RP2040, Cortex-M0+, and Thumb.

Pin Connections (SX1262 to Pico)

The Waveshare Pico-LoRa-SX1262 plugs directly onto the Pico — no wiring needed if you use the HAT form factor. If you're using the SPI breakout version, these are the connections:

Pico to LoRa SX1262 Wiring Map A diagram showing the SPI and control pin connections straight across from a Raspberry Pi Pico to a Waveshare SX1262 LoRa module. Pico (RP2040) 3V3 OUT GND GP2 GP3 GP10 GP11 GP12 GP15 GP20 SX1262 HAT 3.3V GND BUSY NSS (CS) SCK MOSI MISO RST DIO1 Power Control SPI Bus
Figure 1: Standard SPI and control wiring for the Waveshare SX1262. Always use the 3.3V OUT pin from the Pico to power the radio; using VBUS (5V) will damage the module and the Pico.
SX1262 PinPico GPIOFunction
SCKGPIO 10SPI clock
MOSIGPIO 11SPI data out (Pico → radio)
MISOGPIO 12SPI data in (radio → Pico)
NSS / CSGPIO 3SPI chip select (active low)
RSTGPIO 15Reset (active low)
BUSYGPIO 2Radio busy signal (wait when high)
DIO1GPIO 20Interrupt (TX done, RX done)
3.3V3V3 OUTPower
GNDGNDGround

Waveshare's documentation and their example code uses these pins. If you use their HAT, these are pre-wired.

Hardware Checks Before Powering Up

The Pico and radio use 3.3 V logic. A wiring mistake can damage the RP2040 or the SX126x, so check the hardware before loading software:

  • Confirm whether the board is the 433/470 MHz SX1268 version or the 868/915 MHz SX1262 version.
  • Confirm that the antenna is connected before any transmit test.
  • Use the HAT's documented power input and never feed 5 V into a 3.3 V GPIO.
  • Check the HAT orientation and make sure the header pins are fully seated.
  • Keep the radio away from loose metal objects while testing.

The pin table below describes the common Waveshare wiring, but the board revision and driver documentation are the final authority. Treat a breakout board and a direct-mount HAT as separate wiring jobs.

MicroPython Setup

# Flash MicroPython to the Pico:
# 1. Hold BOOTSEL button and plug in USB — appears as mass storage device
# 2. Download .uf2 for the exact board:
#    RPI_PICO for Pico / Pico W
#    RPI_PICO2 for Pico 2 / Pico 2 W
# 3. Copy the .uf2 to the drive — Pico reboots into MicroPython

# Connect with a serial terminal
$ minicom -D /dev/ttyACM0 -b 115200
# or: screen /dev/ttyACM0 115200
# or use Thonny IDE (easiest for beginners)

# On Debian, check which device appeared after plugging in the Pico
$ dmesg --follow
$ ls -l /dev/ttyACM*

Waveshare SX1262 MicroPython Library

# Waveshare provides example code on their wiki.
# Clone their examples or download the sx1262.py driver:
# https://www.waveshare.com/wiki/Pico-LoRa-SX1262

# Basic transmit example (MicroPython):

from machine import SPI, Pin
from sx1262 import SX1262   # Waveshare's driver

# SPI bus on Pico SPI1
spi = SPI(1,
    baudrate=2000000,
    polarity=0,
    phase=0,
    bits=8,
    firstbit=SPI.MSB,
    sck=Pin(10),
    mosi=Pin(11),
    miso=Pin(12)
)

sx = SX1262(spi,
    cs=Pin(3, Pin.OUT),
    irq=Pin(20, Pin.IN),
    rst=Pin(15, Pin.OUT),
    gpio=Pin(2, Pin.IN)
)

# Configure the radio
sx.begin(
    freq=915,           # MHz — match your region
    bw=125.0,           # kHz bandwidth
    sf=10,              # spreading factor (7-12)
    cr=5,               # coding rate 4/5
    syncWord=0x12,      # private network sync word (0x34 = public LoRaWAN)
    power=22,           # dBm TX power (max 22 on SX1262)
    currentLimit=140.0,
    preambleLength=8,
    implicit=False,
    implicitLen=0xFF,
    crcOn=True,
    txIq=False,
    rxIq=False,
    tcxoVoltage=1.7,
    useRegulatorLDO=False,
    blocking=True
)

# Transmit
message = "hello from pico"
sx.send(message.encode())
print("Sent:", message)

Radio Configuration Is a Contract

Every node that should communicate must agree on the radio parameters. Frequency, bandwidth, spreading factor, coding rate, sync word, and packet format all matter. A node can be perfectly wired and still appear dead when it is configured for another band or modem setting.

Before testing two nodes, write down:
  region / frequency: CA_915 for a Canadian 915 MHz setup
  bandwidth:          125 kHz
  spreading factor:   the same on both radios
  coding rate:        the same on both radios
  sync word:          the same on both radios
  antenna:            connected and matched to the band

The example driver call is illustrative; Waveshare libraries use slightly different class and argument names across releases. Start from the example shipped for your exact board, then change one setting at a time.

Receiving

import time

# Switch to receive mode
sx.recv(timeout_en=True, timeout_ms=5000)   # wait up to 5 seconds

while True:
    data, status = sx.recv()
    if data:
        print("Received:", bytes(data).decode("utf-8", errors="replace"))
        # RSSI and SNR from status:
        print(f"RSSI: {status[0]} dBm, SNR: {status[1]} dB")
    time.sleep(0.1)

Reading RSSI and SNR

RSSI (Received Signal Strength Indicator) and SNR (Signal-to-Noise Ratio) are essential for field troubleshooting:

ValueMeaningWhat to do
RSSI > -90 dBmStrong signalGood — room to reduce SF or TX power to save battery
RSSI -90 to -110 dBmModerate signalAcceptable — normal operating range for LoRa
RSSI -110 to -130 dBmWeak signalIncrease SF or TX power; check antenna; adjust node placement
RSSI < -130 dBmVery weak / near limitMaximum SF12; consider relay node; antenna upgrade
SNR > 0 dBSignal above noise floorComfortable margin
SNR -5 to 0 dBSignal near noise floorMarginal — packet loss likely under varying conditions
SNR < -10 dBBelow noise floorLoRa can still decode (up to -20 dB margin) — but unreliable

Bench Test Before Meshtastic

Before adding batteries, enclosures, or a mesh, prove that the radio link works on the bench. Put the antennas a short distance apart, send numbered messages in both directions, and watch for missing sequence numbers. Then move one node farther away and repeat.

Test record:
  node A firmware / library version:
  node B firmware / library version:
  regional band:
  antenna type and orientation:
  message count sent:
  message count received:
  RSSI range:
  SNR range:
  supply voltage under transmit:

Do not judge a link only by RSSI. A strong-looking signal with a mismatched packet format still carries no usable data, and a lower RSSI with a stable SNR may be perfectly serviceable.

Power Consumption

Pico + SX1262 approximate current draw:

Mode            | Current  | Notes
----------------|----------|----------------------------------
Transmit (22dBm)| 120 mA   | Worst case; typical TX is brief
Receive         | 6 mA     | Continuously listening
Sleep (Pico+SX) | 0.5 mA   | Deep sleep both chips
Pico sleep only | 1.3 mA   | SX1262 still running

For battery-powered field nodes:
  - Transmit once per minute, sleep the rest: ~1-2 mA average
  - 2500 mAh battery → ~50-100 days battery life
  - Add a small solar panel + LiPo charger for indefinite operation

Transmit current is a peak, not the whole battery calculation. Measure the regulator output during transmission, include the sleep current of every sensor and charger, and leave capacity for cold weather and battery ageing. A power bank that shuts off at low current is not suitable for a node that sleeps most of the time.

The current table is an approximate RP2040-era reference, not a promise for every Pico revision. Pico W, Pico 2, and Pico 2 W have different wireless and MCU power characteristics. Measure the assembled board in its actual operating modes before sizing a field battery.

References