Compare commits

...
6 Commits
Author SHA1 Message Date
Manuel b01079a281 update commit references 2026-05-31 23:03:13 +02:00
Manuel b9a0100c0d add ES8311, GT911, AW35615, LP5814 to I2C scanner 2026-05-31 22:56:07 +02:00
Manuel 65c7112a39 add ADS1115+AW35615 for wio tracker L2 2026-05-31 22:55:07 +02:00
Manuel 6c23fcddf0 implement mesh LED 2026-05-31 13:55:44 +02:00
Manuel 4d7d021ef5 enable power save 2026-05-31 13:55:05 +02:00
Manuel 025c6854e8 initial commit 2026-05-31 01:17:11 +02:00
16 changed files with 565 additions and 13 deletions
+42
View File
@@ -0,0 +1,42 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"-D BOARD_HAS_PSRAM",
"-D ARDUINO_USB_CDC_ON_BOOT=1",
"-D ARDUINO_USB_MODE=1",
"-D ARDUINO_RUNNING_CORE=1",
"-D ARDUINO_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", "espidf"],
"name": "seeed_wio_tracker_L2 (16 MB FLASH, 8 MB 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"
}
+1 -1
View File
@@ -126,7 +126,7 @@ lib_deps =
[device-ui_base]
lib_deps =
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
https://github.com/meshtastic/device-ui/archive/34e96d298e78ddf28b7c7e0e82b7bea503abafc3.zip
https://github.com/meshtastic/device-ui/archive/c23fdc22f2ba949829661fdf851846fcf7433d89.zip
; Common libs for environmental measurements in telemetry module
[environmental_base]
+1 -1
View File
@@ -307,7 +307,7 @@ void fsInit()
*/
void setupSDCard()
{
#if defined(HAS_SDCARD) && !defined(SDCARD_USE_SOFT_SPI)
#if defined(HAS_SDCARD) && !defined(SDCARD_USE_SOFT_SPI) && !defined(HAS_SD_MMC)
concurrency::LockGuard g(spiLock);
SDHandler.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
if (!SD.begin(SDCARD_CS, SDHandler, SD_SPI_FREQUENCY)) {
+166
View File
@@ -31,6 +31,10 @@
#include "input/LinuxInputImpl.h"
#endif
#ifdef HAS_ADS1115
#include <Adafruit_ADS1X15.h>
#endif
// Working USB detection for powered/charging states on the RAK platform
#ifdef NRF_APM
#include "nrfx_power.h"
@@ -616,6 +620,164 @@ class AnalogBatteryLevel : public HasBatteryLevel
static AnalogBatteryLevel analogLevel;
#ifdef HAS_ADS1115
#include "SPILock.h"
// AW35615 USB-C CC controller register constants (Arduino Wire, no ESP-IDF dependency)
static constexpr uint8_t AW35615_ADDR = 0x22;
static constexpr uint8_t AW35615_REG_DEVID = 0x01; // Device ID (probe)
static constexpr uint8_t AW35615_REG_ST1A = 0x3D; // STATUS1A: TOGSS[5:3]
static constexpr uint8_t AW35615_REG_ST0 = 0x40; // STATUS0: VBUSOK[7]
static constexpr uint8_t AW35615_VBUSOK = (1 << 7);
static constexpr uint8_t AW35615_TOGSS_MASK = 0x38;
static constexpr uint8_t AW35615_TOGSS_SHIFT = 3;
static constexpr uint8_t AW35615_TOGSS_SNK_CC1 = 5; // device is sink on CC1
static constexpr uint8_t AW35615_TOGSS_SNK_CC2 = 6; // device is sink on CC2
/**
* Battery level sensor using an ADS1115 16-bit ADC on I2C (address 0x48).
* Channel 0 is battery voltage through a ×2 resistive divider, so the
* measured voltage is multiplied by 2.0 to recover the true cell voltage.
* USB/charging state is read from the AW35615 USB-C CC controller (0x22)
* when present; falls back to a voltage threshold when not.
*/
class ADS1115BatteryLevel : public AnalogBatteryLevel
{
public:
bool init()
{
concurrency::LockGuard guard(spiLock);
// Wire is already configured (SDA=47, SCL=48) and the ADC-enable
// expander pin (pin 15) is already HIGH from initVariant().
if (!_ads.begin(ADS1115_ADDR, &Wire)) {
LOG_WARN("ADS1115 not found on I2C bus — battery sensor unavailable");
return false;
}
_ads.setGain(GAIN_TWO); // ±2.048 V FSR matches the voltage-divider ratio
initialized = true;
LOG_INFO("[ADS1115] battery sensor initialized");
// Probe and configure AW35615 USB-C CC controller for VBUS / charging detection
uint8_t devId = 0;
if (aw35615Read(AW35615_REG_DEVID, devId)) {
aw35615_initialized = true;
LOG_INFO("[AW35615] found at 0x22, DEVICE_ID=0x%02x", devId);
// Enable all internal power blocks
aw35615Write(0x0B, 0x0F); // POWER = 0x0F
// Put Rd (pull-down) resistors on both CC pins → device acts as USB-C sink
aw35615Write(0x02, 0x03); // SWITCHES0: PDWN1|PDWN2
// Enable sink toggle so the chip detects CC attachment and sets VBUSOK
aw35615Write(0x08, 0x05); // CONTROL2: MODE=SINK (2<<1) | TOGGLE=1
} else {
LOG_WARN("[AW35615] not found at 0x22, falling back to voltage threshold for USB detection");
}
return true;
}
virtual uint16_t getBattVoltage() override
{
if (!initialized) {
return 0;
}
concurrency::LockGuard guard(spiLock);
static constexpr uint32_t MIN_READ_INTERVAL_MS = 30000;
if (!initial_read_done || !Throttle::isWithinTimespanMs(last_read_ms, MIN_READ_INTERVAL_MS)) {
last_read_ms = millis();
float sum = 0;
for (int i = 0; i < SAMPLE_COUNT; i++) {
int16_t raw = _ads.readADC_SingleEnded(0);
float v = _ads.computeVolts(raw);
sum += v;
}
// Channel 0 sees battery/2 (resistive divider); multiply back, convert to mV
float v = (sum / SAMPLE_COUNT) * 2.0f * 1000.0f;
if (!initial_read_done) {
cached_mv = (uint16_t)v;
initial_read_done = true;
} else {
cached_mv = (uint16_t)(cached_mv + (v - cached_mv) * 0.5f);
}
}
return cached_mv;
}
virtual bool isVbusIn() override
{
concurrency::LockGuard guard(spiLock);
if (aw35615_initialized) {
uint8_t st0 = 0;
if (aw35615Read(AW35615_REG_ST0, st0)) {
bool vbus = (st0 & AW35615_VBUSOK) != 0;
//LOG_DEBUG("[AW35615] STATUS0=0x%02x VBUSOK=%d", st0, (int)vbus);
return vbus;
}
}
// Fallback: CV-phase voltage threshold
static constexpr uint16_t CHARGING_THRESH_MV = (4190 + 10) * NUM_CELLS;
return getBattVoltage() > CHARGING_THRESH_MV;
}
virtual bool isCharging() override
{
if (!isBatteryConnect())
return false;
if (aw35615_initialized) {
concurrency::LockGuard guard(spiLock);
uint8_t st1a = 0;
if (aw35615Read(AW35615_REG_ST1A, st1a)) {
uint8_t togss = (st1a & AW35615_TOGSS_MASK) >> AW35615_TOGSS_SHIFT;
bool charging = (togss == AW35615_TOGSS_SNK_CC1 || togss == AW35615_TOGSS_SNK_CC2);
//LOG_DEBUG("[AW35615] STATUS1A=0x%02x TOGSS=%d charging=%d", st1a, (int)togss, (int)charging);
return charging;
}
}
return isVbusIn();
}
private:
// arduino Wire helpers for AW35615 register access
bool aw35615Read(uint8_t reg, uint8_t &val)
{
Wire.beginTransmission(AW35615_ADDR);
Wire.write(reg);
if (Wire.endTransmission(false) != 0)
return false;
if (Wire.requestFrom(AW35615_ADDR, (uint8_t)1) != 1)
return false;
val = Wire.read();
return true;
}
bool aw35615Write(uint8_t reg, uint8_t val)
{
Wire.beginTransmission(AW35615_ADDR);
Wire.write(reg);
Wire.write(val);
return Wire.endTransmission() == 0;
}
static constexpr uint8_t SAMPLE_COUNT = 3;
Adafruit_ADS1115 _ads;
bool initialized = false;
bool aw35615_initialized = false;
bool initial_read_done = false;
uint16_t cached_mv = 0;
uint32_t last_read_ms = 0;
};
static ADS1115BatteryLevel ads1115BattLevel;
bool Power::ads1115Init()
{
if (ads1115BattLevel.init()) {
batteryLevel = &ads1115BattLevel;
return true;
}
else
return false;
}
#endif // HAS_ADS1115
Power::Power() : OSThread("Power")
{
statusHandler = {};
@@ -725,6 +887,10 @@ bool Power::setup()
found = true;
} else if (meshSolarInit()) {
found = true;
#ifdef HAS_ADS1115
} else if (ads1115Init()) {
found = true;
#endif
} else if (analogInit()) {
found = true;
} else {
+9 -1
View File
@@ -293,6 +293,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// -----------------------------------------------------------------------------
#define NCP5623_ADDR 0x38
#define LP5562_ADDR 0x30
#define LP5814_ADDR 0x2C
// -----------------------------------------------------------------------------
// Audio Codec
// -----------------------------------------------------------------------------
#define ES8311_ADDR 0x18 // same address as MCP9808_ADDR / STK8BXX_ADDR / LIS3DH_ADDR
#define ES7243E_ADDR 0x14
// -----------------------------------------------------------------------------
// Security
@@ -307,10 +314,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// -----------------------------------------------------------------------------
// Touchscreen
// -----------------------------------------------------------------------------
#define FT6336U_ADDR 0x48
#define FT6336U_ADDR 0x48 // same address as ADS1115
#define CST328_ADDR 0x1A // same address as CST226SE
#define CHSC6X_ADDR 0x2E
#define CST226SE_ADDR_ALT 0x5A
#define GT911_ADDR 0x5D // same address as SFA30_ADDR / LPS22HB_ADDR_ALT
// -----------------------------------------------------------------------------
// RAK12035VB Soil Monitor (using RAK12023 up to 3 RAK12035 monitors can be connected)
+5
View File
@@ -48,6 +48,7 @@ class ScanI2C
BMA423,
BQ24295,
LSM6DS3,
AW35615,
TCA9535,
TCA9555,
VEML7700,
@@ -97,6 +98,10 @@ class ScanI2C
CW2015,
SCD30,
ADS1115,
GT911,
LP5814,
ES8311,
ES7243E,
} DeviceType;
// typedef uint8_t DeviceAddress;
+53 -9
View File
@@ -362,7 +362,14 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
#ifdef HAS_LP5562
SCAN_SIMPLE_CASE(LP5562_ADDR, LP5562, "LP5562", (uint8_t)addr.address);
#endif
case XPOWERS_AXP192_AXP2101_ADDRESS:
#ifdef HAS_LP5814
SCAN_SIMPLE_CASE(LP5814_ADDR, LP5814, "LP5814", (uint8_t)addr.address);
#endif
#ifdef HAS_ES7243E
SCAN_SIMPLE_CASE(ES7243E_ADDR, ES7243E, "ES7243E", (uint8_t)addr.address);
#endif
case XPOWERS_AXP192_AXP2101_ADDRESS:
#ifndef SEEED_WIO_TRACKER_L2 // false positive
// Do we have the axp2101/192 or the TCA8418
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x90), 1);
if (registerValue == 0x0) {
@@ -372,6 +379,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
logFoundDevice("AXP192/AXP2101", (uint8_t)addr.address);
type = PMU_AXP192_AXP2101;
}
#endif
break;
case BME_ADDR:
case BME_ADDR_ALTERNATE:
@@ -479,6 +487,13 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
// We need to check for STK8BAXX first, since register 0x07 is new data flag for the z-axis and can produce some
// weird result. and register 0x00 doesn't seems to be colliding with MCP9808 and LIS3DH chips.
{
// Check register 0xFD for 0x83 to ID ES8311 audio codec.
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFD), 1);
if (registerValue == 0x83) {
type = ES8311;
logFoundDevice("ES8311", (uint8_t)addr.address);
break;
}
#ifdef HAS_STK8XXX
// Check register 0x00 for 0x8700 response to ID STK8BA53 chip.
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 2);
@@ -535,6 +550,22 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
break;
case LPS22HB_ADDR_ALT:
// GT911 touchscreen: product ID register 0x8140 returns "911"
{
uint8_t gt911_reg[] = {0x81, 0x40};
uint8_t gt911_buf[4] = {0};
i2cBus->beginTransmission(addr.address);
i2cBus->write(gt911_reg, 2);
if (i2cBus->endTransmission() == 0) {
i2cBus->requestFrom((int)addr.address, 4);
i2cBus->readBytes(gt911_buf, 4);
if (gt911_buf[0] == '9' && gt911_buf[1] == '1' && gt911_buf[2] == '1') {
type = GT911;
logFoundDevice("GT911", (uint8_t)addr.address);
break;
}
}
}
// SFA30 detection: send 2-byte command 0xD060 (Get Device Marking) and check for 48-byte response
if (i2cCommandResponseLength(addr, 0xD060, 48)) {
type = SFA30;
@@ -591,9 +622,18 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
logFoundDevice("BMA423", (uint8_t)addr.address);
}
break;
case RAK120353_ADDR: { // AW35615 USB-C CC controller — must be checked before
// RAK120353_ADDR which shares 0x22 but is a TCA9535 variant
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x01), 1);
if ((registerValue & 0xF0) == 0x90) { // DEVICE_ID upper nibble = 0x9 for AW35615
type = AW35615;
logFoundDevice("AW35615", (uint8_t)addr.address);
break;
}
// Fall through to TCA9535/RAK check
}
case TCA9535_ADDR:
case RAK120352_ADDR:
case RAK120353_ADDR:
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x02), 1);
if (registerValue == addr.address) { // RAK12035 returns its I2C address at 0x02 (eg 0x20)
type = RAK12035;
@@ -797,6 +837,17 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
break;
case 0x48: {
// Check for ADS1115 FIRST — the SE050 probe below writes 5 bytes
// to the device, which corrupts the ADS1115 Lo_thresh register and
// leaves its pointer off register 0x01, making the later config-
// register read return 0xC000 instead of the expected 0x8583.
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x01), 2);
if (registerValue == 0x8583 || registerValue == 0x8580) {
type = ADS1115;
logFoundDevice("ADS1115 ADC", (uint8_t)addr.address);
break;
}
i2cBus->beginTransmission(addr.address);
uint8_t getInfo[] = {0x5A, 0xC0, 0x00, 0xFF, 0xFC};
uint8_t expectedInfo[] = {0xa5, 0xE0, 0x00, 0x3F, 0x19};
@@ -811,13 +862,6 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
break;
}
registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x01), 2);
if (registerValue == 0x8583 || registerValue == 0x8580) {
type = ADS1115;
logFoundDevice("ADS1115 ADC", (uint8_t)addr.address);
break;
}
LOG_INFO("FT6336U touchscreen found");
type = FT6336U;
break;
+4
View File
@@ -0,0 +1,4 @@
#include "MeshLED.h"
// Default global instance: no-op dummy. Replace in variant initVariant() for device-specific behaviour.
std::shared_ptr<MeshLED> meshLED = std::make_shared<MeshLED>();
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include <memory>
/**
* Interface for a "mesh activity" LED that lights while the LoRa radio is transmitting.
* The default implementation is a no-op; device variants may replace the global instance
* with a concrete subclass.
*/
class MeshLED
{
public:
virtual ~MeshLED() = default;
virtual void init() {}
virtual void on() {}
virtual void off() {}
};
extern std::shared_ptr<MeshLED> meshLED;
+1 -1
View File
@@ -696,7 +696,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false)
strncpy(config.network.ntp_server, "meshtastic.pool.ntp.org", 32);
#if (defined(T_DECK) || defined(T_WATCH_S3) || defined(UNPHONE) || defined(PICOMPUTER_S3) || defined(SENSECAP_INDICATOR) || \
defined(ELECROW_PANEL) || defined(HELTEC_V4_TFT) || defined(HELTEC_V4_R8_TFT)) && \
defined(ELECROW_PANEL) || defined(HELTEC_V4_TFT) || defined(HELTEC_V4_R8_TFT) || defined(SEEED_WIO_TRACKER_L2)) && \
HAS_TFT
// switch BT off by default; use TFT programming mode or hotkey to enable
config.bluetooth.enabled = false;
+3
View File
@@ -1,4 +1,5 @@
#include "RadioLibInterface.h"
#include "MeshLED.h"
#include "MeshTypes.h"
#include "NodeDB.h"
#include "PowerMon.h"
@@ -425,6 +426,7 @@ void RadioLibInterface::completeSending()
auto p = sendingPacket;
sendingPacket = NULL;
meshLED->off();
if (p) {
// Packet has been sent, count it toward our TX airtime utilization.
uint32_t xmitMsec = getPacketTime(p);
@@ -596,6 +598,7 @@ bool RadioLibInterface::startSend(meshtastic_MeshPacket *txp)
powerMon->clearState(meshtastic_PowerMon_State_Lora_TXOn); // Transmitter off now
startReceive(); // Restart receive mode (because startTransmit failed to put us in xmit mode)
} else {
meshLED->on();
// Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register
// bits
enableInterrupt(isrTxLevel0);
+4
View File
@@ -121,6 +121,10 @@ class Power : public concurrency::OSThread
bool meshSolarInit();
/// Setup a serial battery sensor
bool serialBatteryInit();
#ifdef HAS_ADS1115
/// Setup ADS1115 I2C battery level sensor
bool ads1115Init();
#endif
private:
void shutdown();
@@ -0,0 +1,16 @@
#ifndef Pins_Arduino_h
#define Pins_Arduino_h
#include <stdint.h>
static const uint8_t SDA = 47;
static const uint8_t SCL = 48;
// Default SPI will be mapped to Radio
static const uint8_t SS = 21;
static const uint8_t MOSI = 6;
static const uint8_t MISO = 5;
static const uint8_t SCK = 4;
#endif /* Pins_Arduino_h */
@@ -0,0 +1,69 @@
[env:seeed_wio_tracker_L2]
custom_meshtastic_hw_model = 99 ; TODO: assign a unique number to this hardware model
custom_meshtastic_hw_model_slug = SEEED_WIO_TRACKER_L2
custom_meshtastic_architecture = esp32s3
custom_meshtastic_actively_supported = true
custom_meshtastic_support_level = 1
custom_meshtastic_display_name = Seeed Wio Tracker L2
custom_meshtastic_images = wio_tracker_l2_case.svg
custom_meshtastic_tags = Seeed
custom_meshtastic_requires_dfu = true
board = seeed_wio_tracker_L2
board_level = pr
extends = esp32s3_base
board_check = true
upload_protocol = esptool
board_build.partitions = default_16MB.csv
build_flags = ${esp32s3_base.build_flags}
-I variants/esp32s3/seeed_wio_tracker_L2
-D SEEED_WIO_TRACKER_L2
-D CONFIG_ARDUHAL_ESP_LOG
-D CONFIG_ARDUHAL_LOG_COLORS=1
-D CONFIG_DISABLE_HAL_LOCKS=1
-D MESHTASTIC_EXCLUDE_WEBSERVER=1
-D LV_LVGL_H_INCLUDE_SIMPLE
-D LV_CONF_INCLUDE_SIMPLE
-D LV_COMP_CONF_INCLUDE_SIMPLE
-D INPUTDRIVER_BUTTON_TYPE=0
-D LV_USE_LOG=0
-D LV_BUILD_TEST=0
-D USE_LOG_DEBUG
-D LOG_DEBUG_INC=\"DebugConfiguration.h\"
-D RADIOLIB_SPI_PARANOID=0
-D HAS_SCREEN=0
-D HAS_TFT=1
-D USE_I2S_BUZZER
-D HAS_SDCARD
-D HAS_SD_MMC ; SDIO mode 1-bit
-D SD_SCLK_PIN=2
-D SD_MOSI_PIN=3 ; CMD
-D SD_MISO_PIN=1 ; D0
-D SDCARD_CS=-1
-D RAM_SIZE=5120
-D LGFX_BUFSIZE=153600
-D LV_CACHE_DEF_SIZE=2097152
-D DISPLAY_SIZE=320x240 ; landscape mode
-D LGFX_DRIVER=LGFX_WIO_TRACKER_L2
-D GFX_DRIVER_INC=\"graphics/LGFX/LGFX_WIO_TRACKER_L2.h\"
-D VIEW_320x240
-D MAP_FULL_REDRAW
-D USE_PACKET_API
build_src_filter = ${esp32s3_base.build_src_filter} +<../variants/esp32s3/seeed_wio_tracker_L2>
lib_deps =
${esp32s3_base.lib_deps}
${device-ui_base.lib_deps}
# renovate: datasource=git-refs depName=ESP8266Audio packageName=https://github.com/meshtastic/ESP8266Audio gitBranch=meshtastic-2.0.0-dacfix
https://github.com/meshtastic/ESP8266Audio/archive/343024632ee78d6216907b2353fc943a62422d80.zip
# renovate: datasource=custom.pio depName=ESP8266SAM packageName=earlephilhower/library/ESP8266SAM
earlephilhower/ESP8266SAM@1.1.0
# renovate: datasource=github-tags depName=pschatzmann_arduino-audio-driver packageName=pschatzmann/arduino-audio-driver
https://github.com/pschatzmann/arduino-audio-driver/archive/v0.2.1.zip
# renovate: datasource=github-tags depName=RobTillaart_TCA9555 packageName=RobTillaart/TCA9555
https://github.com/RobTillaart/TCA9555/archive/refs/tags/0.4.4.zip
# renovate: datasource=github-tags depName=LovyanGFX packageName=lovyan03/LovyanGFX
https://github.com/lovyan03/LovyanGFX/archive/29c590749059be69698eaeccaf4da6596755455d.zip
# renovate: datasource=github-tags depName=Adafruit_ADS1X15 packageName=adafruit/Adafruit_ADS1X15
https://github.com/adafruit/Adafruit_ADS1X15/archive/refs/tags/2.6.2.zip
@@ -0,0 +1,107 @@
#include "variant.h"
#include "TCA9555.h"
#include "AudioBoard.h"
#include "DebugConfiguration.h"
#include "mesh/MeshLED.h"
TCA9535 ioExpander(0x21);
DriverPins PinsAudioBoardES8311;
AudioBoard board(AudioDriverES8311, PinsAudioBoardES8311);
class WioTrackerMeshLED : public MeshLED
{
public:
void init() override { ioExpander.write1(10, LOW); } // ensure LED starts off
void on() override { ioExpander.write1(10, HIGH); }
void off() override { ioExpander.write1(10, LOW); }
};
static bool initOK = false;
void initVariant()
{
Wire.begin(I2C_SDA, I2C_SCL);
if (ioExpander.begin()) {
ioExpander.pinMode1(0, INPUT); // wakeup button
ioExpander.pinMode1(1, INPUT); // IIC IRQ
ioExpander.pinMode1(2, INPUT); // SD detect
ioExpander.pinMode1(11, OUTPUT); // OTG EN
ioExpander.write1(11, LOW); // OTG EN low
delay(10);
ioExpander.pinMode1(12, OUTPUT); // PA EN
ioExpander.write1(12, HIGH); // PA EN high
delay(10);
ioExpander.pinMode1(14, OUTPUT); // TF EN
ioExpander.write1(14, HIGH); // TF EN high
delay(10);
ioExpander.pinMode1(15, OUTPUT); // BAT ADC EN
ioExpander.write1(15, HIGH); // BAT ADC EN high
delay(10);
ioExpander.pinMode1(13, OUTPUT); // GNSS EN
ioExpander.write1(13, HIGH); // GNSS EN high
delay(10);
ioExpander.pinMode1(9, OUTPUT); // GNSS RST (active HIGH on this board)
// Expander output defaults to HIGH, so module is already in reset.
// Hold reset for 10ms, then release LOW so the module starts running.
delay(10);
ioExpander.write1(9, LOW); // release reset - module starts running
ioExpander.pinMode1(10, OUTPUT); // User LED / GNSS wakeup
ioExpander.write1(10, LOW); // User LED / GNSS wakeup low
delay(10);
ioExpander.pinMode1(7, OUTPUT); // GROVE EN
ioExpander.write1(7, HIGH); // GROVE EN high
delay(10);
ioExpander.pinMode1(5, OUTPUT); // LCD EN
ioExpander.write1(5, HIGH); // LCD EN high
delay(50);
ioExpander.pinMode1(6, OUTPUT); // LCD RST
ioExpander.write1(6, HIGH); // LCD RST high
delay(5);
ioExpander.write1(6, LOW); // LCD RST low
delay(10);
ioExpander.write1(6, HIGH); // LCD RST high
delay(500);
ioExpander.pinMode1(4, OUTPUT); // LCD CS
ioExpander.write1(4, HIGH); // LCD CS high
delay(10);
ioExpander.pinMode1(8, OUTPUT); // TP RST
ioExpander.write1(8, LOW); // TP RST low
ioExpander.pinMode1(3, OUTPUT); // TP INT
ioExpander.write1(3, LOW); // TP INT low
delay(10);
ioExpander.write1(3, LOW); // TP INT low
delay(1);
ioExpander.write1(8, HIGH); // TP RST high
delay(60);
initOK = true;
meshLED = std::make_shared<WioTrackerMeshLED>();
meshLED->init();
}
}
void lateInitVariant()
{
if (!initOK) {
LOG_ERROR("TCA9535 initialization failed");
return;
}
// AudioDriverLogger.begin(Serial, AudioDriverLogLevel::Debug);
// I2C: function, scl, sda
PinsAudioBoardES8311.addI2C(PinFunction::CODEC, Wire);
// I2S: function, mclk, bck, ws, data_out, data_in
PinsAudioBoardES8311.addI2S(PinFunction::CODEC, DAC_I2S_MCLK, DAC_I2S_BCK, DAC_I2S_WS, DAC_I2S_DOUT, DAC_I2S_DIN);
// configure codec
CodecConfig cfg;
cfg.input_device = ADC_INPUT_LINE1;
cfg.output_device = DAC_OUTPUT_ALL;
cfg.i2s.bits = BIT_LENGTH_16BITS;
cfg.i2s.rate = RATE_44K;
board.begin(cfg);
board.setVolume(75); // 75% volume
LOG_INFO("ES8311 Audio board initialized");
}
@@ -0,0 +1,65 @@
#pragma once
#define BUTTON_PIN 0
#define I2C_SDA 47
#define I2C_SCL 48
#define USE_POWERSAVE
#define SLEEP_TIME 120
#define HAS_ADS1115
#define ADS1115_ADDR 0x48
// LED controller
#define HAS_LP5814
// ES8311 DAC / AMP
#define HAS_I2S
#define HAS_ES8311
#define DAC_I2S_BCK 11 // SCLK
#define DAC_I2S_WS 12 // LRLK
#define DAC_I2S_DOUT 16
#define DAC_I2S_DIN -1
#define DAC_I2S_MCLK 10
#define HAS_ES7243E
#define ADC_I2S_BCK 11
#define ADC_I2S_WS 12
#define ADC_I2S_DOUT -1
#define ADC_I2S_DIN 15
#define ADC_I2S_MCLK 10
// SX1262 LoRa Module Pins
#define USE_SX1262
#define LORA_SCK 4
#define LORA_MISO 5
#define LORA_MOSI 6
#define LORA_CS 21
#define LORA_RESET 7
#define LORA_DIO1 9
#define LORA_DIO0 -1
#define LORA_DIO2 8
#define LORA_DIO3
#define SX126X_CS LORA_CS
#define SX126X_DIO1 LORA_DIO1
#define SX126X_BUSY LORA_DIO2
#define SX126X_RESET LORA_RESET
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
#define SX126X_DIO2_AS_RF_SWITCH
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// GPS L76KB
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#define GPS_L76K
#ifdef GPS_L76K
#define GPS_TX_PIN 17
#define GPS_RX_PIN 18
#define HAS_GPS 1
#define GPS_THREAD_INTERVAL 50
//#define GPS_EN // TODO: add GPS enable pin control via io/expander
#endif