From 60303968bbaa01a0d6ddbf9be609e87d6e54adb1 Mon Sep 17 00:00:00 2001 From: Quency-D <55523105+Quency-D@users.noreply.github.com> Date: Sat, 30 May 2026 01:47:09 +0800 Subject: [PATCH] Add Heltec mesh node t1 (#10416) * add heltec-mesh-node-t1 * fixed low power * Update the sensor enumeration values. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Fix memory leak in ICM42607PSensor * fix ST7735_MISO error --------- Co-authored-by: Ben Meadors Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- boards/heltec_mesh_node_t1.json | 54 ++++++ platformio.ini | 4 + src/configuration.h | 3 + src/detect/ScanI2C.cpp | 11 +- src/detect/ScanI2C.h | 4 + src/detect/ScanI2CTwoWire.cpp | 25 ++- src/graphics/TFTDisplay.cpp | 20 +- src/graphics/draw/MenuHandler.cpp | 5 + src/main.cpp | 23 +++ src/main.h | 5 + src/motion/AccelerometerThread.h | 4 + src/motion/ICM42607PSensor.cpp | 98 ++++++++++ src/motion/ICM42607PSensor.h | 28 +++ src/motion/MMC5983MASensor.cpp | 115 ++++++++++++ src/motion/MMC5983MASensor.h | 31 +++ src/motion/MagnetometerThread.h | 115 ++++++++++++ src/platform/nrf52/architecture.h | 2 + .../heltec_mesh_node_t1/platformio.ini | 35 ++++ .../nrf52840/heltec_mesh_node_t1/variant.cpp | 85 +++++++++ .../nrf52840/heltec_mesh_node_t1/variant.h | 177 ++++++++++++++++++ 20 files changed, 829 insertions(+), 15 deletions(-) create mode 100644 boards/heltec_mesh_node_t1.json create mode 100644 src/motion/ICM42607PSensor.cpp create mode 100644 src/motion/ICM42607PSensor.h create mode 100644 src/motion/MMC5983MASensor.cpp create mode 100644 src/motion/MMC5983MASensor.h create mode 100644 src/motion/MagnetometerThread.h create mode 100644 variants/nrf52840/heltec_mesh_node_t1/platformio.ini create mode 100644 variants/nrf52840/heltec_mesh_node_t1/variant.cpp create mode 100644 variants/nrf52840/heltec_mesh_node_t1/variant.h diff --git a/boards/heltec_mesh_node_t1.json b/boards/heltec_mesh_node_t1.json new file mode 100644 index 000000000..96a28da69 --- /dev/null +++ b/boards/heltec_mesh_node_t1.json @@ -0,0 +1,54 @@ +{ + "build": { + "arduino": { + "ldscript": "nrf52840_s140_v6.ld" + }, + "core": "nRF5", + "cpu": "cortex-m4", + "extra_flags": "-DNRF52840_XXAA", + "f_cpu": "64000000L", + "hwids": [ + ["0x239A", "0x4405"], + ["0x239A", "0x0029"], + ["0x239A", "0x002A"], + ["0x2886", "0x1667"] + ], + "usb_product": "HT-n5262", + "mcu": "nrf52840", + "variant": "heltec_mesh_node_t1", + "variants_dir": "variants", + "bsp": { + "name": "adafruit" + }, + "softdevice": { + "sd_flags": "-DS140", + "sd_name": "s140", + "sd_version": "6.1.1", + "sd_fwid": "0x00B6" + }, + "bootloader": { + "settings_addr": "0xFF000" + } + }, + "connectivity": ["bluetooth"], + "debug": { + "jlink_device": "nRF52840_xxAA", + "onboard_tools": ["jlink"], + "svd_path": "nrf52840.svd", + "openocd_target": "nrf52840-mdk-rs" + }, + "frameworks": ["arduino"], + "name": "Heltec Mesh Node T1", + "upload": { + "maximum_ram_size": 248832, + "maximum_size": 815104, + "speed": 115200, + "protocol": "nrfutil", + "protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"], + "use_1200bps_touch": true, + "require_upload_port": true, + "wait_for_upload_port": true + }, + "url": "https://heltec.org", + "vendor": "Heltec" +} diff --git a/platformio.ini b/platformio.ini index fd25bfa59..d09d13c04 100644 --- a/platformio.ini +++ b/platformio.ini @@ -186,12 +186,16 @@ lib_deps = https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library/archive/refs/tags/v1.1.2.zip # renovate: datasource=github-tags depName=SparkFun 9DoF IMU Breakout ICM 20948 packageName=sparkfun/SparkFun_ICM-20948_ArduinoLibrary https://github.com/sparkfun/SparkFun_ICM-20948_ArduinoLibrary/archive/refs/tags/v1.3.2.zip + # renovate: datasource=github-tags depName=TDK InvenSense ICM42670P packageName=tdk-invn-oss/motion.arduino.ICM42670P + https://github.com/tdk-invn-oss/motion.arduino.ICM42670P/archive/refs/tags/1.0.8.zip # renovate: datasource=github-tags depName=Adafruit LTR390 Library packageName=adafruit/Adafruit_LTR390 https://github.com/adafruit/Adafruit_LTR390/archive/refs/tags/1.1.2.zip # renovate: datasource=github-tags depName=Adafruit PCT2075 packageName=adafruit/Adafruit_PCT2075 https://github.com/adafruit/Adafruit_PCT2075/archive/refs/tags/1.0.6.zip # renovate: datasource=github-tags depName=DFRobot_BMM150 packageName=dfrobot/DFRobot_BMM150 https://github.com/DFRobot/DFRobot_BMM150/archive/refs/tags/V1.0.0.zip + # renovate: datasource=github-tags depName=SparkFun MMC5983MA Magnetometer packageName=sparkfun/SparkFun_MMC5983MA_Magnetometer_Arduino_Library + https://github.com/sparkfun/SparkFun_MMC5983MA_Magnetometer_Arduino_Library/archive/refs/tags/v1.1.4.zip # renovate: datasource=github-tags depName=Adafruit_TSL2561 packageName=adafruit/Adafruit_TSL2561 https://github.com/adafruit/Adafruit_TSL2561/archive/refs/tags/1.1.3.zip # renovate: datasource=github-tags depName=BH1750_WE packageName=wollewald/BH1750_WE diff --git a/src/configuration.h b/src/configuration.h index a31198346..e48f346a5 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -243,6 +243,7 @@ along with this program. If not, see . #define QMI8658_ADDR 0x6B #define QMC5883L_ADDR 0x0D #define HMC5883L_ADDR 0x1E +#define MMC5983MA_ADDR 0x30 #define SHTC3_ADDR 0x70 #define LPS22HB_ADDR 0x5C #define LPS22HB_ADDR_ALT 0x5D @@ -292,6 +293,8 @@ along with this program. If not, see . #define DA217_ADDR 0x26 #define BMI270_ADDR 0x68 #define BMI270_ADDR_ALT 0x69 +#define ICM42607P_ADDR 0x68 +#define ICM42607P_ADDR_ALT 0x69 // ----------------------------------------------------------------------------- // LED diff --git a/src/detect/ScanI2C.cpp b/src/detect/ScanI2C.cpp index 75eabc954..2c839a38b 100644 --- a/src/detect/ScanI2C.cpp +++ b/src/detect/ScanI2C.cpp @@ -37,8 +37,15 @@ ScanI2C::FoundDevice ScanI2C::firstKeyboard() const ScanI2C::FoundDevice ScanI2C::firstAccelerometer() const { - ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, BMA423, LSM6DS3, BMX160, STK8BAXX, ICM20948, QMA6100P, BMM150, BMI270}; - return firstOfOrNONE(10, types); + ScanI2C::DeviceType types[] = {MPU6050, LIS3DH, BMA423, LSM6DS3, BMX160, STK8BAXX, + ICM20948, QMA6100P, BMM150, BMI270, ICM42607P}; + return firstOfOrNONE(11, types); +} + +ScanI2C::FoundDevice ScanI2C::firstMagnetometer() const +{ + ScanI2C::DeviceType types[] = {MMC5983MA}; + return firstOfOrNONE(1, types); } ScanI2C::FoundDevice ScanI2C::firstAQI() const diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 054c7854b..7c4f2f0e3 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -41,6 +41,7 @@ class ScanI2C QMI8658, QMC5883L, HMC5883L, + MMC5983MA, PMSA003I, QMA6100P, MPU6050, @@ -65,6 +66,7 @@ class ScanI2C FT6336U, STK8BAXX, ICM20948, + ICM42607P, SCD4X, MAX30102, TPS65233, @@ -149,6 +151,8 @@ class ScanI2C FoundDevice firstAccelerometer() const; + FoundDevice firstMagnetometer() const; + FoundDevice firstAQI() const; FoundDevice firstRGBLED() const; diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index c1c48eac8..a3bdf1440 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -360,9 +360,6 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "ST7567", (uint8_t)addr.address); #ifdef HAS_NCP5623 SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623", (uint8_t)addr.address); -#endif -#ifdef HAS_LP5562 - SCAN_SIMPLE_CASE(LP5562_ADDR, LP5562, "LP5562", (uint8_t)addr.address); #endif case XPOWERS_AXP192_AXP2101_ADDRESS: // Do we have the axp2101/192 or the TCA8418 @@ -600,6 +597,18 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) #else SCAN_SIMPLE_CASE(PMSA003I_ADDR, PMSA003I, "PMSA003I", (uint8_t)addr.address) #endif + case MMC5983MA_ADDR: + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x2F), 1); + if (registerValue == 0x30) { + type = MMC5983MA; + logFoundDevice("MMC5983MA", (uint8_t)addr.address); +#ifdef HAS_LP5562 + } else { + type = LP5562; + logFoundDevice("LP5562", (uint8_t)addr.address); +#endif + } + break; case BMA423_ADDR: // this can also be LIS3DH_ADDR_ALT registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0F), 2); if (registerValue == 0x3300 || registerValue == 0x3333) { // RAK4631 WisBlock has LIS3DH register at 0x3333 @@ -754,8 +763,8 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) } break; - case ICM20948_ADDR: // same as BMX160_ADDR, BMI270_ADDR_ALT, and SEN5X_ADDR - case ICM20948_ADDR_ALT: // same as MPU6050_ADDR, BMI270_ADDR + case ICM20948_ADDR: // same as BMX160_ADDR, BMI270_ADDR_ALT, ICM42607P_ADDR_ALT, and SEN5X_ADDR + case ICM20948_ADDR_ALT: // same as MPU6050_ADDR, BMI270_ADDR, and ICM42607P_ADDR registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1); #ifdef HAS_ICM20948 type = ICM20948; @@ -775,6 +784,12 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) logFoundDevice("BMX160", (uint8_t)addr.address); break; } else { + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x75), 1); // WHO_AM_I + if (registerValue == 0x60) { + type = ICM42607P; + logFoundDevice("ICM-42607-P", (uint8_t)addr.address); + break; + } #if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_AIR_QUALITY_SENSOR String prod = ""; prod = readSEN5xProductName(i2cBus, addr.address); diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp index a28924ba6..d7f56f2d9 100644 --- a/src/graphics/TFTDisplay.cpp +++ b/src/graphics/TFTDisplay.cpp @@ -1458,7 +1458,8 @@ void TFTDisplay::sendCommand(uint8_t com) digitalWrite(portduino_config.displayBacklight.pin, TFT_BACKLIGHT_ON); #elif defined(HACKADAY_COMMUNICATOR) tft->displayOn(); -#elif !defined(RAK14014) && !defined(M5STACK) && !defined(UNPHONE) && !defined(HELTEC_MESH_NODE_T096) +#elif !defined(RAK14014) && !defined(M5STACK) && !defined(UNPHONE) && !defined(HELTEC_MESH_NODE_T096) && \ + !defined(HELTEC_MESH_NODE_T1) tft->wakeup(); tft->powerSaveOff(); #endif @@ -1469,7 +1470,7 @@ void TFTDisplay::sendCommand(uint8_t com) #ifdef UNPHONE unphone.backlight(true); // using unPhone library #endif -#if defined(RAK14014) || defined(HELTEC_MESH_NODE_T096) +#if defined(RAK14014) || defined(HELTEC_MESH_NODE_T096) || defined(HELTEC_MESH_NODE_T1) #elif !defined(M5STACK) && !defined(ST7789_CS) && \ !defined(HACKADAY_COMMUNICATOR) // T-Deck gets brightness set in Screen.cpp in the handleSetOn function tft->setBrightness(172); @@ -1485,7 +1486,8 @@ void TFTDisplay::sendCommand(uint8_t com) digitalWrite(portduino_config.displayBacklight.pin, !TFT_BACKLIGHT_ON); #elif defined(HACKADAY_COMMUNICATOR) tft->displayOff(); -#elif !defined(RAK14014) && !defined(M5STACK) && !defined(UNPHONE) && !defined(HELTEC_MESH_NODE_T096) +#elif !defined(RAK14014) && !defined(M5STACK) && !defined(UNPHONE) && !defined(HELTEC_MESH_NODE_T096) && \ + !defined(HELTEC_MESH_NODE_T1) tft->sleep(); tft->powerSaveOn(); #endif @@ -1496,7 +1498,7 @@ void TFTDisplay::sendCommand(uint8_t com) #ifdef UNPHONE unphone.backlight(false); // using unPhone library #endif -#if defined(RAK14014) || defined(HELTEC_MESH_NODE_T096) +#if defined(RAK14014) || defined(HELTEC_MESH_NODE_T096) || defined(HELTEC_MESH_NODE_T1) #elif !defined(M5STACK) && !defined(HACKADAY_COMMUNICATOR) tft->setBrightness(0); #endif @@ -1511,7 +1513,7 @@ void TFTDisplay::sendCommand(uint8_t com) void TFTDisplay::setDisplayBrightness(uint8_t _brightness) { -#if defined(RAK14014) || defined(HELTEC_MESH_NODE_T096) +#if defined(RAK14014) || defined(HELTEC_MESH_NODE_T096) || defined(HELTEC_MESH_NODE_T1) // todo #elif !defined(HACKADAY_COMMUNICATOR) tft->setBrightness(_brightness); @@ -1531,7 +1533,8 @@ bool TFTDisplay::hasTouch(void) { #ifdef RAK14014 return true; -#elif !defined(M5STACK) && !defined(HACKADAY_COMMUNICATOR) && !defined(HELTEC_MESH_NODE_T096) +#elif !defined(M5STACK) && !defined(HACKADAY_COMMUNICATOR) && !defined(HELTEC_MESH_NODE_T096) && \ + !defined(HELTEC_MESH_NODE_T1) return tft->touch() != nullptr; #else return false; @@ -1550,7 +1553,8 @@ bool TFTDisplay::getTouch(int16_t *x, int16_t *y) } else { return false; } -#elif !defined(M5STACK) && !defined(HACKADAY_COMMUNICATOR) && !defined(HELTEC_MESH_NODE_T096) +#elif !defined(M5STACK) && !defined(HACKADAY_COMMUNICATOR) && !defined(HELTEC_MESH_NODE_T096) && \ + !defined(HELTEC_MESH_NODE_T1) return tft->getTouch(x, y); #else return false; @@ -1567,7 +1571,7 @@ bool TFTDisplay::connect() { concurrency::LockGuard g(spiLock); LOG_INFO("Do TFT init"); -#if defined(RAK14014) || defined(HELTEC_MESH_NODE_T096) +#if defined(RAK14014) || defined(HELTEC_MESH_NODE_T096) || defined(HELTEC_MESH_NODE_T1) tft = new TFT_eSPI; #elif defined(HACKADAY_COMMUNICATOR) bus = new Arduino_ESP32SPI(TFT_DC, TFT_CS, 38 /* SCK */, 21 /* MOSI */, GFX_NOT_DEFINED /* MISO */, HSPI /* spi_num */); diff --git a/src/graphics/draw/MenuHandler.cpp b/src/graphics/draw/MenuHandler.cpp index 279339acd..654796cce 100644 --- a/src/graphics/draw/MenuHandler.cpp +++ b/src/graphics/draw/MenuHandler.cpp @@ -1333,6 +1333,11 @@ void menuHandler::positionBaseMenu() if (accelerometerThread) { accelerometerThread->calibrate(30); } +#endif +#if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && !MESHTASTIC_EXCLUDE_MAGNETOMETER + if (magnetometerThread) { + magnetometerThread->calibrate(30); + } #endif break; case PositionAction::GPSSmartPosition: diff --git a/src/main.cpp b/src/main.cpp index 979517f0a..1dc078c62 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -136,6 +136,10 @@ void printPartitionTable() #include "motion/AccelerometerThread.h" AccelerometerThread *accelerometerThread = nullptr; #endif +#if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && !MESHTASTIC_EXCLUDE_MAGNETOMETER +#include "motion/MagnetometerThread.h" +MagnetometerThread *magnetometerThread = nullptr; +#endif #ifdef HAS_I2S #include "AudioThread.h" @@ -206,6 +210,8 @@ bool osk_found = false; ScanI2C::DeviceAddress rtc_found = ScanI2C::ADDRESS_NONE; // The I2C address of the Accelerometer (if found) ScanI2C::DeviceAddress accelerometer_found = ScanI2C::ADDRESS_NONE; +// The I2C address of the Magnetometer (if found) +ScanI2C::DeviceAddress magnetometer_found = ScanI2C::ADDRESS_NONE; // The I2C address of the RGB LED (if found) ScanI2C::FoundDevice rgb_found = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ScanI2C::ADDRESS_NONE); /// The I2C address of our Air Quality Indicator (if found) @@ -431,6 +437,11 @@ void setup() digitalWrite(VEXT_ENABLE, VEXT_ON_VALUE); // turn on the display power #endif +#if defined(PIN_SENSOR_EN) + pinMode(PIN_SENSOR_EN, OUTPUT); + digitalWrite(PIN_SENSOR_EN, PIN_SENSOR_EN_ACTIVE); // turn on sensor power +#endif + #if defined(BIAS_T_ENABLE) pinMode(BIAS_T_ENABLE, OUTPUT); digitalWrite(BIAS_T_ENABLE, BIAS_T_VALUE); // turn on 5V for GPS Antenna @@ -671,6 +682,11 @@ void setup() accelerometer_found = acc_info.type != ScanI2C::DeviceType::NONE ? acc_info.address : accelerometer_found; LOG_DEBUG("acc_info = %i", acc_info.type); #endif +#if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_MAGNETOMETER + auto mag_info = i2cScanner->firstMagnetometer(); + magnetometer_found = mag_info.type != ScanI2C::DeviceType::NONE ? mag_info.address : magnetometer_found; + LOG_DEBUG("mag_info = %i", mag_info.type); +#endif scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA260, meshtastic_TelemetrySensorType_INA260); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA226, meshtastic_TelemetrySensorType_INA226); @@ -683,6 +699,8 @@ void setup() scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::QMI8658, meshtastic_TelemetrySensorType_QMI8658); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::QMC5883L, meshtastic_TelemetrySensorType_QMC5883L); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::HMC5883L, meshtastic_TelemetrySensorType_QMC5883L); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MMC5983MA, meshtastic_TelemetrySensorType_MMC5983MA); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::ICM42607P, meshtastic_TelemetrySensorType_ICM42607P); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MLX90614, meshtastic_TelemetrySensorType_MLX90614); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::ICM20948, meshtastic_TelemetrySensorType_ICM20948); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MAX30102, meshtastic_TelemetrySensorType_MAX30102); @@ -766,6 +784,11 @@ void setup() accelerometerThread = new AccelerometerThread(acc_info.type); } #endif +#if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_MAGNETOMETER + if (mag_info.type != ScanI2C::DeviceType::NONE) { + magnetometerThread = new MagnetometerThread(mag_info.type); + } +#endif #if defined(HAS_NEOPIXEL) || defined(UNPHONE) || defined(RGBLED_RED) ambientLightingThread = new AmbientLightingThread(ScanI2C::DeviceType::NONE); diff --git a/src/main.h b/src/main.h index 058a2aebc..d6439f1d1 100644 --- a/src/main.h +++ b/src/main.h @@ -39,6 +39,7 @@ extern bool kb_found; extern bool osk_found; extern ScanI2C::DeviceAddress rtc_found; extern ScanI2C::DeviceAddress accelerometer_found; +extern ScanI2C::DeviceAddress magnetometer_found; extern ScanI2C::FoundDevice rgb_found; extern ScanI2C::DeviceAddress aqi_found; @@ -73,6 +74,10 @@ extern graphics::Screen *screen; #include "motion/AccelerometerThread.h" extern AccelerometerThread *accelerometerThread; #endif +#if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && !MESHTASTIC_EXCLUDE_MAGNETOMETER +#include "motion/MagnetometerThread.h" +extern MagnetometerThread *magnetometerThread; +#endif extern bool isVibrating; diff --git a/src/motion/AccelerometerThread.h b/src/motion/AccelerometerThread.h index d2205fd2a..3d7341e58 100755 --- a/src/motion/AccelerometerThread.h +++ b/src/motion/AccelerometerThread.h @@ -15,6 +15,7 @@ #endif #include "BMM150Sensor.h" #include "BMX160Sensor.h" +#include "ICM42607PSensor.h" #include "ICM20948Sensor.h" #include "LIS3DHSensor.h" #include "LSM6DS3Sensor.h" @@ -111,6 +112,9 @@ class AccelerometerThread : public concurrency::OSThread case ScanI2C::DeviceType::ICM20948: sensor = new ICM20948Sensor(device); break; + case ScanI2C::DeviceType::ICM42607P: + sensor = new ICM42607PSensor(device); + break; case ScanI2C::DeviceType::BMM150: sensor = new BMM150Sensor(device); break; diff --git a/src/motion/ICM42607PSensor.cpp b/src/motion/ICM42607PSensor.cpp new file mode 100644 index 000000000..0bace05a8 --- /dev/null +++ b/src/motion/ICM42607PSensor.cpp @@ -0,0 +1,98 @@ +#include "ICM42607PSensor.h" + +#if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && __has_include() + +#include "detect/ScanI2CTwoWire.h" +#include + +static constexpr uint16_t ICM42607P_ACCEL_ODR_HZ = 50; +static constexpr uint16_t ICM42607P_ACCEL_FSR_G = 2; +static constexpr float ICM42607P_COUNTS_PER_G = 32768.0f / ICM42607P_ACCEL_FSR_G; + +#ifdef ICM_42607P_INT_PIN +volatile static bool ICM42607P_IRQ = false; + +void ICM42607PSetInterrupt() +{ + ICM42607P_IRQ = true; +} +#endif + +ICM42607PSensor::ICM42607PSensor(ScanI2C::FoundDevice foundDevice) : MotionSensor::MotionSensor(foundDevice) +{ + wire = ScanI2CTwoWire::fetchI2CBus(foundDevice.address); +} + +ICM42607PSensor::~ICM42607PSensor() = default; + +bool ICM42607PSensor::init() +{ + bool addressLsb = deviceAddress() == ICM42607P_ADDR_ALT; + + LOG_DEBUG("ICM-42607-P begin on addr 0x%02X (port=%d)", deviceAddress(), devicePort()); + sensor.reset(); + auto newSensor = std::make_unique(*wire, addressLsb); + + int status = newSensor->begin(); + // ICM42670P library returns -3 for ICM42607P because WHO_AM_I differs; the register map is compatible. + if (status != 0 && status != -3) { + LOG_DEBUG("ICM-42607-P init error %d", status); + return false; + } + + status = newSensor->startAccel(ICM42607P_ACCEL_ODR_HZ, ICM42607P_ACCEL_FSR_G); + if (status != 0) { + LOG_DEBUG("ICM-42607-P accel start error %d", status); + return false; + } + +#ifdef ICM_42607P_INT_PIN + ICM42607P_IRQ = false; + status = newSensor->startWakeOnMotion(ICM_42607P_INT_PIN, ICM42607PSetInterrupt); + if (status != 0) { + LOG_DEBUG("ICM-42607-P wake-on-motion start error %d", status); + return false; + } + LOG_DEBUG("ICM-42607-P wake-on-motion interrupt ok pin=%d", ICM_42607P_INT_PIN); +#endif + + sensor = std::move(newSensor); + LOG_DEBUG("ICM-42607-P init ok"); + return true; +} + +int32_t ICM42607PSensor::runOnce() +{ +#ifdef ICM_42607P_INT_PIN + if (ICM42607P_IRQ) { + ICM42607P_IRQ = false; + LOG_DEBUG("ICM-42607-P motion interrupt"); + wakeScreen(); + } + return MOTION_SENSOR_CHECK_INTERVAL_MS; +#else + int16_t x = 0; + int16_t y = 0; + int16_t z = 0; + inv_imu_sensor_event_t event = {}; + + if (sensor == nullptr || sensor->getDataFromRegisters(event) != 0) { + return MOTION_SENSOR_CHECK_INTERVAL_MS; + } + + // getDataFromRegisters() fills accel[] but does not set sensor_mask in this library version. + if (event.accel[0] == 0 && event.accel[1] == 0 && event.accel[2] == 0) { + return MOTION_SENSOR_CHECK_INTERVAL_MS; + } + + x = event.accel[0]; + y = event.accel[1]; + z = event.accel[2]; + // LOG_DEBUG("ICM-42607-P accel read x=%.3fg y=%.3fg z=%.3fg", (float)x / ICM42607P_COUNTS_PER_G, + // (float)y / ICM42607P_COUNTS_PER_G, (float)z / ICM42607P_COUNTS_PER_G); + + return MOTION_SENSOR_CHECK_INTERVAL_MS; +#endif +} + +#endif diff --git a/src/motion/ICM42607PSensor.h b/src/motion/ICM42607PSensor.h new file mode 100644 index 000000000..370fef276 --- /dev/null +++ b/src/motion/ICM42607PSensor.h @@ -0,0 +1,28 @@ +#pragma once +#ifndef _ICM42607P_SENSOR_H_ +#define _ICM42607P_SENSOR_H_ + +#include "MotionSensor.h" + +#if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && __has_include() + +#include + +class ICM42670; + +class ICM42607PSensor : public MotionSensor +{ + private: + std::unique_ptr sensor; + TwoWire *wire = nullptr; + + public: + explicit ICM42607PSensor(ScanI2C::FoundDevice foundDevice); + ~ICM42607PSensor() override; + virtual bool init() override; + virtual int32_t runOnce() override; +}; + +#endif + +#endif diff --git a/src/motion/MMC5983MASensor.cpp b/src/motion/MMC5983MASensor.cpp new file mode 100644 index 000000000..8e77b4c0f --- /dev/null +++ b/src/motion/MMC5983MASensor.cpp @@ -0,0 +1,115 @@ +#include "MMC5983MASensor.h" + +#if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && __has_include() + +#include "detect/ScanI2CTwoWire.h" + +#if !defined(MESHTASTIC_EXCLUDE_SCREEN) +extern graphics::Screen *screen; +#endif + +static constexpr float MMC5983MA_ZERO_FIELD = 131072.0f; +static constexpr float MMC5983MA_COUNTS_PER_GAUSS = 16384.0f; +static constexpr uint16_t MMC5983MA_CONTINUOUS_FREQUENCY_HZ = 10; +static constexpr float MMC5983MA_HEADING_OFFSET_DEG = 180.0f; + +MMC5983MASensor::MMC5983MASensor(ScanI2C::FoundDevice foundDevice) : MotionSensor::MotionSensor(foundDevice) {} + +bool MMC5983MASensor::init() +{ + LOG_DEBUG("MMC5983MA begin on addr 0x%02X (port=%d)", device.address.address, device.address.port); + TwoWire *wire = ScanI2CTwoWire::fetchI2CBus(device.address); + + if (!sensor.begin(*wire)) { + LOG_DEBUG("MMC5983MA init error"); + return false; + } + + sensor.softReset(); + sensor.setFilterBandwidth(100); + sensor.performSetOperation(); + sensor.enableAutomaticSetReset(); + continuousMode = sensor.setContinuousModeFrequency(MMC5983MA_CONTINUOUS_FREQUENCY_HZ); + continuousMode &= sensor.enableContinuousMode(); + + if (!continuousMode) { + LOG_DEBUG("MMC5983MA continuous mode failed, using single-shot reads"); + sensor.disableContinuousMode(); + } + + loadMagnetometerCalibration(compassCalibrationFileName, highestX, lowestX, highestY, lowestY, highestZ, lowestZ); + return true; +} + +bool MMC5983MASensor::readMagnetometer(float &xGauss, float &yGauss, float &zGauss) +{ + uint32_t rawX = 0; + uint32_t rawY = 0; + uint32_t rawZ = 0; + + if (!(continuousMode ? sensor.readFieldsXYZ(&rawX, &rawY, &rawZ) : sensor.getMeasurementXYZ(&rawX, &rawY, &rawZ))) { + LOG_DEBUG("MMC5983MA read failed"); + return false; + } + + xGauss = ((float)rawX - MMC5983MA_ZERO_FIELD) / MMC5983MA_COUNTS_PER_GAUSS; + yGauss = ((float)rawY - MMC5983MA_ZERO_FIELD) / MMC5983MA_COUNTS_PER_GAUSS; + zGauss = ((float)rawZ - MMC5983MA_ZERO_FIELD) / MMC5983MA_COUNTS_PER_GAUSS; + return true; +} + +int32_t MMC5983MASensor::runOnce() + { + float magX = 0, magY = 0, magZ = 0; + if (!readMagnetometer(magX, magY, magZ)) { + return MOTION_SENSOR_CHECK_INTERVAL_MS; + } + + #if !defined(MESHTASTIC_EXCLUDE_SCREEN) + if (doCalibration) { + beginCalibrationDisplay(showingScreen); + updateCalibrationExtrema(magX, magY, magZ, highestX, lowestX, highestY, lowestY, highestZ, lowestZ); + finishCalibrationIfExpired(showingScreen, compassCalibrationFileName, highestX, lowestX, highestY, lowestY, highestZ, + lowestZ); + } + #endif + + magX -= (highestX + lowestX) / 2; + magY -= (highestY + lowestY) / 2; + magZ -= (highestZ + lowestZ) / 2; + + #if !defined(MESHTASTIC_EXCLUDE_SCREEN) && HAS_SCREEN + float heading = atan2f(magY, magX) * RAD_TO_DEG + MMC5983MA_HEADING_OFFSET_DEG; + if (heading < 0.0f) { + heading += 360.0f; + } else if (heading >= 360.0f) { + heading -= 360.0f; + } + + heading = applyCompassOrientation(heading); + if (screen) { + screen->setHeading(heading); + } + #endif + + return MOTION_SENSOR_CHECK_INTERVAL_MS; +} + +void MMC5983MASensor::calibrate(uint16_t forSeconds) +{ +#if !defined(MESHTASTIC_EXCLUDE_SCREEN) + float xGauss = 0.0f; + float yGauss = 0.0f; + float zGauss = 0.0f; + + LOG_DEBUG("MMC5983MA calibration started for %is", forSeconds); + if (readMagnetometer(xGauss, yGauss, zGauss)) { + seedCalibrationExtrema(xGauss, yGauss, zGauss, highestX, lowestX, highestY, lowestY, highestZ, lowestZ); + } else { + seedCalibrationExtrema(0.0f, 0.0f, 0.0f, highestX, lowestX, highestY, lowestY, highestZ, lowestZ); + } + startCalibrationWindow(forSeconds); +#endif +} + +#endif diff --git a/src/motion/MMC5983MASensor.h b/src/motion/MMC5983MASensor.h new file mode 100644 index 000000000..9d349b53a --- /dev/null +++ b/src/motion/MMC5983MASensor.h @@ -0,0 +1,31 @@ +#pragma once +#ifndef _MMC5983MA_SENSOR_H_ +#define _MMC5983MA_SENSOR_H_ + +#include "MotionSensor.h" + +#if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && __has_include() + +#include + +class MMC5983MASensor : public MotionSensor +{ + private: + SFE_MMC5983MA sensor; + bool continuousMode = false; + bool showingScreen = false; + static constexpr const char *compassCalibrationFileName = "/prefs/compass_mmc5983ma.dat"; + float highestX = 0, lowestX = 0, highestY = 0, lowestY = 0, highestZ = 0, lowestZ = 0; + + bool readMagnetometer(float &xGauss, float &yGauss, float &zGauss); + + public: + explicit MMC5983MASensor(ScanI2C::FoundDevice foundDevice); + virtual bool init() override; + virtual int32_t runOnce() override; + virtual void calibrate(uint16_t forSeconds) override; +}; + +#endif + +#endif diff --git a/src/motion/MagnetometerThread.h b/src/motion/MagnetometerThread.h new file mode 100644 index 000000000..affd99e94 --- /dev/null +++ b/src/motion/MagnetometerThread.h @@ -0,0 +1,115 @@ +#pragma once +#ifndef _MAGNETOMETER_THREAD_H_ +#define _MAGNETOMETER_THREAD_H_ + +#include "configuration.h" + +#if !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && !MESHTASTIC_EXCLUDE_MAGNETOMETER + +#include "../concurrency/OSThread.h" +#include "MMC5983MASensor.h" +#include "MotionSensor.h" + +extern ScanI2C::DeviceAddress magnetometer_found; + +class MagnetometerThread : public concurrency::OSThread +{ + private: + MotionSensor *sensor = nullptr; + ScanI2C::FoundDevice device; + bool isInitialised = false; + + public: + explicit MagnetometerThread(ScanI2C::FoundDevice foundDevice) : OSThread("Magnetometer") + { + device = foundDevice; + init(); + } + + explicit MagnetometerThread(ScanI2C::DeviceType type) : MagnetometerThread(ScanI2C::FoundDevice{type, magnetometer_found}) {} + + void start() + { + init(); + setIntervalFromNow(0); + }; + + void calibrate(uint16_t forSeconds) + { + if (sensor) { + sensor->calibrate(forSeconds); + setIntervalFromNow(0); + } + } + + protected: + int32_t runOnce() override + { + canSleep = true; + + if (isInitialised) { + return sensor->runOnce(); + } + + return MOTION_SENSOR_CHECK_INTERVAL_MS; + } + + private: + void init() + { + if (isInitialised) { + return; + } + + if (device.address.port == ScanI2C::I2CPort::NO_I2C || device.address.address == 0 || device.type == ScanI2C::NONE) { + LOG_DEBUG("MagnetometerThread Disable due to no sensors found"); + disable(); + return; + } + + switch (device.type) { + case ScanI2C::DeviceType::MMC5983MA: + sensor = new MMC5983MASensor(device); + break; + default: + disable(); + return; + } + + isInitialised = sensor->init(); + if (!isInitialised) { + clean(); + } + LOG_DEBUG("MagnetometerThread::init %s", isInitialised ? "ok" : "failed"); + } + + MagnetometerThread(const MagnetometerThread &other) : OSThread::OSThread("Magnetometer") { this->copy(other); } + + virtual ~MagnetometerThread() { clean(); } + + MagnetometerThread &operator=(const MagnetometerThread &other) + { + this->copy(other); + return *this; + } + + void copy(const MagnetometerThread &other) + { + if (this != &other) { + clean(); + this->device = ScanI2C::FoundDevice(other.device.type, + ScanI2C::DeviceAddress(other.device.address.port, other.device.address.address)); + } + } + + void clean() + { + isInitialised = false; + delete sensor; + sensor = nullptr; + } +}; + +#endif + +#endif diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h index eafd799fc..ab15bcde5 100644 --- a/src/platform/nrf52/architecture.h +++ b/src/platform/nrf52/architecture.h @@ -117,6 +117,8 @@ #define HW_VENDOR meshtastic_HardwareModel_PRIVATE_HW #elif defined(HELTEC_T114) #define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_NODE_T114 +#elif defined(HELTEC_MESH_NODE_T1) +#define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_NODE_T1 #elif defined(MESHLINK) #define HW_VENDOR meshtastic_HardwareModel_MESHLINK #elif defined(SEEED_XIAO_NRF52840_KIT) diff --git a/variants/nrf52840/heltec_mesh_node_t1/platformio.ini b/variants/nrf52840/heltec_mesh_node_t1/platformio.ini new file mode 100644 index 000000000..664d1616e --- /dev/null +++ b/variants/nrf52840/heltec_mesh_node_t1/platformio.ini @@ -0,0 +1,35 @@ +; Heltec Mesh Node T1 nRF52840/SX1262 device +[env:heltec-mesh-node-t1] +custom_meshtastic_hw_model = 133 +custom_meshtastic_hw_model_slug = HELTEC_MESH_NODE_T1 +custom_meshtastic_architecture = nrf52840 +custom_meshtastic_actively_supported = true +custom_meshtastic_support_level = 1 +custom_meshtastic_display_name = Heltec Mesh Node T1 +custom_meshtastic_images = heltec-mesh-node-t1.svg +custom_meshtastic_tags = Heltec + +extends = nrf52840_base +board = heltec_mesh_node_t1 +board_level = pr +debug_tool = jlink + +build_flags = ${nrf52840_base.build_flags} + -Ivariants/nrf52840/heltec_mesh_node_t1 + -DHELTEC_MESH_NODE_T1 + -DUSE_TFTDISPLAY + -DUSER_SETUP_LOADED + -DST7735_DRIVER + -DST7735_REDTAB160x80 + -D TFT_SPI_PORT=SPI1 + -D TFT_CS=ST7735_CS + -D TFT_DC=ST7735_RS + -D TFT_RST=ST7735_RESET + -D TFT_BL=ST7735_BL + -D TFT_BACKLIGHT_ON=LOW + +build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/heltec_mesh_node_t1> +lib_deps = + ${nrf52840_base.lib_deps} + lewisxhe/PCF8563_Library@^1.0.1 + bodmer/TFT_eSPI@2.5.43 diff --git a/variants/nrf52840/heltec_mesh_node_t1/variant.cpp b/variants/nrf52840/heltec_mesh_node_t1/variant.cpp new file mode 100644 index 000000000..eb719f17f --- /dev/null +++ b/variants/nrf52840/heltec_mesh_node_t1/variant.cpp @@ -0,0 +1,85 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "variant.h" +#include "nrf.h" +#include "wiring_constants.h" +#include "wiring_digital.h" + +const uint32_t g_ADigitalPinMap[] = { + // P0 - pins 0 and 1 are hardwired for xtal and should never be enabled + 0xff, 0xff, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, + + // P1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47}; + +void initVariant() +{ + pinMode(PIN_BUZZER_VOLTAGE_MULTIPLIER_1, OUTPUT); + pinMode(PIN_BUZZER_VOLTAGE_MULTIPLIER_2, OUTPUT); + digitalWrite(PIN_BUZZER_VOLTAGE_MULTIPLIER_1, HIGH); + digitalWrite(PIN_BUZZER_VOLTAGE_MULTIPLIER_2, HIGH); +} + +void variant_shutdown() +{ + nrf_gpio_cfg_default(ST7735_CS); + nrf_gpio_cfg_default(ST7735_RS); + nrf_gpio_cfg_default(ST7735_SDA); + nrf_gpio_cfg_default(ST7735_SCK); + nrf_gpio_cfg_default(ST7735_RESET); + nrf_gpio_cfg_default(ST7735_BL); + nrf_gpio_cfg_default(VTFT_CTRL); + + nrf_gpio_cfg_default(PIN_WIRE_SDA); + nrf_gpio_cfg_default(PIN_WIRE_SCL); + + nrf_gpio_cfg_default(SX126X_CS); + nrf_gpio_cfg_default(SX126X_DIO1); + nrf_gpio_cfg_default(SX126X_BUSY); + nrf_gpio_cfg_default(SX126X_RESET); + + nrf_gpio_cfg_default(PIN_SPI_MISO); + nrf_gpio_cfg_default(PIN_SPI_MOSI); + nrf_gpio_cfg_default(PIN_SPI_SCK); + + // nrf_gpio_cfg_default(PIN_SPI1_MISO);// ST7735 doesn't support MISO, so we don't configure it at all + nrf_gpio_cfg_default(PIN_SPI1_MOSI); + nrf_gpio_cfg_default(PIN_SPI1_SCK); + + nrf_gpio_cfg_default(PIN_GPS_RESET); + nrf_gpio_cfg_default(PIN_GPS_EN); + nrf_gpio_cfg_default(PIN_GPS_PPS); + nrf_gpio_cfg_default(GPS_TX_PIN); + nrf_gpio_cfg_default(GPS_RX_PIN); + + nrf_gpio_cfg_default(PIN_BUZZER_VOLTAGE_MULTIPLIER_1); + nrf_gpio_cfg_default(PIN_BUZZER_VOLTAGE_MULTIPLIER_2); + + pinMode(PIN_BUZZER, OUTPUT); + digitalWrite(PIN_BUZZER, LOW); + + pinMode(PIN_SENSOR_EN, OUTPUT); + digitalWrite(PIN_SENSOR_EN, !PIN_SENSOR_EN_ACTIVE); // Turn off sensor power + + pinMode(PIN_LED1, OUTPUT); + digitalWrite(PIN_LED1, HIGH); +} diff --git a/variants/nrf52840/heltec_mesh_node_t1/variant.h b/variants/nrf52840/heltec_mesh_node_t1/variant.h new file mode 100644 index 000000000..dc84a0487 --- /dev/null +++ b/variants/nrf52840/heltec_mesh_node_t1/variant.h @@ -0,0 +1,177 @@ +/* + Copyright (c) 2014-2015 Arduino LLC. All right reserved. + Copyright (c) 2016 Sandeep Mistry All right reserved. + Copyright (c) 2018, Adafruit Industries (adafruit.com) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _VARIANT_HELTEC_MESH_NODE_T1_ +#define _VARIANT_HELTEC_MESH_NODE_T1_ +/** Master clock frequency */ +#define VARIANT_MCK (64000000ul) + +#define USE_LFXO // Board uses 32khz crystal for LF + +/*---------------------------------------------------------------------------- + * Headers + *----------------------------------------------------------------------------*/ + +#include "WVariant.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#define ST7735_CS (0 + 12) +#define ST7735_RS (0 + 22) // DC +#define ST7735_SDA (0 + 24) +#define ST7735_SCK (32 + 0) +#define ST7735_RESET (0 + 20) +#define ST7735_MISO -1 +#define ST7735_BUSY -1 +#define ST7735_BL (0 + 15) +#define VTFT_CTRL (0 + 13) // Active HIGH, powers the ST7735 display +#define SPI_FREQUENCY 80000000 +#define SPI_READ_FREQUENCY 16000000 +#define SCREEN_ROTATE +#define TFT_HEIGHT 160 +#define TFT_WIDTH 80 +#define TFT_OFFSET_X 24 +#define TFT_OFFSET_Y 0 +#define TFT_INVERT false +#define SCREEN_TRANSITION_FRAMERATE 3 // fps +#define DISPLAY_FORCE_SMALL_FONTS + +// Number of pins defined in PinDescription array +#define PINS_COUNT (48) +#define NUM_DIGITAL_PINS (48) +#define NUM_ANALOG_INPUTS (1) +#define NUM_ANALOG_OUTPUTS (0) + +// LEDs +#define PIN_LED1 (0 + 16) +#define LED_BLUE PIN_LED1 // fake for bluefruit library +#define LED_GREEN PIN_LED1 +#define LED_STATE_ON 0 // State when LED is lit + +/* + * Buttons + */ +#define PIN_BUTTON1 (32 + 10) +#define PIN_BUTTON2 (0 + 14) + +/* +No longer populated on PCB +*/ +#define PIN_SERIAL2_RX (-1) +#define PIN_SERIAL2_TX (-1) + +/* + * I2C + */ + +#define WIRE_INTERFACES_COUNT 1 + +// I2C bus 1 +#define PIN_WIRE_SDA (32 + 3) +#define PIN_WIRE_SCL (0 + 10) + +#define PIN_SENSOR_EN (32 + 6) // Power control pin for sensors +#define PIN_SENSOR_EN_ACTIVE LOW // Power control active state +// #define ICM_42607P_INT_PIN (32 + 1) // ICM42607P INT1, Arduino pin 33 / nRF P1.01 +// #define ICM_42607P_INT2_PIN (32 + 7) // ICM42607P INT2, Arduino pin 39 / nRF P1.07 + +/* + * Lora radio + */ + +#define USE_SX1262 +#define SX126X_CS (32 + 11) // FIXME - we really should define LORA_CS instead +#define LORA_CS SX126X_CS +#define SX126X_DIO1 (0 + 31) +#define SX126X_BUSY (0 + 29) +#define SX126X_RESET (0 + 2) +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + +/* + * SPI Interfaces + */ +#define SPI_INTERFACES_COUNT 2 + +// For LORA, spi 0 +#define PIN_SPI_MISO (0 + 3) +#define PIN_SPI_MOSI (32 + 14) +#define PIN_SPI_SCK (32 + 13) + +#define PIN_SPI1_MISO ST7735_MISO +#define PIN_SPI1_MOSI ST7735_SDA +#define PIN_SPI1_SCK ST7735_SCK + +/* + * GPS pins + */ +#define GPS_UC6580 +#define GPS_BAUDRATE 115200 +#define PIN_GPS_RESET (0 + 26) +#define GPS_RESET_MODE LOW +#define PIN_GPS_EN (0 + 4) +#define GPS_EN_ACTIVE LOW +#define PERIPHERAL_WARMUP_MS 1000 // Make sure I2C QuickLink has stable power before continuing +#define PIN_GPS_PPS (32 + 9) // Pulse per second input from the GPS +#define GPS_TX_PIN (0 + 7) +#define GPS_RX_PIN (0 + 8) + +#define GPS_THREAD_INTERVAL 50 + +#define PIN_SERIAL1_RX GPS_RX_PIN +#define PIN_SERIAL1_TX GPS_TX_PIN + +#define PIN_BUZZER (0 + 9) +#define PIN_BUZZER_VOLTAGE_MULTIPLIER_1 (32 + 2) +#define PIN_BUZZER_VOLTAGE_MULTIPLIER_2 (32 + 5) + +#define ADC_CTRL 11 +#define ADC_CTRL_ENABLED HIGH +#define BATTERY_PIN 5 +#define ADC_RESOLUTION 14 + +#define BATTERY_SENSE_RESOLUTION_BITS 12 +#define BATTERY_SENSE_RESOLUTION 4096.0 +#undef AREF_VOLTAGE +#define AREF_VOLTAGE 3.0 +#define VBAT_AR_INTERNAL AR_INTERNAL_3_0 +#define ADC_MULTIPLIER (4.916F) + +// nrf52840 AIN3 = Pin 5 +// commented out due to power leakage of 2.9mA in shutdown state see reported issue #8801 +#define BATTERY_LPCOMP_INPUT NRF_LPCOMP_INPUT_3 + +// We have AIN3 with a VBAT divider so AIN3 = VBAT * (100/490) +// We have the device going deep sleep under 3.1V, which is AIN3 = 0.63V +// So we can wake up when VBAT>=VDD is restored to 3.3V, where AIN3 = 0.67V +// Ratio 0.67/3.3 = 0.20, so we can pick a bit higher, 2/8 VDD, which means +// VBAT=4.04V +#define BATTERY_LPCOMP_THRESHOLD NRF_LPCOMP_REF_SUPPLY_2_8 + +#define HAS_RTC 0 +#ifdef __cplusplus +} +#endif + +/*---------------------------------------------------------------------------- + * Arduino objects - C++ only + *----------------------------------------------------------------------------*/ + +#endif