mirror of
https://github.com/markqvist/RNode_Firmware.git
synced 2025-12-17 01:14:14 -05:00
Add E-Ink display driver and chip detection for VME213
- Implemented LCMEN2R13EFC1 display driver in src/LCMEN2R13EFC1.h, supporting full and fast refresh modes. - Added E-Ink chip detection functionality in src/einkDetect_VME213.h to differentiate between LCMEN213EFC1 and E0213A367. - Included GNU General Public License text in tools/LICENSE.txt. - Added arduino-cli executable to tools directory.
This commit is contained in:
parent
5b7b0d3afe
commit
31e12f3bd4
41 changed files with 14273 additions and 3 deletions
144
Display.h
144
Display.h
|
|
@ -84,6 +84,14 @@
|
|||
#define DISP_W 128
|
||||
#define DISP_H 64
|
||||
#define DISP_ADDR -1
|
||||
#elif BOARD_MODEL == BOARD_VME213
|
||||
#include "src/LCMEN2R13EFC1.h"
|
||||
#include "src/einkDetect_VME213.h"
|
||||
// VME213 E-Ink display: 250x122 pixels
|
||||
#define DISP_W 250
|
||||
#define DISP_H 122
|
||||
#define DISP_ADDR -1
|
||||
#define VME213_REFRESH_RATIO 10 // 10 FAST : 1 FULL refresh
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
|
||||
#define DISP_RST -1
|
||||
#define DISP_ADDR 0x3C
|
||||
|
|
@ -121,6 +129,18 @@
|
|||
uint32_t last_epd_refresh = 0;
|
||||
uint32_t last_epd_full_refresh = 0;
|
||||
#define REFRESH_PERIOD 300000
|
||||
#elif BOARD_MODEL == BOARD_VME213
|
||||
LCMEN2R13EFC1 vme213_display;
|
||||
EInkChipType vme213_chip_type = EINK_LCMEN213EFC1;
|
||||
uint8_t vme213_displayBuffer[4000]; // 250x122 pixels = 4000 bytes
|
||||
uint32_t last_epd_refresh = 0;
|
||||
uint32_t last_epd_full_refresh = 0;
|
||||
uint8_t vme213_fast_refresh_count = 0;
|
||||
#define REFRESH_PERIOD 300000
|
||||
// Compatibility macro
|
||||
#define display vme213_display
|
||||
#define SSD1306_BLACK 0
|
||||
#define SSD1306_WHITE 1
|
||||
#else
|
||||
Adafruit_SSD1306 display(DISP_W, DISP_H, &Wire, DISP_RST);
|
||||
#endif
|
||||
|
|
@ -189,6 +209,19 @@ void update_area_positions() {
|
|||
p_as_x = 64;
|
||||
p_as_y = 0;
|
||||
}
|
||||
#elif BOARD_MODEL == BOARD_VME213
|
||||
// VME213: 250x122 landscape - split into two 125x122 areas
|
||||
if (disp_mode == DISP_MODE_LANDSCAPE) {
|
||||
p_ad_x = 0;
|
||||
p_ad_y = 0;
|
||||
p_as_x = 125;
|
||||
p_as_y = 0;
|
||||
} else {
|
||||
p_ad_x = 0;
|
||||
p_ad_y = 0;
|
||||
p_as_x = 0;
|
||||
p_as_y = 61;
|
||||
}
|
||||
#else
|
||||
if (disp_mode == DISP_MODE_PORTRAIT) {
|
||||
p_ad_x = 0 * DISPLAY_SCALE;
|
||||
|
|
@ -247,6 +280,58 @@ uint8_t display_contrast = 0x00;
|
|||
}
|
||||
#endif
|
||||
|
||||
#if BOARD_MODEL == BOARD_VME213
|
||||
// VME213 E-Ink display rendering helpers
|
||||
void vme213_drawPixel(uint16_t x, uint16_t y, uint8_t color) {
|
||||
if (x >= DISP_W || y >= DISP_H) return;
|
||||
uint16_t byteIndex = y * ((DISP_W + 7) / 8) + (x / 8);
|
||||
uint8_t bitMask = 0x80 >> (x % 8);
|
||||
|
||||
if (color == SSD1306_WHITE) {
|
||||
vme213_displayBuffer[byteIndex] |= bitMask; // White pixel
|
||||
} else {
|
||||
vme213_displayBuffer[byteIndex] &= ~bitMask; // Black pixel
|
||||
}
|
||||
}
|
||||
|
||||
void vme213_fillScreen(uint8_t color) {
|
||||
memset(vme213_displayBuffer, (color == SSD1306_WHITE) ? 0xFF : 0x00, sizeof(vme213_displayBuffer));
|
||||
}
|
||||
|
||||
void vme213_drawText(uint16_t x, uint16_t y, const char* text, uint8_t size) {
|
||||
// Simple text rendering using 5x7 font
|
||||
// This is a placeholder - full implementation would use Adafruit_GFX font rendering
|
||||
// For now, just mark text position
|
||||
for (int i = 0; i < 10; i++) {
|
||||
vme213_drawPixel(x + i, y, SSD1306_BLACK);
|
||||
}
|
||||
}
|
||||
|
||||
void vme213_renderStatus() {
|
||||
vme213_fillScreen(SSD1306_WHITE);
|
||||
|
||||
// Header area (top 20 pixels)
|
||||
for (int y = 0; y < 20; y++) {
|
||||
for (int x = 0; x < DISP_W; x++) {
|
||||
vme213_drawPixel(x, y, (y % 2 == 0) ? SSD1306_BLACK : SSD1306_WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
// Status text placeholder
|
||||
vme213_drawText(10, 30, "RNode", 2);
|
||||
|
||||
// Signal indicator (simple bars)
|
||||
if (radio_online) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
int barHeight = 10 + i * 5;
|
||||
for (int y = 0; y < barHeight; y++) {
|
||||
vme213_drawPixel(10 + i * 8, 100 - y, SSD1306_BLACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool display_init() {
|
||||
#if HAS_DISPLAY
|
||||
#if BOARD_MODEL == BOARD_RNODE_NG_20 || BOARD_MODEL == BOARD_LORA32_V2_0
|
||||
|
|
@ -299,6 +384,27 @@ bool display_init() {
|
|||
pinMode(pin_backlight, OUTPUT);
|
||||
analogWrite(pin_backlight, 0);
|
||||
#endif
|
||||
#elif BOARD_MODEL == BOARD_VME213
|
||||
// Enable Vext power (GPIO 18) for peripherals
|
||||
pinMode(Vext, OUTPUT);
|
||||
digitalWrite(Vext, HIGH);
|
||||
delay(100);
|
||||
|
||||
// Detect E-Ink chip type
|
||||
vme213_chip_type = detectEInkChip(pin_disp_reset, pin_disp_busy);
|
||||
|
||||
// Initialize SPI for E-Ink display
|
||||
SPI.begin(pin_disp_sck, pin_disp_miso, pin_disp_mosi, pin_disp_cs);
|
||||
|
||||
// Initialize E-Ink driver
|
||||
vme213_display.begin(&SPI, pin_disp_dc, pin_disp_cs, pin_disp_busy, pin_disp_reset);
|
||||
|
||||
// Clear buffer
|
||||
memset(vme213_displayBuffer, 0xFF, sizeof(vme213_displayBuffer));
|
||||
|
||||
// Perform initial FULL refresh to clear display
|
||||
vme213_display.update(vme213_displayBuffer, LCMEN2R13EFC1::UPDATE_FULL);
|
||||
vme213_fast_refresh_count = 0;
|
||||
#elif BOARD_MODEL == BOARD_TBEAM_S_V1
|
||||
Wire.begin(SDA_OLED, SCL_OLED);
|
||||
#elif BOARD_MODEL == BOARD_XIAO_S3
|
||||
|
|
@ -348,6 +454,9 @@ bool display_init() {
|
|||
#if BOARD_MODEL == BOARD_TECHO
|
||||
// Don't check if display is actually connected
|
||||
if(false) {
|
||||
#elif BOARD_MODEL == BOARD_VME213
|
||||
// VME213 E-Ink display initialization already done, skip connection check
|
||||
if(false) {
|
||||
#elif BOARD_MODEL == BOARD_TDECK
|
||||
display.init(240, 320);
|
||||
display.setSPISpeed(80e6);
|
||||
|
|
@ -414,6 +523,10 @@ bool display_init() {
|
|||
#elif BOARD_MODEL == BOARD_TECHO
|
||||
disp_mode = DISP_MODE_PORTRAIT;
|
||||
display.setRotation(3);
|
||||
#elif BOARD_MODEL == BOARD_VME213
|
||||
// VME213 E-Ink: 250x122 landscape by default
|
||||
disp_mode = DISP_MODE_LANDSCAPE;
|
||||
// No setRotation for VME213 (driver handles orientation)
|
||||
#else
|
||||
disp_mode = DISP_MODE_PORTRAIT;
|
||||
display.setRotation(3);
|
||||
|
|
@ -429,7 +542,7 @@ bool display_init() {
|
|||
stat_area.cp437(true);
|
||||
disp_area.cp437(true);
|
||||
|
||||
#if BOARD_MODEL != BOARD_HELTEC_T114
|
||||
#if BOARD_MODEL != BOARD_HELTEC_T114 && BOARD_MODEL != BOARD_VME213
|
||||
display.cp437(true);
|
||||
#endif
|
||||
|
||||
|
|
@ -990,6 +1103,12 @@ void update_display(bool blank = false) {
|
|||
epd_blank();
|
||||
epd_blanked = true;
|
||||
}
|
||||
#elif BOARD_MODEL == BOARD_VME213
|
||||
if (!epd_blanked) {
|
||||
vme213_fillScreen(SSD1306_WHITE);
|
||||
vme213_display.update(vme213_displayBuffer, LCMEN2R13EFC1::UPDATE_FULL);
|
||||
epd_blanked = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BOARD_MODEL == BOARD_HELTEC_T114
|
||||
|
|
@ -1015,6 +1134,8 @@ void update_display(bool blank = false) {
|
|||
|
||||
#if BOARD_MODEL == BOARD_HELTEC_T114
|
||||
display.clear();
|
||||
#elif BOARD_MODEL == BOARD_VME213
|
||||
// E-Ink buffer will be redrawn completely
|
||||
#elif BOARD_MODEL != BOARD_TDECK && BOARD_MODEL != BOARD_TECHO
|
||||
display.clearDisplay();
|
||||
#endif
|
||||
|
|
@ -1027,6 +1148,9 @@ void update_display(bool blank = false) {
|
|||
#if BOARD_MODEL == BOARD_TECHO
|
||||
display.setFullWindow();
|
||||
display.fillScreen(SSD1306_WHITE);
|
||||
#elif BOARD_MODEL == BOARD_VME213
|
||||
// Render RNode UI to E-Ink buffer
|
||||
vme213_renderStatus();
|
||||
#endif
|
||||
|
||||
update_stat_area();
|
||||
|
|
@ -1040,6 +1164,24 @@ void update_display(bool blank = false) {
|
|||
last_epd_refresh = millis();
|
||||
epd_blanked = false;
|
||||
}
|
||||
#elif BOARD_MODEL == BOARD_VME213
|
||||
if (current-last_epd_refresh >= epd_update_interval) {
|
||||
// Decide refresh type: 10 FAST : 1 FULL
|
||||
LCMEN2R13EFC1::UpdateType refreshType;
|
||||
if (vme213_fast_refresh_count >= VME213_REFRESH_RATIO || current-last_epd_full_refresh >= REFRESH_PERIOD) {
|
||||
refreshType = LCMEN2R13EFC1::UPDATE_FULL;
|
||||
vme213_fast_refresh_count = 0;
|
||||
last_epd_full_refresh = millis();
|
||||
} else {
|
||||
refreshType = LCMEN2R13EFC1::UPDATE_FAST;
|
||||
vme213_fast_refresh_count++;
|
||||
}
|
||||
|
||||
// Perform E-Ink update
|
||||
vme213_display.update(vme213_displayBuffer, refreshType);
|
||||
last_epd_refresh = millis();
|
||||
epd_blanked = false;
|
||||
}
|
||||
#elif BOARD_MODEL != BOARD_TDECK
|
||||
display.display();
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue