From 8f6b2b75d7cfd1dace9eea34cac73ce33de14e4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Br=C3=A1zio?= Date: Sun, 15 Jun 2025 23:48:49 +0100 Subject: [PATCH] Waveshare RP2040-LoRa board support --- platformio.ini | 2 + src/helpers/rp2040/WaveshareBoard.cpp | 29 +++++ src/helpers/rp2040/WaveshareBoard.h | 65 +++++++++++ variants/picow/platformio.ini | 2 +- variants/waveshare_rp2040_lora/platformio.ini | 107 ++++++++++++++++++ variants/waveshare_rp2040_lora/target.cpp | 81 +++++++++++++ variants/waveshare_rp2040_lora/target.h | 21 ++++ 7 files changed, 306 insertions(+), 1 deletion(-) create mode 100644 src/helpers/rp2040/WaveshareBoard.cpp create mode 100644 src/helpers/rp2040/WaveshareBoard.h create mode 100644 variants/waveshare_rp2040_lora/platformio.ini create mode 100644 variants/waveshare_rp2040_lora/target.cpp create mode 100644 variants/waveshare_rp2040_lora/target.h diff --git a/platformio.ini b/platformio.ini index 2c3ffd83..ad3ce4eb 100644 --- a/platformio.ini +++ b/platformio.ini @@ -70,6 +70,8 @@ lib_deps = [rp2040_base] extends = arduino_base +platform = https://github.com/maxgerhardt/platform-raspberrypi.git +board_build.core = earlephilhower build_flags = ${arduino_base.build_flags} -D RP2040_PLATFORM diff --git a/src/helpers/rp2040/WaveshareBoard.cpp b/src/helpers/rp2040/WaveshareBoard.cpp new file mode 100644 index 00000000..f4154dbe --- /dev/null +++ b/src/helpers/rp2040/WaveshareBoard.cpp @@ -0,0 +1,29 @@ +#include "WaveshareBoard.h" + +#include +#include + +void WaveshareBoard::begin() { + // for future use, sub-classes SHOULD call this from their begin() + startup_reason = BD_STARTUP_NORMAL; + +#ifdef PIN_LED_BUILTIN + pinMode(PIN_LED_BUILTIN, OUTPUT); +#endif + +#ifdef PIN_VBAT_READ + pinMode(PIN_VBAT_READ, INPUT); +#endif + +#if defined(PIN_BOARD_SDA) && defined(PIN_BOARD_SCL) + Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL); +#endif + + Wire.begin(); + + delay(10); // give sx1262 some time to power up +} + +bool WaveshareBoard::startOTAUpdate(const char *id, char reply[]) { + return false; +} diff --git a/src/helpers/rp2040/WaveshareBoard.h b/src/helpers/rp2040/WaveshareBoard.h new file mode 100644 index 00000000..0aa136ab --- /dev/null +++ b/src/helpers/rp2040/WaveshareBoard.h @@ -0,0 +1,65 @@ +#pragma once + +#include +#include + +// LoRa radio module pins for Waveshare RP2040-LoRa-HF/LF +// https://files.waveshare.com/wiki/RP2040-LoRa/Rp2040-lora-sch.pdf + +#define P_LORA_DIO_1 16 +#define P_LORA_NSS 13 // CS +#define P_LORA_RESET 23 +#define P_LORA_BUSY 18 +#define P_LORA_SCLK 14 +#define P_LORA_MISO 24 +#define P_LORA_MOSI 15 + +#define SX126X_DIO2_AS_RF_SWITCH true +#define SX126X_DIO3_TCXO_VOLTAGE 0 + +// built-ins +#define PIN_LED_BUILTIN 25 + +// This board has no built-in way to read battery voltage +// #define PIN_VBAT_READ 26 +// #define BATTERY_SAMPLES 8 +// #define ADC_MULTIPLIER (3.1 * 3.3 * 1000) // MT Uses 3.1 + +class WaveshareBoard : public mesh::MainBoard { +protected: + uint8_t startup_reason; + +public: + void begin(); + uint8_t getStartupReason() const override { return startup_reason; } + + void onBeforeTransmit() override { + digitalWrite(PIN_LED_BUILTIN, HIGH); // turn TX LED on + } + + void onAfterTransmit() override { + digitalWrite(PIN_LED_BUILTIN, LOW); // turn TX LED off + } + + uint16_t getBattMilliVolts() override { +#if defined(PIN_VBAT_READ) && defined(ADC_MULTIPLIER) + analogReadResolution(12); + + uint32_t raw = 0; + for (int i = 0; i < BATTERY_SAMPLES; i++) { + raw += analogRead(PIN_VBAT_READ); + } + raw = raw / BATTERY_SAMPLES; + + return (ADC_MULTIPLIER * raw) / 4096; +#else + return 0; +#endif + } + + const char *getManufacturerName() const override { return "Waveshare RP2040-LoRa"; } + + void reboot() override { rp2040.reboot(); } + + bool startOTAUpdate(const char *id, char reply[]) override; +}; diff --git a/variants/picow/platformio.ini b/variants/picow/platformio.ini index 0e925486..8b6c2506 100644 --- a/variants/picow/platformio.ini +++ b/variants/picow/platformio.ini @@ -14,7 +14,7 @@ build_flags = ${rp2040_base.build_flags} -D LORA_TX_POWER=22 -D SX126X_RX_BOOSTED_GAIN=1 build_src_filter = ${rp2040_base.build_src_filter} - + + + +<../variants/picow> lib_deps = ${rp2040_base.lib_deps} diff --git a/variants/waveshare_rp2040_lora/platformio.ini b/variants/waveshare_rp2040_lora/platformio.ini new file mode 100644 index 00000000..e84e57ad --- /dev/null +++ b/variants/waveshare_rp2040_lora/platformio.ini @@ -0,0 +1,107 @@ +; Waveshare RP2040-LoRa-HF/LF +; https://files.waveshare.com/wiki/RP2040-LoRa/Rp2040-lora-sch.pdf + +[waveshare_rp2040_lora] +extends = rp2040_base + +board = pico +board_build.filesystem_size = 0.5m + +build_flags = ${rp2040_base.build_flags} + -I variants/waveshare_rp2040_lora + -D SX126X_CURRENT_LIMIT=130 + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D SX126X_RX_BOOSTED_GAIN=1 +; Debug options + ; -D DEBUG_RP2040_WIRE=1 + ; -D DEBUG_RP2040_SPI=1 + ; -D DEBUG_RP2040_CORE=1 + ; -D RADIOLIB_DEBUG_SPI=1 + ; -D DEBUG_RP2040_PORT=Serial + +build_src_filter = ${rp2040_base.build_src_filter} + + + +<../variants/waveshare_rp2040_lora> + +lib_deps = ${rp2040_base.lib_deps} + +[env:waveshare_rp2040_lora_Repeater] +extends = waveshare_rp2040_lora +build_flags = ${waveshare_rp2040_lora.build_flags} + -D ADVERT_NAME='"Waveshare RP2040-LoRa Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=8 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${waveshare_rp2040_lora.build_src_filter} + +<../examples/simple_repeater> + +[env:waveshare_rp2040_lora_room_server] +extends = waveshare_rp2040_lora +build_flags = ${waveshare_rp2040_lora.build_flags} + -D ADVERT_NAME='"Test Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${waveshare_rp2040_lora.build_src_filter} + +<../examples/simple_room_server> + +[env:waveshare_rp2040_lora_companion_radio_usb] +extends = waveshare_rp2040_lora +build_flags = ${waveshare_rp2040_lora.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=8 +; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 +; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 +build_src_filter = ${waveshare_rp2040_lora.build_src_filter} + +<../examples/companion_radio> +lib_deps = ${waveshare_rp2040_lora.lib_deps} + densaugeo/base64 @ ~1.4.0 + +; [env:waveshare_rp2040_lora_companion_radio_ble] +; extends = waveshare_rp2040_lora +; build_flags = ${waveshare_rp2040_lora.build_flags} +; -D MAX_CONTACTS=100 +; -D MAX_GROUP_CHANNELS=8 +; -D BLE_PIN_CODE=123456 +; -D BLE_DEBUG_LOGGING=1 +; ; -D MESH_PACKET_LOGGING=1 +; ; -D MESH_DEBUG=1 +; build_src_filter = ${waveshare_rp2040_lora.build_src_filter} +; +<../examples/companion_radio> +; lib_deps = ${waveshare_rp2040_lora.lib_deps} +; densaugeo/base64 @ ~1.4.0 + +; [env:waveshare_rp2040_lora_companion_radio_wifi] +; extends = waveshare_rp2040_lora +; build_flags = ${waveshare_rp2040_lora.build_flags} +; -D MAX_CONTACTS=100 +; -D MAX_GROUP_CHANNELS=8 +; -D WIFI_DEBUG_LOGGING=1 +; -D WIFI_SSID='"myssid"' +; -D WIFI_PWD='"mypwd"' +; ; -D MESH_PACKET_LOGGING=1 +; ; -D MESH_DEBUG=1 +; build_src_filter = ${waveshare_rp2040_lora.build_src_filter} +; +<../examples/companion_radio> +; lib_deps = ${waveshare_rp2040_lora.lib_deps} +; densaugeo/base64 @ ~1.4.0 + +[env:waveshare_rp2040_lora_terminal_chat] +extends = waveshare_rp2040_lora +build_flags = ${waveshare_rp2040_lora.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${waveshare_rp2040_lora.build_src_filter} + +<../examples/simple_secure_chat/main.cpp> +lib_deps = ${waveshare_rp2040_lora.lib_deps} + densaugeo/base64 @ ~1.4.0 diff --git a/variants/waveshare_rp2040_lora/target.cpp b/variants/waveshare_rp2040_lora/target.cpp new file mode 100644 index 00000000..895f6db2 --- /dev/null +++ b/variants/waveshare_rp2040_lora/target.cpp @@ -0,0 +1,81 @@ +#include "target.h" + +#include +#include + +WaveshareBoard board; + +RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI1); +WRAPPER_CLASS radio_driver(radio, board); + +VolatileRTCClock fallback_clock; +AutoDiscoverRTCClock rtc_clock(fallback_clock); +SensorManager sensors; + +#ifndef LORA_CR +#define LORA_CR 5 +#endif + +bool radio_init() { + rtc_clock.begin(Wire); + +#ifdef SX126X_DIO3_TCXO_VOLTAGE + float tcxo = SX126X_DIO3_TCXO_VOLTAGE; +#else + float tcxo = 1.6f; +#endif + + SPI1.setSCK(P_LORA_SCLK); + SPI1.setTX(P_LORA_MOSI); + SPI1.setRX(P_LORA_MISO); + + pinMode(P_LORA_NSS, OUTPUT); + digitalWrite(P_LORA_NSS, HIGH); + + SPI1.begin(false); + + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, + LORA_TX_POWER, 8, tcxo); + + if (status != RADIOLIB_ERR_NONE) { + Serial.print("ERROR: radio init failed: "); + Serial.println(status); + return false; // fail + } + + radio.setCRC(1); + +#ifdef SX126X_CURRENT_LIMIT + radio.setCurrentLimit(SX126X_CURRENT_LIMIT); +#endif + +#ifdef SX126X_DIO2_AS_RF_SWITCH + radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH); +#endif + +#ifdef SX126X_RX_BOOSTED_GAIN + radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN); +#endif + + return true; // success +} + +uint32_t radio_get_rng_seed() { + return radio.random(0x7FFFFFFF); +} + +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { + radio.setFrequency(freq); + radio.setSpreadingFactor(sf); + radio.setBandwidth(bw); + radio.setCodingRate(cr); +} + +void radio_set_tx_power(uint8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} diff --git a/variants/waveshare_rp2040_lora/target.h b/variants/waveshare_rp2040_lora/target.h new file mode 100644 index 00000000..3ebe0570 --- /dev/null +++ b/variants/waveshare_rp2040_lora/target.h @@ -0,0 +1,21 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 + +#include +#include +#include +#include +#include +#include + +extern WaveshareBoard board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; +extern SensorManager sensors; + +bool radio_init(); +uint32_t radio_get_rng_seed(); +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); +void radio_set_tx_power(uint8_t dbm); +mesh::LocalIdentity radio_new_identity();