<!--order=5-->


<h1>Raspberry Pi Pico with Waveshare LoRa HAT</h1>
<p>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.</p>

<h2>The Hardware</h2>

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

<h2>What the Names Mean</h2>
<p>The four names describe two separate choices:</p>
<table>
  <thead><tr><th>Choice</th><th>Original generation</th><th>Second generation</th></tr></thead>
  <tbody>
    <tr><td>Microcontroller</td><td>Pico / Pico W use RP2040</td><td>Pico 2 / Pico 2 W use RP2350</td></tr>
    <tr><td>Wireless</td><td>Pico and Pico 2 have no built-in WiFi/Bluetooth</td><td>The <code>W</code> versions add WiFi/Bluetooth; the LoRa radio is still a separate SX126x device</td></tr>
  </tbody>
</table>
<p>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.</p>
<p>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.</p>

<h2>Pin Connections (SX1262 to Pico)</h2>
<p>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:</p>

<table>
  <thead><tr><th>SX1262 Pin</th><th>Pico GPIO</th><th>Function</th></tr></thead>
  <tbody>
    <tr><td>SCK</td><td>GPIO 10</td><td>SPI clock</td></tr>
    <tr><td>MOSI</td><td>GPIO 11</td><td>SPI data out (Pico → radio)</td></tr>
    <tr><td>MISO</td><td>GPIO 12</td><td>SPI data in (radio → Pico)</td></tr>
    <tr><td>NSS / CS</td><td>GPIO 3</td><td>SPI chip select (active low)</td></tr>
    <tr><td>RST</td><td>GPIO 15</td><td>Reset (active low)</td></tr>
    <tr><td>BUSY</td><td>GPIO 2</td><td>Radio busy signal (wait when high)</td></tr>
    <tr><td>DIO1</td><td>GPIO 20</td><td>Interrupt (TX done, RX done)</td></tr>
    <tr><td>3.3V</td><td>3V3 OUT</td><td>Power</td></tr>
    <tr><td>GND</td><td>GND</td><td>Ground</td></tr>
  </tbody>
</table>

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

<h2>Hardware Checks Before Powering Up</h2>
<p>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:</p>
<ul>
  <li>Confirm whether the board is the 433/470 MHz SX1268 version or the 868/915 MHz SX1262 version.</li>
  <li>Confirm that the antenna is connected before any transmit test.</li>
  <li>Use the HAT's documented power input and never feed 5 V into a 3.3 V GPIO.</li>
  <li>Check the HAT orientation and make sure the header pins are fully seated.</li>
  <li>Keep the radio away from loose metal objects while testing.</li>
</ul>
<p>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.</p>

<h2>MicroPython Setup</h2>
<pre>
# 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*
</pre>

<h2>Waveshare SX1262 MicroPython Library</h2>
<pre>
# 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)
</pre>

<h2>Radio Configuration Is a Contract</h2>
<p>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.</p>
<pre>
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
</pre>
<p>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.</p>

<h2>Receiving</h2>
<pre>
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)
</pre>

<h2>Reading RSSI and SNR</h2>
<p>RSSI (Received Signal Strength Indicator) and SNR (Signal-to-Noise Ratio) are essential for field troubleshooting:</p>

<table>
  <thead><tr><th>Value</th><th>Meaning</th><th>What to do</th></tr></thead>
  <tbody>
    <tr><td>RSSI > -90 dBm</td><td>Strong signal</td><td>Good — room to reduce SF or TX power to save battery</td></tr>
    <tr><td>RSSI -90 to -110 dBm</td><td>Moderate signal</td><td>Acceptable — normal operating range for LoRa</td></tr>
    <tr><td>RSSI -110 to -130 dBm</td><td>Weak signal</td><td>Increase SF or TX power; check antenna; adjust node placement</td></tr>
    <tr><td>RSSI < -130 dBm</td><td>Very weak / near limit</td><td>Maximum SF12; consider relay node; antenna upgrade</td></tr>
    <tr><td>SNR > 0 dB</td><td>Signal above noise floor</td><td>Comfortable margin</td></tr>
    <tr><td>SNR -5 to 0 dB</td><td>Signal near noise floor</td><td>Marginal — packet loss likely under varying conditions</td></tr>
    <tr><td>SNR < -10 dB</td><td>Below noise floor</td><td>LoRa can still decode (up to -20 dB margin) — but unreliable</td></tr>
  </tbody>
</table>

<h2>Bench Test Before Meshtastic</h2>
<p>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.</p>
<pre>
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:
</pre>
<p>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.</p>

<h2>Power Consumption</h2>
<pre>
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
</pre>
<p>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.</p>
<p>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.</p>

<h2>References</h2>
<ul>
  <li><a href="https://www.waveshare.com/wiki/Pico-LoRa-SX1262" target="_blank" rel="noopener">Waveshare Pico-LoRa-SX1262 Wiki ↗</a></li>
  <li><a href="https://micropython.org/download/RPI_PICO/" target="_blank" rel="noopener">MicroPython for Raspberry Pi Pico ↗</a></li>
  <li><a href="https://semtech.com/products/wireless-rf/lora-connect/sx1262" target="_blank" rel="noopener">Semtech SX1262 datasheet ↗</a></li>
</ul>
