mirror of
https://github.com/pelgraine/Meck.git
synced 2026-08-07 17:22:44 +02:00
prelim techo card WIP files while I wait for hardware to arrive. claude putting excessive comments in platformio descriptors
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "nrf52840_s140_v6.ld"
|
||||
},
|
||||
"core": "nRF5",
|
||||
"cpu": "cortex-m4",
|
||||
"extra_flags": [
|
||||
"-DARDUINO_NRF52840_TECHO_CARD",
|
||||
"-DNRF52840_XXAA",
|
||||
"-DNRF52_SERIES"
|
||||
],
|
||||
"f_cpu": "64000000L",
|
||||
"hwids": [["0x239A", "0x8029"]],
|
||||
"mcu": "nrf52840",
|
||||
"variant": "lilygo_techo_card",
|
||||
"bsp": {
|
||||
"name": "adafruit"
|
||||
},
|
||||
"softdevice": {
|
||||
"sd_name": "s140",
|
||||
"sd_version": "6.1.1",
|
||||
"sd_fwid": "0x00B6"
|
||||
},
|
||||
"usb_product": "T-Echo Card"
|
||||
},
|
||||
"connectivity": ["bluetooth", "lora"],
|
||||
"debug": {
|
||||
"jlink_device": "nRF52840_xxAA",
|
||||
"openocd_target": "nrf52840"
|
||||
},
|
||||
"frameworks": ["arduino"],
|
||||
"name": "LilyGo T-Echo Card (nRF52840, SX1262, 4MB Flash)",
|
||||
"upload": {
|
||||
"flash_size": "796KB",
|
||||
"maximum_ram_size": 248832,
|
||||
"maximum_size": 815104,
|
||||
"native_usb": true,
|
||||
"protocol": "nrfutil",
|
||||
"protocols": ["nrfutil", "jlink", "cmsis-dap"],
|
||||
"require_upload_port": true,
|
||||
"speed": 115200,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": true
|
||||
},
|
||||
"url": "https://github.com/Xinyuan-LilyGO/T-Echo-Card",
|
||||
"vendor": "LILYGO"
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
// =============================================================================
|
||||
// TechoCardBoard — Implementation for LilyGo T-Echo Card
|
||||
// =============================================================================
|
||||
|
||||
#include "TechoCardBoard.h"
|
||||
#include "variant.h"
|
||||
|
||||
// nRF52840 SAADC includes
|
||||
#include "nrf.h"
|
||||
|
||||
void TechoCardBoard::begin() {
|
||||
NRF52BoardDCDC::begin();
|
||||
|
||||
// Configure battery ADC pin as analog input
|
||||
pinMode(PIN_VBAT_READ, INPUT);
|
||||
|
||||
// Configure button(s)
|
||||
pinMode(PIN_BUTTON_A, INPUT_PULLUP);
|
||||
pinMode(PIN_BUTTON_BOOT, INPUT_PULLUP);
|
||||
|
||||
// Buzzer off
|
||||
#if defined(HAS_BUZZER) && PIN_BUZZER >= 0
|
||||
pinMode(PIN_BUZZER, OUTPUT);
|
||||
digitalWrite(PIN_BUZZER, LOW);
|
||||
#endif
|
||||
|
||||
// RGB LED off at boot
|
||||
#if defined(HAS_RGB_LED)
|
||||
ledOff();
|
||||
#endif
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Battery voltage reading via nRF52840 SAADC
|
||||
//
|
||||
// The T-Echo Card has a voltage divider on AIN0 (P0.02).
|
||||
// nRF52840 SAADC: 12-bit, internal 0.6V reference, configurable gain.
|
||||
// With 1/6 gain: input range 0–3.6V. Multiply by divider ratio (ADC_MULTIPLIER).
|
||||
//
|
||||
// NOTE: The T-Echo Lite has a known issue reading 100% / 6.00V constantly.
|
||||
// This is likely caused by incorrect SAADC configuration (wrong gain, wrong
|
||||
// reference, or the pin being pulled high by the charging circuit).
|
||||
// We use explicit SAADC register programming to avoid that issue.
|
||||
// -----------------------------------------------------------------------------
|
||||
float TechoCardBoard::getBatteryVoltage() {
|
||||
uint32_t now = millis();
|
||||
|
||||
// Cache battery reading — only read every 10 seconds
|
||||
if (_cached_battery_mv > 0 && (now - _last_battery_read) < 10000) {
|
||||
return _cached_battery_mv;
|
||||
}
|
||||
|
||||
// Configure SAADC for single-shot reading
|
||||
NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_12bit;
|
||||
|
||||
// Channel 0: AIN0 (P0.02), 1/6 gain, internal 0.6V reference
|
||||
// Effective range: 0 – 3.6V
|
||||
NRF_SAADC->CH[0].PSELP = SAADC_CH_PSELP_PSELP_AnalogInput0; // AIN0
|
||||
NRF_SAADC->CH[0].PSELN = SAADC_CH_PSELN_PSELN_NC; // Single-ended
|
||||
NRF_SAADC->CH[0].CONFIG =
|
||||
(SAADC_CH_CONFIG_GAIN_Gain1_6 << SAADC_CH_CONFIG_GAIN_Pos) |
|
||||
(SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_REFSEL_Pos) |
|
||||
(SAADC_CH_CONFIG_TACQ_40us << SAADC_CH_CONFIG_TACQ_Pos) |
|
||||
(SAADC_CH_CONFIG_MODE_SE << SAADC_CH_CONFIG_MODE_Pos) |
|
||||
(SAADC_CH_CONFIG_BURST_Disabled << SAADC_CH_CONFIG_BURST_Pos) |
|
||||
(SAADC_CH_CONFIG_RESP_Bypass << SAADC_CH_CONFIG_RESP_Pos) |
|
||||
(SAADC_CH_CONFIG_RESN_Bypass << SAADC_CH_CONFIG_RESN_Pos);
|
||||
|
||||
// Set up result buffer
|
||||
volatile int16_t result = 0;
|
||||
NRF_SAADC->RESULT.PTR = (uint32_t)&result;
|
||||
NRF_SAADC->RESULT.MAXCNT = 1;
|
||||
|
||||
// Enable, calibrate on first use
|
||||
NRF_SAADC->ENABLE = SAADC_ENABLE_ENABLE_Enabled;
|
||||
|
||||
// Start and wait for sample
|
||||
NRF_SAADC->EVENTS_END = 0;
|
||||
NRF_SAADC->TASKS_START = 1;
|
||||
while (!NRF_SAADC->EVENTS_STARTED);
|
||||
NRF_SAADC->EVENTS_STARTED = 0;
|
||||
|
||||
NRF_SAADC->TASKS_SAMPLE = 1;
|
||||
while (!NRF_SAADC->EVENTS_END);
|
||||
NRF_SAADC->EVENTS_END = 0;
|
||||
|
||||
NRF_SAADC->TASKS_STOP = 1;
|
||||
while (!NRF_SAADC->EVENTS_STOPPED);
|
||||
NRF_SAADC->EVENTS_STOPPED = 0;
|
||||
|
||||
// Disable SAADC to save power
|
||||
NRF_SAADC->ENABLE = SAADC_ENABLE_ENABLE_Disabled;
|
||||
|
||||
// Convert: voltage = (result / 4096) * 3.6V * ADC_MULTIPLIER * 1000 (mV)
|
||||
if (result < 0) result = 0;
|
||||
float voltage_mv = ((float)result / 4096.0f) * 3600.0f * _adc_multiplier;
|
||||
|
||||
_cached_battery_mv = voltage_mv;
|
||||
_last_battery_read = now;
|
||||
|
||||
return voltage_mv;
|
||||
}
|
||||
|
||||
uint8_t TechoCardBoard::getBatteryPercent() {
|
||||
float mv = getBatteryVoltage();
|
||||
if (mv <= 0) return 0;
|
||||
|
||||
// Simple linear approximation for single-cell LiPo
|
||||
// 3200 mV = 0%, 4200 mV = 100%
|
||||
if (mv >= 4200.0f) return 100;
|
||||
if (mv <= 3200.0f) return 0;
|
||||
return (uint8_t)(((mv - 3200.0f) / 1000.0f) * 100.0f);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// GPS power control
|
||||
// -----------------------------------------------------------------------------
|
||||
void TechoCardBoard::enableGPS(bool enable) {
|
||||
#if defined(HAS_GPS) && PIN_GPS_EN >= 0
|
||||
digitalWrite(PIN_GPS_EN, enable ? HIGH : LOW);
|
||||
#endif
|
||||
#if defined(HAS_GPS) && PIN_GPS_RF_EN >= 0
|
||||
digitalWrite(PIN_GPS_RF_EN, enable ? HIGH : LOW);
|
||||
#endif
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Speaker power control
|
||||
// -----------------------------------------------------------------------------
|
||||
void TechoCardBoard::enableSpeaker(bool enable) {
|
||||
#if defined(HAS_SPEAKER)
|
||||
digitalWrite(PIN_SPK_EN, enable ? HIGH : LOW);
|
||||
#if PIN_SPK_EN2 >= 0
|
||||
digitalWrite(PIN_SPK_EN2, enable ? HIGH : LOW);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// RGB LED — WS2812 via NeoPixel protocol
|
||||
// Simple bit-bang implementation for nRF52840 at 64MHz
|
||||
// -----------------------------------------------------------------------------
|
||||
void TechoCardBoard::setLED(uint8_t r, uint8_t g, uint8_t b) {
|
||||
#if defined(HAS_RGB_LED)
|
||||
// TODO: Implement WS2812 bit-bang or use Adafruit_NeoPixel library
|
||||
// For initial bringup, just use the Adafruit_NeoPixel library
|
||||
// which is available in the Adafruit nRF52 Arduino core
|
||||
(void)r; (void)g; (void)b;
|
||||
#endif
|
||||
}
|
||||
|
||||
void TechoCardBoard::ledOff() {
|
||||
setLED(0, 0, 0);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Buzzer — PWM tone generation
|
||||
// -----------------------------------------------------------------------------
|
||||
void TechoCardBoard::buzz(uint16_t freq_hz, uint16_t duration_ms) {
|
||||
#if defined(HAS_BUZZER) && PIN_BUZZER >= 0
|
||||
if (freq_hz == 0 || duration_ms == 0) {
|
||||
noTone(PIN_BUZZER);
|
||||
return;
|
||||
}
|
||||
tone(PIN_BUZZER, freq_hz, duration_ms);
|
||||
#else
|
||||
(void)freq_hz; (void)duration_ms;
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
// =============================================================================
|
||||
// TechoCardBoard — Board class for LilyGo T-Echo Card
|
||||
//
|
||||
// Extends NRF52BoardDCDC with:
|
||||
// - Battery ADC (AIN0, P0.02) with solar charging via BQ25896
|
||||
// - GPS power control (L76K)
|
||||
// - Speaker/mic enable
|
||||
// - RGB LED control
|
||||
// - Buzzer
|
||||
// - NFC NDEF contact sharing
|
||||
// =============================================================================
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <helpers/NRF52Board.h>
|
||||
#include "variant.h"
|
||||
|
||||
#ifdef NRF52_POWER_MANAGEMENT
|
||||
// Power management config for T-Echo Card
|
||||
// AIN0 (P0.02) for battery voltage sensing
|
||||
// REFSEL=4 → 5/8 VDD ≈ 2.0625V threshold (with 2:1 divider → ~4.125V cell)
|
||||
static const PowerMgtConfig TECHO_CARD_POWER_CONFIG = {
|
||||
.lpcomp_ain_channel = BATTERY_ADC_AIN, // AIN0
|
||||
.lpcomp_refsel = 4, // 5/8 VDD
|
||||
.voltage_bootlock = 3100, // Don't boot below 3.1V
|
||||
};
|
||||
#endif
|
||||
|
||||
class TechoCardBoard : public NRF52BoardDCDC {
|
||||
private:
|
||||
float _adc_multiplier;
|
||||
uint32_t _last_battery_read;
|
||||
float _cached_battery_mv;
|
||||
|
||||
public:
|
||||
TechoCardBoard()
|
||||
: _adc_multiplier(ADC_MULTIPLIER),
|
||||
_last_battery_read(0),
|
||||
_cached_battery_mv(0) {}
|
||||
|
||||
void begin() override;
|
||||
|
||||
// Battery
|
||||
float getBatteryVoltage() override;
|
||||
uint8_t getBatteryPercent() override;
|
||||
float getAdcMultiplier() override { return _adc_multiplier; }
|
||||
void setAdcMultiplier(float mult) { _adc_multiplier = mult; }
|
||||
|
||||
// GPS power control
|
||||
void enableGPS(bool enable);
|
||||
|
||||
// Speaker power control
|
||||
void enableSpeaker(bool enable);
|
||||
|
||||
// RGB LED
|
||||
void setLED(uint8_t r, uint8_t g, uint8_t b);
|
||||
void ledOff();
|
||||
|
||||
// Buzzer
|
||||
void buzz(uint16_t freq_hz, uint16_t duration_ms);
|
||||
|
||||
#ifdef NRF52_POWER_MANAGEMENT
|
||||
const PowerMgtConfig* getPowerConfig() const override {
|
||||
return &TECHO_CARD_POWER_CONFIG;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
// =============================================================================
|
||||
// Arduino pin compatibility header for LilyGo T-Echo Card
|
||||
//
|
||||
// This file provides Arduino-standard pin name aliases for the nRF52840 GPIOs.
|
||||
// Only needed if creating a custom board variant inside the Adafruit nRF52
|
||||
// Arduino framework package. If using build flag overrides in platformio.ini,
|
||||
// this file is optional.
|
||||
// =============================================================================
|
||||
|
||||
// On nRF52840, Arduino digital pin numbers map 1:1 to nRF GPIO numbers
|
||||
// (0–47 for port 0 and port 1).
|
||||
|
||||
// LED
|
||||
#define LED_BUILTIN PIN_LED1
|
||||
#define PIN_LED1 39 // WS2812 RGB LED data (1, 7)
|
||||
#define LED_STATE_ON 1
|
||||
|
||||
// Buttons
|
||||
#define PIN_BUTTON1 42 // Button A — orange front button (1, 10)
|
||||
#define PIN_BUTTON2 24 // Boot button (0, 24)
|
||||
|
||||
// Serial (USB CDC)
|
||||
// nRF52840 native USB — no UART pin assignment needed for Serial
|
||||
// Serial1 is used for GPS
|
||||
#define PIN_SERIAL1_RX 21 // GPS TX → nRF RX (0, 21)
|
||||
#define PIN_SERIAL1_TX 19 // nRF TX → GPS RX (0, 19)
|
||||
|
||||
// I2C
|
||||
#define PIN_WIRE_SDA 36 // (1, 4)
|
||||
#define PIN_WIRE_SCL 34 // (1, 2)
|
||||
|
||||
// SPI (LoRa — directly mapped, RadioLib handles pin control)
|
||||
#define PIN_SPI_MISO 17 // (0, 17)
|
||||
#define PIN_SPI_MOSI 15 // (0, 15)
|
||||
#define PIN_SPI_SCK 13 // (0, 13)
|
||||
|
||||
// Analog
|
||||
#define PIN_A0 2 // (0, 2) — Battery ADC / AIN0
|
||||
|
||||
// QSPI Flash (ZD25WQ32CEIGR 4MB)
|
||||
// nRF52840 QSPI uses fixed pins — framework handles these
|
||||
// #define PIN_QSPI_SCK 19 // Conflict with GPS TX — check if QSPI is on different pins
|
||||
// NOTE: QSPI pin mapping needs verification on actual hardware.
|
||||
// The T-Echo Card may use SPI (not QSPI) for external flash.
|
||||
|
||||
// NFC (dedicated nRF52840 NFC pins — not GPIO-assignable)
|
||||
// NFC1 = P0.09, NFC2 = P0.10
|
||||
// These are only usable as NFC when NFC is enabled in UICR.
|
||||
// If NFC is disabled, they become GPIO9 and GPIO10.
|
||||
|
||||
// PDM Microphone
|
||||
#define PIN_PDM_CLK 35 // (1, 3)
|
||||
#define PIN_PDM_DIN 37 // (1, 5)
|
||||
|
||||
// I2S Speaker (MAX98357)
|
||||
#define PIN_I2S_SCK 16 // BCLK (0, 16)
|
||||
#define PIN_I2S_LRCK 22 // LRCK / WS (0, 22)
|
||||
#define PIN_I2S_SDOUT 20 // DATA (0, 20)
|
||||
@@ -0,0 +1,106 @@
|
||||
; =============================================================================
|
||||
; LilyGo T-Echo Card — Meck variant configuration
|
||||
;
|
||||
; nRF52840 + SX1262 (HPB16B3) + SSD1315 OLED (72×40) + L76K GPS
|
||||
; + MAX98357 Speaker + MP34DT05 PDM Mic + ICM20948 IMU + Solar + NFC
|
||||
;
|
||||
; Platform: nRF52 (Adafruit nRF52 Arduino)
|
||||
; =============================================================================
|
||||
|
||||
; --- Base configuration for all T-Echo Card builds ---
|
||||
[lilygo_techo_card]
|
||||
extends = nrf52_base
|
||||
platform = https://github.com/maxgerhardt/platform-nordicnrf52.git
|
||||
board = lilygo_techo_card
|
||||
board_check = false
|
||||
extra_scripts =
|
||||
create-uf2.py
|
||||
build_flags = ${nrf52_base.build_flags}
|
||||
-I variants/lilygo_techo_card
|
||||
-D LILYGO_TECHO_CARD
|
||||
-D NRF52_POWER_MANAGEMENT
|
||||
; I2C
|
||||
-D PIN_BOARD_SDA=36
|
||||
-D PIN_BOARD_SCL=34
|
||||
; LoRa SX1262 (HPB16B3 module)
|
||||
-D RADIO_CLASS=CustomSX1262
|
||||
-D WRAPPER_CLASS=CustomSX1262Wrapper
|
||||
-D P_LORA_NSS=11
|
||||
-D P_LORA_DIO_1=40
|
||||
-D P_LORA_RESET=7
|
||||
-D P_LORA_BUSY=14
|
||||
-D P_LORA_SCLK=13
|
||||
-D P_LORA_MISO=17
|
||||
-D P_LORA_MOSI=15
|
||||
-D LORA_TX_POWER=22
|
||||
-D SX126X_CURRENT_LIMIT=140
|
||||
-D SX126X_RX_BOOSTED_GAIN=1
|
||||
-D SX126X_DIO2_AS_RF_SWITCH=1
|
||||
; Display — SSD1315 OLED (72×40, I2C, SSD1306-compatible)
|
||||
-D DISPLAY_CLASS=SSD1306Display
|
||||
-D PIN_OLED_RESET=-1
|
||||
; GPS — L76K
|
||||
-D HAS_GPS=1
|
||||
-D PIN_GPS_TX=19
|
||||
-D PIN_GPS_RX=21
|
||||
-D PIN_GPS_EN=47
|
||||
-D GPS_BAUDRATE=9600
|
||||
-D ENV_INCLUDE_GPS=1
|
||||
; Battery ADC
|
||||
-D PIN_VBAT_READ=2
|
||||
; User button
|
||||
-D PIN_USER_BTN=42
|
||||
; Board class
|
||||
-D BOARD_CLASS=TechoCardBoard
|
||||
build_src_filter = ${nrf52_base.build_src_filter}
|
||||
+<../variants/lilygo_techo_card/*.cpp>
|
||||
lib_deps = ${nrf52_base.lib_deps}
|
||||
olikraus/U8g2 @ ^2.35.19
|
||||
stevemarple/MicroNMEA @ ^2.0.6
|
||||
|
||||
; =============================================================================
|
||||
; Build Environments
|
||||
; =============================================================================
|
||||
|
||||
; --- BLE Companion Radio ---
|
||||
; Pairs with MeshCore companion app (Android/iOS/Web) over Bluetooth.
|
||||
; Includes GPS for location and time sync.
|
||||
[env:meck_techo_card_companion_radio_ble]
|
||||
extends = lilygo_techo_card
|
||||
build_flags = ${lilygo_techo_card.build_flags}
|
||||
-D FIRMWARE_NAME='"Meck T-Echo Card BLE"'
|
||||
; Debug (disable for release)
|
||||
; -D MESH_DEBUG
|
||||
; -D BLE_DEBUG_LOGGING
|
||||
build_src_filter = ${lilygo_techo_card.build_src_filter}
|
||||
+<../examples/companion_radio/*.cpp>
|
||||
|
||||
; --- Repeater ---
|
||||
; Standalone LoRa repeater node. GPS for position adverts.
|
||||
; OLED shows status. Solar + 800mAh battery for outdoor deployment.
|
||||
[env:meck_techo_card_repeater]
|
||||
extends = lilygo_techo_card
|
||||
build_flags = ${lilygo_techo_card.build_flags}
|
||||
-D FIRMWARE_NAME='"Meck T-Echo Card Repeater"'
|
||||
; -D MESH_DEBUG
|
||||
build_src_filter = ${lilygo_techo_card.build_src_filter}
|
||||
+<../examples/simple_repeater/*.cpp>
|
||||
|
||||
; --- Room Server ---
|
||||
; BBS-style message board node.
|
||||
[env:meck_techo_card_room_server]
|
||||
extends = lilygo_techo_card
|
||||
build_flags = ${lilygo_techo_card.build_flags}
|
||||
-D FIRMWARE_NAME='"Meck T-Echo Card Room"'
|
||||
build_src_filter = ${lilygo_techo_card.build_src_filter}
|
||||
+<../examples/simple_room_server/*.cpp>
|
||||
|
||||
; --- Sensor Node ---
|
||||
; Telemetry node with GPS position reporting.
|
||||
; IMU data (ICM20948) can be added as a custom sensor source.
|
||||
[env:meck_techo_card_sensor]
|
||||
extends = lilygo_techo_card
|
||||
build_flags = ${lilygo_techo_card.build_flags}
|
||||
-D FIRMWARE_NAME='"Meck T-Echo Card Sensor"'
|
||||
build_src_filter = ${lilygo_techo_card.build_src_filter}
|
||||
+<../examples/simple_sensor/*.cpp>
|
||||
@@ -0,0 +1,95 @@
|
||||
// =============================================================================
|
||||
// MeshCore target implementation for LilyGo T-Echo Card
|
||||
//
|
||||
// nRF52840 + SX1262 (HPB16B3 module) + SSD1315 OLED + L76K GPS
|
||||
// =============================================================================
|
||||
|
||||
#include "target.h"
|
||||
#include "variant.h"
|
||||
|
||||
// --- SPI for LoRa radio (software SPI on nRF52) ---
|
||||
// The HPB16B3 SX1262 module uses dedicated SPI pins, not shared with anything else.
|
||||
// RadioLib Module handles the SPI internally when given pin numbers.
|
||||
static Module radio_module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
|
||||
|
||||
// --- Radio driver ---
|
||||
RADIO_CLASS radio_driver(&radio_module);
|
||||
WRAPPER_CLASS radio_wrapper(radio_driver);
|
||||
|
||||
// --- Board ---
|
||||
TechoCardBoard board;
|
||||
|
||||
// --- Display (SSD1306-compatible, SSD1315 at 0x3C, 72x40) ---
|
||||
#ifdef DISPLAY_CLASS
|
||||
DISPLAY_CLASS display(OLED_WIDTH, OLED_HEIGHT);
|
||||
#endif
|
||||
|
||||
// --- MeshCore stores ---
|
||||
mesh::IdentityStore identity_store;
|
||||
mesh::NodePrefs node_prefs;
|
||||
mesh::DataStore data_store;
|
||||
|
||||
// --- Sensor manager ---
|
||||
#if defined(ENV_INCLUDE_GPS) && ENV_INCLUDE_GPS
|
||||
#include <helpers/sensors/MicroNMEALocationProvider.h>
|
||||
static MicroNMEALocationProvider gps_provider(Serial1);
|
||||
EnvironmentSensorManager sensor_manager(gps_provider);
|
||||
#else
|
||||
EnvironmentSensorManager sensor_manager;
|
||||
#endif
|
||||
|
||||
// --- Target initialization ---
|
||||
void target_setup() {
|
||||
// Enable OLED power
|
||||
#if PIN_OLED_EN >= 0
|
||||
pinMode(PIN_OLED_EN, OUTPUT);
|
||||
digitalWrite(PIN_OLED_EN, HIGH);
|
||||
delay(10);
|
||||
#endif
|
||||
|
||||
// Enable GPS power
|
||||
#if defined(HAS_GPS) && PIN_GPS_EN >= 0
|
||||
pinMode(PIN_GPS_EN, OUTPUT);
|
||||
digitalWrite(PIN_GPS_EN, HIGH);
|
||||
delay(10);
|
||||
#endif
|
||||
|
||||
// GPS RF/LNA enable
|
||||
#if defined(HAS_GPS) && PIN_GPS_RF_EN >= 0
|
||||
pinMode(PIN_GPS_RF_EN, OUTPUT);
|
||||
digitalWrite(PIN_GPS_RF_EN, HIGH);
|
||||
#endif
|
||||
|
||||
// Initialize GPS UART
|
||||
#if defined(HAS_GPS)
|
||||
Serial1.setPins(PIN_GPS_RX, PIN_GPS_TX);
|
||||
Serial1.begin(GPS_BAUDRATE);
|
||||
#endif
|
||||
|
||||
// Speaker off by default (save power)
|
||||
#if defined(HAS_SPEAKER)
|
||||
pinMode(PIN_SPK_EN, OUTPUT);
|
||||
digitalWrite(PIN_SPK_EN, LOW);
|
||||
#if PIN_SPK_EN2 >= 0
|
||||
pinMode(PIN_SPK_EN2, OUTPUT);
|
||||
digitalWrite(PIN_SPK_EN2, LOW);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Initialize I2C
|
||||
Wire.setPins(I2C_SDA, I2C_SCL);
|
||||
Wire.begin();
|
||||
Wire.setClock(400000);
|
||||
|
||||
// Initialize display
|
||||
#ifdef DISPLAY_CLASS
|
||||
display.begin(OLED_I2C_ADDR);
|
||||
#endif
|
||||
|
||||
// Board-level init
|
||||
board.begin();
|
||||
|
||||
// Initialize LoRa radio
|
||||
// SX1262 DIO2 as RF switch control (common for HPB16B3 modules)
|
||||
radio_driver.setDio2AsRfSwitch(true);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
// =============================================================================
|
||||
// MeshCore target declarations for LilyGo T-Echo Card
|
||||
// =============================================================================
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <RadioLib.h>
|
||||
#include <helpers/ArduinoHelpers.h>
|
||||
#include <helpers/RadioLibWrappers.h>
|
||||
#include <helpers/NRF52Board.h>
|
||||
#include <helpers/CustomSX1262Wrapper.h>
|
||||
#include <helpers/IdentityStore.h>
|
||||
#include <helpers/NodePrefs.h>
|
||||
#include <helpers/DataStore.h>
|
||||
#include <helpers/SensorManager.h>
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
#include <helpers/ui/DisplaySSD1306.h>
|
||||
#endif
|
||||
|
||||
#include "TechoCardBoard.h"
|
||||
|
||||
// Hardware object declarations (instantiated in target.cpp)
|
||||
extern RADIO_CLASS radio_driver;
|
||||
extern WRAPPER_CLASS radio_wrapper;
|
||||
extern TechoCardBoard board;
|
||||
|
||||
#ifdef DISPLAY_CLASS
|
||||
extern DISPLAY_CLASS display;
|
||||
#endif
|
||||
|
||||
extern mesh::IdentityStore identity_store;
|
||||
extern mesh::NodePrefs node_prefs;
|
||||
extern mesh::DataStore data_store;
|
||||
extern EnvironmentSensorManager sensor_manager;
|
||||
|
||||
// Target initialization
|
||||
void target_setup();
|
||||
@@ -0,0 +1,193 @@
|
||||
#pragma once
|
||||
|
||||
// =============================================================================
|
||||
// LilyGo T-Echo Card — Pin Definitions for Meck Firmware
|
||||
//
|
||||
// nRF52840 + SX1262 + SSD1315 (72×40 OLED) + L76K GPS + MAX98357 Speaker
|
||||
// + MP34DT05 PDM Microphone + ICM20948 IMU + BQ25896 Charger + Solar
|
||||
//
|
||||
// Pin notation from LilyGo pinmap: (port, pin) → nRF GPIO = port*32 + pin
|
||||
// =============================================================================
|
||||
|
||||
#define LILYGO_TECHO_CARD
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// I2C Bus (shared: OLED, IMU ICM20948, fuel gauge BQ27220 if present)
|
||||
// -----------------------------------------------------------------------------
|
||||
#define I2C_SDA 36 // (1, 4)
|
||||
#define I2C_SCL 34 // (1, 2)
|
||||
#define PIN_BOARD_SDA I2C_SDA
|
||||
#define PIN_BOARD_SCL I2C_SCL
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SX1262 LoRa Radio (SPI bit-bang on nRF52)
|
||||
// -----------------------------------------------------------------------------
|
||||
#define P_LORA_NSS 11 // (0, 11) — CS
|
||||
#define P_LORA_RESET 7 // (0, 7) — RST
|
||||
#define P_LORA_SCLK 13 // (0, 13) — SCK
|
||||
#define P_LORA_MOSI 15 // (0, 15) — MOSI
|
||||
#define P_LORA_MISO 17 // (0, 17) — MISO
|
||||
#define P_LORA_BUSY 14 // (0, 14) — BUSY
|
||||
#define P_LORA_DIO_1 40 // (1, 8) — DIO1 / interrupt
|
||||
|
||||
// RF switch control (HPB16B3 module)
|
||||
#define LORA_DIO2 5 // (0, 5) — DIO2 (TXCO / RF switch)
|
||||
#define LORA_RF_VC1 27 // (0, 27) — RF_VC1
|
||||
#define LORA_RF_VC2 33 // (1, 1) — RF_VC2
|
||||
|
||||
// LoRa radio power enable (from schematic: LORA_EN drives RT9080 for LORA_VDD)
|
||||
// NOTE: Confirm actual GPIO — pinmap shows dedicated enable pin
|
||||
// For now use -1 if always powered
|
||||
#define PIN_LORA_EN -1
|
||||
|
||||
// Default radio settings (Australia)
|
||||
#ifndef LORA_TX_POWER
|
||||
#define LORA_TX_POWER 22
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 0.42" OLED Display — SSD1315 (SSD1306-compatible), 72×40, I2C
|
||||
// -----------------------------------------------------------------------------
|
||||
#define HAS_OLED 1
|
||||
#define OLED_I2C_ADDR 0x3C
|
||||
#define OLED_WIDTH 72
|
||||
#define OLED_HEIGHT 40
|
||||
#define OLED_SDA I2C_SDA
|
||||
#define OLED_SCL I2C_SCL
|
||||
|
||||
// OLED power control via RT9080 enable pin
|
||||
#define PIN_OLED_EN 30 // (0, 30) — RT9080_EN
|
||||
|
||||
// No hardware reset pin for OLED on T-Echo Card
|
||||
#define PIN_OLED_RESET -1
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// GPS — L76K Multi-GNSS (GPS, GLONASS, BeiDou, QZSS)
|
||||
// -----------------------------------------------------------------------------
|
||||
#define HAS_GPS 1
|
||||
#define GPS_BAUDRATE 9600
|
||||
#define PIN_GPS_TX 19 // (0, 19) — nRF TX → GPS RX
|
||||
#define PIN_GPS_RX 21 // (0, 21) — nRF RX ← GPS TX
|
||||
#define PIN_GPS_EN 47 // (1, 15) — GPS power enable
|
||||
#define PIN_GPS_WAKEUP 25 // (0, 25) — GPS wakeup
|
||||
#define PIN_GPS_1PPS 23 // (0, 23) — 1PPS time pulse
|
||||
#define PIN_GPS_RF_EN 29 // (0, 29) — GPS RF / LNA enable
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Battery & Power
|
||||
// -----------------------------------------------------------------------------
|
||||
#define PIN_VBAT_READ 2 // (0, 2) = AIN0 — battery voltage ADC
|
||||
#define BATTERY_ADC_AIN 0 // nRF SAADC AIN channel number
|
||||
#define BATTERY_CAPACITY_MAH 800
|
||||
|
||||
// Battery voltage divider calibration
|
||||
// The T-Echo Lite has issues reading battery correctly — we'll need to
|
||||
// calibrate this with actual hardware. Starting with a reasonable default.
|
||||
// nRF52840 SAADC: 0.6V internal ref, 1/6 gain → 0–3.6V range
|
||||
// If there's a voltage divider (e.g. 2:1), multiply by 2.
|
||||
// Adjust ADC_MULTIPLIER after measuring real voltage vs ADC reading.
|
||||
#ifndef ADC_MULTIPLIER
|
||||
#define ADC_MULTIPLIER 2.0f
|
||||
#endif
|
||||
|
||||
// BQ25896 charger is on I2C but managed by hardware — no software control needed
|
||||
// Solar panel input: 0.25W 5V via VBUS
|
||||
|
||||
// Auto-shutdown threshold (millivolts)
|
||||
#define AUTO_SHUTDOWN_MILLIVOLTS 3200
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Speaker — MAX98357 I2S Class-D Mono Amp (8Ω, 1W)
|
||||
// -----------------------------------------------------------------------------
|
||||
#define HAS_SPEAKER 1
|
||||
#define PIN_SPK_EN 43 // (1, 11) — speaker amplifier enable
|
||||
#define PIN_SPK_EN2 3 // (0, 3) — secondary enable
|
||||
#define PIN_SPK_BCLK 16 // (0, 16) — I2S bit clock
|
||||
#define PIN_SPK_DATA 20 // (0, 20) — I2S data out
|
||||
#define PIN_SPK_LRCK 22 // (0, 22) — I2S word select / LRCK
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Microphone — MP34DT05 Digital MEMS PDM
|
||||
// -----------------------------------------------------------------------------
|
||||
#define HAS_MICROPHONE 1
|
||||
#define PIN_MIC_CLK 35 // (1, 3) — PDM clock
|
||||
#define PIN_MIC_DATA 37 // (1, 5) — PDM data
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Buttons
|
||||
// -----------------------------------------------------------------------------
|
||||
#define PIN_BUTTON_A 42 // (1, 10) — orange button (front, main user button)
|
||||
#define PIN_BUTTON_BOOT 24 // (0, 24) — boot button (nRF52840 BOOT)
|
||||
#define PIN_USER_BTN PIN_BUTTON_A
|
||||
|
||||
// Button_B is RESET — hardware only, no GPIO
|
||||
|
||||
// Active LOW for nRF52 buttons (internal pull-up, press = LOW)
|
||||
#define BUTTON_ACTIVE_LOW 1
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Buzzer
|
||||
// -----------------------------------------------------------------------------
|
||||
#define HAS_BUZZER 1
|
||||
#define PIN_BUZZER 38 // (1, 6) — piezo buzzer data / PWM
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// WS2812 RGB LED (3 LEDs in series)
|
||||
// -----------------------------------------------------------------------------
|
||||
#define HAS_RGB_LED 1
|
||||
#define PIN_RGB_LED_1 39 // (1, 7) — WS2812 data 1
|
||||
#define PIN_RGB_LED_2 44 // (1, 12) — WS2812 data 2
|
||||
#define PIN_RGB_LED_3 28 // (0, 28) — WS2812 data 3
|
||||
// Typically only one data pin drives the chain; confirm wiring on hardware
|
||||
#define PIN_NEOPIXEL PIN_RGB_LED_1
|
||||
#define NUM_NEOPIXELS 3
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// IMU — ICM20948 9-axis MotionTracking (accelerometer + gyro + compass)
|
||||
// -----------------------------------------------------------------------------
|
||||
#define HAS_IMU 1
|
||||
#define IMU_I2C_ADDR 0x68
|
||||
#define IMU_SDA I2C_SDA
|
||||
#define IMU_SCL I2C_SCL
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// NFC — nRF52840 NFC-A (Type 2 Tag)
|
||||
// NFC uses dedicated NFC1/NFC2 pins on nRF52840 (P0.09 / P0.10)
|
||||
// These are fixed by silicon — no GPIO config needed.
|
||||
// NFC is handled by the nRF52 SDK nfc_t2t_lib.
|
||||
// -----------------------------------------------------------------------------
|
||||
#define HAS_NFC 1
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// External Flash — ZD25WQ32CEIGR (4MB SPI Flash)
|
||||
// Uses QSPI interface on nRF52840
|
||||
// Pin mapping from nRF52840 QSPI peripheral (typically fixed)
|
||||
// -----------------------------------------------------------------------------
|
||||
#define HAS_EXT_FLASH 1
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// No SD Card on T-Echo Card (unlike T-Echo which has e-paper + no SD either)
|
||||
// Settings stored in LittleFS on internal/external flash
|
||||
// -----------------------------------------------------------------------------
|
||||
// #define HAS_SDCARD
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// No dedicated RTC chip — time from GPS or BLE companion sync
|
||||
// nRF52840 has a 32.768 kHz RTC peripheral for timekeeping while running
|
||||
// -----------------------------------------------------------------------------
|
||||
// #define HAS_PCF85063_RTC
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Misc / Compatibility
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// No e-ink display
|
||||
// #define HAS_EINK
|
||||
|
||||
// This board has no physical keyboard
|
||||
// #define HAS_PHYSICAL_KEYBOARD
|
||||
|
||||
// Fallback for code that references GPS_BAUDRATE without HAS_GPS guard
|
||||
#ifndef GPS_BAUDRATE
|
||||
#define GPS_BAUDRATE 9600
|
||||
#endif
|
||||
Reference in New Issue
Block a user