Skip to content

Commit be243a2

Browse files
committed
Add heltec_vision_master_e213 board.
1 parent dc6b830 commit be243a2

File tree

11 files changed

+493
-21
lines changed

11 files changed

+493
-21
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_8MB.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_e213"
26+
},
27+
"connectivity": ["wifi", "bluetooth", "lora"],
28+
"debug": {
29+
"openocd_target": "esp32s3.cfg"
30+
},
31+
"frameworks": ["arduino", "espidf"],
32+
"name": "Heltec Vision Master E213",
33+
"upload": {
34+
"flash_size": "8MB",
35+
"maximum_ram_size": 8388608,
36+
"maximum_size": 8388608,
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-e213/",
43+
"vendor": "Heltec"
44+
}

src/helpers/RefCountedDigitalPin.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,25 @@
55
class RefCountedDigitalPin {
66
uint8_t _pin;
77
int8_t _claims = 0;
8-
8+
uint8_t _active = 0;
99
public:
10-
RefCountedDigitalPin(uint8_t pin): _pin(pin) { }
10+
RefCountedDigitalPin(uint8_t pin,uint8_t active=HIGH): _pin(pin), _active(active) { }
1111

1212
void begin() {
1313
pinMode(_pin, OUTPUT);
14-
digitalWrite(_pin, LOW); // initial state
14+
digitalWrite(_pin, !_active); // initial state
1515
}
1616

1717
void claim() {
1818
_claims++;
1919
if (_claims > 0) {
20-
digitalWrite(_pin, HIGH);
20+
digitalWrite(_pin, _active);
2121
}
2222
}
2323
void release() {
2424
_claims--;
2525
if (_claims == 0) {
26-
digitalWrite(_pin, LOW);
26+
digitalWrite(_pin, !_active);
2727
}
2828
}
2929
};

src/helpers/ui/E213Display.cpp

Lines changed: 106 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,83 @@
22

33
#include "../../MeshCore.h"
44

5+
EInkDetectionResult E213Display::detectEInk()
6+
{
7+
// Test 1: Logic of BUSY pin
8+
9+
// Determines controller IC manufacturer
10+
// Fitipower: busy when LOW
11+
// Solomon Systech: busy when HIGH
12+
13+
// Force display BUSY by holding reset pin active
14+
pinMode(DISP_RST, OUTPUT);
15+
digitalWrite(DISP_RST, LOW);
16+
17+
delay(10);
18+
19+
// Read whether pin is HIGH or LOW while busy
20+
pinMode(DISP_BUSY, INPUT);
21+
bool busyLogic = digitalRead(DISP_BUSY);
22+
23+
// Test complete. Release pin
24+
pinMode(DISP_RST, INPUT);
25+
26+
if (busyLogic == LOW)
27+
return V_LCMEN213EFC1;
28+
else // busy HIGH
29+
return V_E0213A367;
30+
}
31+
32+
533
bool E213Display::begin() {
634
if (_init) return true;
735

836
powerOn();
9-
display.begin();
37+
_version = detectEInk();
38+
if(_version==V_LCMEN213EFC1) {
39+
display.begin();
40+
// Set to landscape mode rotated 180 degrees
41+
display.setRotation(3);
42+
} else{
43+
display1.begin();
44+
// Set to landscape mode rotated 180 degrees
45+
display1.setRotation(3);
46+
}
1047

11-
// Set to landscape mode rotated 180 degrees
12-
display.setRotation(3);
1348

1449
_init = true;
1550
_isOn = true;
1651

1752
clear();
18-
display.fastmodeOn(); // Enable fast mode for quicker (partial) updates
53+
if(_version==V_LCMEN213EFC1) {
54+
display.fastmodeOn(); // Enable fast mode for quicker (partial) updates
55+
} else{
56+
display1.fastmodeOn(); // Enable fast mode for quicker (partial) updates
57+
}
1958

2059
return true;
2160
}
2261

2362
void E213Display::powerOn() {
2463
#ifdef PIN_VEXT_EN
2564
pinMode(PIN_VEXT_EN, OUTPUT);
65+
#ifdef PIN_VEXT_EN_ACTIVE
66+
digitalWrite(PIN_VEXT_EN, PIN_VEXT_EN_ACTIVE);
67+
#else
2668
digitalWrite(PIN_VEXT_EN, LOW); // Active low
69+
#endif
2770
delay(50); // Allow power to stabilize
2871
#endif
2972
}
3073

3174
void E213Display::powerOff() {
3275
#ifdef PIN_VEXT_EN
76+
#ifdef PIN_VEXT_EN_ACTIVE
77+
digitalWrite(PIN_VEXT_EN, !PIN_VEXT_EN_ACTIVE);
78+
#else
3379
digitalWrite(PIN_VEXT_EN, HIGH); // Turn off power
3480
#endif
81+
#endif
3582
}
3683

3784
void E213Display::turnOn() {
@@ -46,41 +93,73 @@ void E213Display::turnOff() {
4693
}
4794

4895
void E213Display::clear() {
49-
display.clear();
96+
if(_version==V_LCMEN213EFC1) {
97+
display.clear();
98+
} else{
99+
display1.clear();
100+
}
50101
}
51102

52103
void E213Display::startFrame(Color bkg) {
53104
// Fill screen with white first to ensure clean background
54-
display.fillRect(0, 0, width(), height(), WHITE);
105+
if(_version==V_LCMEN213EFC1) {
106+
display.fillRect(0, 0, width(), height(), WHITE);
107+
} else{
108+
display1.fillRect(0, 0, width(), height(), WHITE);
109+
}
55110
if (bkg == LIGHT) {
56111
// Fill with black if light background requested (inverted for e-ink)
57-
display.fillRect(0, 0, width(), height(), BLACK);
112+
if(_version==V_LCMEN213EFC1) {
113+
display.fillRect(0, 0, width(), height(), BLACK);
114+
} else{
115+
display1.fillRect(0, 0, width(), height(), BLACK);
116+
}
58117
}
59118
}
60119

61120
void E213Display::setTextSize(int sz) {
62121
// The library handles text size internally
63-
display.setTextSize(sz);
122+
if(_version==V_LCMEN213EFC1) {
123+
display.setTextSize(sz);
124+
} else{
125+
display1.setTextSize(sz);
126+
}
64127
}
65128

66129
void E213Display::setColor(Color c) {
67130
// implemented in individual display methods
68131
}
69132

70133
void E213Display::setCursor(int x, int y) {
71-
display.setCursor(x, y);
134+
if(_version==V_LCMEN213EFC1) {
135+
display.setCursor(x, y);
136+
} else{
137+
display1.setCursor(x, y);
138+
}
72139
}
73140

74141
void E213Display::print(const char *str) {
75-
display.print(str);
142+
if(_version==V_LCMEN213EFC1) {
143+
display.print(str);
144+
} else {
145+
display1.print(str);
146+
}
76147
}
77148

78149
void E213Display::fillRect(int x, int y, int w, int h) {
79-
display.fillRect(x, y, w, h, BLACK);
150+
if(_version==V_LCMEN213EFC1) {
151+
display.fillRect(x, y, w, h, BLACK);
152+
} else {
153+
display1.fillRect(x, y, w, h, BLACK);
154+
}
80155
}
81156

82157
void E213Display::drawRect(int x, int y, int w, int h) {
83-
display.drawRect(x, y, w, h, BLACK);
158+
if(_version==V_LCMEN213EFC1) {
159+
display.drawRect(x, y, w, h, BLACK);
160+
} else {
161+
display1.drawRect(x, y, w, h, BLACK);
162+
}
84163
}
85164

86165
void E213Display::drawXbm(int x, int y, const uint8_t *bits, int w, int h) {
@@ -98,7 +177,11 @@ void E213Display::drawXbm(int x, int y, const uint8_t *bits, int w, int h) {
98177

99178
// If the bit is set, draw the pixel
100179
if (bitSet) {
101-
display.drawPixel(x + bx, y + by, BLACK);
180+
if(_version==V_LCMEN213EFC1) {
181+
display.drawPixel(x + bx, y + by, BLACK);
182+
} else {
183+
display1.drawPixel(x + bx, y + by, BLACK);
184+
}
102185
}
103186
}
104187
}
@@ -107,10 +190,18 @@ void E213Display::drawXbm(int x, int y, const uint8_t *bits, int w, int h) {
107190
uint16_t E213Display::getTextWidth(const char *str) {
108191
int16_t x1, y1;
109192
uint16_t w, h;
110-
display.getTextBounds(str, 0, 0, &x1, &y1, &w, &h);
193+
if(_version==V_LCMEN213EFC1) {
194+
display.getTextBounds(str, 0, 0, &x1, &y1, &w, &h);
195+
} else {
196+
display1.getTextBounds(str, 0, 0, &x1, &y1, &w, &h);
197+
}
111198
return w;
112199
}
113200

114201
void E213Display::endFrame() {
115-
display.update();
202+
if(_version==V_LCMEN213EFC1) {
203+
display.update();
204+
} else {
205+
display1.update();
206+
}
116207
}

src/helpers/ui/E213Display.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,21 @@
66
#include <Wire.h>
77
#include <heltec-eink-modules.h>
88

9+
enum EInkDetectionResult {
10+
V_LCMEN213EFC1 = 0, // Initial version
11+
V_E0213A367 = 1, // E213 PCB marked V1.1 (Mid 2025)
12+
};
13+
914
// Display driver for E213 e-ink display
1015
class E213Display : public DisplayDriver {
16+
#ifdef VISION_MASTER_E213
1117
EInkDisplay_VisionMasterE213 display;
18+
EInkDisplay_VisionMasterE213V1_1 display1;
19+
#else
20+
EInkDisplay_WirelessPaperV1_1 display;
21+
EInkDisplay_WirelessPaperV1_1_1 display1;
22+
#endif
23+
EInkDetectionResult _version =V_LCMEN213EFC1;
1224
bool _init = false;
1325
bool _isOn = false;
1426

@@ -32,6 +44,7 @@ class E213Display : public DisplayDriver {
3244
void endFrame() override;
3345

3446
private:
47+
EInkDetectionResult detectEInk();
3548
void powerOn();
3649
void powerOff();
3750
};
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#include "HeltecE213Board.h"
2+
3+
void HeltecE213Board::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 HeltecE213Board::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 HeltecE213Board::powerOff() {
47+
// TODO: re-enable this when there is a definite wake-up source pin:
48+
// enterDeepSleep(0);
49+
}
50+
51+
uint16_t HeltecE213Board::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* HeltecE213Board::getManufacturerName() const {
67+
return "Heltec E213";
68+
}
69+

0 commit comments

Comments
 (0)