Skip to content

Commit 9108a70

Browse files
authored
Merge pull request #612 from Quency-D/dec-heltec_e290
Add heltec_vision_master_e290 board.
2 parents a7dcd11 + 6d18e2c commit 9108a70

File tree

9 files changed

+515
-0
lines changed

9 files changed

+515
-0
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{
2+
"build": {
3+
"arduino": {
4+
"ldscript": "esp32s3_out.ld",
5+
"partitions": "default_16MB.csv",
6+
"memory_type": "qio_opi"
7+
},
8+
"core": "esp32",
9+
"extra_flags": [
10+
"-DBOARD_HAS_PSRAM",
11+
"-DARDUINO_USB_MODE=0",
12+
"-DARDUINO_USB_CDC_ON_BOOT=1",
13+
"-DARDUINO_RUNNING_CORE=1",
14+
"-DARDUINO_EVENT_RUNNING_CORE=1"
15+
],
16+
"f_cpu": "240000000L",
17+
"f_flash": "80000000L",
18+
"flash_mode": "qio",
19+
"psram_type": "opi",
20+
"hwids": [
21+
["0x303A", "0x1001"],
22+
["0x303A", "0x0002"]
23+
],
24+
"mcu": "esp32s3",
25+
"variant": "heltec_vision_master_e290"
26+
},
27+
"connectivity": ["wifi", "bluetooth", "lora"],
28+
"debug": {
29+
"openocd_target": "esp32s3.cfg"
30+
},
31+
"frameworks": ["arduino", "espidf"],
32+
"name": "Heltec Vision Master E290",
33+
"upload": {
34+
"flash_size": "16MB",
35+
"maximum_ram_size": 8388608,
36+
"maximum_size": 16777216,
37+
"use_1200bps_touch": true,
38+
"wait_for_upload_port": true,
39+
"require_upload_port": true,
40+
"speed": 921600
41+
},
42+
"url": "https://heltec.org/project/vision-master-e290/",
43+
"vendor": "Heltec"
44+
}

src/helpers/ui/E290Display.cpp

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#include "E290Display.h"
2+
3+
#include "../../MeshCore.h"
4+
5+
bool E290Display::begin() {
6+
if (_init) return true;
7+
8+
powerOn();
9+
display.begin();
10+
11+
// Set to landscape mode rotated 180 degrees
12+
display.setRotation(3);
13+
14+
_init = true;
15+
_isOn = true;
16+
17+
clear();
18+
display.fastmodeOn(); // Enable fast mode for quicker (partial) updates
19+
20+
return true;
21+
}
22+
23+
void E290Display::powerOn() {
24+
#ifdef PIN_VEXT_EN
25+
pinMode(PIN_VEXT_EN, OUTPUT);
26+
digitalWrite(PIN_VEXT_EN, PIN_VEXT_EN_ACTIVE);
27+
delay(50); // Allow power to stabilize
28+
#endif
29+
}
30+
31+
void E290Display::powerOff() {
32+
#ifdef PIN_VEXT_EN
33+
digitalWrite(PIN_VEXT_EN, !PIN_VEXT_EN_ACTIVE); // Turn off power
34+
#endif
35+
}
36+
37+
void E290Display::turnOn() {
38+
if (!_init) begin();
39+
powerOn();
40+
_isOn = true;
41+
}
42+
43+
void E290Display::turnOff() {
44+
powerOff();
45+
_isOn = false;
46+
}
47+
48+
void E290Display::clear() {
49+
display.clear();
50+
}
51+
52+
void E290Display::startFrame(Color bkg) {
53+
// Fill screen with white first to ensure clean background
54+
display.fillRect(0, 0, width(), height(), WHITE);
55+
if (bkg == LIGHT) {
56+
// Fill with black if light background requested (inverted for e-ink)
57+
display.fillRect(0, 0, width(), height(), BLACK);
58+
}
59+
}
60+
61+
void E290Display::setTextSize(int sz) {
62+
// The library handles text size internally
63+
display.setTextSize(sz);
64+
}
65+
66+
void E290Display::setColor(Color c) {
67+
// implemented in individual display methods
68+
}
69+
70+
void E290Display::setCursor(int x, int y) {
71+
display.setCursor(x, y);
72+
}
73+
74+
void E290Display::print(const char *str) {
75+
display.print(str);
76+
}
77+
78+
void E290Display::fillRect(int x, int y, int w, int h) {
79+
display.fillRect(x, y, w, h, BLACK);
80+
}
81+
82+
void E290Display::drawRect(int x, int y, int w, int h) {
83+
display.drawRect(x, y, w, h, BLACK);
84+
}
85+
86+
void E290Display::drawXbm(int x, int y, const uint8_t *bits, int w, int h) {
87+
// Width in bytes for bitmap processing
88+
uint16_t widthInBytes = (w + 7) / 8;
89+
90+
// Process the bitmap row by row
91+
for (int by = 0; by < h; by++) {
92+
// Scan across the row bit by bit
93+
for (int bx = 0; bx < w; bx++) {
94+
// Get the current bit using MSB ordering (like GxEPDDisplay)
95+
uint16_t byteOffset = (by * widthInBytes) + (bx / 8);
96+
uint8_t bitMask = 0x80 >> (bx & 7);
97+
bool bitSet = bits[byteOffset] & bitMask;
98+
99+
// If the bit is set, draw the pixel
100+
if (bitSet) {
101+
display.drawPixel(x + bx, y + by, BLACK);
102+
}
103+
}
104+
}
105+
}
106+
107+
uint16_t E290Display::getTextWidth(const char *str) {
108+
int16_t x1, y1;
109+
uint16_t w, h;
110+
display.getTextBounds(str, 0, 0, &x1, &y1, &w, &h);
111+
return w;
112+
}
113+
114+
void E290Display::endFrame() {
115+
display.update();
116+
}

src/helpers/ui/E290Display.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#pragma once
2+
3+
#include "DisplayDriver.h"
4+
5+
#include <SPI.h>
6+
#include <Wire.h>
7+
#include <heltec-eink-modules.h>
8+
9+
// Display driver for E290 e-ink display
10+
class E290Display : public DisplayDriver {
11+
EInkDisplay_VisionMasterE290 display;
12+
bool _init = false;
13+
bool _isOn = false;
14+
15+
public:
16+
E290Display() : DisplayDriver(296, 128) {}
17+
18+
bool begin();
19+
bool isOn() override { return _isOn; }
20+
void turnOn() override;
21+
void turnOff() override;
22+
void clear() override;
23+
void startFrame(Color bkg = DARK) override;
24+
void setTextSize(int sz) override;
25+
void setColor(Color c) override;
26+
void setCursor(int x, int y) override;
27+
void print(const char *str) override;
28+
void fillRect(int x, int y, int w, int h) override;
29+
void drawRect(int x, int y, int w, int h) override;
30+
void drawXbm(int x, int y, const uint8_t *bits, int w, int h) override;
31+
uint16_t getTextWidth(const char *str) override;
32+
void endFrame() override;
33+
34+
private:
35+
void powerOn();
36+
void powerOff();
37+
};
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#include "HeltecE290Board.h"
2+
3+
void HeltecE290Board::begin() {
4+
ESP32Board::begin();
5+
6+
pinMode(PIN_ADC_CTRL, OUTPUT);
7+
digitalWrite(PIN_ADC_CTRL, LOW); // Initially inactive
8+
9+
periph_power.begin();
10+
11+
esp_reset_reason_t reason = esp_reset_reason();
12+
if (reason == ESP_RST_DEEPSLEEP) {
13+
long wakeup_source = esp_sleep_get_ext1_wakeup_status();
14+
if (wakeup_source & (1 << P_LORA_DIO_1)) { // received a LoRa packet (while in deep sleep)
15+
startup_reason = BD_STARTUP_RX_PACKET;
16+
}
17+
18+
rtc_gpio_hold_dis((gpio_num_t)P_LORA_NSS);
19+
rtc_gpio_deinit((gpio_num_t)P_LORA_DIO_1);
20+
}
21+
}
22+
23+
void HeltecE290Board::enterDeepSleep(uint32_t secs, int pin_wake_btn) {
24+
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
25+
26+
// Make sure the DIO1 and NSS GPIOs are hold on required levels during deep sleep
27+
rtc_gpio_set_direction((gpio_num_t)P_LORA_DIO_1, RTC_GPIO_MODE_INPUT_ONLY);
28+
rtc_gpio_pulldown_en((gpio_num_t)P_LORA_DIO_1);
29+
30+
rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS);
31+
32+
if (pin_wake_btn < 0) {
33+
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet
34+
} else {
35+
esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1) | (1L << pin_wake_btn), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet OR wake btn
36+
}
37+
38+
if (secs > 0) {
39+
esp_sleep_enable_timer_wakeup(secs * 1000000);
40+
}
41+
42+
// Finally set ESP32 into sleep
43+
esp_deep_sleep_start(); // CPU halts here and never returns!
44+
}
45+
46+
void HeltecE290Board::powerOff() {
47+
// TODO: re-enable this when there is a definite wake-up source pin:
48+
// enterDeepSleep(0);
49+
}
50+
51+
uint16_t HeltecE290Board::getBattMilliVolts() {
52+
analogReadResolution(10);
53+
digitalWrite(PIN_ADC_CTRL, HIGH);
54+
55+
uint32_t raw = 0;
56+
for (int i = 0; i < 8; i++) {
57+
raw += analogRead(PIN_VBAT_READ);
58+
}
59+
raw = raw / 8;
60+
61+
digitalWrite(PIN_ADC_CTRL, LOW);
62+
63+
return (5.42 * (3.3 / 1024.0) * raw) * 1000;
64+
}
65+
66+
const char* HeltecE290Board::getManufacturerName() const {
67+
return "Heltec E290";
68+
}
69+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#pragma once
2+
3+
#include <Arduino.h>
4+
#include <helpers/RefCountedDigitalPin.h>
5+
#include <helpers/ESP32Board.h>
6+
#include <driver/rtc_io.h>
7+
8+
// LoRa radio module pins for heltec_vision_master_e290
9+
#define P_LORA_DIO_1 14
10+
#define P_LORA_NSS 8
11+
#define P_LORA_RESET 12
12+
#define P_LORA_BUSY 13
13+
#define P_LORA_SCLK 9
14+
#define P_LORA_MISO 11
15+
#define P_LORA_MOSI 10
16+
17+
class HeltecE290Board : public ESP32Board {
18+
19+
public:
20+
RefCountedDigitalPin periph_power;
21+
22+
HeltecE290Board() : periph_power(PIN_VEXT_EN) { }
23+
24+
void begin();
25+
void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1);
26+
void powerOff() override;
27+
uint16_t getBattMilliVolts() override;
28+
const char* getManufacturerName() const override ;
29+
30+
};
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#ifndef Pins_Arduino_h
2+
#define Pins_Arduino_h
3+
4+
#include <stdint.h>
5+
6+
static const uint8_t LED_BUILTIN = 45; // LED is not populated on earliest board variant
7+
#define BUILTIN_LED LED_BUILTIN // Backward compatibility
8+
#define LED_BUILTIN LED_BUILTIN
9+
10+
static const uint8_t TX = 43;
11+
static const uint8_t RX = 44;
12+
13+
static const uint8_t SDA = 39;
14+
static const uint8_t SCL = 38;
15+
16+
static const uint8_t SS = 8;
17+
static const uint8_t MOSI = 10;
18+
static const uint8_t MISO = 11;
19+
static const uint8_t SCK = 9;
20+
21+
static const uint8_t A0 = 1;
22+
static const uint8_t A1 = 2;
23+
static const uint8_t A2 = 3;
24+
static const uint8_t A3 = 4;
25+
static const uint8_t A4 = 5;
26+
static const uint8_t A5 = 6;
27+
static const uint8_t A6 = 7;
28+
static const uint8_t A7 = 8;
29+
static const uint8_t A8 = 9;
30+
static const uint8_t A9 = 10;
31+
static const uint8_t A10 = 11;
32+
static const uint8_t A11 = 12;
33+
static const uint8_t A12 = 13;
34+
static const uint8_t A13 = 14;
35+
static const uint8_t A14 = 15;
36+
static const uint8_t A15 = 16;
37+
static const uint8_t A16 = 17;
38+
static const uint8_t A17 = 18;
39+
static const uint8_t A18 = 19;
40+
static const uint8_t A19 = 20;
41+
42+
static const uint8_t T1 = 1;
43+
static const uint8_t T2 = 2;
44+
static const uint8_t T3 = 3;
45+
static const uint8_t T4 = 4;
46+
static const uint8_t T5 = 5;
47+
static const uint8_t T6 = 6;
48+
static const uint8_t T7 = 7;
49+
static const uint8_t T8 = 8;
50+
static const uint8_t T9 = 9;
51+
static const uint8_t T10 = 10;
52+
static const uint8_t T11 = 11;
53+
static const uint8_t T12 = 12;
54+
static const uint8_t T13 = 13;
55+
static const uint8_t T14 = 14;
56+
57+
static const uint8_t RST_LoRa = 12;
58+
static const uint8_t BUSY_LoRa = 13;
59+
static const uint8_t DIO1 = 14;
60+
61+
#endif /* Pins_Arduino_h */

0 commit comments

Comments
 (0)