mirror of
https://github.com/open-x4-epaper/community-sdk.git
synced 2026-04-29 10:24:18 -07:00
feat: X3 grayscale LUTs and fast diff BB reinforcement (#32)
## Summary Adds dedicated X3 grayscale LUTs and improves fast differential refresh for better antialiased text rendering on the Xteink X3 display. ## Changes - Dedicated grayscale LUTs (lut_x3_*_gray): Single-phase waveforms with tuned VDL drive for dark gray (2 units) and light gray (3 units), with active GND hold on non-gray transitions to prevent crosstalk - Tight scan timing: TP2/TP3 reduced from 6 to 1 to minimize idle gate-on time (17 to 7 units per row), reducing parasitic charge leakage that causes white lines through letter strokes - BB reinforcement: Added mild VDH pulse (VS=0x10) to lut_x3_bb_full so black pixels get actively reinforced during fast differential refreshes, clearing gray residue/ghosting - displayGrayBuffer() updated to use the dedicated gray LUT bank instead of full refresh LUTs Companion to crosspoint-reader/crosspoint-reader#1607 ## AI Disclosure Yes, AI was used to assist with the development of these changes.
This commit is contained in:
@@ -125,7 +125,40 @@ const uint8_t lut_x3_wb_full[] PROGMEM = {
|
||||
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};
|
||||
const uint8_t lut_x3_bb_full[] PROGMEM = {
|
||||
0x00, 0x06, 0x02, 0x06, 0x06, 0x01, 0x00, 0x05, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
|
||||
0x10, 0x06, 0x02, 0x06, 0x06, 0x01, 0x00, 0x05, 0x01, 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};
|
||||
|
||||
// X3 dedicated grayscale LUTs — tuned drive strengths for 4-level gray
|
||||
// All entries share the same single-phase timing so the controller scans
|
||||
// every row with consistent gate timing. Source voltages differ per transition:
|
||||
// VCOM: GND (stable common electrode reference)
|
||||
// BB: GND (active hold — prevents floating source crosstalk)
|
||||
// WW: brief VDL pulse (dark gray)
|
||||
// BW: moderate VDL pulse (light gray)
|
||||
// WB: GND (active hold — unused transition)
|
||||
const uint8_t lut_x3_vcom_gray[] PROGMEM = {
|
||||
0x00, 0x03, 0x02, 0x01, 0x01, 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};
|
||||
const uint8_t lut_x3_ww_gray[] PROGMEM = {
|
||||
// Dark gray: VS=0x20 → GND,VDL(2),GND,GND — brief pulse (sub-phase B)
|
||||
0x20, 0x03, 0x02, 0x01, 0x01, 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};
|
||||
const uint8_t lut_x3_bw_gray[] PROGMEM = {
|
||||
// Light gray: VS=0x80 → VDL(3),GND,GND,GND — subtle pulse (sub-phase A, TP0=3)
|
||||
0x80, 0x03, 0x02, 0x01, 0x01, 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};
|
||||
const uint8_t lut_x3_wb_gray[] PROGMEM = {
|
||||
// Active GND hold: VS=0x00 → all GND, matching timing
|
||||
0x00, 0x03, 0x02, 0x01, 0x01, 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};
|
||||
const uint8_t lut_x3_bb_gray[] PROGMEM = {
|
||||
// Active GND hold: VS=0x00 → all GND, matching timing
|
||||
0x00, 0x03, 0x02, 0x01, 0x01, 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};
|
||||
|
||||
@@ -1014,14 +1047,14 @@ void EInkDisplay::displayGrayBuffer(const bool turnOffScreen) {
|
||||
}
|
||||
};
|
||||
|
||||
const uint8_t* vcom = lut_x3_vcom_full;
|
||||
const uint8_t* ww = lut_x3_ww_full;
|
||||
const uint8_t* bw = lut_x3_bw_full;
|
||||
const uint8_t* wb = lut_x3_wb_full;
|
||||
const uint8_t* bb = lut_x3_bb_full;
|
||||
const uint8_t* vcom = lut_x3_vcom_gray;
|
||||
const uint8_t* ww = lut_x3_ww_gray;
|
||||
const uint8_t* bw = lut_x3_bw_gray;
|
||||
const uint8_t* wb = lut_x3_wb_gray;
|
||||
const uint8_t* bb = lut_x3_bb_gray;
|
||||
uint8_t dataInterval0 = 0x29;
|
||||
uint8_t dataInterval1 = 0x07;
|
||||
if (Serial) Serial.printf("[%lu] X3_GRAY_MODE=full29\n", millis());
|
||||
if (Serial) Serial.printf("[%lu] X3_GRAY_MODE=gray_tuned\n", millis());
|
||||
sendCommandDataX3(0x20, vcom, 42);
|
||||
sendCommandDataX3(0x21, ww, 42);
|
||||
sendCommandDataX3(0x22, bw, 42);
|
||||
|
||||
Reference in New Issue
Block a user