diff --git a/boards/t_beams3_supreme.json b/boards/t_beams3_supreme.json new file mode 100644 index 00000000..6a725247 --- /dev/null +++ b/boards/t_beams3_supreme.json @@ -0,0 +1,51 @@ +{ + "build": { + "arduino":{ + "ldscript": "esp32s3_out.ld", + "partitions": "default.csv", + "memory_type": "qio_qspi" + }, + "core": "esp32", + "extra_flags": [ + "-DARDUINO_USB_MODE=1", + "-DARDUINO_USB_CDC_ON_BOOT=1", + "-DARDUINO_RUNNING_CORE=1", + "-DARDUINO_EVENT_RUNNING_CORE=1" + ], + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "hwids": [ + [ + "0x303A", + "0x1001" + ] + ], + "mcu": "esp32s3", + "variant": "esp32s3" + }, + "connectivity": [ + "wifi" + ], + "debug": { + "default_tool": "esp-builtin", + "onboard_tools": [ + "esp-builtin" + ], + "openocd_target": "esp32s3.cfg" + }, + "frameworks": [ + "arduino", + "espidf" + ], + "name": "LilyGo T-Beam supreme (8MB Flash 8MB PSRAM)", + "upload": { + "flash_size": "8MB", + "maximum_ram_size": 327680, + "maximum_size": 8388608, + "require_upload_port": true, + "speed": 460800 + }, + "url": "https://www.lilygo.cc/products/t-beamsupreme-m", + "vendor": "LilyGo" + } \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 1652f1e3..985943c7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -59,4 +59,4 @@ build_flags = ${nrf52_base.build_flags} lib_deps = ${nrf52_base.lib_deps} rweather/Crypto @ ^0.4.0 - https://github.com/adafruit/Adafruit_nRF52_Arduino + https://github.com/adafruit/Adafruit_nRF52_Arduino \ No newline at end of file diff --git a/src/helpers/AutoDiscoverRTCClock.cpp b/src/helpers/AutoDiscoverRTCClock.cpp index e087744a..4c069d37 100644 --- a/src/helpers/AutoDiscoverRTCClock.cpp +++ b/src/helpers/AutoDiscoverRTCClock.cpp @@ -1,6 +1,7 @@ #include "AutoDiscoverRTCClock.h" #include "RTClib.h" #include +#include "pcf8563.h" static RTC_DS3231 rtc_3231; static bool ds3231_success = false; @@ -8,8 +9,12 @@ static bool ds3231_success = false; static Melopero_RV3028 rtc_rv3028; static bool rv3028_success = false; +static RTC_PCF8563 rtc_8563; +static bool rtc_8563_success = false; + #define DS3231_ADDRESS 0x68 #define RV3028_ADDRESS 0x52 +#define PCF8563_ADDRESS 0x51 bool AutoDiscoverRTCClock::i2c_probe(TwoWire& wire, uint8_t addr) { wire.beginTransmission(addr); @@ -28,6 +33,9 @@ void AutoDiscoverRTCClock::begin(TwoWire& wire) { rtc_rv3028.set24HourMode(); // Set the device to use the 24hour format (default) instead of the 12 hour format rv3028_success = true; } + if(i2c_probe(wire,PCF8563_ADDRESS)){ + rtc_8563_success = rtc_8563.begin(&wire); + } } uint32_t AutoDiscoverRTCClock::getCurrentTime() { @@ -44,6 +52,9 @@ uint32_t AutoDiscoverRTCClock::getCurrentTime() { rtc_rv3028.getSecond() ).unixtime(); } + if(rtc_8563_success){ + return rtc_8563.now().unixtime(); + } return _fallback->getCurrentTime(); } @@ -52,9 +63,10 @@ void AutoDiscoverRTCClock::setCurrentTime(uint32_t time) { rtc_3231.adjust(DateTime(time)); } else if (rv3028_success) { auto dt = DateTime(time); - uint8_t weekday = (dt.day() + (uint16_t)((2.6 * dt.month()) - 0.2) - (2 * (dt.year() / 100)) + dt.year() + (uint16_t)(dt.year() / 4) + (uint16_t)(dt.year() / 400)) % 7; - + uint8_t weekday = (dt.day() + (uint16_t)((2.6 * dt.month()) - 0.2) - (2 * (dt.year() / 100)) + dt.year() + (uint16_t)(dt.year() / 4) + (uint16_t)(dt.year() / 400)) % 7; rtc_rv3028.setTime(dt.year(), dt.month(), weekday, dt.day(), dt.hour(), dt.minute(), dt.second()); + } else if (rtc_8563_success) { + rtc_8563.adjust(DateTime(time)); } else { _fallback->setCurrentTime(time); } diff --git a/src/helpers/TBeamS3SupremeBoard.h b/src/helpers/TBeamS3SupremeBoard.h new file mode 100644 index 00000000..2b8232d8 --- /dev/null +++ b/src/helpers/TBeamS3SupremeBoard.h @@ -0,0 +1,106 @@ +#pragma once + +#include "ESP32Board.h" +#include +#include +#include +#include "XPowersLib.h" + +// LoRa radio module pins for TBeam S3 Supreme +#define P_LORA_DIO_1 1 //SX1262 IRQ pin +#define P_LORA_NSS 10 //SX1262 SS pin +#define P_LORA_RESET 5 //SX1262 Rest pin +#define P_LORA_BUSY 4 //SX1262 Busy pin +#define P_LORA_SCLK 12 //SX1262 SCLK pin +#define P_LORA_MISO 13 //SX1262 MISO pin +#define P_LORA_MOSI 11 //SX1262 MOSI pin + +#define PIN_BOARD_SDA 17 //SDA for OLED, BME280, and QMC6310U (0x1C) +#define PIN_BOARD_SCL 18 //SCL for OLED, BME280, and QMC6310U (0x1C) + +#define PIN_BOARD_SDA1 42 //SDA for PMU and PFC8563 (RTC) +#define PIN_BOARD_SCL1 41 //SCL for PMU and PFC8563 (RTC) +#define PIN_PMU_IRQ 40 //IRQ pin for PMU + +#define PIN_USER_BTN 0 + +#define P_BOARD_SPI_MOSI 35 //SPI for SD Card and QMI8653 (IMU) +#define P_BOARD_SPI_MISO 37 //SPI for SD Card and QMI8653 (IMU) +#define P_BOARD_SPI_SCK 36 //SPI for SD Card and QMI8653 (IMU) +#define P_BPARD_SPI_CS 47 //SPI for SD Card and QMI8653 (IMU) +#define P_BOARD_IMU_CS 34 //Pin for QMI8653 (IMU) CS + +#define P_BOARD_IMU_INT 33 //IMU Int pin +#define P_BOARD_RTC_INT 14 //RTC Int pin + +#define P_GPS_RX 9 //GPS RX pin +#define P_GPS_TX 8 //GPS TX pin +#define P_GPS_WAKE 7 //GPS Wakeup pin +#define P_GPS_1PPS 6 //GPS 1PPS pin + +//I2C Wire addresses +#define I2C_BME280_ADD 0x76 //BME280 sensor I2C address on Wire +#define I2C_OLED_ADD 0x3C //SH1106 OLED I2C address on Wire +#define I2C_QMC6310U_ADD 0x1C //QMC6310U mag sensor I2C address on Wire + +//I2C Wire1 addresses +#define I2C_RTC_ADD 0x51 //RTC I2C address on Wire1 +#define I2C_PMU_ADD 0x34 //AXP2101 I2C address on Wire1 + + + +class TBeamS3SupremeBoard : public ESP32Board { + +public: + void begin() { + + bool power_init(); + + ESP32Board::begin(); + + 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)) { // received a LoRa packet (while in deep sleep) + startup_reason = BD_STARTUP_RX_PACKET; + } + + rtc_gpio_hold_dis((gpio_num_t)P_LORA_NSS); + rtc_gpio_deinit((gpio_num_t)P_LORA_DIO_1); + } + } + + void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1) { + esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); + + // Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep + rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY); + rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1); + + rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS); + + if (pin_wake_btn < 0) { + esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet + } else { + esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn + } + + if (secs > 0) { + esp_sleep_enable_timer_wakeup(secs * 1000000); + } + + // Finally set ESP32 into sleep + esp_deep_sleep_start(); // CPU halts here and never returns! + } + + uint16_t getBattMilliVolts() override { + + return 0; + } + + uint16_t getBattPercent(); + + const char* getManufacturerName() const override { + return "LilyGo T-Beam S3 Supreme SX1262"; + } +}; diff --git a/variants/lilygo_tbeam_supreme_SX1262/platformio.ini b/variants/lilygo_tbeam_supreme_SX1262/platformio.ini new file mode 100644 index 00000000..57cc68db --- /dev/null +++ b/variants/lilygo_tbeam_supreme_SX1262/platformio.ini @@ -0,0 +1,72 @@ +[T_Beam_S3_Supreme_SX1262] +extends = esp32_base +board = t_beams3_supreme ; LILYGO T-Beam Supreme ESP32S3 with SX1262 +build_flags = + ${esp32_base.build_flags} + -I variants/lilygo_tbeam_supreme_SX1262 + -D LORA_TX_POWER=22 + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + ;-D DISPLAY_CLASS=SSD1306Display ;Needs to be modified for SH1106 + -D SX126X_RX_BOOSTED_GAIN=1 +build_src_filter = ${esp32_base.build_src_filter} + +<../variants/lilygo_tbeam_supreme_SX1262> +board_build.partitions = min_spiffs.csv ; get around 4mb flash limit +lib_deps = + ${esp32_base.lib_deps} + lewisxhe/PCF8563_Library@^1.0.1 + lewisxhe/XPowersLib @ ^0.2.7 + ;adafruit/Adafruit SSD1306 @ ^2.5.13 + +; === LILYGO T-Beam S3 Supreme with SX1262 environments === +[env:T_Beam_S3_Supreme_SX1262_repeater] +extends = T_Beam_S3_Supreme_SX1262 +build_flags = + ${T_Beam_S3_Supreme_SX1262.build_flags} + -D ADVERT_NAME='"T-Beam S3 Supreme SX1262 Repeater"' + -D ADVERT_LAT=0 + -D ADVERT_LON=0 + -D ADMIN_PASSWORD='"password"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${T_Beam_S3_Supreme_SX1262.build_src_filter} + +<../examples/simple_repeater> +lib_deps = + ${T_Beam_S3_Supreme_SX1262.lib_deps} + ${esp32_ota.lib_deps} + +[env:T_Beam_S3_Supreme_SX1262_room_server] +extends = T_Beam_S3_Supreme_SX1262 +build_flags = + ${T_Beam_S3_Supreme_SX1262.build_flags} + -D ADVERT_NAME='"T_Beam_S3_Supreme_SX1262 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 = ${T_Beam_S3_Supreme_SX1262.build_src_filter} + +<../examples/simple_room_server> +lib_deps = + ${T_Beam_S3_Supreme_SX1262.lib_deps} + ${esp32_ota.lib_deps} + +[env:T_Beam_S3_Supreme_SX1262_companion_radio_ble] +extends = T_Beam_S3_Supreme_SX1262 +build_flags = + ${T_Beam_S3_Supreme_SX1262.build_flags} + -D MAX_CONTACTS=100 + -D MAX_GROUP_CHANNELS=1 + -D BLE_PIN_CODE=123456 + -D BLE_DEBUG_LOGGING=1 +; -D ENABLE_PRIVATE_KEY_IMPORT=1 +; -D ENABLE_PRIVATE_KEY_EXPORT=1 + -D MESH_PACKET_LOGGING=8 + -D MESH_DEBUG=1 +build_src_filter = ${T_Beam_S3_Supreme_SX1262.build_src_filter} + + + +<../examples/companion_radio> +lib_deps = + ${T_Beam_S3_Supreme_SX1262.lib_deps} + densaugeo/base64 @ ~1.4.0 \ No newline at end of file diff --git a/variants/lilygo_tbeam_supreme_SX1262/target.cpp b/variants/lilygo_tbeam_supreme_SX1262/target.cpp new file mode 100644 index 00000000..c7ab2984 --- /dev/null +++ b/variants/lilygo_tbeam_supreme_SX1262/target.cpp @@ -0,0 +1,182 @@ +#include +#include "target.h" + +TBeamS3SupremeBoard board; + +// Using PMU AXP2102 +XPowersAXP2101 PMU; + +bool pmuIntFlag; + +#ifndef LORA_CR + #define LORA_CR 5 +#endif + +#if defined(P_LORA_SCLK) + static SPIClass spi; + RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); +#else + RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY); +#endif + +WRAPPER_CLASS radio_driver(radio, board); + +ESP32RTCClock fallback_clock; +AutoDiscoverRTCClock rtc_clock(fallback_clock); + + +static void setPMUIntFlag(){ + pmuIntFlag = true; +} + +bool power_init() { + //Start up Wire1 with PMU address + //Serial.println("Starting Wire1 for PMU"); + //Wire1.begin(I2C_PMU_ADD); + //Wire1.begin(PIN_BOARD_SDA1,PIN_BOARD_SCL1); + + //Set LED to indicate charge state + Serial.println("Setting charge led"); + PMU.setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG); + + //Set up PMU interrupts + Serial.println("Setting up PMU interrupts"); + pinMode(PIN_PMU_IRQ,INPUT_PULLUP); + attachInterrupt(PIN_PMU_IRQ,setPMUIntFlag,FALLING); + + //GPS + Serial.println("Setting and enabling a-ldo4 for GPS"); + PMU.setALDO4Voltage(3300); + PMU.enableALDO4(); //disable to save power + + //Lora + Serial.println("Setting and enabling a-ldo3 for LoRa"); + PMU.setALDO3Voltage(3300); + PMU.enableALDO3(); + + //To avoid SPI bus issues during power up, reset OLED, sensor, and SD card supplies + Serial.println("Reset a-ldo1&2 and b-ldo1"); + if(ESP_SLEEP_WAKEUP_UNDEFINED == esp_sleep_get_wakeup_cause()){ + PMU.enableALDO1(); + PMU.enableALDO2(); + PMU.enableBLDO1(); + delay(250); + } + + //BME280 and OLED + Serial.println("Setting and enabling a-ldo1 for oled"); + PMU.setALDO1Voltage(3300); + PMU.enableALDO1(); + + //QMC6310U + Serial.println("Setting and enabling a-ldo2 for QMC"); + PMU.setALDO2Voltage(3300); + PMU.enableALDO2(); //disable to save power + + //SD card + Serial.println("Setting and enabling b-ldo2 for SD card"); + PMU.setBLDO1Voltage(3300); + PMU.enableBLDO1(); + + //Out to header pins + Serial.println("Setting and enabling b-ldo2 for output to header"); + PMU.setBLDO2Voltage(3300); + PMU.enableBLDO2(); + + Serial.println("Setting and enabling dcdc4 for output to header"); + PMU.setDC4Voltage(XPOWERS_AXP2101_DCDC4_VOL2_MAX); //1.8V + PMU.enableDC4(); + + Serial.println("Setting and enabling dcdc5 for output to header"); + PMU.setDC5Voltage(3300); + PMU.enableDC5(); + + //Other power rails + Serial.println("Setting and enabling dcdc3 for ?"); + PMU.setDC3Voltage(3300); //doesn't go anywhere in the schematic?? + PMU.enableDC3(); + + //Unused power rails + Serial.println("Disabling unused supplies dcdc2, dldo1 and dldo2"); + PMU.disableDC2(); + PMU.disableDLDO1(); + PMU.disableDLDO2(); + + //Set charge current to 300mA + Serial.println("Setting battery charge current limit and voltage"); + PMU.setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_300MA); + PMU.setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2); + + //enable battery voltage measurement + Serial.println("Enabling battery measurement"); + PMU.enableBattVoltageMeasure(); + + //Reset and re-enable PMU interrupts + Serial.println("Re-enable interrupts"); + PMU.disableIRQ(XPOWERS_AXP2101_ALL_IRQ); + PMU.clearIrqStatus(); + PMU.enableIRQ( + XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_BAT_REMOVE_IRQ | //Battery interrupts + XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_VBUS_REMOVE_IRQ | //VBUS interrupts + XPOWERS_AXP2101_PKEY_SHORT_IRQ | XPOWERS_AXP2101_PKEY_LONG_IRQ | //Power Key interrupts + XPOWERS_AXP2101_BAT_CHG_DONE_IRQ | XPOWERS_AXP2101_BAT_CHG_START_IRQ //Charging interrupts + ); + + //Set the power key off press time + PMU.setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S); + + return true; +} + +bool radio_init() { + fallback_clock.begin(); + Wire1.begin(PIN_BOARD_SDA1,PIN_BOARD_SCL1); + rtc_clock.begin(Wire1); + +#ifdef SX126X_DIO3_TCXO_VOLTAGE + float tcxo = SX126X_DIO3_TCXO_VOLTAGE; +#else + float tcxo = 1.6f; +#endif + +#if defined(P_LORA_SCLK) + spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); +#endif + 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); + + return true; // success +} + +uint16_t getBattPercent() { + //Read the PMU fuel guage for battery % + uint16_t battPercent = PMU.getBatteryPercent(); + + return battPercent; +} + +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/lilygo_tbeam_supreme_SX1262/target.h b/variants/lilygo_tbeam_supreme_SX1262/target.h new file mode 100644 index 00000000..2ee3cb01 --- /dev/null +++ b/variants/lilygo_tbeam_supreme_SX1262/target.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include +#include +#include + +extern TBeamS3SupremeBoard board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; + +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(); \ No newline at end of file