diff --git a/boards/seeed_wio_tracker_l2.json b/boards/seeed_wio_tracker_l2.json new file mode 100644 index 00000000..706ed4c1 --- /dev/null +++ b/boards/seeed_wio_tracker_l2.json @@ -0,0 +1,43 @@ +{ + "build": { + "arduino": { + "ldscript": "esp32s3_out.ld", + "memory_type": "qio_opi", + "partitions": "default_16MB.csv" + }, + "core": "esp32", + "extra_flags": [ + "-DBOARD_HAS_PSRAM", + "-DARDUINO_USB_CDC_ON_BOOT=1", + "-DARDUINO_USB_MODE=1", + "-DARDUINO_RUNNING_CORE=1", + "-DARDUINO_EVENT_RUNNING_CORE=1" + ], + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "psram_type": "opi", + "hwids": [["0x303A", "0x1001"]], + "mcu": "esp32s3", + "variant": "esp32s3" + }, + "connectivity": ["wifi", "bluetooth", "lora"], + "debug": { + "default_tool": "esp-builtin", + "onboard_tools": ["esp-builtin"], + "openocd_target": "esp32s3.cfg" + }, + "frameworks": ["arduino"], + "name": "Seeed Wio Tracker L2 (16 MB flash, 8 MB OPI PSRAM)", + "upload": { + "flash_size": "16MB", + "maximum_ram_size": 327680, + "maximum_size": 16777216, + "use_1200bps_touch": true, + "wait_for_upload_port": true, + "require_upload_port": true, + "speed": 921600 + }, + "url": "https://www.seeedstudio.com/", + "vendor": "Seeed Studio" +} diff --git a/solo/wio-tracker-l2/platformio.ini b/solo/wio-tracker-l2/platformio.ini new file mode 100644 index 00000000..b0070340 --- /dev/null +++ b/solo/wio-tracker-l2/platformio.ini @@ -0,0 +1,37 @@ +; Solo build for Seeed Wio Tracker L2 -- extends the board base defined in +; variants/wio-tracker-l2/platformio.ini. Solo configs live in their own +; top-level solo/ folder, separate from the shared upstream board variants. +; +; BRING-UP ONLY: this env runs the existing ui-new (OLED-era, joystick-driven) +; UI zoomed 2x (160x120 logical on the 320x240 panel) purely to compile-test +; and smoke-test the board layer -- display, radio, GPS, battery. It has no +; touch input yet; the only control is the BOOT button. The real interface for +; this board is the planned LVGL frontend over a shared UI Core. +; +; Deliberately NOT named *_solo_dual yet, so build-solo-firmwares.yml doesn't +; publish it as a release artifact. +[env:Wio_Tracker_L2_companion_solo_bringup] +extends = Wio_Tracker_L2 +build_flags = + ${Wio_Tracker_L2.build_flags} + -I examples/companion_radio/ui-new + -D DISPLAY_CLASS=WioTrackerL2Display + -D UI_ZOOM=2 + -D MAX_CONTACTS=350 + -D MAX_GROUP_CHANNELS=40 + -D BLE_PIN_CODE=123456 + -D DUAL_SERIAL=1 + -D OFFLINE_QUEUE_SIZE=256 + -D FIRMWARE_SOLO_BUILD=1 + -D MESHCORE_VERSION='"1.17.1"' + -D OLED_MISC_FIXED_FONT=1 + -D AUTO_OFF_MILLIS=60000 +build_src_filter = ${Wio_Tracker_L2.build_src_filter} + + + + + + + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-new/*.cpp> +lib_deps = + ${Wio_Tracker_L2.lib_deps} + densaugeo/base64 @ ~1.4.0 diff --git a/variants/wio-tracker-l2/WioTrackerL2Board.cpp b/variants/wio-tracker-l2/WioTrackerL2Board.cpp new file mode 100644 index 00000000..edeaacce --- /dev/null +++ b/variants/wio-tracker-l2/WioTrackerL2Board.cpp @@ -0,0 +1,204 @@ +#include "WioTrackerL2Board.h" + +// TCA9535 register map +static const uint8_t TCA_REG_OUTPUT0 = 0x02; +static const uint8_t TCA_REG_OUTPUT1 = 0x03; +static const uint8_t TCA_REG_CONFIG0 = 0x06; // 1 = input, 0 = output +static const uint8_t TCA_REG_CONFIG1 = 0x07; + +// ADS1115 registers / config bits +static const uint8_t ADS_REG_CONVERSION = 0x00; +static const uint8_t ADS_REG_CONFIG = 0x01; +// OS=1 (start single shot) | MUX=100 (AIN0 vs GND) | PGA=001 (+/-4.096V) +// | MODE=1 (single shot) | DR=100 (128 SPS) | COMP_QUE=11 (disabled) +static const uint16_t ADS_CFG_BATT = 0x8000 | 0x4000 | 0x0200 | 0x0100 | 0x0080 | 0x0003; +// +/-4.096V FSR -> 125uV/LSB; battery is behind a x2 divider -> 0.25 mV/LSB +static const float ADS_MV_PER_LSB = 0.125f * 2.0f; + +bool WioTrackerL2Board::expWriteReg(uint8_t reg, uint8_t val) { + Wire.beginTransmission(TCA9535_ADDR); + Wire.write(reg); + Wire.write(val); + return Wire.endTransmission() == 0; +} + +void WioTrackerL2Board::expSetOutput(uint8_t pin, bool initial_level) { + uint8_t port = pin >> 3, bit = pin & 7; + // set desired level first so the pin doesn't glitch when direction flips + if (initial_level) out_shadow[port] |= (1 << bit); + else out_shadow[port] &= ~(1 << bit); + expWriteReg(port ? TCA_REG_OUTPUT1 : TCA_REG_OUTPUT0, out_shadow[port]); + + cfg_shadow[port] &= ~(1 << bit); // 0 = output + expWriteReg(port ? TCA_REG_CONFIG1 : TCA_REG_CONFIG0, cfg_shadow[port]); +} + +void WioTrackerL2Board::expSetInput(uint8_t pin) { + uint8_t port = pin >> 3, bit = pin & 7; + cfg_shadow[port] |= (1 << bit); + expWriteReg(port ? TCA_REG_CONFIG1 : TCA_REG_CONFIG0, cfg_shadow[port]); +} + +void WioTrackerL2Board::expWritePin(uint8_t pin, bool level) { + uint8_t port = pin >> 3, bit = pin & 7; + if (level) out_shadow[port] |= (1 << bit); + else out_shadow[port] &= ~(1 << bit); + expWriteReg(port ? TCA_REG_OUTPUT1 : TCA_REG_OUTPUT0, out_shadow[port]); +} + +// Power-up sequence mirrors Seeed's reference firmware for this board +// (order and delays matter, especially the LCD reset settle time). +bool WioTrackerL2Board::initExpander() { + Wire.beginTransmission(TCA9535_ADDR); + if (Wire.endTransmission() != 0) { + return false; // expander not responding + } + + expSetInput(EXP_PIN_WAKE_BTN); + expSetInput(EXP_PIN_I2C_IRQ); + expSetInput(EXP_PIN_SD_DETECT); + + expSetOutput(EXP_PIN_OTG_EN, LOW); + delay(10); + expSetOutput(EXP_PIN_PA_EN, LOW); // amp only powered while a tone plays + delay(10); + expSetOutput(EXP_PIN_TF_EN, HIGH); + delay(10); + expSetOutput(EXP_PIN_BAT_ADC_EN, HIGH); + delay(10); + expSetOutput(EXP_PIN_GNSS_EN, HIGH); + delay(10); + // GNSS reset is active HIGH; hold 10ms then release LOW so the L76K runs + expSetOutput(EXP_PIN_GNSS_RST, HIGH); + delay(10); + expWritePin(EXP_PIN_GNSS_RST, LOW); + // user LED is driven active-low through the expander; idle level HIGH = off + expSetOutput(EXP_PIN_USER_LED, HIGH); + delay(10); + expSetOutput(EXP_PIN_GROVE_EN, HIGH); + delay(10); + + expSetOutput(EXP_PIN_LCD_EN, HIGH); + delay(50); + expSetOutput(EXP_PIN_LCD_RST, HIGH); + delay(5); + expWritePin(EXP_PIN_LCD_RST, LOW); + delay(10); + expWritePin(EXP_PIN_LCD_RST, HIGH); + delay(500); // NV3031B needs a long settle after reset before init commands + expSetOutput(EXP_PIN_LCD_CS, HIGH); + delay(10); + + // GT911 touch reset sequence: INT low during reset selects I2C addr 0x5D + expSetOutput(EXP_PIN_TP_RST, LOW); + expSetOutput(EXP_PIN_TP_INT, LOW); + delay(10); + expWritePin(EXP_PIN_TP_RST, HIGH); + delay(60); + + // capture WAKE button idle level (polarity unknown on alpha hardware) + int inputs = expReadInputs(); + wake_btn_baseline = inputs >= 0 ? (uint8_t)(inputs & 1) : 0; + + return true; +} + +void WioTrackerL2Board::begin() { + // GNSS UART: NMEA arrives at ~500 B/s and the main loop can stall for + // hundreds of ms on SD tile decodes; the 256-byte default overflowed + Serial1.setRxBufferSize(1024); + + uint32_t t0 = millis(); + while (!Serial && millis() - t0 < 3000) { delay(50); } + MESH_DEBUG_PRINTLN("WioTrackerL2Board: ESP32Board init"); + + ESP32Board::begin(); // starts Wire on PIN_BOARD_SDA/PIN_BOARD_SCL (47/48) + + pinMode(PIN_USER_BTN, INPUT_PULLUP); + pinMode(P_LORA_MISO, INPUT_PULLUP); + + MESH_DEBUG_PRINTLN("WioTrackerL2Board: TCA9535 expander init"); + expander_ok = initExpander(); + if (!expander_ok) { + Serial.println("ERROR: TCA9535 IO expander not found - peripherals unpowered!"); + } + + Wire.beginTransmission(0x22); + aw_ok = Wire.endTransmission() == 0; + MESH_DEBUG_PRINTLN("WioTrackerL2Board: init done"); + + esp_reset_reason_t reason = esp_reset_reason(); + if (reason == ESP_RST_DEEPSLEEP) { + long wakeup_source = esp_sleep_get_ext1_wakeup_status(); + if (wakeup_source & (1 << P_LORA_DIO_1)) { + startup_reason = BD_STARTUP_RX_PACKET; // LoRa packet woke us from deep sleep + } + rtc_gpio_hold_dis((gpio_num_t)P_LORA_NSS); + rtc_gpio_deinit((gpio_num_t)P_LORA_DIO_1); + } +} + +void WioTrackerL2Board::setLed(bool on) { + // P10 doubles as GNSS wakeup and idles HIGH; blink = brief LOW pulses so + // the GPS never sees a sustained low level + if (expander_ok) { + expWritePin(EXP_PIN_USER_LED, !on); + } +} + +int WioTrackerL2Board::expReadInputs() { + Wire.beginTransmission(TCA9535_ADDR); + Wire.write((uint8_t)0x00); // input port 0 register + if (Wire.endTransmission() != 0) return -1; + if (Wire.requestFrom((int)TCA9535_ADDR, 2) != 2) return -1; + int lo = Wire.read(); + int hi = Wire.read(); + return lo | (hi << 8); +} + +bool WioTrackerL2Board::isExternalPowered() { + if (!aw_ok) return false; + Wire.beginTransmission(0x22); + Wire.write((uint8_t)0x40); // STATUS0 + if (Wire.endTransmission() != 0) return false; + if (Wire.requestFrom(0x22, 1) != 1) return false; + return (Wire.read() & 0x80) != 0; // VBUSOK bit +} + +bool WioTrackerL2Board::readWakeButton() { + if (!expander_ok) return false; + int v = expReadInputs(); + if (v < 0) return false; + return ((uint8_t)(v & 1)) != wake_btn_baseline; +} + +int16_t WioTrackerL2Board::adsReadRaw() { + Wire.beginTransmission(ADS1115_ADDR); + Wire.write(ADS_REG_CONFIG); + Wire.write((uint8_t)(ADS_CFG_BATT >> 8)); + Wire.write((uint8_t)(ADS_CFG_BATT & 0xFF)); + if (Wire.endTransmission() != 0) return -1; + + delay(10); // 128 SPS -> ~8ms conversion time + + Wire.beginTransmission(ADS1115_ADDR); + Wire.write(ADS_REG_CONVERSION); + if (Wire.endTransmission() != 0) return -1; + if (Wire.requestFrom((int)ADS1115_ADDR, 2) != 2) return -1; + + // sequence the two reads explicitly: operand evaluation order of <<| + // is unspecified and each read dequeues a byte + uint8_t hi = Wire.read(); + uint8_t lo = Wire.read(); + int16_t raw = ((int16_t)hi << 8) | lo; + return raw < 0 ? 0 : raw; +} + +uint16_t WioTrackerL2Board::getBattMilliVolts() { + if (!expander_ok) return 0; // BAT_ADC_EN rail never came up + + int16_t raw = adsReadRaw(); + if (raw < 0) return 0; + + return (uint16_t)(raw * ADS_MV_PER_LSB); +} diff --git a/variants/wio-tracker-l2/WioTrackerL2Board.h b/variants/wio-tracker-l2/WioTrackerL2Board.h new file mode 100644 index 00000000..c5644e2f --- /dev/null +++ b/variants/wio-tracker-l2/WioTrackerL2Board.h @@ -0,0 +1,106 @@ +#pragma once + +#include +#include +#include "helpers/ESP32Board.h" + +// --------------------------------------------------------------------------- +// Seeed Wio Tracker L2 Pro (Wio-S3 module: ESP32-S3 + SX1262) +// +// Nearly all peripheral power rails and reset lines are behind a TCA9535 +// 16-bit I2C IO expander at address 0x21. Nothing (GNSS, LCD, touch, SD, +// battery ADC, speaker amp) works until the expander is configured, so +// begin() must run before any display / GPS / sensor init. +// +// Battery voltage is read through an ADS1115 16-bit I2C ADC at 0x48, +// channel AIN0, behind a x2 resistive divider (rail gated by expander). +// --------------------------------------------------------------------------- + +#define TCA9535_ADDR 0x21 +#define ADS1115_ADDR 0x48 + +// TCA9535 pin numbering: 0..7 = port 0 (P00..P07), 8..15 = port 1 (P10..P17) +#define EXP_PIN_WAKE_BTN 0 // input - side WAKE button +#define EXP_PIN_I2C_IRQ 1 // input - shared I2C IRQ +#define EXP_PIN_SD_DETECT 2 // input - microSD card detect +#define EXP_PIN_TP_INT 3 // output - touch panel interrupt (driven for reset seq) +#define EXP_PIN_LCD_CS 4 // output - LCD chip select (idle high) +#define EXP_PIN_LCD_EN 5 // output - LCD power enable +#define EXP_PIN_LCD_RST 6 // output - LCD reset +#define EXP_PIN_GROVE_EN 7 // output - Grove port power +#define EXP_PIN_TP_RST 8 // output - touch panel reset +#define EXP_PIN_GNSS_RST 9 // output - GNSS reset (active HIGH) +#define EXP_PIN_USER_LED 10 // output - mesh/user LED (also GNSS wakeup) +#define EXP_PIN_OTG_EN 11 // output - USB OTG power +#define EXP_PIN_PA_EN 12 // output - speaker amp power +#define EXP_PIN_GNSS_EN 13 // output - GNSS power +#define EXP_PIN_TF_EN 14 // output - microSD power +#define EXP_PIN_BAT_ADC_EN 15 // output - battery ADC divider enable + +class WioTrackerL2Board : public ESP32Board { +public: + void begin(); + + uint16_t getBattMilliVolts() override; + + const char* getManufacturerName() const override { + return "Seeed Wio Tracker L2 Pro"; + } + + void onBeforeTransmit() override { setLed(true); } + void onAfterTransmit() override { setLed(false); } + + // Mesh/user LED lives on the IO expander, not a GPIO + void setLed(bool on); + + // speaker amplifier power (expander P12); off when idle to keep the GNSS + // antenna away from class-D switching noise and to save battery + void setSpeakerAmp(bool on) { expWritePin(EXP_PIN_PA_EN, on); } + + // hardware reset pulse to the L76K GNSS (active HIGH on this board); the + // module keeps almanac/ephemeris across it, so this is a warm restart + // GNSS rail: off saves the whole receiver when GPS is disabled; on re-runs + // the power-up reset so the module comes back cleanly + void setGnssPower(bool on) { + if (on) { + expWritePin(EXP_PIN_GNSS_EN, HIGH); + delay(10); + gnssReset(); + } else { + expWritePin(EXP_PIN_GNSS_EN, LOW); + } + } + // Grove expansion port rail (nothing on-board depends on it) + void setGrovePower(bool on) { expWritePin(EXP_PIN_GROVE_EN, on); } + + void gnssReset() { + expWritePin(EXP_PIN_GNSS_RST, HIGH); + delay(10); + expWritePin(EXP_PIN_GNSS_RST, LOW); + } + + // WAKE button on expander P00: pressed = level differs from boot baseline + bool readWakeButton(); + + // VBUS presence via the AW35615 USB-C controller (I2C 0x22) + bool isExternalPowered() override; + + bool expanderOK() const { return expander_ok; } + +private: + uint8_t out_shadow[2] = { 0xFF, 0xFF }; // TCA9535 output regs default high + uint8_t cfg_shadow[2] = { 0xFF, 0xFF }; // 1 = input (power-on default) + bool expander_ok = false; + bool aw_ok = false; // AW35615 USB-C controller responded at probe + uint8_t wake_btn_baseline = 0; // idle level of P00, captured at init + + int expReadInputs(); // 16-bit input register pair, -1 on error + + bool expWriteReg(uint8_t reg, uint8_t val); + void expSetOutput(uint8_t pin, bool initial_level); + void expSetInput(uint8_t pin); + void expWritePin(uint8_t pin, bool level); + bool initExpander(); + + int16_t adsReadRaw(); +}; diff --git a/variants/wio-tracker-l2/WioTrackerL2Display.h b/variants/wio-tracker-l2/WioTrackerL2Display.h new file mode 100644 index 00000000..299df949 --- /dev/null +++ b/variants/wio-tracker-l2/WioTrackerL2Display.h @@ -0,0 +1,199 @@ +#pragma once + +#include +#include + +#define LGFX_USE_V1 +#include + +// --------------------------------------------------------------------------- +// Wio Tracker L2 Pro display stack: +// - NV3031B 320x240 panel on quad-SPI (SCLK 42, IO0-3 = 41/40/39/38, CS 46) +// - GT911 capacitive touch on I2C 0x5D (SDA 47 / SCL 48) +// - LP5814 4-channel LED driver on I2C 0x2C used as backlight +// Panel power/reset lines are on the TCA9535 expander and are already +// sequenced by WioTrackerL2Board::begin() before this driver initializes. +// --------------------------------------------------------------------------- + +#ifndef L2_SPI_FREQUENCY + #define L2_SPI_FREQUENCY 75000000 +#endif + +#define LP5814_I2C_ADDR 0x2C + +// LP5814 used as backlight controller (all 4 channels in parallel) +class WioTrackerL2Backlight : public lgfx::v1::ILight { + static constexpr uint8_t REG_DEVICE_CONFIG0 = 0x00; + static constexpr uint8_t REG_MAX_CURRENT = 0x01; + static constexpr uint8_t REG_ENABLE_CONTROL = 0x02; + static constexpr uint8_t REG_DIM_MODE = 0x04; + static constexpr uint8_t REG_ENGINE_MODE = 0x05; + static constexpr uint8_t REG_UPDATE = 0x0F; + static constexpr uint8_t REG_LED0_DC = 0x14; + static constexpr uint8_t REG_LED0_PWM = 0x18; + + uint8_t _brightness = 153; // 60% + + void writeReg(uint8_t reg, uint8_t value) { + Wire.beginTransmission(LP5814_I2C_ADDR); + Wire.write(reg); + Wire.write(value); + Wire.endTransmission(); + } + +public: + bool init(uint8_t brightness) override { + Wire.beginTransmission(LP5814_I2C_ADDR); + if (Wire.endTransmission() != 0) { + return false; // LP5814 not found + } + + writeReg(REG_DEVICE_CONFIG0, 0x01); // chip enable + writeReg(REG_MAX_CURRENT, 0x01); // 51 mA max current + writeReg(REG_ENABLE_CONTROL, 0x00); // outputs off while configuring + writeReg(REG_DIM_MODE, 0x4E); + writeReg(REG_ENGINE_MODE, 0xF0); + for (uint8_t i = 0; i < 4; i++) { + writeReg(REG_LED0_DC + i, 200); + } + writeReg(REG_ENABLE_CONTROL, 0x0F); // enable all 4 channels + writeReg(REG_UPDATE, 0x55); // latch (LP5814 requires 0x55) + delay(5); + + setBrightness(brightness); + return true; + } + + void setBrightness(uint8_t brightness) override { + for (uint8_t i = 0; i < 4; i++) { + writeReg(REG_LED0_PWM + i, brightness); + } + _brightness = brightness; + } + + uint8_t getBrightness() const { return _brightness; } + + virtual ~WioTrackerL2Backlight() = default; +}; + +class LGFX_WioTrackerL2 : public lgfx::LGFX_Device { + lgfx::Panel_NV3031B _panel_instance; + lgfx::Bus_SPI _bus_instance; + lgfx::Touch_GT911 _touch_instance; + WioTrackerL2Backlight _light_instance; + +public: + bool init_impl(bool use_reset, bool use_clear) override { + // bring up backlight controller while the I2C bus is still clean + _light_instance.init(_light_instance.getBrightness()); + + bool result = LGFX_Device::init_impl(use_reset, use_clear); + + // GT911 probe can leave the ESP32 I2C peripheral with a stuck BUSY flag; + // cycling Wire resets it so later LP5814/sensor traffic doesn't time out + Wire.end(); + Wire.begin(47, 48); + + return result; + } + + LGFX_WioTrackerL2(void) { + { + auto cfg = _bus_instance.config(); + cfg.spi_host = SPI3_HOST; + cfg.spi_mode = 3; + cfg.freq_write = L2_SPI_FREQUENCY; + cfg.freq_read = 16000000; + cfg.pin_sclk = 42; + // quad SPI data pins + cfg.pin_io0 = 41; + cfg.pin_io1 = 40; + cfg.pin_io2 = 39; + cfg.pin_io3 = 38; + _bus_instance.config(cfg); + _panel_instance.setBus(&_bus_instance); + } + + { + auto cfg = _panel_instance.config(); + cfg.pin_cs = 46; + cfg.pin_rst = -1; // reset is on the IO expander, done in board init + cfg.pin_busy = -1; + cfg.panel_width = 240; // native portrait orientation + cfg.panel_height = 320; + cfg.memory_width = 240; + cfg.memory_height = 320; + cfg.offset_x = 0; + cfg.offset_y = 0; + cfg.offset_rotation = 1; // panel mounted landscape (320x240) + cfg.invert = true; + cfg.rgb_order = true; + cfg.dlen_16bit = false; + cfg.bus_shared = false; + _panel_instance.config(cfg); + } + + { + auto cfg = _touch_instance.config(); + cfg.pin_cs = -1; + cfg.x_min = 0; + cfg.x_max = 239; + cfg.y_min = 0; + cfg.y_max = 319; + cfg.pin_int = -1; // INT is on the IO expander + cfg.offset_rotation = 2; + cfg.i2c_port = 0; + cfg.i2c_addr = 0x5D; + cfg.pin_sda = 47; + cfg.pin_scl = 48; + cfg.bus_shared = false; + cfg.freq = 400000; + _touch_instance.config(cfg); + _panel_instance.setTouch(&_touch_instance); + } + + _panel_instance.setLight(&_light_instance); + setPanel(&_panel_instance); + } +}; + +class WioTrackerL2Display : public LGFXDisplay { + LGFX_WioTrackerL2 disp; +public: + WioTrackerL2Display() : LGFXDisplay(320, 240, disp) {} + + // direct access to the LGFX device (LVGL flush/touch glue) + lgfx::LGFX_Device* lgfxDevice() { return &disp; } + + // reliable touch read in logical (UI_ZOOM-scaled) coords; returns false when + // not touched (LGFXDisplay::getTouch reads an uninitialized point on release) + bool readTouch(int& x, int& y) { + lgfx::touch_point_t tp; + if (disp.getTouch(&tp, 1) == 0) return false; + x = tp.x / UI_ZOOM; + y = tp.y / UI_ZOOM; + return true; + } + + // shadows LGFXDisplay::begin() (non-virtual, called on the concrete type in + // main.cpp) - identical except rotation: our panel config already carries + // offset_rotation=1 for the landscape mounting, so no extra rotation here + bool begin() { + turnOn(); + display->init(); + display->setRotation(0); + display->setColorDepth(8); + // The zoomed sprite blit stops a pixel short of the panel edge, so those + // pixels keep whatever the panel powered up with (they showed as coloured + // lines down the right side and along the bottom). Clear the panel once. + display->fillScreen(TFT_BLACK); + display->setBrightness(153); + display->setTextColor(TFT_WHITE); + + buffer.setColorDepth(8); + buffer.setPsram(true); + buffer.createSprite(width(), height()); + + return true; + } +}; diff --git a/variants/wio-tracker-l2/platformio.ini b/variants/wio-tracker-l2/platformio.ini new file mode 100644 index 00000000..711211c4 --- /dev/null +++ b/variants/wio-tracker-l2/platformio.ini @@ -0,0 +1,78 @@ +; Seeed Wio Tracker L2 - Wio-S3 module: ESP32-S3R8 + SX1262 +; Board layer ported from meshcore-dev/MeshCore PR #3381 (Hacuchino-hash), whose +; pin map was derived from Seeed's Meshtastic support branch (meshtastic/firmware +; PR #10909 + device-ui `wio-l2` branch). Pre-release hardware: verify the pin +; map against a real unit. +[Wio_Tracker_L2] +extends = esp32_base +board = seeed_wio_tracker_l2 +; Native USB-Serial/JTAG: the baud rate is virtual (no effect on transfer +; speed); staying at the ROM's 115200 skips esptool's post-stub baud switch, +; one less step to fail on a marginal USB link. +upload_speed = 115200 +build_flags = ${esp32_base.build_flags} + ${sensor_base.build_flags} + -I variants/wio-tracker-l2 + -D SEEED_WIO_TRACKER_L2 + -D PIN_BOARD_SDA=47 + -D PIN_BOARD_SCL=48 + -D PIN_USER_BTN=0 + -D USE_SX1262 + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D P_LORA_NSS=21 + -D P_LORA_RESET=7 + -D P_LORA_BUSY=8 + -D P_LORA_DIO_1=9 + -D P_LORA_SCLK=4 + -D P_LORA_MISO=5 + -D P_LORA_MOSI=6 + -D SX126X_DIO2_AS_RF_SWITCH=true + -D SX126X_DIO3_TCXO_VOLTAGE=1.8 + -D SX126X_CURRENT_LIMIT=140 + -D SX126X_RX_BOOSTED_GAIN=1 + -D ENV_INCLUDE_GPS=1 + -D PIN_GPS_TX=18 ; L76K TX -> ESP32 RX + -D PIN_GPS_RX=17 ; L76K RX <- ESP32 TX + -D GPS_BAUD_RATE=9600 + -D ENV_SKIP_GPS_DETECT=1 ; GPS is always present, powered via IO expander + ; disable ALL env sensor I2C probes: this bus carries six onboard chips + ; (TCA9535 0x21, AW35615 0x22, LP5814 0x2C, ADS1115 0x48, GT911 0x5D, + ; ES8311 0x18) and stray probe matches can hang sensors.begin() + -D ENV_INCLUDE_AHTX0=0 + -D ENV_INCLUDE_BME280=0 + -D ENV_INCLUDE_BMP280=0 + -D ENV_INCLUDE_SHTC3=0 + -D ENV_INCLUDE_SHT4X=0 + -D ENV_INCLUDE_INA3221=0 + -D ENV_INCLUDE_INA219=0 + -D ENV_INCLUDE_INA226=0 + -D ENV_INCLUDE_INA260=0 + -D ENV_INCLUDE_MLX90614=0 + -D ENV_INCLUDE_VL53L0X=0 + -D ENV_INCLUDE_BME680=0 + -D ENV_INCLUDE_BMP085=0 + -D ENV_INCLUDE_LPS22HB=0 +build_src_filter = ${esp32_base.build_src_filter} + +<../variants/wio-tracker-l2> + + +lib_deps = + ${esp32_base.lib_deps} + ${sensor_base.lib_deps} + lovyan03/LovyanGFX @ ^1.2.30 ; >=1.2.30 defines Panel_NV3031B::init_cmds itself (PR #3381 needed an ODR fix for older) + +[env:Wio_Tracker_L2_repeater] +extends = Wio_Tracker_L2 +build_flags = + ${Wio_Tracker_L2.build_flags} + -D ADVERT_NAME='"WioL2 Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=50 +build_src_filter = ${Wio_Tracker_L2.build_src_filter} + +<../examples/simple_repeater/*.cpp> +lib_deps = + ${Wio_Tracker_L2.lib_deps} + ${esp32_ota.lib_deps} diff --git a/variants/wio-tracker-l2/target.cpp b/variants/wio-tracker-l2/target.cpp new file mode 100644 index 00000000..b1dfefaf --- /dev/null +++ b/variants/wio-tracker-l2/target.cpp @@ -0,0 +1,34 @@ +#include +#include "target.h" + +WioTrackerL2Board board; + +static SPIClass spi; +RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); + +WRAPPER_CLASS radio_driver(radio, board); + +ESP32RTCClock fallback_clock; +AutoDiscoverRTCClock rtc_clock(fallback_clock); +MicroNMEALocationProvider gps(Serial1, &rtc_clock); +EnvironmentSensorManager sensors(gps); + +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display; + MomentaryButton user_btn(PIN_USER_BTN, 1000, true, true); +#endif + +bool radio_init() { + MESH_DEBUG_PRINTLN("radio_init: rtc + sx1262 init"); + fallback_clock.begin(); + rtc_clock.begin(Wire); // Wire already running on 47/48 from board.begin() + + bool ok = radio.std_init(&spi); + MESH_DEBUG_PRINTLN("radio_init: SX1262 %s", ok ? "OK" : "FAILED"); + return ok; +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} diff --git a/variants/wio-tracker-l2/target.h b/variants/wio-tracker-l2/target.h new file mode 100644 index 00000000..d08701ab --- /dev/null +++ b/variants/wio-tracker-l2/target.h @@ -0,0 +1,28 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include "WioTrackerL2Board.h" +#include +#include +#include +#include +#ifdef DISPLAY_CLASS + #include "WioTrackerL2Display.h" + #include +#endif + +extern WioTrackerL2Board board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; +extern EnvironmentSensorManager sensors; + +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; + extern MomentaryButton user_btn; +#endif + +bool radio_init(); +mesh::LocalIdentity radio_new_identity();