Skip to content

Commit d0c7936

Browse files
committed
Create SetVCOM.ino
1 parent fbfebfe commit d0c7936

File tree

1 file changed

+259
-0
lines changed

1 file changed

+259
-0
lines changed
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
/**
2+
**************************************************
3+
*
4+
* @file SetVCOM_Inkplate10.ino
5+
* @brief WARNING! - VCOM voltage is written in EEPROM, which means it can be
6+
* set a limited number of times, so don't run this sketch repeatedly!
7+
* VCOM should be set once and then left as is.
8+
*
9+
* This example:
10+
* - Reads the current VCOM value from the panel
11+
* - Shows it on screen with a grayscale test pattern (LVGL)
12+
* - Lets you type a new VCOM value over Serial ([-5.00, 0.00] V)
13+
* - Programs it into the panel EEPROM (and stores it in ESP32 EEPROM too)
14+
*
15+
* For info on how to quickly get started with Inkplate 10 visit:
16+
* https://soldered.com/documentation/inkplate/10/overview/
17+
*
18+
* WARNING: Each VCOM write wears panel EEPROM. Use sparingly.
19+
*
20+
* @authors Soldered
21+
* @date November 2025
22+
***************************************************/
23+
24+
#if !defined(ARDUINO_INKPLATE10) && !defined(ARDUINO_INKPLATE10V2)
25+
#error "Wrong board selection for this example, please select e-radionica Inkplate10 or Soldered Inkplate10 in the boards menu."
26+
#endif
27+
28+
#include <EEPROM.h>
29+
#include <Inkplate-LVGL.h>
30+
#include <Wire.h>
31+
32+
// Inkplate 10 in 3-bit grayscale mode
33+
Inkplate inkplate(INKPLATE_3BIT);
34+
35+
double currentVCOM; // Stores the current VCOM value read from panel
36+
const int EEPROMAddress = 0; // Keep address 0 for correct VCOM storage in ESP32 EEPROM
37+
double vcomVoltage;
38+
39+
// Forward declarations
40+
double readPanelVCOM();
41+
double getVCOMFromSerial(double *_vcom);
42+
uint8_t writeVCOMToEEPROM(double v);
43+
static inline int display_width();
44+
static inline int display_height();
45+
void displayTestImage();
46+
void writeReg(uint8_t reg, float data);
47+
uint8_t readReg(uint8_t reg);
48+
49+
void setup()
50+
{
51+
Serial.begin(115200); // Start serial at 115200 baud
52+
EEPROM.begin(512); // Initialize ESP32 EEPROM
53+
Wire.begin(); // Initialize I2C bus
54+
inkplate.begin(); // Initialize Inkplate + LVGL backend
55+
56+
Serial.println("The optimal VCOM Voltage for your Inkplate's panel can sometimes");
57+
Serial.println("be found written on the flat cable connector.");
58+
Serial.println("Write VCOM voltage from epaper panel.");
59+
Serial.println("Don't forget negative (-) sign!");
60+
Serial.println("Use dot as the decimal point.");
61+
Serial.println("For example: -1.23");
62+
Serial.println();
63+
64+
// First screen: current VCOM + grayscale bars
65+
displayTestImage();
66+
}
67+
68+
void loop()
69+
{
70+
if (Serial.available())
71+
{
72+
// Read VCOM from Serial until it's in range [-5.0, 0.0]
73+
do
74+
{
75+
getVCOMFromSerial(&vcomVoltage);
76+
Serial.println(vcomVoltage, 2);
77+
78+
if (vcomVoltage < -5.0 || vcomVoltage > 0.0)
79+
{
80+
Serial.println("VCOM out of range! [-5.0, 0.0]");
81+
}
82+
} while (vcomVoltage < -5.0 || vcomVoltage > 0.0);
83+
84+
// Program the panel EEPROM
85+
// Internal IO pin 6 is used as the TPS65186 VCOM programming status pin
86+
inkplate.internalIO.pinMode(6, INPUT_PULLUP);
87+
88+
if (writeVCOMToEEPROM(vcomVoltage))
89+
{
90+
EEPROM.put(EEPROMAddress, vcomVoltage);
91+
EEPROM.commit();
92+
}
93+
94+
// Clear LVGL screen and redraw test image with updated VCOM value
95+
lv_obj_clean(lv_scr_act());
96+
displayTestImage();
97+
}
98+
}
99+
100+
// ----- VCOM helpers -----
101+
102+
double readPanelVCOM()
103+
{
104+
delay(10); // Give TPS65186 time so registers respond
105+
uint8_t vcomL = readReg(0x03); // Low 8 bits from register 0x03
106+
uint8_t vcomH = readReg(0x04) & 0x01; // Mask bit 0 (MSB of raw)
107+
delay(10);
108+
int raw = (vcomH << 8) | vcomL; // 0 .. 511
109+
return -(raw / 100.0); // VCOM in volts (negative)
110+
}
111+
112+
double getVCOMFromSerial(double *_vcom)
113+
{
114+
double vcom = 0;
115+
char buff[32];
116+
unsigned long start;
117+
118+
// Wait for first char
119+
while (!Serial.available())
120+
;
121+
122+
start = millis();
123+
int idx = 0;
124+
125+
// Collect characters for up to 500 ms idle gap
126+
while ((millis() - start) < 500 && idx < (int)sizeof(buff) - 1)
127+
{
128+
if (Serial.available())
129+
{
130+
char c = Serial.read();
131+
buff[idx++] = c;
132+
start = millis();
133+
}
134+
}
135+
136+
buff[idx] = '\0';
137+
sscanf(buff, "%lf", &vcom);
138+
*_vcom = vcom;
139+
return vcom;
140+
}
141+
142+
uint8_t writeVCOMToEEPROM(double v)
143+
{
144+
// Build a 9-bit raw value (0 - 511)
145+
int raw = int(abs(v) * 100) & 0x1FF;
146+
uint8_t lsb = raw & 0xFF;
147+
uint8_t msb = (raw >> 8) & 0x01;
148+
149+
// NOTE: With Inkplate-LVGL, power control is handled internally.
150+
// We assume the TPS65186 is powered from inkplate.begin().
151+
152+
writeReg(0x03, lsb);
153+
uint8_t r4 = readReg(0x04) & ~0x01;
154+
writeReg(0x04, r4 | msb);
155+
// Set bit 6 to trigger EEPROM programming
156+
writeReg(0x04, (r4 | msb) | (1 << 6));
157+
158+
// Wait for VCOM programming to finish
159+
while (inkplate.internalIO.digitalRead(6))
160+
{
161+
delay(1);
162+
}
163+
164+
// Clear interrupt flag and clean registers
165+
readReg(0x07); // clear interrupt flag
166+
writeReg(0x03, 0);
167+
writeReg(0x04, 0);
168+
169+
// We skip explicit einkOff/einkOn here because those are private
170+
// in the LVGL Inkplate10 driver and the driver takes care of power.
171+
172+
// Verify written value
173+
uint8_t vL = readReg(0x03);
174+
uint8_t vH = readReg(0x04) & 0x01;
175+
int check = (vH << 8) | vL;
176+
177+
if (check != raw)
178+
{
179+
Serial.printf("Verification failed: got %d, want %d\n", check, raw);
180+
return 0;
181+
}
182+
183+
Serial.println("VCOM EEPROM PROGRAMMING OK");
184+
return 1;
185+
}
186+
187+
// ----- TPS65186 I2C access -----
188+
189+
void writeReg(uint8_t reg, float data)
190+
{
191+
Wire.beginTransmission(0x48);
192+
Wire.write(reg);
193+
Wire.write((uint8_t)data);
194+
Wire.endTransmission();
195+
}
196+
197+
uint8_t readReg(uint8_t reg)
198+
{
199+
Wire.beginTransmission(0x48);
200+
Wire.write(reg);
201+
Wire.endTransmission(false);
202+
Wire.requestFrom((uint8_t)0x48, (uint8_t)1);
203+
return Wire.read();
204+
}
205+
206+
// ----- LVGL helpers -----
207+
208+
static inline int display_width()
209+
{
210+
lv_display_t *disp = lv_disp_get_default();
211+
return lv_display_get_horizontal_resolution(disp);
212+
}
213+
214+
static inline int display_height()
215+
{
216+
lv_display_t *disp = lv_disp_get_default();
217+
return lv_display_get_vertical_resolution(disp);
218+
}
219+
220+
void displayTestImage()
221+
{
222+
inkplate.clearDisplay();
223+
currentVCOM = readPanelVCOM();
224+
225+
// Top text: "Current VCOM: <value> V"
226+
lv_obj_t *label = lv_label_create(lv_screen_active());
227+
lv_label_set_text(label, "Current VCOM: ");
228+
lv_obj_set_style_text_color(lv_screen_active(), lv_color_hex(0x000000), LV_PART_MAIN);
229+
lv_obj_set_style_text_font(label, &lv_font_montserrat_28, 0);
230+
lv_obj_align(label, LV_ALIGN_TOP_LEFT, 5, 5);
231+
232+
lv_obj_t *label2 = lv_label_create(lv_scr_act());
233+
String vcomText = String(currentVCOM, 2) + " V";
234+
lv_label_set_text(label2, vcomText.c_str());
235+
lv_obj_set_style_text_color(label2, lv_color_hex(0x000000), 0);
236+
lv_obj_set_style_text_font(label2, &lv_font_montserrat_28, 0);
237+
lv_obj_align_to(label2, label, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
238+
239+
// Grayscale gradient bars across the screen
240+
for (int i = 0; i < 8; i++)
241+
{
242+
int x = (display_width() / 8) * i;
243+
244+
uint8_t v = (i * 255) / 7;
245+
lv_color_t color = lv_color_make(v, v, v);
246+
247+
lv_obj_t *rect = lv_obj_create(lv_scr_act());
248+
lv_obj_set_size(rect, display_width() / 8, display_height());
249+
lv_obj_set_pos(rect, x, 40);
250+
lv_obj_set_style_bg_color(rect, color, 0);
251+
lv_obj_set_style_border_width(rect, 0, 0);
252+
lv_obj_set_style_radius(rect, 0, 0);
253+
}
254+
255+
// Push LVGL buffer to the e-paper
256+
lv_tick_inc(50);
257+
lv_timer_handler();
258+
inkplate.display();
259+
}

0 commit comments

Comments
 (0)