Skip to content

Commit 0ddcb73

Browse files
committed
Update SetVCOM.ino
1 parent d0c7936 commit 0ddcb73

File tree

1 file changed

+138
-195
lines changed

1 file changed

+138
-195
lines changed
Lines changed: 138 additions & 195 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,28 @@
11
/**
22
**************************************************
33
*
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)
4+
* @file SetVCOM.ino
5+
* @brief WARNING! - VCOM voltage is written in EEPROM, which means it can be set a limited number of times,
6+
* so don't run this sketch repeateadly! VCOM should be set once and then left as is.
147
*
158
* For info on how to quickly get started with Inkplate 10 visit:
169
* https://soldered.com/documentation/inkplate/10/overview/
1710
*
18-
* WARNING: Each VCOM write wears panel EEPROM. Use sparingly.
19-
*
2011
* @authors Soldered
2112
* @date November 2025
2213
***************************************************/
2314

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
2715

2816
#include <EEPROM.h>
2917
#include <Inkplate-LVGL.h>
3018
#include <Wire.h>
3119

32-
// Inkplate 10 in 3-bit grayscale mode
33-
Inkplate inkplate(INKPLATE_3BIT);
20+
Inkplate inkplate(INKPLATE_3BIT); // Create an object on Inkplate library and also set the grayscale to 3bit.
3421

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
22+
double currentVCOM; // Stores the current VCOM value stored on EEPROM
23+
const int EEPROMAddress=0; // Should leave the address as it is for correct EEPROM reading later
3724
double vcomVoltage;
3825

39-
// Forward declarations
4026
double readPanelVCOM();
4127
double getVCOMFromSerial(double *_vcom);
4228
uint8_t writeVCOMToEEPROM(double v);
@@ -46,214 +32,171 @@ void displayTestImage();
4632
void writeReg(uint8_t reg, float data);
4733
uint8_t readReg(uint8_t reg);
4834

49-
void setup()
35+
void setup()
5036
{
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();
37+
Serial.begin(115200); //Start serial at 115200 baud
38+
EEPROM.begin(512); //Initialize EEPROM
39+
Wire.begin(); //Initialize I2C buss
40+
inkplate.begin(); //Initialize the Inkplate
41+
Serial.println("The optimal VCOM Voltage for your Inkplate's panel can sometimes be found written on the flat cable connector");
42+
Serial.println("Write VCOM voltage from epaper panel. \r\nDon't forget negative (-) sign!\r\nUse dot as the decimal point.\r\nFor example -1.23\n");
43+
displayTestImage();
6644
}
6745

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();
46+
void loop()
47+
{
48+
if (Serial.available()){
49+
//Serial.println("Enter VCOM value, it must be [-5, 0]");
50+
do{
51+
getVCOMFromSerial(&vcomVoltage);
52+
Serial.println(vcomVoltage, 2);
53+
if(vcomVoltage < -5.0 || vcomVoltage > 0.0){
54+
Serial.println("VCOM out of range! [-5, 0]");
55+
}
56+
}while(vcomVoltage <-5.0 || vcomVoltage > 0.0);
57+
58+
//Program the panel EEPROM
59+
inkplate.internalIO.pinMode(6, INPUT_PULLUP);
60+
if(writeVCOMToEEPROM(vcomVoltage)){
61+
EEPROM.put(EEPROMAddress, vcomVoltage);
62+
EEPROM.commit();
9763
}
64+
lv_obj_clean(lv_scr_act());
65+
displayTestImage();
66+
}
9867
}
9968

100-
// ----- VCOM helpers -----
101-
10269
double readPanelVCOM()
10370
{
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)
71+
delay(10); //Wake up TPS65186 so registers respond
72+
uint8_t vcomL=readReg(0x03); // Read low 8 bits from register 0x03
73+
uint8_t vcomH = readReg(0x04) & 0x01; // Read full byte, mask off all but bit 0 (MSB)
74+
delay(10); //Power down driver
75+
int raw=(vcomH << 8) | vcomL; //Value between 0 - 511
76+
return -(raw/100.0);
11077
}
11178

11279
double getVCOMFromSerial(double *_vcom)
11380
{
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-
}
81+
double vcom=0;
82+
char buff[32];
83+
unsigned long start;
84+
while (!Serial.available());
85+
start=millis();
86+
int idx=0;
87+
while ((millis()-start)<500 && idx<sizeof(buff)-1){
88+
if(Serial.available()){
89+
char c=Serial.read();
90+
buff[idx++]=c;
91+
start=millis();
13492
}
135-
136-
buff[idx] = '\0';
137-
sscanf(buff, "%lf", &vcom);
138-
*_vcom = vcom;
139-
return vcom;
93+
}
94+
buff[idx]='\0';
95+
sscanf(buff, "%lf", &vcom);
96+
*_vcom=vcom;
97+
return vcom;
14098
}
14199

142100
uint8_t writeVCOMToEEPROM(double v)
143101
{
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;
102+
//Build a 9-bit raw value (0 - 511)
103+
int raw=int(abs(v)*100)&0x1FF;
104+
uint8_t lsb=raw & 0xFF;
105+
uint8_t msb=(raw >> 8)&0x01;
106+
107+
inkplate.einkOn();
108+
delay(10);
109+
110+
writeReg(0x03, lsb);
111+
uint8_t r4=readReg(0x04)&~0x01;
112+
writeReg(0x04, r4 | msb);
113+
writeReg(0x04, (r4 | msb) | (1 << 6));
114+
while ( inkplate.internalIO.digitalRead(6) ) {
115+
delay(1);
116+
}
117+
readReg(0x07); // clear interrupt flag
118+
writeReg(0x03, 0);
119+
writeReg(0x04, 0);
120+
inkplate.einkOff(); // WAKEUP low
121+
delay(10);
122+
inkplate.einkOn(); // WAKEUP high
123+
delay(10);
124+
uint8_t vL = readReg(0x03);
125+
uint8_t vH = readReg(0x04) & 0x01;
126+
int check = (vH << 8) | vL;
127+
if (check != raw) {
128+
Serial.printf("Verification failed: got %d, want %d\n", check, raw);
129+
return 0;
130+
}
131+
Serial.println("VCOM EEPROM PROGRAMMING OK");
132+
return 1;
185133
}
186134

187-
// ----- TPS65186 I2C access -----
188-
189135
void writeReg(uint8_t reg, float data)
190136
{
191-
Wire.beginTransmission(0x48);
192-
Wire.write(reg);
193-
Wire.write((uint8_t)data);
194-
Wire.endTransmission();
137+
Wire.beginTransmission(0x48);
138+
Wire.write(reg);
139+
Wire.write((uint8_t)data);
140+
Wire.endTransmission();
195141
}
196142

197143
uint8_t readReg(uint8_t reg)
198144
{
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();
145+
Wire.beginTransmission(0x48);
146+
Wire.write(reg);
147+
Wire.endTransmission(false);
148+
Wire.requestFrom((uint8_t)0x48, (uint8_t)1);
149+
return Wire.read();
204150
}
205151

206-
// ----- LVGL helpers -----
207-
208152
static inline int display_width()
209153
{
210-
lv_display_t *disp = lv_disp_get_default();
211-
return lv_display_get_horizontal_resolution(disp);
154+
lv_display_t *disp = lv_disp_get_default();
155+
return lv_display_get_horizontal_resolution(disp);
212156
}
213157

214158
static inline int display_height()
215159
{
216-
lv_display_t *disp = lv_disp_get_default();
217-
return lv_display_get_vertical_resolution(disp);
160+
lv_display_t *disp = lv_disp_get_default();
161+
return lv_display_get_vertical_resolution(disp);
218162
}
219163

220-
void displayTestImage()
164+
void displayTestImage()
221165
{
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-
}
166+
inkplate.clearDisplay();
167+
currentVCOM = readPanelVCOM();
168+
169+
/* Show text on the screen */
170+
lv_obj_t *label = lv_label_create(lv_screen_active());
171+
lv_label_set_text(label, "Current VCOM: ");
172+
lv_obj_set_style_text_color(lv_screen_active(), lv_color_hex(0x000000), LV_PART_MAIN);
173+
lv_obj_set_style_text_font(label, &lv_font_montserrat_28, 0);
174+
lv_obj_align(label, LV_ALIGN_TOP_LEFT, 5, 5);
175+
176+
/* Display value */
177+
lv_obj_t *label2 = lv_label_create(lv_scr_act());
178+
lv_label_set_text(label2, String(currentVCOM, 2).c_str());
179+
lv_obj_set_style_text_color(label2, lv_color_hex(0x000000), 0);
180+
lv_obj_set_style_text_font(label2, &lv_font_montserrat_28, 0);
181+
// Position label2 just to the right of label1
182+
lv_obj_align_to(label2, label, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
183+
184+
for (int i = 0; i < 8; i++)
185+
{
186+
int x = (display_width() / 8) * i;
187+
188+
uint8_t v = (i * 255) / 7;
189+
lv_color_t color = lv_color_make(v, v, v);
190+
191+
lv_obj_t *rect = lv_obj_create(lv_scr_act());
192+
lv_obj_set_size(rect, display_width() / 8, display_height());
193+
lv_obj_set_pos(rect, x, 40);
194+
lv_obj_set_style_bg_color(rect, color, 0);
195+
lv_obj_set_style_border_width(rect, 0, 0); // Remove 'padding'
196+
lv_obj_set_style_radius(rect, 0, 0); // No round corners
197+
}
198+
// Update the display
199+
lv_tick_inc(50);
200+
lv_timer_handler();
201+
inkplate.display();
202+
}

0 commit comments

Comments
 (0)