mirror of
https://github.com/meshtastic/firmware.git
synced 2026-03-28 03:53:13 -04:00
T-mini Eink S3 Support for both InkHUD and BaseUI (#9856)
* Tmini Eink fix * tuning * better refresh * Fix to lora pins to be like the original. * Update pins_arduino.h * removed dead flags from previous tests * Update src/graphics/niche/Drivers/EInk/GDEW0102T4.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
committed by
Ben Meadors
parent
e282491cd8
commit
286bc852b3
@@ -143,6 +143,10 @@ bool EInkDisplay::connect()
|
||||
#ifdef ELECROW_ThinkNode_M1
|
||||
// ThinkNode M1 has a hardware dimmable backlight. Start enabled
|
||||
digitalWrite(PIN_EINK_EN, HIGH);
|
||||
#elif defined(MINI_EPAPER_S3)
|
||||
// T-Mini Epaper S3 requires panel power rail enabled before SPI transfer.
|
||||
digitalWrite(PIN_EINK_EN, HIGH);
|
||||
delay(10);
|
||||
#else
|
||||
digitalWrite(PIN_EINK_EN, LOW);
|
||||
#endif
|
||||
@@ -202,7 +206,8 @@ bool EInkDisplay::connect()
|
||||
}
|
||||
|
||||
#elif defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || \
|
||||
defined(CROWPANEL_ESP32S3_5_EPAPER) || defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER)
|
||||
defined(CROWPANEL_ESP32S3_5_EPAPER) || defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER) || \
|
||||
defined(MINI_EPAPER_S3)
|
||||
{
|
||||
// Start HSPI
|
||||
hspi = new SPIClass(HSPI);
|
||||
@@ -216,9 +221,13 @@ bool EInkDisplay::connect()
|
||||
|
||||
// Init GxEPD2
|
||||
adafruitDisplay->init();
|
||||
#if defined(MINI_EPAPER_S3)
|
||||
adafruitDisplay->setRotation(3);
|
||||
#else
|
||||
adafruitDisplay->setRotation(3);
|
||||
#if defined(CROWPANEL_ESP32S3_5_EPAPER) || defined(CROWPANEL_ESP32S3_4_EPAPER)
|
||||
adafruitDisplay->setRotation(0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#elif defined(PCA10059) || defined(ME25LS01)
|
||||
@@ -259,17 +268,6 @@ bool EInkDisplay::connect()
|
||||
adafruitDisplay->setRotation(3);
|
||||
adafruitDisplay->setPartialWindow(0, 0, EINK_WIDTH, EINK_HEIGHT);
|
||||
}
|
||||
#elif defined(MINI_EPAPER_S3)
|
||||
spi1 = new SPIClass(HSPI);
|
||||
spi1->begin(PIN_SPI1_SCK, PIN_SPI1_MISO, PIN_SPI1_MOSI, PIN_EINK_CS);
|
||||
|
||||
// Create GxEPD2 objects
|
||||
auto lowLevel = new EINK_DISPLAY_MODEL(PIN_EINK_CS, PIN_EINK_DC, PIN_EINK_RES, PIN_EINK_BUSY, *spi1);
|
||||
adafruitDisplay = new GxEPD2_BW<EINK_DISPLAY_MODEL, EINK_DISPLAY_MODEL::HEIGHT>(*lowLevel);
|
||||
|
||||
// Init GxEPD2
|
||||
adafruitDisplay->init();
|
||||
adafruitDisplay->setRotation(1);
|
||||
#elif defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_VISION_MASTER_E213)
|
||||
|
||||
// Detect display model, before starting SPI
|
||||
|
||||
@@ -89,12 +89,12 @@ class EInkDisplay : public OLEDDisplay
|
||||
// If display uses HSPI
|
||||
#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0) || defined(HELTEC_VISION_MASTER_E213) || \
|
||||
defined(HELTEC_VISION_MASTER_E290) || defined(TLORA_T3S3_EPAPER) || defined(CROWPANEL_ESP32S3_5_EPAPER) || \
|
||||
defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER) || defined(ELECROW_ThinkNode_M5)
|
||||
defined(CROWPANEL_ESP32S3_4_EPAPER) || defined(CROWPANEL_ESP32S3_2_EPAPER) || defined(ELECROW_ThinkNode_M5) || \
|
||||
defined(MINI_EPAPER_S3)
|
||||
SPIClass *hspi = NULL;
|
||||
#endif
|
||||
|
||||
#if defined(HELTEC_MESH_POCKET) || defined(SEEED_WIO_TRACKER_L1_EINK) || defined(HELTEC_MESH_SOLAR_EINK) || \
|
||||
defined(MINI_EPAPER_S3)
|
||||
#if defined(HELTEC_MESH_POCKET) || defined(SEEED_WIO_TRACKER_L1_EINK) || defined(HELTEC_MESH_SOLAR_EINK)
|
||||
SPIClass *spi1 = NULL;
|
||||
#endif
|
||||
|
||||
|
||||
178
src/graphics/niche/Drivers/EInk/GDEW0102T4.cpp
Normal file
178
src/graphics/niche/Drivers/EInk/GDEW0102T4.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
|
||||
#include "./GDEW0102T4.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
using namespace NicheGraphics::Drivers;
|
||||
|
||||
// LUTs from GxEPD2_102.cpp (GDEW0102T4 / UC8175).
|
||||
static const uint8_t LUT_W_FULL[] = {
|
||||
0x60, 0x5A, 0x5A, 0x00, 0x00, 0x01, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
};
|
||||
|
||||
static const uint8_t LUT_B_FULL[] = {
|
||||
0x90, 0x5A, 0x5A, 0x00, 0x00, 0x01, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
};
|
||||
|
||||
static const uint8_t LUT_W_FAST[] = {
|
||||
0x60, 0x01, 0x01, 0x00, 0x00, 0x01, //
|
||||
0x80, 0x12, 0x00, 0x00, 0x00, 0x01, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
};
|
||||
|
||||
static const uint8_t LUT_B_FAST[] = {
|
||||
0x90, 0x01, 0x01, 0x00, 0x00, 0x01, //
|
||||
0x40, 0x14, 0x00, 0x00, 0x00, 0x01, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //
|
||||
};
|
||||
|
||||
GDEW0102T4::GDEW0102T4() : UC8175(width, height, supported) {}
|
||||
|
||||
void GDEW0102T4::setFastConfig(FastConfig cfg)
|
||||
{
|
||||
// Clamp out only clearly invalid PLL settings.
|
||||
if (cfg.reg30 < 0x05)
|
||||
cfg.reg30 = 0x05;
|
||||
fastConfig = cfg;
|
||||
}
|
||||
|
||||
GDEW0102T4::FastConfig GDEW0102T4::getFastConfig() const
|
||||
{
|
||||
return fastConfig;
|
||||
}
|
||||
|
||||
void GDEW0102T4::configCommon()
|
||||
{
|
||||
// Init path aligned with GxEPD2_GDEW0102T4 (UC8175 family).
|
||||
sendCommand(0xD2);
|
||||
sendData(0x3F);
|
||||
|
||||
sendCommand(0x00);
|
||||
sendData(0x6F);
|
||||
|
||||
sendCommand(0x01);
|
||||
sendData(0x03);
|
||||
sendData(0x00);
|
||||
sendData(0x2B);
|
||||
sendData(0x2B);
|
||||
|
||||
sendCommand(0x06);
|
||||
sendData(0x3F);
|
||||
|
||||
sendCommand(0x2A);
|
||||
sendData(0x00);
|
||||
sendData(0x00);
|
||||
|
||||
sendCommand(0x30); // PLL / drive clock
|
||||
sendData(0x13);
|
||||
|
||||
sendCommand(0x50); // Last border/data interval; subtle but can affect artifacts
|
||||
sendData(0x57);
|
||||
|
||||
sendCommand(0x60);
|
||||
sendData(0x22);
|
||||
|
||||
sendCommand(0x61);
|
||||
sendData(width);
|
||||
sendData(height);
|
||||
|
||||
sendCommand(0x82); // VCOM DC setting
|
||||
sendData(0x12);
|
||||
|
||||
sendCommand(0xE3);
|
||||
sendData(0x33);
|
||||
}
|
||||
|
||||
void GDEW0102T4::configFull()
|
||||
{
|
||||
sendCommand(0x23);
|
||||
sendData(LUT_W_FULL, sizeof(LUT_W_FULL));
|
||||
sendCommand(0x24);
|
||||
sendData(LUT_B_FULL, sizeof(LUT_B_FULL));
|
||||
|
||||
powerOn();
|
||||
}
|
||||
|
||||
void GDEW0102T4::configFast()
|
||||
{
|
||||
uint8_t lutW[sizeof(LUT_W_FAST)];
|
||||
uint8_t lutB[sizeof(LUT_B_FAST)];
|
||||
memcpy(lutW, LUT_W_FAST, sizeof(LUT_W_FAST));
|
||||
memcpy(lutB, LUT_B_FAST, sizeof(LUT_B_FAST));
|
||||
|
||||
// Second stage duration bytes are the main "darkness vs ghosting" control for this panel.
|
||||
lutW[7] = fastConfig.lutW2;
|
||||
lutB[7] = fastConfig.lutB2;
|
||||
|
||||
sendCommand(0x30);
|
||||
sendData(fastConfig.reg30);
|
||||
|
||||
sendCommand(0x50);
|
||||
sendData(fastConfig.reg50);
|
||||
|
||||
sendCommand(0x82);
|
||||
sendData(fastConfig.reg82);
|
||||
|
||||
sendCommand(0x23);
|
||||
sendData(lutW, sizeof(lutW));
|
||||
sendCommand(0x24);
|
||||
sendData(lutB, sizeof(lutB));
|
||||
|
||||
powerOn();
|
||||
}
|
||||
|
||||
void GDEW0102T4::writeOldImage()
|
||||
{
|
||||
// On this panel, FULL refresh is most reliable when "old image" is all white.
|
||||
if (updateType == FULL) {
|
||||
sendCommand(0x10);
|
||||
// Use buffered writes of 0xFF to avoid per-byte SPI transactions.
|
||||
const uint16_t chunkSize = 64;
|
||||
uint8_t ffBuf[chunkSize];
|
||||
memset(ffBuf, 0xFF, sizeof(ffBuf));
|
||||
|
||||
uint32_t remaining = bufferSize;
|
||||
while (remaining > 0) {
|
||||
uint16_t toSend = remaining > chunkSize ? chunkSize : static_cast<uint16_t>(remaining);
|
||||
sendData(ffBuf, toSend);
|
||||
remaining -= toSend;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// FAST refresh uses differential data (previous frame as old image).
|
||||
if (previousBuffer) {
|
||||
writeImage(0x10, previousBuffer);
|
||||
} else {
|
||||
writeImage(0x10, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void GDEW0102T4::finalizeUpdate()
|
||||
{
|
||||
// Keep panel out of deep-sleep between updates for better reliability of repeated FAST refresh.
|
||||
powerOff();
|
||||
}
|
||||
|
||||
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
55
src/graphics/niche/Drivers/EInk/GDEW0102T4.h
Normal file
55
src/graphics/niche/Drivers/EInk/GDEW0102T4.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
|
||||
E-Ink display driver
|
||||
- GDEW0102T4
|
||||
- Controller: UC8175
|
||||
- Size: 1.02 inch
|
||||
- Resolution: 80px x 128px
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
#include "./UC8175.h"
|
||||
|
||||
namespace NicheGraphics::Drivers
|
||||
{
|
||||
|
||||
class GDEW0102T4 : public UC8175
|
||||
{
|
||||
private:
|
||||
static constexpr uint16_t width = 80;
|
||||
static constexpr uint16_t height = 128;
|
||||
static constexpr UpdateTypes supported = (UpdateTypes)(FULL | FAST);
|
||||
|
||||
public:
|
||||
struct FastConfig {
|
||||
uint8_t reg30;
|
||||
uint8_t reg50;
|
||||
uint8_t reg82;
|
||||
uint8_t lutW2;
|
||||
uint8_t lutB2;
|
||||
};
|
||||
|
||||
GDEW0102T4();
|
||||
void setFastConfig(FastConfig cfg);
|
||||
FastConfig getFastConfig() const;
|
||||
|
||||
protected:
|
||||
void configCommon() override;
|
||||
void configFull() override;
|
||||
void configFast() override;
|
||||
void writeOldImage() override;
|
||||
void finalizeUpdate() override;
|
||||
|
||||
private:
|
||||
FastConfig fastConfig = {0x13, 0xF2, 0x12, 0x0E, 0x14};
|
||||
};
|
||||
|
||||
} // namespace NicheGraphics::Drivers
|
||||
|
||||
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
203
src/graphics/niche/Drivers/EInk/UC8175.cpp
Normal file
203
src/graphics/niche/Drivers/EInk/UC8175.cpp
Normal file
@@ -0,0 +1,203 @@
|
||||
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
|
||||
#include "./UC8175.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "SPILock.h"
|
||||
|
||||
using namespace NicheGraphics::Drivers;
|
||||
|
||||
UC8175::UC8175(uint16_t width, uint16_t height, UpdateTypes supported) : EInk(width, height, supported)
|
||||
{
|
||||
bufferRowSize = ((width - 1) / 8) + 1;
|
||||
bufferSize = bufferRowSize * height;
|
||||
}
|
||||
|
||||
void UC8175::begin(SPIClass *spi, uint8_t pin_dc, uint8_t pin_cs, uint8_t pin_busy, uint8_t pin_rst)
|
||||
{
|
||||
this->spi = spi;
|
||||
this->pin_dc = pin_dc;
|
||||
this->pin_cs = pin_cs;
|
||||
this->pin_busy = pin_busy;
|
||||
this->pin_rst = pin_rst;
|
||||
|
||||
pinMode(pin_dc, OUTPUT);
|
||||
pinMode(pin_cs, OUTPUT);
|
||||
pinMode(pin_busy, INPUT);
|
||||
|
||||
// Reset is active LOW, hold HIGH when idle.
|
||||
if (pin_rst != (uint8_t)-1) {
|
||||
pinMode(pin_rst, OUTPUT);
|
||||
digitalWrite(pin_rst, HIGH);
|
||||
}
|
||||
|
||||
if (!previousBuffer) {
|
||||
previousBuffer = new uint8_t[bufferSize];
|
||||
if (previousBuffer)
|
||||
memset(previousBuffer, 0xFF, bufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
void UC8175::update(uint8_t *imageData, UpdateTypes type)
|
||||
{
|
||||
buffer = imageData;
|
||||
updateType = (type == UpdateTypes::UNSPECIFIED) ? UpdateTypes::FULL : type;
|
||||
|
||||
if (updateType == FAST && hasPreviousBuffer && previousBuffer && memcmp(previousBuffer, buffer, bufferSize) == 0)
|
||||
return;
|
||||
|
||||
reset();
|
||||
configCommon();
|
||||
|
||||
if (updateType == FAST)
|
||||
configFast();
|
||||
else
|
||||
configFull();
|
||||
|
||||
writeOldImage();
|
||||
writeNewImage();
|
||||
sendCommand(0x12); // Display refresh.
|
||||
|
||||
if (previousBuffer) {
|
||||
memcpy(previousBuffer, buffer, bufferSize);
|
||||
hasPreviousBuffer = true;
|
||||
}
|
||||
|
||||
detachFromUpdate();
|
||||
}
|
||||
|
||||
void UC8175::wait(uint32_t timeoutMs)
|
||||
{
|
||||
if (failed)
|
||||
return;
|
||||
|
||||
uint32_t started = millis();
|
||||
while (digitalRead(pin_busy) == BUSY_ACTIVE) {
|
||||
if ((millis() - started) > timeoutMs) {
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
||||
void UC8175::reset()
|
||||
{
|
||||
if (pin_rst != (uint8_t)-1) {
|
||||
digitalWrite(pin_rst, LOW);
|
||||
delay(20);
|
||||
digitalWrite(pin_rst, HIGH);
|
||||
delay(20);
|
||||
} else {
|
||||
sendCommand(0x12); // Software reset.
|
||||
delay(10);
|
||||
}
|
||||
|
||||
wait(3000);
|
||||
}
|
||||
|
||||
void UC8175::sendCommand(uint8_t command)
|
||||
{
|
||||
if (failed)
|
||||
return;
|
||||
|
||||
spiLock->lock();
|
||||
spi->beginTransaction(spiSettings);
|
||||
digitalWrite(pin_dc, LOW);
|
||||
digitalWrite(pin_cs, LOW);
|
||||
spi->transfer(command);
|
||||
digitalWrite(pin_cs, HIGH);
|
||||
digitalWrite(pin_dc, HIGH);
|
||||
spi->endTransaction();
|
||||
spiLock->unlock();
|
||||
}
|
||||
|
||||
void UC8175::sendData(uint8_t data)
|
||||
{
|
||||
sendData(&data, 1);
|
||||
}
|
||||
|
||||
void UC8175::sendData(const uint8_t *data, uint32_t size)
|
||||
{
|
||||
if (failed)
|
||||
return;
|
||||
|
||||
spiLock->lock();
|
||||
spi->beginTransaction(spiSettings);
|
||||
digitalWrite(pin_dc, HIGH);
|
||||
digitalWrite(pin_cs, LOW);
|
||||
|
||||
#if defined(ARCH_ESP32)
|
||||
spi->transferBytes(data, NULL, size);
|
||||
#elif defined(ARCH_NRF52)
|
||||
spi->transfer(data, NULL, size);
|
||||
#else
|
||||
for (uint32_t i = 0; i < size; ++i)
|
||||
spi->transfer(data[i]);
|
||||
#endif
|
||||
|
||||
digitalWrite(pin_cs, HIGH);
|
||||
digitalWrite(pin_dc, HIGH);
|
||||
spi->endTransaction();
|
||||
spiLock->unlock();
|
||||
}
|
||||
|
||||
void UC8175::powerOn()
|
||||
{
|
||||
sendCommand(0x04);
|
||||
wait(2000);
|
||||
}
|
||||
|
||||
void UC8175::powerOff()
|
||||
{
|
||||
sendCommand(0x02); // Power off.
|
||||
wait(1500);
|
||||
}
|
||||
|
||||
void UC8175::writeImage(uint8_t command, const uint8_t *image)
|
||||
{
|
||||
sendCommand(command);
|
||||
sendData(image, bufferSize);
|
||||
}
|
||||
|
||||
void UC8175::writeOldImage()
|
||||
{
|
||||
if (updateType == FAST && previousBuffer)
|
||||
writeImage(0x10, previousBuffer);
|
||||
else
|
||||
writeImage(0x10, buffer);
|
||||
}
|
||||
|
||||
void UC8175::writeNewImage()
|
||||
{
|
||||
writeImage(0x13, buffer);
|
||||
}
|
||||
|
||||
void UC8175::detachFromUpdate()
|
||||
{
|
||||
switch (updateType) {
|
||||
case FAST:
|
||||
return beginPolling(50, 400);
|
||||
case FULL:
|
||||
default:
|
||||
return beginPolling(100, 2000);
|
||||
}
|
||||
}
|
||||
|
||||
bool UC8175::isUpdateDone()
|
||||
{
|
||||
return digitalRead(pin_busy) != BUSY_ACTIVE;
|
||||
}
|
||||
|
||||
void UC8175::finalizeUpdate()
|
||||
{
|
||||
powerOff();
|
||||
|
||||
if (pin_rst != (uint8_t)-1) {
|
||||
sendCommand(0x07); // Deep sleep.
|
||||
sendData(0xA5);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
62
src/graphics/niche/Drivers/EInk/UC8175.h
Normal file
62
src/graphics/niche/Drivers/EInk/UC8175.h
Normal file
@@ -0,0 +1,62 @@
|
||||
// E-Ink base class for displays based on UC8175 / UC8176 style controller ICs.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
#include "./EInk.h"
|
||||
|
||||
namespace NicheGraphics::Drivers
|
||||
{
|
||||
|
||||
class UC8175 : public EInk
|
||||
{
|
||||
public:
|
||||
UC8175(uint16_t width, uint16_t height, UpdateTypes supported);
|
||||
void begin(SPIClass *spi, uint8_t pin_dc, uint8_t pin_cs, uint8_t pin_busy, uint8_t pin_rst = -1) override;
|
||||
void update(uint8_t *imageData, UpdateTypes type) override;
|
||||
|
||||
protected:
|
||||
virtual void wait(uint32_t timeoutMs = 1000);
|
||||
virtual void reset();
|
||||
virtual void sendCommand(uint8_t command);
|
||||
virtual void sendData(uint8_t data);
|
||||
virtual void sendData(const uint8_t *data, uint32_t size);
|
||||
|
||||
virtual void configCommon() = 0; // Always run
|
||||
virtual void configFull() = 0; // Run when updateType == FULL
|
||||
virtual void configFast() = 0; // Run when updateType == FAST
|
||||
|
||||
virtual void powerOn();
|
||||
virtual void powerOff();
|
||||
virtual void writeOldImage();
|
||||
virtual void writeNewImage();
|
||||
virtual void writeImage(uint8_t command, const uint8_t *image);
|
||||
|
||||
virtual void detachFromUpdate();
|
||||
virtual bool isUpdateDone() override;
|
||||
virtual void finalizeUpdate() override;
|
||||
|
||||
protected:
|
||||
static constexpr uint8_t BUSY_ACTIVE = LOW;
|
||||
|
||||
uint16_t bufferRowSize = 0;
|
||||
uint32_t bufferSize = 0;
|
||||
uint8_t *buffer = nullptr;
|
||||
uint8_t *previousBuffer = nullptr;
|
||||
bool hasPreviousBuffer = false;
|
||||
UpdateTypes updateType = UpdateTypes::UNSPECIFIED;
|
||||
|
||||
uint8_t pin_dc = (uint8_t)-1;
|
||||
uint8_t pin_cs = (uint8_t)-1;
|
||||
uint8_t pin_busy = (uint8_t)-1;
|
||||
uint8_t pin_rst = (uint8_t)-1;
|
||||
SPIClass *spi = nullptr;
|
||||
SPISettings spiSettings = SPISettings(8000000, MSBFIRST, SPI_MODE0);
|
||||
};
|
||||
|
||||
} // namespace NicheGraphics::Drivers
|
||||
|
||||
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
@@ -349,13 +349,13 @@ void InkHUD::MenuApplet::execute(MenuItem item)
|
||||
handleFreeText = true;
|
||||
cm.freeTextItem.rawText.erase(); // clear the previous freetext message
|
||||
freeTextMode = true; // render input field instead of normal menu
|
||||
// Open the on-screen keyboard if the joystick is enabled
|
||||
if (settings->joystick.enabled)
|
||||
// Open the on-screen keyboard only for full joystick devices
|
||||
if (settings->joystick.enabled && !inkhud->twoWayRocker)
|
||||
inkhud->openKeyboard();
|
||||
break;
|
||||
|
||||
case STORE_CANNEDMESSAGE_SELECTION:
|
||||
if (!settings->joystick.enabled)
|
||||
if (!settings->joystick.enabled || inkhud->twoWayRocker)
|
||||
cm.selectedMessageItem = &cm.messageItems.at(cursor - 1); // Minus one: offset for the initial "Send Ping" entry
|
||||
else
|
||||
cm.selectedMessageItem = &cm.messageItems.at(cursor - 2); // Minus two: offset for the "Send Ping" and free text entry
|
||||
@@ -922,7 +922,7 @@ void InkHUD::MenuApplet::showPage(MenuPage page)
|
||||
if (settings->userTiles.maxCount > 1)
|
||||
items.push_back(MenuItem("Layout", MenuAction::LAYOUT, MenuPage::OPTIONS));
|
||||
items.push_back(MenuItem("Rotate", MenuAction::ROTATE, MenuPage::OPTIONS));
|
||||
if (settings->joystick.enabled)
|
||||
if (settings->joystick.enabled && !inkhud->twoWayRocker)
|
||||
items.push_back(MenuItem("Align Joystick", MenuAction::ALIGN_JOYSTICK, MenuPage::EXIT));
|
||||
items.push_back(MenuItem("Notifications", MenuAction::TOGGLE_NOTIFICATIONS, MenuPage::OPTIONS,
|
||||
&settings->optionalFeatures.notifications));
|
||||
@@ -1751,7 +1751,7 @@ void InkHUD::MenuApplet::populateSendPage()
|
||||
items.push_back(MenuItem("Ping", MenuAction::SEND_PING, MenuPage::EXIT));
|
||||
|
||||
// If joystick is available, include the Free Text option
|
||||
if (settings->joystick.enabled)
|
||||
if (settings->joystick.enabled && !inkhud->twoWayRocker)
|
||||
items.push_back(MenuItem("Free Text", MenuAction::FREE_TEXT, MenuPage::SEND));
|
||||
|
||||
// One menu item for each canned message
|
||||
|
||||
@@ -152,6 +152,11 @@ void InkHUD::TipsApplet::onRender(bool full)
|
||||
drawBullet("User Button");
|
||||
drawBullet("- short press: next");
|
||||
drawBullet("- long press: select or open menu");
|
||||
} else if (inkhud->twoWayRocker) {
|
||||
drawBullet("Rocker + Button");
|
||||
drawBullet("- center press: open menu or select");
|
||||
drawBullet("- left/right: applet nav");
|
||||
drawBullet("- in menu: up/down");
|
||||
} else {
|
||||
drawBullet("Joystick");
|
||||
drawBullet("- press: open menu or select");
|
||||
|
||||
@@ -88,6 +88,9 @@ class InkHUD
|
||||
// Used by TipsApplet to force menu to start on Region selection
|
||||
bool forceRegionMenu = false;
|
||||
|
||||
// Input mode hint for devices that use a left/right rocker plus center button
|
||||
bool twoWayRocker = false;
|
||||
|
||||
// Updating the display
|
||||
// - called by various InkHUD components
|
||||
|
||||
@@ -130,4 +133,4 @@ class InkHUD
|
||||
|
||||
} // namespace NicheGraphics::InkHUD
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -143,7 +143,7 @@ void InkHUD::WindowManager::openMenu()
|
||||
// Bring the AlignStick applet to the foreground
|
||||
void InkHUD::WindowManager::openAlignStick()
|
||||
{
|
||||
if (settings->joystick.enabled) {
|
||||
if (settings->joystick.enabled && !inkhud->twoWayRocker) {
|
||||
AlignStickApplet *alignStick = (AlignStickApplet *)inkhud->getSystemApplet("AlignStick");
|
||||
alignStick->bringToForeground();
|
||||
}
|
||||
@@ -151,6 +151,9 @@ void InkHUD::WindowManager::openAlignStick()
|
||||
|
||||
void InkHUD::WindowManager::openKeyboard()
|
||||
{
|
||||
if (!settings->joystick.enabled || inkhud->twoWayRocker)
|
||||
return;
|
||||
|
||||
KeyboardApplet *keyboard = (KeyboardApplet *)inkhud->getSystemApplet("Keyboard");
|
||||
|
||||
if (keyboard) {
|
||||
@@ -162,6 +165,9 @@ void InkHUD::WindowManager::openKeyboard()
|
||||
|
||||
void InkHUD::WindowManager::closeKeyboard()
|
||||
{
|
||||
if (!settings->joystick.enabled || inkhud->twoWayRocker)
|
||||
return;
|
||||
|
||||
KeyboardApplet *keyboard = (KeyboardApplet *)inkhud->getSystemApplet("Keyboard");
|
||||
|
||||
if (keyboard) {
|
||||
@@ -477,7 +483,7 @@ void InkHUD::WindowManager::createSystemApplets()
|
||||
addSystemApplet("Logo", new LogoApplet, new Tile);
|
||||
addSystemApplet("Pairing", new PairingApplet, new Tile);
|
||||
addSystemApplet("Tips", new TipsApplet, new Tile);
|
||||
if (settings->joystick.enabled) {
|
||||
if (settings->joystick.enabled && !inkhud->twoWayRocker) {
|
||||
addSystemApplet("AlignStick", new AlignStickApplet, new Tile);
|
||||
addSystemApplet("Keyboard", new KeyboardApplet, new Tile);
|
||||
}
|
||||
@@ -503,7 +509,7 @@ void InkHUD::WindowManager::placeSystemTiles()
|
||||
inkhud->getSystemApplet("Logo")->getTile()->setRegion(0, 0, inkhud->width(), inkhud->height());
|
||||
inkhud->getSystemApplet("Pairing")->getTile()->setRegion(0, 0, inkhud->width(), inkhud->height());
|
||||
inkhud->getSystemApplet("Tips")->getTile()->setRegion(0, 0, inkhud->width(), inkhud->height());
|
||||
if (settings->joystick.enabled) {
|
||||
if (settings->joystick.enabled && !inkhud->twoWayRocker) {
|
||||
inkhud->getSystemApplet("AlignStick")->getTile()->setRegion(0, 0, inkhud->width(), inkhud->height());
|
||||
const uint16_t keyboardHeight = KeyboardApplet::getKeyboardHeight();
|
||||
inkhud->getSystemApplet("Keyboard")
|
||||
|
||||
@@ -156,6 +156,24 @@ void TwoButtonExtended::setJoystickWiring(uint8_t uPin, uint8_t dPin, uint8_t lP
|
||||
pinMode(joystick[Direction::RIGHT].pin, internalPullup ? INPUT_PULLUP : INPUT);
|
||||
}
|
||||
|
||||
// Configures only left/right joystick directions for a two-way rocker
|
||||
void TwoButtonExtended::setTwoWayRockerWiring(uint8_t leftPin, uint8_t rightPin, bool internalPullup)
|
||||
{
|
||||
if (leftPin == rightPin) {
|
||||
LOG_WARN("Attempted reuse of TwoWayRocker GPIO. Ignoring assignment");
|
||||
return;
|
||||
}
|
||||
|
||||
joystick[Direction::UP].pin = 0xFF;
|
||||
joystick[Direction::DOWN].pin = 0xFF;
|
||||
joystick[Direction::LEFT].pin = leftPin;
|
||||
joystick[Direction::RIGHT].pin = rightPin;
|
||||
joystickActiveLogic = LOW;
|
||||
|
||||
pinMode(joystick[Direction::LEFT].pin, internalPullup ? INPUT_PULLUP : INPUT);
|
||||
pinMode(joystick[Direction::RIGHT].pin, internalPullup ? INPUT_PULLUP : INPUT);
|
||||
}
|
||||
|
||||
void TwoButtonExtended::setTiming(uint8_t whichButton, uint32_t debounceMs, uint32_t longpressMs)
|
||||
{
|
||||
assert(whichButton < 2);
|
||||
@@ -229,6 +247,13 @@ void TwoButtonExtended::setJoystickPressHandlers(Callback uPress, Callback dPres
|
||||
joystick[Direction::RIGHT].onPress = rPress;
|
||||
}
|
||||
|
||||
// Set press handlers for a two-way rocker mapped to left/right directions
|
||||
void TwoButtonExtended::setTwoWayRockerPressHandlers(Callback lPress, Callback rPress)
|
||||
{
|
||||
joystick[Direction::LEFT].onPress = lPress;
|
||||
joystick[Direction::RIGHT].onPress = rPress;
|
||||
}
|
||||
|
||||
// Handle the start of a press to the primary button
|
||||
// Wakes our button thread
|
||||
void TwoButtonExtended::isrPrimary()
|
||||
|
||||
@@ -45,6 +45,7 @@ class TwoButtonExtended : protected concurrency::OSThread
|
||||
void stop(); // Stop handling button input (disconnect ISRs for sleep)
|
||||
void setWiring(uint8_t whichButton, uint8_t pin, bool internalPullup = false);
|
||||
void setJoystickWiring(uint8_t uPin, uint8_t dPin, uint8_t lPin, uint8_t rPin, bool internalPullup = false);
|
||||
void setTwoWayRockerWiring(uint8_t leftPin, uint8_t rightPin, bool internalPullup = false);
|
||||
void setTiming(uint8_t whichButton, uint32_t debounceMs, uint32_t longpressMs);
|
||||
void setJoystickDebounce(uint32_t debounceMs);
|
||||
void setHandlerDown(uint8_t whichButton, Callback onDown);
|
||||
@@ -54,6 +55,7 @@ class TwoButtonExtended : protected concurrency::OSThread
|
||||
void setJoystickDownHandlers(Callback uDown, Callback dDown, Callback ldown, Callback rDown);
|
||||
void setJoystickUpHandlers(Callback uUp, Callback dUp, Callback lUp, Callback rUp);
|
||||
void setJoystickPressHandlers(Callback uPress, Callback dPress, Callback lPress, Callback rPress);
|
||||
void setTwoWayRockerPressHandlers(Callback lPress, Callback rPress);
|
||||
|
||||
// Disconnect and reconnect interrupts for light sleep
|
||||
#ifdef ARCH_ESP32
|
||||
|
||||
@@ -8,6 +8,14 @@ UpDownInterruptImpl1::UpDownInterruptImpl1() : UpDownInterruptBase("upDown1") {}
|
||||
|
||||
bool UpDownInterruptImpl1::init()
|
||||
{
|
||||
#if defined(INPUTDRIVER_TWO_WAY_ROCKER) && defined(INPUTDRIVER_TWO_WAY_ROCKER_LEFT) && defined(INPUTDRIVER_TWO_WAY_ROCKER_RIGHT)
|
||||
moduleConfig.canned_message.updown1_enabled = true;
|
||||
moduleConfig.canned_message.inputbroker_pin_a = INPUTDRIVER_TWO_WAY_ROCKER_LEFT;
|
||||
moduleConfig.canned_message.inputbroker_pin_b = INPUTDRIVER_TWO_WAY_ROCKER_RIGHT;
|
||||
#if defined(INPUTDRIVER_TWO_WAY_ROCKER_BTN)
|
||||
moduleConfig.canned_message.inputbroker_pin_press = INPUTDRIVER_TWO_WAY_ROCKER_BTN;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!moduleConfig.canned_message.updown1_enabled) {
|
||||
// Input device is disabled.
|
||||
@@ -46,4 +54,4 @@ void UpDownInterruptImpl1::handleIntUp()
|
||||
void UpDownInterruptImpl1::handleIntPressed()
|
||||
{
|
||||
upDownInterruptImpl1->intPressHandler();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,8 +429,13 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
|
||||
gpio_num_t pin = (gpio_num_t)(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN);
|
||||
gpio_wakeup_enable(pin, GPIO_INTR_LOW_LEVEL);
|
||||
#endif
|
||||
#ifdef INPUTDRIVER_ENCODER_BTN
|
||||
gpio_wakeup_enable((gpio_num_t)INPUTDRIVER_ENCODER_BTN, GPIO_INTR_LOW_LEVEL);
|
||||
#if defined(INPUTDRIVER_TWO_WAY_ROCKER_BTN) || defined(INPUTDRIVER_ENCODER_BTN)
|
||||
#if defined(INPUTDRIVER_TWO_WAY_ROCKER_BTN)
|
||||
#define INPUTDRIVER_WAKE_BTN_PIN INPUTDRIVER_TWO_WAY_ROCKER_BTN
|
||||
#else
|
||||
#define INPUTDRIVER_WAKE_BTN_PIN INPUTDRIVER_ENCODER_BTN
|
||||
#endif
|
||||
gpio_wakeup_enable((gpio_num_t)INPUTDRIVER_WAKE_BTN_PIN, GPIO_INTR_LOW_LEVEL);
|
||||
#endif
|
||||
#if defined(WAKE_ON_TOUCH)
|
||||
gpio_wakeup_enable((gpio_num_t)SCREEN_TOUCH_INT, GPIO_INTR_LOW_LEVEL);
|
||||
@@ -471,8 +476,9 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
|
||||
// Disable wake-on-button interrupt. Re-attach normal button-interrupts
|
||||
gpio_wakeup_disable(pin);
|
||||
#endif
|
||||
#if defined(INPUTDRIVER_ENCODER_BTN)
|
||||
gpio_wakeup_disable((gpio_num_t)INPUTDRIVER_ENCODER_BTN);
|
||||
#ifdef INPUTDRIVER_WAKE_BTN_PIN
|
||||
gpio_wakeup_disable((gpio_num_t)INPUTDRIVER_WAKE_BTN_PIN);
|
||||
#undef INPUTDRIVER_WAKE_BTN_PIN
|
||||
#endif
|
||||
#if defined(WAKE_ON_TOUCH)
|
||||
gpio_wakeup_disable((gpio_num_t)SCREEN_TOUCH_INT);
|
||||
|
||||
131
variants/esp32s3/mini-epaper-s3/nicheGraphics.h
Normal file
131
variants/esp32s3/mini-epaper-s3/nicheGraphics.h
Normal file
@@ -0,0 +1,131 @@
|
||||
#pragma once
|
||||
|
||||
#include "configuration.h"
|
||||
|
||||
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
||||
|
||||
// InkHUD-specific components
|
||||
#include "graphics/niche/InkHUD/InkHUD.h"
|
||||
|
||||
// Applets
|
||||
#include "graphics/niche/InkHUD/Applet.h"
|
||||
#include "graphics/niche/InkHUD/Applets/User/AllMessage/AllMessageApplet.h"
|
||||
#include "graphics/niche/InkHUD/Applets/User/DM/DMApplet.h"
|
||||
#include "graphics/niche/InkHUD/Applets/User/FavoritesMap/FavoritesMapApplet.h"
|
||||
#include "graphics/niche/InkHUD/Applets/User/Heard/HeardApplet.h"
|
||||
#include "graphics/niche/InkHUD/Applets/User/Positions/PositionsApplet.h"
|
||||
#include "graphics/niche/InkHUD/Applets/User/RecentsList/RecentsListApplet.h"
|
||||
#include "graphics/niche/InkHUD/Applets/User/ThreadedMessage/ThreadedMessageApplet.h"
|
||||
#include "graphics/niche/InkHUD/SystemApplet.h"
|
||||
|
||||
// Shared NicheGraphics components
|
||||
#include "graphics/niche/Drivers/EInk/GDEW0102T4.h"
|
||||
#include "graphics/niche/Inputs/TwoButtonExtended.h"
|
||||
|
||||
void setupNicheGraphics()
|
||||
{
|
||||
using namespace NicheGraphics;
|
||||
|
||||
// Power-enable the E-Ink panel on this board before any SPI traffic.
|
||||
pinMode(PIN_EINK_EN, OUTPUT);
|
||||
digitalWrite(PIN_EINK_EN, HIGH);
|
||||
delay(10);
|
||||
|
||||
// Display uses HSPI on this board
|
||||
SPIClass *hspi = new SPIClass(HSPI);
|
||||
hspi->begin(PIN_EINK_SCLK, -1, PIN_EINK_MOSI, PIN_EINK_CS);
|
||||
|
||||
Drivers::GDEW0102T4 *displayDriver = new Drivers::GDEW0102T4;
|
||||
displayDriver->begin(hspi, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY, PIN_EINK_RES);
|
||||
// Tuned fast-refresh values reg30 reg50 reg82 lutW2 lutB2 = 11 F2 04 11 0D
|
||||
displayDriver->setFastConfig({0x11, 0xF2, 0x04, 0x11, 0x0D});
|
||||
Drivers::EInk *driver = displayDriver;
|
||||
|
||||
InkHUD::InkHUD *inkhud = InkHUD::InkHUD::getInstance();
|
||||
inkhud->setDriver(driver);
|
||||
// Slightly stricter FAST/FULL
|
||||
inkhud->setDisplayResilience(5, 1.5);
|
||||
inkhud->twoWayRocker = true;
|
||||
|
||||
// Fonts
|
||||
InkHUD::Applet::fontLarge = FREESANS_9PT_WIN1252;
|
||||
InkHUD::Applet::fontMedium = FREESANS_6PT_WIN1252;
|
||||
InkHUD::Applet::fontSmall = FREESANS_6PT_WIN1252;
|
||||
|
||||
// Small display defaults
|
||||
inkhud->persistence->settings.rotation = 0;
|
||||
inkhud->persistence->settings.userTiles.maxCount = 1;
|
||||
inkhud->persistence->settings.userTiles.count = 1;
|
||||
inkhud->persistence->settings.joystick.enabled = true;
|
||||
inkhud->persistence->settings.joystick.aligned = true;
|
||||
inkhud->persistence->settings.optionalMenuItems.nextTile = false;
|
||||
|
||||
// Pick applets
|
||||
// Note: order of applets determines priority of "auto-show" feature
|
||||
inkhud->addApplet("All Messages", new InkHUD::AllMessageApplet, false, false); // -
|
||||
inkhud->addApplet("DMs", new InkHUD::DMApplet, true, false); // Activated, not autoshown
|
||||
inkhud->addApplet("Channel 0", new InkHUD::ThreadedMessageApplet(0), true, true); // Activated, Autoshown
|
||||
inkhud->addApplet("Channel 1", new InkHUD::ThreadedMessageApplet(1), false, false); // -
|
||||
inkhud->addApplet("Positions", new InkHUD::PositionsApplet, true); // Activated
|
||||
inkhud->addApplet("Favorites Map", new InkHUD::FavoritesMapApplet, false, false); // -
|
||||
inkhud->addApplet("Recents List", new InkHUD::RecentsListApplet, false, false); // -
|
||||
inkhud->addApplet("Heard", new InkHUD::HeardApplet, true, false, 0); // Activated, not autoshown, default on tile 0
|
||||
// Start running InkHUD
|
||||
inkhud->begin();
|
||||
|
||||
// Enforce two-way rocker behavior regardless of persisted settings.
|
||||
inkhud->persistence->settings.joystick.enabled = true;
|
||||
inkhud->persistence->settings.joystick.aligned = true;
|
||||
inkhud->persistence->settings.optionalMenuItems.nextTile = false;
|
||||
|
||||
// Inputs
|
||||
Inputs::TwoButtonExtended *buttons = Inputs::TwoButtonExtended::getInstance();
|
||||
|
||||
// Center press (boot button)
|
||||
buttons->setWiring(0, INPUTDRIVER_TWO_WAY_ROCKER_BTN, true);
|
||||
// Match baseUI encoder long-press feel.
|
||||
buttons->setTiming(0, 75, 300);
|
||||
buttons->setHandlerShortPress(0, [inkhud]() { inkhud->shortpress(); });
|
||||
buttons->setHandlerLongPress(0, [inkhud]() { inkhud->longpress(); });
|
||||
|
||||
// LEFT rocker pin is IO4; RIGHT rocker pin is IO3.
|
||||
buttons->setTwoWayRockerWiring(INPUTDRIVER_TWO_WAY_ROCKER_LEFT, INPUTDRIVER_TWO_WAY_ROCKER_RIGHT, true);
|
||||
buttons->setJoystickDebounce(50);
|
||||
|
||||
// Two-way rocker behavior:
|
||||
// - when a system applet is handling input (menu, tips, etc): LEFT=up, RIGHT=down
|
||||
// - otherwise: LEFT=previous applet, RIGHT=next applet
|
||||
buttons->setTwoWayRockerPressHandlers(
|
||||
[inkhud]() {
|
||||
bool systemHandlingInput = false;
|
||||
for (InkHUD::SystemApplet *sa : inkhud->systemApplets) {
|
||||
if (sa->handleInput) {
|
||||
systemHandlingInput = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (systemHandlingInput)
|
||||
inkhud->navUp();
|
||||
else
|
||||
inkhud->prevApplet();
|
||||
},
|
||||
[inkhud]() {
|
||||
bool systemHandlingInput = false;
|
||||
for (InkHUD::SystemApplet *sa : inkhud->systemApplets) {
|
||||
if (sa->handleInput) {
|
||||
systemHandlingInput = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (systemHandlingInput)
|
||||
inkhud->navDown();
|
||||
else
|
||||
inkhud->nextApplet();
|
||||
});
|
||||
|
||||
buttons->start();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -3,24 +3,23 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define USB_VID 0x303a
|
||||
#define USB_VID 0x303A
|
||||
#define USB_PID 0x1001
|
||||
|
||||
// The default Wire will be mapped to PMU and RTC
|
||||
static const uint8_t SDA = 18;
|
||||
static const uint8_t SCL = 9;
|
||||
|
||||
// Default SPI will be mapped to Radio
|
||||
// Default SPI (LoRa bus)
|
||||
static const uint8_t SS = -1;
|
||||
static const uint8_t MOSI = 17;
|
||||
static const uint8_t MISO = 6;
|
||||
static const uint8_t SCK = 8;
|
||||
|
||||
// SD card SPI bus
|
||||
#define SPI_MOSI (39)
|
||||
#define SPI_SCK (41)
|
||||
#define SPI_MISO (38)
|
||||
#define SPI_CS (40)
|
||||
|
||||
#define SDCARD_CS SPI_CS
|
||||
|
||||
#endif /* Pins_Arduino_h */
|
||||
|
||||
@@ -17,11 +17,15 @@ upload_protocol = esptool
|
||||
build_flags =
|
||||
${esp32s3_base.build_flags}
|
||||
-I variants/esp32s3/mini-epaper-s3
|
||||
-DMINI_EPAPER_S3
|
||||
-DUSE_EINK
|
||||
-DEINK_DISPLAY_MODEL=GxEPD2_102
|
||||
-DEINK_WIDTH=128
|
||||
-DEINK_HEIGHT=80
|
||||
-D MINI_EPAPER_S3
|
||||
-D USE_EINK
|
||||
-D EINK_DISPLAY_MODEL=GxEPD2_102
|
||||
-D EINK_WIDTH=128
|
||||
-D EINK_HEIGHT=80
|
||||
-D USE_EINK_DYNAMICDISPLAY
|
||||
-D EINK_LIMIT_FASTREFRESH=3
|
||||
-D EINK_BACKGROUND_USES_FAST
|
||||
-D EINK_HASQUIRK_GHOSTING
|
||||
|
||||
lib_deps =
|
||||
${esp32s3_base.lib_deps}
|
||||
@@ -29,3 +33,22 @@ lib_deps =
|
||||
https://github.com/meshtastic/GxEPD2/archive/c7eb4c3c167cf396ef4f541cc5d4c6aa42f3c46b.zip
|
||||
# renovate: datasource=custom.pio depName=SensorLib packageName=lewisxhe/library/SensorLib
|
||||
lewisxhe/SensorLib@0.3.4
|
||||
|
||||
[env:mini-epaper-s3-inkhud]
|
||||
extends = esp32s3_base, inkhud
|
||||
board = mini-epaper-s3
|
||||
board_check = true
|
||||
upload_protocol = esptool
|
||||
build_src_filter =
|
||||
${esp32s3_base.build_src_filter}
|
||||
${inkhud.build_src_filter}
|
||||
build_flags =
|
||||
${esp32s3_base.build_flags}
|
||||
${inkhud.build_flags}
|
||||
-I variants/esp32s3/mini-epaper-s3
|
||||
-D MINI_EPAPER_S3
|
||||
lib_deps =
|
||||
${inkhud.lib_deps} ; InkHUD libs first, so we get GFXRoot instead of AdafruitGFX
|
||||
${esp32s3_base.lib_deps}
|
||||
# renovate: datasource=custom.pio depName=SensorLib packageName=lewisxhe/library/SensorLib
|
||||
lewisxhe/SensorLib@0.3.4
|
||||
|
||||
@@ -1,46 +1,46 @@
|
||||
// Display (E-Ink)
|
||||
#pragma once
|
||||
|
||||
#define PIN_EINK_CS 13
|
||||
#define PIN_EINK_BUSY 10
|
||||
#define PIN_EINK_RES 11
|
||||
#define PIN_EINK_SCLK 14
|
||||
#define PIN_EINK_MOSI 15
|
||||
#define PIN_EINK_DC 12
|
||||
#define PIN_EINK_EN 42
|
||||
#define GPS_DEFAULT_NOT_PRESENT 1
|
||||
|
||||
#define SPI_INTERFACES_COUNT 2
|
||||
#define PIN_SPI1_MISO -1
|
||||
#define PIN_SPI1_MOSI PIN_EINK_MOSI
|
||||
#define PIN_SPI1_SCK PIN_EINK_SCLK
|
||||
#define DISPLAY_FORCE_SMALL_FONTS
|
||||
// SD card (TF)
|
||||
#define HAS_SDCARD
|
||||
#define SDCARD_USE_SPI1
|
||||
#define SDCARD_CS 40
|
||||
#define SD_SPI_FREQUENCY 25000000U
|
||||
|
||||
// Built-in RTC (I2C)
|
||||
#define PCF8563_RTC 0x51
|
||||
#define HAS_RTC 1
|
||||
#define I2C_SDA SDA
|
||||
#define I2C_SCL SCL
|
||||
|
||||
// Battery voltage monitoring
|
||||
#define BATTERY_PIN 2 // A battery voltage measurement pin, voltage divider connected here to
|
||||
// measure battery voltage ratio of voltage divider = 2.0 (assumption)
|
||||
#define ADC_MULTIPLIER 2.11 // 2.0 + 10% for correction of display undervoltage.
|
||||
#define ADC_CHANNEL ADC1_GPIO2_CHANNEL
|
||||
|
||||
#define HAS_GPS 0
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
// Display (E-Ink)
|
||||
#define PIN_EINK_EN 42
|
||||
#define PIN_EINK_CS 13
|
||||
#define PIN_EINK_BUSY 10
|
||||
#define PIN_EINK_DC 12
|
||||
#define PIN_EINK_RES 11
|
||||
#define PIN_EINK_SCLK 14
|
||||
#define PIN_EINK_MOSI 15
|
||||
#define DISPLAY_FORCE_SMALL_FONTS
|
||||
|
||||
#define BUTTON_PIN 3
|
||||
#define BUTTON_NEED_PULLUP
|
||||
#define ALT_BUTTON_PIN 4
|
||||
#define ALT_BUTTON_ACTIVE_LOW true
|
||||
#define ALT_BUTTON_ACTIVE_PULLUP true
|
||||
#define PIN_BUTTON3 0
|
||||
|
||||
// #define HAS_SDCARD 1
|
||||
// #define SDCARD_USE_SOFT_SPI
|
||||
|
||||
// PCF85063 RTC Module
|
||||
#define PCF85063_RTC 0x51
|
||||
#define HAS_RTC 1
|
||||
// Two-Way Rocker input (left/right + boot as press)
|
||||
#define INPUTDRIVER_TWO_WAY_ROCKER
|
||||
#define INPUTDRIVER_ENCODER_TYPE 2
|
||||
#define INPUTDRIVER_TWO_WAY_ROCKER_RIGHT 3
|
||||
#define INPUTDRIVER_TWO_WAY_ROCKER_LEFT 4
|
||||
#define INPUTDRIVER_TWO_WAY_ROCKER_BTN 0
|
||||
#define UPDOWN_LONG_PRESS_REPEAT_INTERVAL 150
|
||||
|
||||
// LoRa (SX1262)
|
||||
#define USE_SX1262
|
||||
|
||||
#define LORA_DIO1 5
|
||||
#define LORA_SCK 8
|
||||
#define LORA_MISO 6
|
||||
|
||||
Reference in New Issue
Block a user